From 6a035578017935304c77ac8821a5dc5d49f3d3cf Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 23 Jan 2018 14:44:10 -0800 Subject: [PATCH 01/25] don't override sensorToWorldMatrix --- interface/src/avatar/MyAvatar.cpp | 10 ++++++---- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e93b897013..2943cf7fd8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1790,7 +1790,7 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) { updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes } -void MyAvatar::initAnimGraph() { +void MyAvatar::initAnimGraph(bool updateBodySensorMat) { QUrl graphUrl; if (!_prefOverrideAnimGraphUrl.get().isEmpty()) { graphUrl = _prefOverrideAnimGraphUrl.get(); @@ -1803,8 +1803,10 @@ void MyAvatar::initAnimGraph() { _skeletonModel->getRig().initAnimGraph(graphUrl); _currentAnimGraphUrl.set(graphUrl); - _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. - updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + if (updateBodySensorMat) { + _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. + updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + } } void MyAvatar::destroyAnimGraph() { @@ -1819,7 +1821,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); - initAnimGraph(); + initAnimGraph(false); _isAnimatingScale = true; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 58b49b61ff..cdcd6f4607 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -730,7 +730,7 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void initHeadBones(); - void initAnimGraph(); + void initAnimGraph(bool updateBodySensorMat = true); // Avatar Preferences QUrl _fullAvatarURLFromPreferences; From 2cbcc28bd4c860a45e0e050ae959537c6b795a02 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 24 Jan 2018 10:44:04 -0800 Subject: [PATCH 02/25] only call init animGraph once --- interface/src/avatar/MyAvatar.cpp | 27 +++++++++++++++------------ interface/src/avatar/MyAvatar.h | 4 +++- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1475860665..5f2cbf92b2 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1785,12 +1785,10 @@ void MyAvatar::setAnimGraphUrl(const QUrl& url) { _currentAnimGraphUrl.set(url); _skeletonModel->getRig().initAnimGraph(url); - - _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. - updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); } -void MyAvatar::initAnimGraph(bool updateBodySensorMat) { +void MyAvatar::initAnimGraph() { QUrl graphUrl; if (!_prefOverrideAnimGraphUrl.get().isEmpty()) { graphUrl = _prefOverrideAnimGraphUrl.get(); @@ -1802,27 +1800,32 @@ void MyAvatar::initAnimGraph(bool updateBodySensorMat) { _skeletonModel->getRig().initAnimGraph(graphUrl); _currentAnimGraphUrl.set(graphUrl); - - if (updateBodySensorMat) { - _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. - updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes - } + connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); } void MyAvatar::destroyAnimGraph() { _skeletonModel->getRig().destroyAnimGraph(); } +void MyAvatar::animGraphLoaded() { + _bodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. + updateSensorToWorldMatrix(); // Uses updated position/orientation and _bodySensorMatrix changes + _isAnimatingScale = true; + disconnect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); +} + void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { Avatar::postUpdate(deltaTime, scene); - if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode()) { + if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode() && _initHeadBones) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); - initAnimGraph(false); - _isAnimatingScale = true; + initAnimGraph(); + _initHeadBones = false; + } else if (!_skeletonModel->isLoaded()) { + _initHeadBones = true; } if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index cdcd6f4607..6a9e0e6a38 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -566,6 +566,7 @@ public slots: void increaseSize(); void decreaseSize(); void resetSize(); + void animGraphLoaded(); void setGravity(float gravity); float getGravity(); @@ -730,7 +731,7 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void initHeadBones(); - void initAnimGraph(bool updateBodySensorMat = true); + void initAnimGraph(); // Avatar Preferences QUrl _fullAvatarURLFromPreferences; @@ -808,6 +809,7 @@ private: bool _enableDebugDrawIKConstraints { false }; bool _enableDebugDrawIKChains { false }; bool _enableDebugDrawDetailedCollision { false }; + bool _initHeadBones { false }; AudioListenerMode _audioListenerMode; glm::vec3 _customListenPosition; From b7ba7862aa929a501a7fec542974d6ce3ebb4d5c Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 24 Jan 2018 11:18:42 -0800 Subject: [PATCH 03/25] give animGrapgh loader a high priority --- libraries/animation/src/AnimNodeLoader.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/animation/src/AnimNodeLoader.cpp b/libraries/animation/src/AnimNodeLoader.cpp index 33f3d72756..8173845205 100644 --- a/libraries/animation/src/AnimNodeLoader.cpp +++ b/libraries/animation/src/AnimNodeLoader.cpp @@ -38,6 +38,8 @@ static AnimNode::Pointer loadManipulatorNode(const QJsonObject& jsonObj, const Q static AnimNode::Pointer loadInverseKinematicsNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); static AnimNode::Pointer loadDefaultPoseNode(const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl); +static const float ANIM_GRAPH_LOAD_PRIORITY = 10.0f; + // called after children have been loaded // returns node on success, nullptr on failure. static bool processDoNothing(AnimNode::Pointer node, const QJsonObject& jsonObj, const QString& id, const QUrl& jsonUrl) { return true; } @@ -653,6 +655,7 @@ AnimNodeLoader::AnimNodeLoader(const QUrl& url) : { _resource = QSharedPointer::create(url); _resource->setSelf(_resource); + _resource->setLoadPriority(this, ANIM_GRAPH_LOAD_PRIORITY); connect(_resource.data(), &Resource::loaded, this, &AnimNodeLoader::onRequestDone); connect(_resource.data(), &Resource::failed, this, &AnimNodeLoader::onRequestError); _resource->ensureLoading(); From 5a771e3a168357708d646dcba70c79ceb7eb4cb4 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 26 Jan 2018 17:08:53 -0500 Subject: [PATCH 04/25] [Case 10865] Ctrl/Cmd/Shift+Click Multi-Select for Asset Browser. * Removes manual selectionModel update from controls-uit/Tree.qml * This was interfering with the Key+Click functionality. It was introduced via Commit 99617600c47 to address a selection issue; however, it's unclear what that issue was. Selection within the Asset Browser works without it at present. * Amends the ContextMenu within the AssetBrowser to work in conjunction with the multi-selection changes. * ContextMenu will _only_ display when triggered within the current selection be it one or more items as opposed to previous behavior of selecting the item the menu was triggered on. * CopyURL is only enabled when the selection size is 1 * Rename is only enabled when the selection size is 1 * Delete is enabled when the selection size is greater than 0 Changes Committed: modified: interface/resources/qml/controls-uit/Tree.qml modified: interface/resources/qml/hifi/AssetServer.qml --- interface/resources/qml/controls-uit/Tree.qml | 4 -- interface/resources/qml/hifi/AssetServer.qml | 41 +++++++++++-------- 2 files changed, 25 insertions(+), 20 deletions(-) diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml index 6bd11295b1..5199a10a27 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -202,8 +202,4 @@ TreeView { } onDoubleClicked: isExpanded(index) ? collapse(index) : expand(index) - - onClicked: { - selectionModel.setCurrentIndex(index, ItemSelectionModel.ClearAndSelect); - } } diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 37c3c2adab..7c16b19865 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -694,7 +694,7 @@ Windows.ScrollingWindow { } } } - } + }// End_OF( itemLoader ) Rectangle { id: treeLabelToolTip @@ -731,50 +731,59 @@ Windows.ScrollingWindow { showTimer.stop(); treeLabelToolTip.visible = false; } - } + }// End_OF( treeLabelToolTip ) MouseArea { propagateComposedEvents: true anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - if (!HMD.active) { // Popup only displays properly on desktop - var index = treeView.indexAt(mouse.x, mouse.y); - treeView.selection.setCurrentIndex(index, 0x0002); - contextMenu.currentIndex = index; - contextMenu.popup(); + if (treeView.selection.hasSelection && !HMD.active) { // Popup only displays properly on desktop + // Only display the popup if the click triggered within + // the selection. + var clickedIndex = treeView.indexAt(mouse.x, mouse.y); + var displayContextMenu = false; + for ( var i = 0; i < selectedItems; ++i) { + var currentSelectedIndex = treeView.selection.selectedIndexes[i]; + if (clickedIndex === currentSelectedIndex) { + contextMenu.popup(); + break; + } + } } } } - + Menu { id: contextMenu title: "Edit" property var url: "" - property var currentIndex: null MenuItem { text: "Copy URL" + enabled: (selectedItems == 1) onTriggered: { - copyURLToClipboard(contextMenu.currentIndex); + copyURLToClipboard(treeView.selection.currentIndex); } } MenuItem { text: "Rename" + enabled: (selectedItems == 1) onTriggered: { - renameFile(contextMenu.currentIndex); + renameFile(treeView.selection.currentIndex); } } MenuItem { text: "Delete" + enabled: (selectedItems > 0) onTriggered: { - deleteFile(contextMenu.currentIndex); + deleteFile(); } } - } - } + }// End_OF( contextMenu ) + }// End_OF( treeView ) Row { id: infoRow @@ -885,7 +894,7 @@ Windows.ScrollingWindow { "Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors."); } } - } + }// End_OF( infoRow ) HifiControls.ContentSection { id: uploadSection @@ -945,7 +954,7 @@ Windows.ScrollingWindow { } } } - } + }// End_OF( uploadSection ) } } From dfdf28f37e4572bb95b6354be850356ad8bffa27 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Fri, 26 Jan 2018 17:34:05 -0500 Subject: [PATCH 05/25] [Case 10865] Some cleanup for multi-selection (details below). * Remove setCurrentIndex call when looping over current selection. * Changed selectedItems var name to selectedItemCount to clarify what it represents. * Change path arg name to paths to clarify that there can be more than a single path contained within it. Changes Committed: modified: interface/resources/qml/hifi/AssetServer.qml --- interface/resources/qml/hifi/AssetServer.qml | 49 ++++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 7c16b19865..30f76fecd6 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -37,7 +37,7 @@ Windows.ScrollingWindow { property var assetProxyModel: Assets.proxyModel; property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; - property var selectedItems: treeView.selection.selectedIndexes.length; + property var selectedItemCount: treeView.selection.selectedIndexes.length; Settings { category: "Overlay.AssetServer" @@ -75,17 +75,17 @@ Windows.ScrollingWindow { }); } - function doDeleteFile(path) { - console.log("Deleting " + path); + function doDeleteFile(paths) { + console.log("Deleting " + paths); - Assets.deleteMappings(path, function(err) { + Assets.deleteMappings(paths, function(err) { if (err) { - console.log("Asset browser - error deleting path: ", path, err); + console.log("Asset browser - error deleting paths: ", paths, err); - box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err); + box = errorMessageBox("There was an error deleting:\n" + paths + "\n" + err); box.selected.connect(reload); } else { - console.log("Asset browser - finished deleting path: ", path); + console.log("Asset browser - finished deleting paths: ", paths); reload(); } }); @@ -145,7 +145,7 @@ Windows.ScrollingWindow { function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - if (selectedItems > 1) { + if (selectedItemCount > 1) { return false; } @@ -155,7 +155,7 @@ Windows.ScrollingWindow { } function canRename() { - if (treeView.selection.hasSelection && selectedItems == 1) { + if (treeView.selection.hasSelection && selectedItemCount == 1) { return true; } else { return false; @@ -333,29 +333,28 @@ Windows.ScrollingWindow { }); } function deleteFile(index) { - var path = []; + var paths = []; if (!index) { - for (var i = 0; i < selectedItems; i++) { - treeView.selection.setCurrentIndex(treeView.selection.selectedIndexes[i], 0x100); - index = treeView.selection.currentIndex; - path[i] = assetProxyModel.data(index, 0x100); + for (var i = 0; i < selectedItemCount; ++i) { + index = treeView.selection.selectedIndexes[i]; + paths[i] = assetProxyModel.data(index, 0x100); } } - if (!path) { + if (!paths) { return; } var modalMessage = ""; - var items = selectedItems.toString(); + var items = selectedItemCount.toString(); var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; - if (selectedItems > 1) { + if (selectedItemCount > 1) { modalMessage = "You are about to delete " + items + " items \nDo you want to continue?"; } else { - modalMessage = "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"; + modalMessage = "You are about to delete the following " + typeString + ":\n" + paths + "\nDo you want to continue?"; } var object = desktop.messageBox({ @@ -367,7 +366,7 @@ Windows.ScrollingWindow { }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { - doDeleteFile(path); + doDeleteFile(paths); } }); } @@ -743,7 +742,7 @@ Windows.ScrollingWindow { // the selection. var clickedIndex = treeView.indexAt(mouse.x, mouse.y); var displayContextMenu = false; - for ( var i = 0; i < selectedItems; ++i) { + for ( var i = 0; i < selectedItemCount; ++i) { var currentSelectedIndex = treeView.selection.selectedIndexes[i]; if (clickedIndex === currentSelectedIndex) { contextMenu.popup(); @@ -761,7 +760,7 @@ Windows.ScrollingWindow { MenuItem { text: "Copy URL" - enabled: (selectedItems == 1) + enabled: (selectedItemCount == 1) onTriggered: { copyURLToClipboard(treeView.selection.currentIndex); } @@ -769,7 +768,7 @@ Windows.ScrollingWindow { MenuItem { text: "Rename" - enabled: (selectedItems == 1) + enabled: (selectedItemCount == 1) onTriggered: { renameFile(treeView.selection.currentIndex); } @@ -777,7 +776,7 @@ Windows.ScrollingWindow { MenuItem { text: "Delete" - enabled: (selectedItems > 0) + enabled: (selectedItemCount > 0) onTriggered: { deleteFile(); } @@ -796,8 +795,8 @@ Windows.ScrollingWindow { function makeText() { var numPendingBakes = assetMappingsModel.numPendingBakes; - if (selectedItems > 1 || numPendingBakes === 0) { - return selectedItems + " items selected"; + if (selectedItemCount > 1 || numPendingBakes === 0) { + return selectedItemCount + " items selected"; } else { return numPendingBakes + " bakes pending" } From 70e23f3ce86f5837f24eaea39c422aeea23c64f0 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 30 Jan 2018 14:00:09 -0500 Subject: [PATCH 06/25] [Case 10865] Bringing in multi-select fix from Desktop AssetServer. Changes Committed: modified: interface/resources/qml/hifi/dialogs/TabletAssetServer.qml --- .../qml/hifi/dialogs/TabletAssetServer.qml | 82 ++++++++++--------- 1 file changed, 45 insertions(+), 37 deletions(-) diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index a02496a252..9c61206592 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -39,7 +39,7 @@ Rectangle { property var assetProxyModel: Assets.proxyModel; property var assetMappingsModel: Assets.mappingModel; property var currentDirectory; - property var selectedItems: treeView.selection.selectedIndexes.length; + property var selectedItemCount: treeView.selection.selectedIndexes.length; Settings { category: "Overlay.AssetServer" @@ -76,17 +76,17 @@ Rectangle { }); } - function doDeleteFile(path) { - console.log("Deleting " + path); + function doDeleteFile(paths) { + console.log("Deleting " + paths); - Assets.deleteMappings(path, function(err) { + Assets.deleteMappings(paths, function(err) { if (err) { - console.log("Asset browser - error deleting path: ", path, err); + console.log("Asset browser - error deleting paths: ", paths, err); - box = errorMessageBox("There was an error deleting:\n" + path + "\n" + err); + box = errorMessageBox("There was an error deleting:\n" + paths + "\n" + err); box.selected.connect(reload); } else { - console.log("Asset browser - finished deleting path: ", path); + console.log("Asset browser - finished deleting paths: ", paths); reload(); } }); @@ -146,7 +146,7 @@ Rectangle { function canAddToWorld(path) { var supportedExtensions = [/\.fbx\b/i, /\.obj\b/i]; - if (selectedItems > 1) { + if (selectedItemCount > 1) { return false; } @@ -156,7 +156,7 @@ Rectangle { } function canRename() { - if (treeView.selection.hasSelection && selectedItems == 1) { + if (treeView.selection.hasSelection && selectedItemCount == 1) { return true; } else { return false; @@ -334,29 +334,28 @@ Rectangle { }); } function deleteFile(index) { - var path = []; + var paths = []; if (!index) { - for (var i = 0; i < selectedItems; i++) { - treeView.selection.setCurrentIndex(treeView.selection.selectedIndexes[i], 0x100); - index = treeView.selection.currentIndex; - path[i] = assetProxyModel.data(index, 0x100); + for (var i = 0; i < selectedItemCount; ++i) { + index = treeView.selection.selectedIndexes[i]; + paths[i] = assetProxyModel.data(index, 0x100); } } - if (!path) { + if (!paths) { return; } var modalMessage = ""; - var items = selectedItems.toString(); + var items = selectedItemCount.toString(); var isFolder = assetProxyModel.data(treeView.selection.currentIndex, 0x101); var typeString = isFolder ? 'folder' : 'file'; - if (selectedItems > 1) { + if (selectedItemCount > 1) { modalMessage = "You are about to delete " + items + " items \nDo you want to continue?"; } else { - modalMessage = "You are about to delete the following " + typeString + ":\n" + path + "\nDo you want to continue?"; + modalMessage = "You are about to delete the following " + typeString + ":\n" + paths + "\nDo you want to continue?"; } var object = tabletRoot.messageBox({ @@ -368,7 +367,7 @@ Rectangle { }); object.selected.connect(function(button) { if (button === OriginalDialogs.StandardButton.Yes) { - doDeleteFile(path); + doDeleteFile(paths); } }); } @@ -693,7 +692,7 @@ Rectangle { } } } - } + }// End_OF( itemLoader ) Rectangle { id: treeLabelToolTip @@ -730,50 +729,59 @@ Rectangle { showTimer.stop(); treeLabelToolTip.visible = false; } - } + }// End_OF( treeLabelToolTip ) MouseArea { propagateComposedEvents: true anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - if (!HMD.active) { // Popup only displays properly on desktop - var index = treeView.indexAt(mouse.x, mouse.y); - treeView.selection.setCurrentIndex(index, 0x0002); - contextMenu.currentIndex = index; - contextMenu.popup(); + if (treeView.selection.hasSelection && !HMD.active) { // Popup only displays properly on desktop + // Only display the popup if the click triggered within + // the selection. + var clickedIndex = treeView.indexAt(mouse.x, mouse.y); + var displayContextMenu = false; + for ( var i = 0; i < selectedItemCount; ++i) { + var currentSelectedIndex = treeView.selection.selectedIndexes[i]; + if (clickedIndex === currentSelectedIndex) { + contextMenu.popup(); + break; + } + } } } } - + Menu { id: contextMenu title: "Edit" property var url: "" - property var currentIndex: null MenuItem { text: "Copy URL" + enabled: (selectedItemCount == 1) onTriggered: { - copyURLToClipboard(contextMenu.currentIndex); + copyURLToClipboard(treeView.selection.currentIndex); } } MenuItem { text: "Rename" + enabled: (selectedItemCount == 1) onTriggered: { - renameFile(contextMenu.currentIndex); + renameFile(treeView.selection.currentIndex); } } MenuItem { text: "Delete" + enabled: (selectedItemCount > 0) onTriggered: { - deleteFile(contextMenu.currentIndex); + deleteFile(); } } - } - } + }// End_OF( contextMenu ) + }// End_OF( treeView ) Row { id: infoRow @@ -786,8 +794,8 @@ Rectangle { function makeText() { var numPendingBakes = assetMappingsModel.numPendingBakes; - if (selectedItems > 1 || numPendingBakes === 0) { - return selectedItems + " items selected"; + if (selectedItemCount > 1 || numPendingBakes === 0) { + return selectedItemCount + " items selected"; } else { return numPendingBakes + " bakes pending" } @@ -884,7 +892,7 @@ Rectangle { "Baking compresses and optimizes files for faster network transfer and display. We recommend you bake your content to reduce initial load times for your visitors."); } } - } + }// End_OF( infoRow ) HifiControls.TabletContentSection { id: uploadSection @@ -961,7 +969,7 @@ Rectangle { } } } - } + }// End_OF( uploadSection ) } } From 22b33c7391a76afdb4dcef188404c0b7c56ee6a0 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Mon, 5 Feb 2018 11:22:40 +1300 Subject: [PATCH 07/25] Update Overlays circle3d JSDoc per recent code changes --- interface/src/ui/overlays/Circle3DOverlay.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 5e38f28a06..33f40f7c63 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -425,10 +425,10 @@ void Circle3DOverlay::setProperties(const QVariantMap& properties) { * Write-only. * @property {Color} outerColor - Sets the values of outerStartColor and outerEndColor. * Write-only. - * @property {Color} innerStartcolor - The color at the inner start point of the overlay. Write-only. - * @property {Color} innerEndColor - The color at the inner end point of the overlay. Write-only. - * @property {Color} outerStartColor - The color at the outer start point of the overlay. Write-only. - * @property {Color} outerEndColor - The color at the outer end point of the overlay. Write-only. + * @property {Color} innerStartcolor - The color at the inner start point of the overlay. + * @property {Color} innerEndColor - The color at the inner end point of the overlay. + * @property {Color} outerStartColor - The color at the outer start point of the overlay. + * @property {Color} outerEndColor - The color at the outer end point of the overlay. * @property {number} alpha=0.5 - The opacity of the overlay, 0.0 - 1.0. Setting this value also sets * the values of innerStartAlpha, innerEndAlpha, outerStartAlpha, and * outerEndAlpha. Synonym: Alpha; write-only. @@ -440,10 +440,10 @@ void Circle3DOverlay::setProperties(const QVariantMap& properties) { * Write-only. * @property {number} outerAlpha - Sets the values of outerStartAlpha and outerEndAlpha. * Write-only. - * @property {number} innerStartAlpha=0 - The alpha at the inner start point of the overlay. Write-only. - * @property {number} innerEndAlpha=0 - The alpha at the inner end point of the overlay. Write-only. - * @property {number} outerStartAlpha=0 - The alpha at the outer start point of the overlay. Write-only. - * @property {number} outerEndAlpha=0 - The alpha at the outer end point of the overlay. Write-only. + * @property {number} innerStartAlpha=0 - The alpha at the inner start point of the overlay. + * @property {number} innerEndAlpha=0 - The alpha at the inner end point of the overlay. + * @property {number} outerStartAlpha=0 - The alpha at the outer start point of the overlay. + * @property {number} outerEndAlpha=0 - The alpha at the outer end point of the overlay. * @property {boolean} hasTickMarks=false - If true, tick marks are drawn. * @property {number} majorTickMarksAngle=0 - The angle between major tick marks, in degrees. From e87067f93d0841312c540073b755100ceb458f48 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 5 Feb 2018 15:31:37 -0800 Subject: [PATCH 08/25] fix variable naming and edge case --- interface/src/avatar/MyAvatar.cpp | 10 ++++++---- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 516c601931..0ee409745f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1448,6 +1448,10 @@ void MyAvatar::clearJointsData() { } void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { + if (skeletonModelURL != _skeletonModelURL) { + _shouldInitHeadBones = true; + } + Avatar::setSkeletonModelURL(skeletonModelURL); _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); _headBoneSet.clear(); @@ -1893,14 +1897,12 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { Avatar::postUpdate(deltaTime, scene); - if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode() && _initHeadBones) { + if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode() && _shouldInitHeadBones) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); initAnimGraph(); - _initHeadBones = false; - } else if (!_skeletonModel->isLoaded()) { - _initHeadBones = true; + _shouldInitHeadBones = false; } if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 532eb06974..45dddb45a4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -817,7 +817,7 @@ private: bool _enableDebugDrawIKConstraints { false }; bool _enableDebugDrawIKChains { false }; bool _enableDebugDrawDetailedCollision { false }; - bool _initHeadBones { false }; + bool _shouldInitHeadBones { true }; mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state? From b6ac3484284f7d05e9322658bd281d91bdd95d1e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 7 Feb 2018 16:30:07 -0800 Subject: [PATCH 09/25] get children of animated entity joints to follow along, again --- .../entities-renderer/src/RenderableModelEntityItem.cpp | 9 +++++++++ libraries/shared/src/SpatiallyNestable.h | 8 ++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 137203f475..c8d22bb06c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -985,6 +985,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() { return; } + bool changed { false }; // relay any inbound joint changes from scripts/animation/network to the model/rig _jointDataLock.withWriteLock([&] { for (int index = 0; index < _localJointData.size(); ++index) { @@ -992,13 +993,21 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() { if (jointData.rotationDirty) { model->setJointRotation(index, true, jointData.joint.rotation, 1.0f); jointData.rotationDirty = false; + changed = true; } if (jointData.translationDirty) { model->setJointTranslation(index, true, jointData.joint.translation, 1.0f); jointData.translationDirty = false; + changed = true; } } }); + + if (changed) { + forEachChild([&](SpatiallyNestablePointer object) { + object->locationChanged(tellPhysics); + }); + } } using namespace render; diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 090ca4c266..5d4793ba4e 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -207,6 +207,10 @@ public: void dump(const QString& prefix = "") const; + virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed + virtual void dimensionsChanged() { _queryAACubeSet = false; } // called when a this object's dimensions have changed + virtual void parentDeleted() { } // called on children of a deleted parent + protected: const NestableType _nestableType; // EntityItem or an AvatarData QUuid _id; @@ -218,10 +222,6 @@ protected: mutable ReadWriteLockable _childrenLock; mutable QHash _children; - virtual void locationChanged(bool tellPhysics = true); // called when a this object's location has changed - virtual void dimensionsChanged() { _queryAACubeSet = false; } // called when a this object's dimensions have changed - virtual void parentDeleted() { } // called on children of a deleted parent - // _queryAACube is used to decide where something lives in the octree mutable AACube _queryAACube; mutable bool _queryAACubeSet { false }; From 31c2b8fea92c3b01ca9d8b379ee705205a1aebc5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 7 Feb 2018 16:31:38 -0800 Subject: [PATCH 10/25] oops --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c8d22bb06c..ca15382c71 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1005,7 +1005,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() { if (changed) { forEachChild([&](SpatiallyNestablePointer object) { - object->locationChanged(tellPhysics); + object->locationChanged(false); }); } } From 87f77b625784aac995379f76654b4b9e4c450317 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 22 Jan 2018 18:12:12 -0800 Subject: [PATCH 11/25] Asset Server Backup --- assignment-client/src/assets/AssetServer.cpp | 58 ++- assignment-client/src/assets/AssetServer.h | 20 +- .../src/assets/SendAssetTask.cpp | 6 +- .../src/assets/UploadAssetTask.cpp | 12 +- domain-server/src/BackupSupervisor.cpp | 409 ++++++++++++++++++ domain-server/src/BackupSupervisor.h | 86 ++++ domain-server/src/DomainServer.cpp | 19 +- domain-server/src/DomainServer.h | 5 + libraries/networking/src/AssetClient.cpp | 22 +- libraries/networking/src/AssetUtils.h | 7 +- libraries/networking/src/DomainHandler.h | 2 +- libraries/networking/src/LimitedNodeList.cpp | 32 +- libraries/networking/src/LimitedNodeList.h | 4 + libraries/networking/src/MappingRequest.cpp | 3 - libraries/networking/src/MappingRequest.h | 8 +- libraries/networking/src/NodeList.h | 4 + libraries/networking/src/PacketReceiver.cpp | 112 ++--- libraries/networking/src/udt/PacketHeaders.h | 11 + 18 files changed, 677 insertions(+), 143 deletions(-) create mode 100644 domain-server/src/BackupSupervisor.cpp create mode 100644 domain-server/src/BackupSupervisor.h diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 0a868737b0..1ae65290ff 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -464,32 +464,41 @@ void AssetServer::handleAssetMappingOperation(QSharedPointer me auto replyPacket = NLPacketList::create(PacketType::AssetMappingOperationReply, QByteArray(), true, true); replyPacket->writePrimitive(messageID); + bool canWriteToAssetServer = true; + if (senderNode) { + canWriteToAssetServer = senderNode->getCanWriteToAssetServer(); + } + switch (operationType) { case AssetMappingOperationType::Get: - handleGetMappingOperation(*message, senderNode, *replyPacket); + handleGetMappingOperation(*message, *replyPacket); break; case AssetMappingOperationType::GetAll: - handleGetAllMappingOperation(*message, senderNode, *replyPacket); + handleGetAllMappingOperation(*replyPacket); break; case AssetMappingOperationType::Set: - handleSetMappingOperation(*message, senderNode, *replyPacket); + handleSetMappingOperation(*message, canWriteToAssetServer, *replyPacket); break; case AssetMappingOperationType::Delete: - handleDeleteMappingsOperation(*message, senderNode, *replyPacket); + handleDeleteMappingsOperation(*message, canWriteToAssetServer, *replyPacket); break; case AssetMappingOperationType::Rename: - handleRenameMappingOperation(*message, senderNode, *replyPacket); + handleRenameMappingOperation(*message, canWriteToAssetServer, *replyPacket); break; case AssetMappingOperationType::SetBakingEnabled: - handleSetBakingEnabledOperation(*message, senderNode, *replyPacket); + handleSetBakingEnabledOperation(*message, canWriteToAssetServer, *replyPacket); break; } auto nodeList = DependencyManager::get(); - nodeList->sendPacketList(std::move(replyPacket), *senderNode); + if (senderNode) { + nodeList->sendPacketList(std::move(replyPacket), *senderNode); + } else { + nodeList->sendPacketList(std::move(replyPacket), message->getSenderSockAddr()); + } } -void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { +void AssetServer::handleGetMappingOperation(ReceivedMessage& message, NLPacketList& replyPacket) { QString assetPath = message.readString(); QUrl url { assetPath }; @@ -568,7 +577,7 @@ void AssetServer::handleGetMappingOperation(ReceivedMessage& message, SharedNode } } -void AssetServer::handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { +void AssetServer::handleGetAllMappingOperation(NLPacketList& replyPacket) { replyPacket.writePrimitive(AssetUtils::AssetServerError::NoError); uint32_t count = (uint32_t)_fileMappings.size(); @@ -591,8 +600,8 @@ void AssetServer::handleGetAllMappingOperation(ReceivedMessage& message, SharedN } } -void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { - if (senderNode->getCanWriteToAssetServer()) { +void AssetServer::handleSetMappingOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket) { + if (hasWriteAccess) { QString assetPath = message.readString(); auto assetHash = message.read(AssetUtils::SHA256_HASH_LENGTH).toHex(); @@ -614,8 +623,8 @@ void AssetServer::handleSetMappingOperation(ReceivedMessage& message, SharedNode } } -void AssetServer::handleDeleteMappingsOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { - if (senderNode->getCanWriteToAssetServer()) { +void AssetServer::handleDeleteMappingsOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket) { + if (hasWriteAccess) { int numberOfDeletedMappings { 0 }; message.readPrimitive(&numberOfDeletedMappings); @@ -642,8 +651,8 @@ void AssetServer::handleDeleteMappingsOperation(ReceivedMessage& message, Shared } } -void AssetServer::handleRenameMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { - if (senderNode->getCanWriteToAssetServer()) { +void AssetServer::handleRenameMappingOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket) { + if (hasWriteAccess) { QString oldPath = message.readString(); QString newPath = message.readString(); @@ -664,8 +673,8 @@ void AssetServer::handleRenameMappingOperation(ReceivedMessage& message, SharedN } } -void AssetServer::handleSetBakingEnabledOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket) { - if (senderNode->getCanWriteToAssetServer()) { +void AssetServer::handleSetBakingEnabledOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket) { + if (hasWriteAccess) { bool enabled { true }; message.readPrimitive(&enabled); @@ -739,9 +748,14 @@ void AssetServer::handleAssetGet(QSharedPointer message, Shared } void AssetServer::handleAssetUpload(QSharedPointer message, SharedNodePointer senderNode) { + bool canWriteToAssetServer = true; + if (senderNode) { + canWriteToAssetServer = senderNode->getCanWriteToAssetServer(); + } - if (senderNode->getCanWriteToAssetServer()) { - qCDebug(asset_server) << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(senderNode->getUUID()); + + if (canWriteToAssetServer) { + qCDebug(asset_server) << "Starting an UploadAssetTask for upload from" << uuidStringWithoutCurlyBraces(message->getSourceID()); auto task = new UploadAssetTask(message, senderNode, _filesDirectory, _filesizeLimit); _transferTaskPool.start(task); @@ -761,7 +775,11 @@ void AssetServer::handleAssetUpload(QSharedPointer message, Sha // send off the packet auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(permissionErrorPacket), *senderNode); + if (senderNode) { + nodeList->sendPacket(std::move(permissionErrorPacket), *senderNode); + } else { + nodeList->sendPacket(std::move(permissionErrorPacket), message->getSenderSockAddr()); + } } } diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index 5e7a3c1700..c6336a3a4d 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -29,9 +29,6 @@ namespace std { } struct AssetMeta { - AssetMeta() { - } - int bakeVersion { 0 }; bool failedLastBake { false }; QString lastBakeErrors; @@ -60,14 +57,15 @@ private slots: void sendStatsPacket() override; private: - using Mappings = std::unordered_map; + void handleGetMappingOperation(ReceivedMessage& message, NLPacketList& replyPacket); + void handleGetAllMappingOperation(NLPacketList& replyPacket); + void handleSetMappingOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket); + void handleDeleteMappingsOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket); + void handleRenameMappingOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket); + void handleSetBakingEnabledOperation(ReceivedMessage& message, bool hasWriteAccess, NLPacketList& replyPacket); - void handleGetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); - void handleGetAllMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); - void handleSetMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); - void handleDeleteMappingsOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); - void handleRenameMappingOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); - void handleSetBakingEnabledOperation(ReceivedMessage& message, SharedNodePointer senderNode, NLPacketList& replyPacket); + void handleAssetServerBackup(ReceivedMessage& message, NLPacketList& replyPacket); + void handleAssetServerRestore(ReceivedMessage& message, NLPacketList& replyPacket); // Mapping file operations must be called from main assignment thread only bool loadMappingsFromFile(); @@ -111,7 +109,7 @@ private: /// Remove baked paths when the original asset is deleteds void removeBakedPathsForDeletedAsset(AssetUtils::AssetHash originalAssetHash); - Mappings _fileMappings; + AssetUtils::Mappings _fileMappings; QDir _resourcesDirectory; QDir _filesDirectory; diff --git a/assignment-client/src/assets/SendAssetTask.cpp b/assignment-client/src/assets/SendAssetTask.cpp index 6da092357f..d17d254afd 100644 --- a/assignment-client/src/assets/SendAssetTask.cpp +++ b/assignment-client/src/assets/SendAssetTask.cpp @@ -112,5 +112,9 @@ void SendAssetTask::run() { } auto nodeList = DependencyManager::get(); - nodeList->sendPacketList(std::move(replyPacketList), *_senderNode); + if (_senderNode) { + nodeList->sendPacketList(std::move(replyPacketList), *_senderNode); + } else { + nodeList->sendPacketList(std::move(replyPacketList), _message->getSenderSockAddr()); + } } diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index 68bf4db5fd..f2ba431875 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -42,8 +42,7 @@ void UploadAssetTask::run() { uint64_t fileSize; buffer.read(reinterpret_cast(&fileSize), sizeof(fileSize)); - qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes from" - << uuidStringWithoutCurlyBraces(_senderNode->getUUID()); + qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes."; auto replyPacket = NLPacket::create(PacketType::AssetUploadReply, -1, true); replyPacket->writePrimitive(messageID); @@ -56,8 +55,7 @@ void UploadAssetTask::run() { auto hash = AssetUtils::hashData(fileData); auto hexHash = hash.toHex(); - qDebug() << "Hash for uploaded file from" << uuidStringWithoutCurlyBraces(_senderNode->getUUID()) - << "is: (" << hexHash << ") "; + qDebug() << "Hash for uploaded file is: (" << hexHash << ") "; QFile file { _resourcesDir.filePath(QString(hexHash)) }; @@ -103,5 +101,9 @@ void UploadAssetTask::run() { } auto nodeList = DependencyManager::get(); - nodeList->sendPacket(std::move(replyPacket), *_senderNode); + if (_senderNode) { + nodeList->sendPacket(std::move(replyPacket), *_senderNode); + } else { + nodeList->sendPacket(std::move(replyPacket), _receivedMessage->getSenderSockAddr()); + } } diff --git a/domain-server/src/BackupSupervisor.cpp b/domain-server/src/BackupSupervisor.cpp new file mode 100644 index 0000000000..829208913f --- /dev/null +++ b/domain-server/src/BackupSupervisor.cpp @@ -0,0 +1,409 @@ +// +// BackupSupervisor.cpp +// assignment-client/src +// +// Created by Clement Brisset on 1/12/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "BackupSupervisor.h" + +#include +#include + +#include +#include +#include +#include +#include + +const QString BACKUPS_DIR = "backups/"; +const QString ASSETS_DIR = "files/"; +const QString MAPPINGS_PREFIX = "mappings-"; + +using namespace std; + +BackupSupervisor::BackupSupervisor() { + _backupsDirectory = PathUtils::getAppDataPath() + BACKUPS_DIR; + QDir backupDir { _backupsDirectory }; + if (!backupDir.exists()) { + backupDir.mkpath("."); + } + + _assetsDirectory = PathUtils::getAppDataPath() + BACKUPS_DIR + ASSETS_DIR; + QDir assetsDir { _assetsDirectory }; + if (!assetsDir.exists()) { + assetsDir.mkpath("."); + } + + loadAllBackups(); +} + +void BackupSupervisor::loadAllBackups() { + _backups.clear(); + _assetsInBackups.clear(); + _assetsOnDisk.clear(); + _allBackupsLoadedSuccessfully = true; + + QDir assetsDir { _assetsDirectory }; + auto assetNames = assetsDir.entryList(QDir::Files); + qDebug() << "Loading" << assetNames.size() << "assets."; + + // store all valid hashes + copy_if(begin(assetNames), end(assetNames), + inserter(_assetsOnDisk, begin(_assetsOnDisk)), AssetUtils::isValidHash); + + QDir backupsDir { _backupsDirectory }; + auto files = backupsDir.entryList({ MAPPINGS_PREFIX + "*.json" }, QDir::Files); + qDebug() << "Loading" << files.size() << "backups."; + + for (const auto& fileName : files) { + auto filePath = backupsDir.filePath(fileName); + auto success = loadBackup(filePath); + if (!success) { + qCritical() << "Failed to load backup file" << filePath; + _allBackupsLoadedSuccessfully = false; + } + } + + vector missingAssets; + set_difference(begin(_assetsInBackups), end(_assetsInBackups), + begin(_assetsOnDisk), end(_assetsOnDisk), + back_inserter(missingAssets)); + if (missingAssets.size() > 0) { + qWarning() << "Found" << missingAssets.size() << "assets missing."; + } + + vector deprecatedAssets; + set_difference(begin(_assetsOnDisk), end(_assetsOnDisk), + begin(_assetsInBackups), end(_assetsInBackups), + back_inserter(deprecatedAssets)); + + if (deprecatedAssets.size() > 0) { + qDebug() << "Found" << deprecatedAssets.size() << "assets to delete."; + if (_allBackupsLoadedSuccessfully) { + for (const auto& hash : deprecatedAssets) { + QFile::remove(_assetsDirectory + hash); + } + } else { + qWarning() << "Some backups did not load properly, aborting deleting for safety."; + } + } +} + +bool BackupSupervisor::loadBackup(const QString& backupFile) { + _backups.push_back({ backupFile.toStdString(), {}, false }); + auto& backup = _backups.back(); + + QFile file { backupFile }; + if (!file.open(QFile::ReadOnly)) { + qCritical() << "Could not open backup file:" << backupFile; + backup.corruptedBackup = true; + return false; + } + QJsonParseError error; + auto document = QJsonDocument::fromJson(file.readAll(), &error); + if (document.isNull()) { + qCritical() << "Could not parse backup file:" << backupFile; + qCritical() << " Error:" << error.errorString(); + backup.corruptedBackup = true; + return false; + } + + if (!document.isObject()) { + qCritical() << "Backup file corrupted" << backupFile; + backup.corruptedBackup = true; + return false; + } + + auto jsonObject = document.object(); + for (auto it = begin(jsonObject); it != end(jsonObject); ++it) { + if (!it.value().isString()) { + qCritical() << "Corrupted mapping in backup file" << backupFile << ":" << it.key(); + backup.corruptedBackup = true; + return false; + } + const auto& assetPath = it.key(); + const auto& assetHash = it.value().toString(); + + backup.mappings[assetPath] = assetHash; + _assetsInBackups.insert(assetHash); + } + + _backups.push_back(backup); + return true; +} + +void BackupSupervisor::backupAssetServer() { + if (backupInProgress() || restoreInProgress()) { + qWarning() << "There is already a backup/restore in progress."; + return; + } + + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this](GetAllMappingsRequest* request) { + qDebug() << "Got" << request->getMappings().size() << "mappings!"; + + if (request->getError() != MappingRequest::NoError) { + qCritical() << "Could not complete backup."; + qCritical() << " Error:" << request->getErrorString(); + finishBackup(); + request->deleteLater(); + return; + } + + if (!writeBackupFile(request->getMappings())) { + finishBackup(); + request->deleteLater(); + return; + } + + assert(!_backups.empty()); + const auto& mappings = _backups.back().mappings; + backupMissingFiles(mappings); + + request->deleteLater(); + }); + + startBackup(); + qDebug() << "Requesting mappings for backup!"; + request->start(); +} + +void BackupSupervisor::backupMissingFiles(const AssetUtils::Mappings& mappings) { + _assetsLeftToRequest.reserve(mappings.size()); + for (auto& mapping : mappings) { + const auto& hash = mapping.second; + if (_assetsOnDisk.find(hash) == end(_assetsOnDisk)) { + _assetsLeftToRequest.push_back(hash); + } + } + + backupNextMissingFile(); +} + +void BackupSupervisor::backupNextMissingFile() { + if (_assetsLeftToRequest.empty()) { + finishBackup(); + return; + } + + auto hash = _assetsLeftToRequest.back(); + _assetsLeftToRequest.pop_back(); + + auto assetClient = DependencyManager::get(); + auto assetRequest = assetClient->createRequest(hash); + + connect(assetRequest, &AssetRequest::finished, this, [this](AssetRequest* request) { + if (request->getError() == AssetRequest::NoError) { + qDebug() << "Got" << request->getHash(); + + bool success = writeAssetFile(request->getHash(),request->getData()); + if (!success) { + qCritical() << "Failed to write asset file" << request->getHash(); + } + } else { + qCritical() << "Failed to backup asset" << request->getHash(); + } + + backupNextMissingFile(); + + request->deleteLater(); + }); + + assetRequest->start(); +} + +bool BackupSupervisor::writeBackupFile(const AssetUtils::AssetMappings& mappings) { + auto filename = MAPPINGS_PREFIX + QDateTime::currentDateTimeUtc().toString(Qt::ISODate) + ".json"; + QFile file { PathUtils::getAppDataPath() + BACKUPS_DIR + filename }; + if (!file.open(QFile::WriteOnly)) { + qCritical() << "Could not open backup file" << file.fileName(); + return false; + } + + AssetServerBackup backup; + QJsonObject jsonObject; + for (auto& mapping : mappings) { + backup.mappings[mapping.first] = mapping.second.hash; + _assetsInBackups.insert(mapping.second.hash); + jsonObject.insert(mapping.first, mapping.second.hash); + } + + QJsonDocument document(jsonObject); + file.write(document.toJson()); + + backup.filePath = file.fileName().toStdString(); + _backups.push_back(backup); + + return true; +} + +bool BackupSupervisor::writeAssetFile(const AssetUtils::AssetHash& hash, const QByteArray& data) { + QDir assetsDir { _assetsDirectory }; + QFile file { assetsDir.filePath(hash) }; + if (!file.open(QFile::WriteOnly)) { + qCritical() << "Could not open backup file" << file.fileName(); + return false; + } + + file.write(data); + + _assetsOnDisk.insert(hash); + + return true; +} + +void BackupSupervisor::restoreAssetServer(int backupIndex) { + if (backupInProgress() || restoreInProgress()) { + qWarning() << "There is already a backup/restore in progress."; + return; + } + + auto assetClient = DependencyManager::get(); + auto request = assetClient->createGetAllMappingsRequest(); + + connect(request, &GetAllMappingsRequest::finished, this, [this, backupIndex](GetAllMappingsRequest* request) { + qDebug() << "Got" << request->getMappings().size() << "mappings!"; + + if (request->getError() == MappingRequest::NoError) { + const auto& newMappings = _backups.at(backupIndex).mappings; + computeServerStateDifference(request->getMappings(), newMappings); + + restoreAllAssets(); + } else { + finishRestore(); + } + + request->deleteLater(); + }); + + startRestore(); + qDebug() << "Requesting mappings for restore!"; + request->start(); +} + +void BackupSupervisor::computeServerStateDifference(const AssetUtils::AssetMappings& currentMappings, + const AssetUtils::Mappings& newMappings) { + _mappingsLeftToSet.reserve((int)newMappings.size()); + _assetsLeftToUpload.reserve((int)newMappings.size()); + _mappingsLeftToDelete.reserve((int)currentMappings.size()); + + set currentAssets; + for (const auto& currentMapping : currentMappings) { + const auto& currentPath = currentMapping.first; + const auto& currentHash = currentMapping.second.hash; + + if (newMappings.find(currentPath) == end(newMappings)) { + _mappingsLeftToDelete.push_back(currentPath); + } + currentAssets.insert(currentHash); + } + + for (const auto& newMapping : newMappings) { + const auto& newPath = newMapping.first; + const auto& newHash = newMapping.second; + + auto it = currentMappings.find(newPath); + if (it == end(currentMappings) || it->second.hash != newHash) { + _mappingsLeftToSet.push_back({ newPath, newHash }); + } + if (currentAssets.find(newHash) == end(currentAssets)) { + _assetsLeftToUpload.push_back(newHash); + } + } + + qDebug() << "Mappings to set:" << _mappingsLeftToSet.size(); + qDebug() << "Mappings to del:" << _mappingsLeftToDelete.size(); + qDebug() << "Assets to upload:" << _assetsLeftToUpload.size(); +} + +void BackupSupervisor::restoreAllAssets() { + restoreNextAsset(); +} + +void BackupSupervisor::restoreNextAsset() { + if (_assetsLeftToUpload.empty()) { + updateMappings(); + return; + } + + auto hash = _assetsLeftToUpload.back(); + _assetsLeftToUpload.pop_back(); + + auto assetFilename = _assetsDirectory + hash; + + auto assetClient = DependencyManager::get(); + auto request = assetClient->createUpload(assetFilename); + + connect(request, &AssetUpload::finished, this, [this](AssetUpload* request) { + if (request->getError() != AssetUpload::NoError) { + qCritical() << "Failed to restore asset:" << request->getFilename(); + qCritical() << " Error:" << request->getErrorString(); + } + + restoreNextAsset(); + + request->deleteLater(); + }); + + request->start(); +} + +void BackupSupervisor::updateMappings() { + auto assetClient = DependencyManager::get(); + for (const auto& mapping : _mappingsLeftToSet) { + auto request = assetClient->createSetMappingRequest(mapping.first, mapping.second); + connect(request, &SetMappingRequest::finished, this, [this](SetMappingRequest* request) { + if (request->getError() != MappingRequest::NoError) { + qCritical() << "Failed to set mapping:" << request->getPath(); + qCritical() << " Error:" << request->getErrorString(); + } + + if (--_mappingRequestsInFlight == 0) { + finishRestore(); + } + + request->deleteLater(); + }); + + request->start(); + ++_mappingRequestsInFlight; + } + _mappingsLeftToSet.clear(); + + auto request = assetClient->createDeleteMappingsRequest(_mappingsLeftToDelete); + connect(request, &DeleteMappingsRequest::finished, this, [this](DeleteMappingsRequest* request) { + if (request->getError() != MappingRequest::NoError) { + qCritical() << "Failed to delete mappings"; + qCritical() << " Error:" << request->getErrorString(); + } + + if (--_mappingRequestsInFlight == 0) { + finishRestore(); + } + + request->deleteLater(); + }); + _mappingsLeftToDelete.clear(); + + request->start(); + ++_mappingRequestsInFlight; +} +bool BackupSupervisor::deleteBackup(int backupIndex) { + if (backupInProgress() || restoreInProgress()) { + qWarning() << "There is a backup/restore in progress."; + return false; + } + const auto& filePath = _backups.at(backupIndex).filePath; + auto success = QFile::remove(filePath.c_str()); + + loadAllBackups(); + + return success; +} diff --git a/domain-server/src/BackupSupervisor.h b/domain-server/src/BackupSupervisor.h new file mode 100644 index 0000000000..a4129fca12 --- /dev/null +++ b/domain-server/src/BackupSupervisor.h @@ -0,0 +1,86 @@ +// +// BackupSupervisor.h +// assignment-client/src +// +// Created by Clement Brisset on 1/12/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_BackupSupervisor_h +#define hifi_BackupSupervisor_h + +#include +#include + +#include + +#include + +#include + +struct AssetServerBackup { + std::string filePath; + AssetUtils::Mappings mappings; + bool corruptedBackup; +}; + +class BackupSupervisor : public QObject { + Q_OBJECT + +public: + BackupSupervisor(); + + void backupAssetServer(); + void restoreAssetServer(int backupIndex); + bool deleteBackup(int backupIndex); + + const std::vector& getBackups() const { return _backups; }; + + bool backupInProgress() const { return _backupInProgress; } + bool restoreInProgress() const { return _restoreInProgress; } + +private: + void loadAllBackups(); + bool loadBackup(const QString& backupFile); + + void startBackup() { _backupInProgress = true; } + void finishBackup() { _backupInProgress = false; } + void backupMissingFiles(const AssetUtils::Mappings& mappings); + void backupNextMissingFile(); + bool writeBackupFile(const AssetUtils::AssetMappings& mappings); + bool writeAssetFile(const AssetUtils::AssetHash& hash, const QByteArray& data); + + + void startRestore() { _restoreInProgress = true; } + void finishRestore() { _restoreInProgress = false; } + void computeServerStateDifference(const AssetUtils::AssetMappings& currentMappings, + const AssetUtils::Mappings& newMappings); + void restoreAllAssets(); + void restoreNextAsset(); + void updateMappings(); + + QString _backupsDirectory; + QString _assetsDirectory; + + // Internal storage for backups on disk + bool _allBackupsLoadedSuccessfully { false }; + std::vector _backups; + std::set _assetsInBackups; + std::set _assetsOnDisk; + + // Internal storage for backup in progress + bool _backupInProgress { false }; + std::vector _assetsLeftToRequest; + + // Internal storage for restor in progress + bool _restoreInProgress { false }; + std::vector _assetsLeftToUpload; + std::vector> _mappingsLeftToSet; + AssetUtils::AssetPathList _mappingsLeftToDelete; + int _mappingRequestsInFlight { 0 }; +}; + +#endif /* hifi_BackupSupervisor_h */ diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 22273ae85f..65053b7366 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -343,6 +344,12 @@ void DomainServer::parseCommandLine() { DomainServer::~DomainServer() { qInfo() << "Domain Server is shutting down."; + + // cleanup the AssetClient thread + DependencyManager::destroy(); + _assetClientThread.quit(); + _assetClientThread.wait(); + // destroy the LimitedNodeList before the DomainServer QCoreApplication is down DependencyManager::destroy(); } @@ -684,11 +691,17 @@ void DomainServer::setupNodeListAndAssignments() { packetReceiver.registerListener(PacketType::ICEServerHeartbeatDenied, this, "processICEServerHeartbeatDenialPacket"); packetReceiver.registerListener(PacketType::ICEServerHeartbeatACK, this, "processICEServerHeartbeatACK"); - // add whatever static assignments that have been parsed to the queue - addStaticAssignmentsToQueue(); - // set a custom packetVersionMatch as the verify packet operator for the udt::Socket nodeList->setPacketFilterOperator(&DomainServer::isPacketVerified); + + _assetClientThread.setObjectName("AssetClient Thread"); + auto assetClient = DependencyManager::set(); + assetClient->moveToThread(&_assetClientThread); + QObject::connect(&_assetClientThread, &QThread::started, assetClient.data(), &AssetClient::init); + _assetClientThread.start(); + + // add whatever static assignments that have been parsed to the queue + addStaticAssignmentsToQueue(); } bool DomainServer::resetAccountManagerAccessToken() { diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index b45b8a4816..f84a47d457 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,7 @@ #include #include +#include "BackupSupervisor.h" #include "DomainGatekeeper.h" #include "DomainMetadata.h" #include "DomainServerSettingsManager.h" @@ -251,6 +253,9 @@ private: bool _sendICEServerAddressToMetaverseAPIRedo { false }; QHash> _pendingOAuthConnections; + BackupSupervisor _backupSupervisor; + + QThread _assetClientThread; }; diff --git a/libraries/networking/src/AssetClient.cpp b/libraries/networking/src/AssetClient.cpp index 1db93e8cb9..41d988eca4 100644 --- a/libraries/networking/src/AssetClient.cpp +++ b/libraries/networking/src/AssetClient.cpp @@ -40,7 +40,7 @@ AssetClient::AssetClient() { static_cast(dependency)->deleteLater(); }); - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); auto& packetReceiver = nodeList->getPacketReceiver(); packetReceiver.registerListener(PacketType::AssetMappingOperationReply, this, "handleAssetMappingOperationReply"); @@ -308,7 +308,7 @@ void AssetClient::handleAssetMappingOperationReply(QSharedPointer(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (!assetServer) { @@ -402,7 +402,7 @@ MessageID AssetClient::getAsset(const QString& hash, AssetUtils::DataOffset star return false; } - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { @@ -435,7 +435,7 @@ MessageID AssetClient::getAsset(const QString& hash, AssetUtils::DataOffset star MessageID AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callback) { Q_ASSERT(QThread::currentThread() == thread()); - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { @@ -635,7 +635,7 @@ void AssetClient::handleCompleteCallback(const QWeakPointer& node, Message MessageID AssetClient::getAssetMapping(const AssetUtils::AssetPath& path, MappingOperationCallback callback) { Q_ASSERT(QThread::currentThread() == thread()); - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { @@ -662,7 +662,7 @@ MessageID AssetClient::getAssetMapping(const AssetUtils::AssetPath& path, Mappin MessageID AssetClient::getAllAssetMappings(MappingOperationCallback callback) { Q_ASSERT(QThread::currentThread() == thread()); - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { @@ -685,7 +685,7 @@ MessageID AssetClient::getAllAssetMappings(MappingOperationCallback callback) { } MessageID AssetClient::deleteAssetMappings(const AssetUtils::AssetPathList& paths, MappingOperationCallback callback) { - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { @@ -716,7 +716,7 @@ MessageID AssetClient::deleteAssetMappings(const AssetUtils::AssetPathList& path MessageID AssetClient::setAssetMapping(const QString& path, const AssetUtils::AssetHash& hash, MappingOperationCallback callback) { Q_ASSERT(QThread::currentThread() == thread()); - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { @@ -742,7 +742,7 @@ MessageID AssetClient::setAssetMapping(const QString& path, const AssetUtils::As } MessageID AssetClient::renameAssetMapping(const AssetUtils::AssetPath& oldPath, const AssetUtils::AssetPath& newPath, MappingOperationCallback callback) { - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { @@ -769,7 +769,7 @@ MessageID AssetClient::renameAssetMapping(const AssetUtils::AssetPath& oldPath, } MessageID AssetClient::setBakingEnabled(const AssetUtils::AssetPathList& paths, bool enabled, MappingOperationCallback callback) { - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { @@ -859,7 +859,7 @@ bool AssetClient::cancelUploadAssetRequest(MessageID id) { MessageID AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback callback) { Q_ASSERT(QThread::currentThread() == thread()); - auto nodeList = DependencyManager::get(); + auto nodeList = DependencyManager::get(); SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer); if (assetServer) { diff --git a/libraries/networking/src/AssetUtils.h b/libraries/networking/src/AssetUtils.h index 42e8dfad62..6c84417aae 100644 --- a/libraries/networking/src/AssetUtils.h +++ b/libraries/networking/src/AssetUtils.h @@ -44,7 +44,9 @@ enum AssetServerError : uint8_t { AssetTooLarge, PermissionDenied, MappingOperationFailed, - FileOperationFailed + FileOperationFailed, + NoAssetServer, + LostConnection }; enum AssetMappingOperationType : uint8_t { @@ -71,7 +73,8 @@ struct MappingInfo { QString bakingErrors; }; -using AssetMapping = std::map; +using AssetMappings = std::map; +using Mappings = std::map; QUrl getATPUrl(const QString& input); AssetHash extractAssetHash(const QString& input); diff --git a/libraries/networking/src/DomainHandler.h b/libraries/networking/src/DomainHandler.h index b72c172c3e..78f9798089 100644 --- a/libraries/networking/src/DomainHandler.h +++ b/libraries/networking/src/DomainHandler.h @@ -49,7 +49,7 @@ public: const QHostAddress& getIP() const { return _sockAddr.getAddress(); } void setIPToLocalhost() { _sockAddr.setAddress(QHostAddress(QHostAddress::LocalHost)); } - const HifiSockAddr& getSockAddr() { return _sockAddr; } + const HifiSockAddr& getSockAddr() const { return _sockAddr; } void setSockAddr(const HifiSockAddr& sockAddr, const QString& hostname); unsigned short getPort() const { return _sockAddr.getPort(); } diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 0950cb5556..2343695914 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -90,21 +90,16 @@ LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) : updateLocalSocket(); // set &PacketReceiver::handleVerifiedPacket as the verified packet callback for the udt::Socket - _nodeSocket.setPacketHandler( - [this](std::unique_ptr packet) { + _nodeSocket.setPacketHandler([this](std::unique_ptr packet) { _packetReceiver->handleVerifiedPacket(std::move(packet)); - } - ); - _nodeSocket.setMessageHandler( - [this](std::unique_ptr packet) { + }); + _nodeSocket.setMessageHandler([this](std::unique_ptr packet) { _packetReceiver->handleVerifiedMessagePacket(std::move(packet)); - } - ); - _nodeSocket.setMessageFailureHandler( - [this](HifiSockAddr from, udt::Packet::MessageNumber messageNumber) { + }); + _nodeSocket.setMessageFailureHandler([this](HifiSockAddr from, + udt::Packet::MessageNumber messageNumber) { _packetReceiver->handleMessageFailure(from, messageNumber); - } - ); + }); // set our isPacketVerified method as the verify operator for the udt::Socket using std::placeholders::_1; @@ -309,8 +304,19 @@ bool LimitedNodeList::packetSourceAndHashMatchAndTrackBandwidth(const udt::Packe sourceNode = matchingNode.data(); } + if (!sourceNode && + sourceID == getDomainUUID() && + packet.getSenderSockAddr() == getDomainSockAddr() && + PacketTypeEnum::getDomainSourcedPackets().contains(headerType)) { + // This is a packet sourced by the domain server + + emit dataReceived(NodeType::Unassigned, packet.getPayloadSize()); + return true; + } + if (sourceNode) { - if (!PacketTypeEnum::getNonVerifiedPackets().contains(headerType)) { + if (!PacketTypeEnum::getNonVerifiedPackets().contains(headerType) && + !isDomainServer()) { QByteArray packetHeaderHash = NLPacket::verificationHashInHeader(packet); QByteArray expectedHash = NLPacket::hashForPacketAndSecret(packet, sourceNode->getConnectionSecret()); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index e21f01a470..1b1c809279 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -124,6 +124,10 @@ public: PacketReceiver& getPacketReceiver() { return *_packetReceiver; } + virtual bool isDomainServer() const { return true; } + virtual QUuid getDomainUUID() const { assert(false); return QUuid(); } + virtual HifiSockAddr getDomainSockAddr() const { assert(false); return HifiSockAddr(); } + // use sendUnreliablePacket to send an unrelaible packet (that you do not need to move) // either to a node (via its active socket) or to a manual sockaddr qint64 sendUnreliablePacket(const NLPacket& packet, const Node& destinationNode); diff --git a/libraries/networking/src/MappingRequest.cpp b/libraries/networking/src/MappingRequest.cpp index 07639d4994..96f4b63c59 100644 --- a/libraries/networking/src/MappingRequest.cpp +++ b/libraries/networking/src/MappingRequest.cpp @@ -106,9 +106,6 @@ void GetMappingRequest::doStart() { }); }; -GetAllMappingsRequest::GetAllMappingsRequest() { -}; - void GetAllMappingsRequest::doStart() { auto assetClient = DependencyManager::get(); _mappingRequestID = assetClient->getAllAssetMappings( diff --git a/libraries/networking/src/MappingRequest.h b/libraries/networking/src/MappingRequest.h index 5286849dd1..6af8552c1e 100644 --- a/libraries/networking/src/MappingRequest.h +++ b/libraries/networking/src/MappingRequest.h @@ -120,17 +120,15 @@ private: class GetAllMappingsRequest : public MappingRequest { Q_OBJECT public: - GetAllMappingsRequest(); - - AssetUtils::AssetMapping getMappings() const { return _mappings; } + AssetUtils::AssetMappings getMappings() const { return _mappings; } signals: void finished(GetAllMappingsRequest* thisRequest); private: virtual void doStart() override; - - AssetUtils::AssetMapping _mappings; + + AssetUtils::AssetMappings _mappings; }; class SetBakingEnabledRequest : public MappingRequest { diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 2dd9d3c869..a49cb7c3f5 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -92,6 +92,10 @@ public: void removeFromIgnoreMuteSets(const QUuid& nodeID); + virtual bool isDomainServer() const override { return false; } + virtual QUuid getDomainUUID() const override { return _domainHandler.getUUID(); } + virtual HifiSockAddr getDomainSockAddr() const override { return _domainHandler.getSockAddr(); } + public slots: void reset(bool skipDomainHandlerReset = false); void resetFromDomainHandler() { reset(true); } diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 556e55beb2..0834a55148 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -267,10 +267,7 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei QMutexLocker packetListenerLocker(&_packetListenerLock); - bool listenerIsDead = false; - auto it = _messageListenerMap.find(receivedMessage->getType()); - if (it != _messageListenerMap.end() && it->method.isValid()) { auto listener = it.value(); @@ -278,82 +275,61 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei if ((listener.deliverPending && !justReceived) || (!listener.deliverPending && !receivedMessage->isComplete())) { return; } - - if (listener.object) { - bool success = false; + bool success = false; - Qt::ConnectionType connectionType; - // check if this is a directly connected listener - { - QMutexLocker directConnectLocker(&_directConnectSetMutex); - - connectionType = _directlyConnectedObjects.contains(listener.object) ? Qt::DirectConnection : Qt::AutoConnection; - } - - PacketType packetType = receivedMessage->getType(); - - if (matchingNode) { - matchingNode->recordBytesReceived(receivedMessage->getSize()); - - QMetaMethod metaMethod = listener.method; - - static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); - static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("SharedNodePointer"); - - // one final check on the QPointer before we go to invoke - if (listener.object) { - if (metaMethod.parameterTypes().contains(SHARED_NODE_NORMALIZED)) { - success = metaMethod.invoke(listener.object, - connectionType, - Q_ARG(QSharedPointer, receivedMessage), - Q_ARG(SharedNodePointer, matchingNode)); - - } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { - success = metaMethod.invoke(listener.object, - connectionType, - Q_ARG(QSharedPointer, receivedMessage), - Q_ARG(QSharedPointer, matchingNode)); - - } else { - success = metaMethod.invoke(listener.object, - connectionType, - Q_ARG(QSharedPointer, receivedMessage)); - } - } else { - listenerIsDead = true; - } - } else { - // one final check on the QPointer before we invoke - if (listener.object) { - success = listener.method.invoke(listener.object, - Q_ARG(QSharedPointer, receivedMessage)); - } else { - listenerIsDead = true; - } - - } - - if (!success) { - qCDebug(networking).nospace() << "Error delivering packet " << packetType << " to listener " - << listener.object << "::" << qPrintable(listener.method.methodSignature()); - } - - } else { - listenerIsDead = true; + Qt::ConnectionType connectionType; + // check if this is a directly connected listener + { + QMutexLocker directConnectLocker(&_directConnectSetMutex); + connectionType = _directlyConnectedObjects.contains(listener.object) ? Qt::DirectConnection : Qt::AutoConnection; } - - if (listenerIsDead) { + + if (matchingNode) { + matchingNode->recordBytesReceived(receivedMessage->getSize()); + } + + QMetaMethod metaMethod = listener.method; + + static const QByteArray QSHAREDPOINTER_NODE_NORMALIZED = QMetaObject::normalizedType("QSharedPointer"); + static const QByteArray SHARED_NODE_NORMALIZED = QMetaObject::normalizedType("SharedNodePointer"); + + // one final check on the QPointer before we go to invoke + if (listener.object) { + if (metaMethod.parameterTypes().contains(SHARED_NODE_NORMALIZED)) { + success = metaMethod.invoke(listener.object, + connectionType, + Q_ARG(QSharedPointer, receivedMessage), + Q_ARG(SharedNodePointer, matchingNode)); + + } else if (metaMethod.parameterTypes().contains(QSHAREDPOINTER_NODE_NORMALIZED)) { + success = metaMethod.invoke(listener.object, + connectionType, + Q_ARG(QSharedPointer, receivedMessage), + Q_ARG(QSharedPointer, matchingNode)); + + } else { + success = metaMethod.invoke(listener.object, + connectionType, + Q_ARG(QSharedPointer, receivedMessage)); + } + } else { qCDebug(networking).nospace() << "Listener for packet " << receivedMessage->getType() - << " has been destroyed. Removing from listener map."; + << " has been destroyed. Removing from listener map."; it = _messageListenerMap.erase(it); - + // if it exists, remove the listener from _directlyConnectedObjects { QMutexLocker directConnectLocker(&_directConnectSetMutex); _directlyConnectedObjects.remove(listener.object); } } + + if (!success) { + qCDebug(networking).nospace() << "Error delivering packet " << receivedMessage->getType() << " to listener " + << listener.object << "::" << qPrintable(listener.method.methodSignature()); + } + } else if (it == _messageListenerMap.end()) { qCWarning(networking) << "No listener found for packet type" << receivedMessage->getType(); diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index d186ed41c3..5757cea496 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -177,6 +177,17 @@ public: << PacketTypeEnum::Value::ReplicatedKillAvatar << PacketTypeEnum::Value::ReplicatedBulkAvatarData; return NON_SOURCED_PACKETS; } + + const static QSet getDomainSourcedPackets() { + const static QSet DOMAIN_SOURCED_PACKETS = QSet() + << PacketTypeEnum::Value::AssetMappingOperation + << PacketTypeEnum::Value::AssetMappingOperationReply + << PacketTypeEnum::Value::AssetGet + << PacketTypeEnum::Value::AssetGetReply + << PacketTypeEnum::Value::AssetUpload + << PacketTypeEnum::Value::AssetUploadReply; + return DOMAIN_SOURCED_PACKETS; + } }; using PacketType = PacketTypeEnum::Value; From 46449256ce26b905f145e214f23e16d0d580cdff Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 9 Feb 2018 11:32:54 -0800 Subject: [PATCH 12/25] CR --- .../src/assets/UploadAssetTask.cpp | 16 +++++++++++---- domain-server/src/BackupSupervisor.cpp | 20 +++++++------------ domain-server/src/BackupSupervisor.h | 2 +- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/assets/UploadAssetTask.cpp b/assignment-client/src/assets/UploadAssetTask.cpp index f2ba431875..d3e755212a 100644 --- a/assignment-client/src/assets/UploadAssetTask.cpp +++ b/assignment-client/src/assets/UploadAssetTask.cpp @@ -41,8 +41,12 @@ void UploadAssetTask::run() { uint64_t fileSize; buffer.read(reinterpret_cast(&fileSize), sizeof(fileSize)); - - qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes."; + + if (_senderNode) { + qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes from" << uuidStringWithoutCurlyBraces(_senderNode->getUUID()); + } else { + qDebug() << "UploadAssetTask reading a file of " << fileSize << "bytes from" << _receivedMessage->getSenderSockAddr(); + } auto replyPacket = NLPacket::create(PacketType::AssetUploadReply, -1, true); replyPacket->writePrimitive(messageID); @@ -54,8 +58,12 @@ void UploadAssetTask::run() { auto hash = AssetUtils::hashData(fileData); auto hexHash = hash.toHex(); - - qDebug() << "Hash for uploaded file is: (" << hexHash << ") "; + + if (_senderNode) { + qDebug() << "Hash for uploaded file from" << uuidStringWithoutCurlyBraces(_senderNode->getUUID()) << "is: (" << hexHash << ")"; + } else { + qDebug() << "Hash for uploaded file from" << _receivedMessage->getSenderSockAddr() << "is: (" << hexHash << ")"; + } QFile file { _resourcesDir.filePath(QString(hexHash)) }; diff --git a/domain-server/src/BackupSupervisor.cpp b/domain-server/src/BackupSupervisor.cpp index 829208913f..1bf1e9e199 100644 --- a/domain-server/src/BackupSupervisor.cpp +++ b/domain-server/src/BackupSupervisor.cpp @@ -1,6 +1,6 @@ // // BackupSupervisor.cpp -// assignment-client/src +// domain-server/src // // Created by Clement Brisset on 1/12/18. // Copyright 2018 High Fidelity, Inc. @@ -106,28 +106,22 @@ bool BackupSupervisor::loadBackup(const QString& backupFile) { } QJsonParseError error; auto document = QJsonDocument::fromJson(file.readAll(), &error); - if (document.isNull()) { - qCritical() << "Could not parse backup file:" << backupFile; - qCritical() << " Error:" << error.errorString(); - backup.corruptedBackup = true; - return false; - } - - if (!document.isObject()) { - qCritical() << "Backup file corrupted" << backupFile; + if (document.isNull() || !document.isObject()) { + qCritical() << "Could not parse backup file to JSON object:" << backupFile; backup.corruptedBackup = true; return false; } auto jsonObject = document.object(); for (auto it = begin(jsonObject); it != end(jsonObject); ++it) { - if (!it.value().isString()) { + const auto& assetPath = it.key(); + const auto& assetHash = it.value().toString(); + + if (!AssetUtils::isValidHash(assetHash)) { qCritical() << "Corrupted mapping in backup file" << backupFile << ":" << it.key(); backup.corruptedBackup = true; return false; } - const auto& assetPath = it.key(); - const auto& assetHash = it.value().toString(); backup.mappings[assetPath] = assetHash; _assetsInBackups.insert(assetHash); diff --git a/domain-server/src/BackupSupervisor.h b/domain-server/src/BackupSupervisor.h index a4129fca12..f01e389c39 100644 --- a/domain-server/src/BackupSupervisor.h +++ b/domain-server/src/BackupSupervisor.h @@ -1,6 +1,6 @@ // // BackupSupervisor.h -// assignment-client/src +// domain-server/src // // Created by Clement Brisset on 1/12/18. // Copyright 2018 High Fidelity, Inc. From 5325b22b011cf8ad6b2b23dd350c1312d23fd807 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 9 Feb 2018 16:46:11 -0800 Subject: [PATCH 13/25] working on lambdas --- interface/src/avatar/MyAvatar.cpp | 28 +++++++++++++++------------- interface/src/avatar/MyAvatar.h | 1 + 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0ee409745f..5710dcc354 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1448,10 +1448,20 @@ void MyAvatar::clearJointsData() { } void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { - if (skeletonModelURL != _skeletonModelURL) { - _shouldInitHeadBones = true; - } - + _skeletonModelChangeCount++; + int skeletonModelChangeCount = _skeletonModelChangeCount; + std::shared_ptr skeletonConnection = std::make_shared(); + *skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded, [this, skeletonModelChangeCount, skeletonConnection]() { + qDebug() << "checkingCount " << skeletonModelChangeCount << " -- " << _skeletonModelChangeCount; + if (skeletonModelChangeCount == _skeletonModelChangeCount && _skeletonModel->isLoaded()) { + qDebug() << "count is the same"; + initHeadBones(); + _skeletonModel->setCauterizeBoneSet(_headBoneSet); + _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); + initAnimGraph(); + } + QObject::disconnect(*skeletonConnection); + }); Avatar::setSkeletonModelURL(skeletonModelURL); _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); _headBoneSet.clear(); @@ -1878,6 +1888,7 @@ void MyAvatar::initAnimGraph() { _skeletonModel->getRig().initAnimGraph(graphUrl); _currentAnimGraphUrl.set(graphUrl); + qDebug() << "init anim graph"; connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); } @@ -1896,15 +1907,6 @@ void MyAvatar::animGraphLoaded() { void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { Avatar::postUpdate(deltaTime, scene); - - if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode() && _shouldInitHeadBones) { - initHeadBones(); - _skeletonModel->setCauterizeBoneSet(_headBoneSet); - _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); - initAnimGraph(); - _shouldInitHeadBones = false; - } - if (_enableDebugDrawDefaultPose || _enableDebugDrawAnimPose) { auto animSkeleton = _skeletonModel->getRig().getAnimSkeleton(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 45dddb45a4..180cf04a18 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -654,6 +654,7 @@ private: bool isMyAvatar() const override { return true; } virtual int parseDataFromBuffer(const QByteArray& buffer) override; virtual glm::vec3 getSkeletonPosition() const override; + int _skeletonModelChangeCount { 0 }; void saveAvatarScale(); From d381beb2132c224c383ff797b5faf7081396dd3e Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 12 Feb 2018 10:53:42 -0800 Subject: [PATCH 14/25] cleaning up code --- interface/src/avatar/MyAvatar.cpp | 14 ++++++-------- libraries/animation/src/Rig.cpp | 4 +--- libraries/animation/src/Rig.h | 1 - 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5710dcc354..67796bcc8b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1450,11 +1450,14 @@ void MyAvatar::clearJointsData() { void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _skeletonModelChangeCount++; int skeletonModelChangeCount = _skeletonModelChangeCount; + Avatar::setSkeletonModelURL(skeletonModelURL); + _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); + _headBoneSet.clear(); + _cauterizationNeedsUpdate = true; + std::shared_ptr skeletonConnection = std::make_shared(); *skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded, [this, skeletonModelChangeCount, skeletonConnection]() { - qDebug() << "checkingCount " << skeletonModelChangeCount << " -- " << _skeletonModelChangeCount; - if (skeletonModelChangeCount == _skeletonModelChangeCount && _skeletonModel->isLoaded()) { - qDebug() << "count is the same"; + if (skeletonModelChangeCount == _skeletonModelChangeCount) { initHeadBones(); _skeletonModel->setCauterizeBoneSet(_headBoneSet); _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); @@ -1462,10 +1465,6 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { } QObject::disconnect(*skeletonConnection); }); - Avatar::setSkeletonModelURL(skeletonModelURL); - _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); - _headBoneSet.clear(); - _cauterizationNeedsUpdate = true; emit skeletonChanged(); } @@ -1888,7 +1887,6 @@ void MyAvatar::initAnimGraph() { _skeletonModel->getRig().initAnimGraph(graphUrl); _currentAnimGraphUrl.set(graphUrl); - qDebug() << "init anim graph"; connect(&(_skeletonModel->getRig()), SIGNAL(onLoadComplete()), this, SLOT(animGraphLoaded())); } diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index ba496c5cd4..31151669c8 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1585,14 +1585,13 @@ void Rig::updateFromControllerParameters(const ControllerParameters& params, flo } void Rig::initAnimGraph(const QUrl& url) { - if (_animGraphURL != url || (!_animNode && !_animLoading)) { + if (_animGraphURL != url || !_animNode) { _animGraphURL = url; _animNode.reset(); // load the anim graph _animLoader.reset(new AnimNodeLoader(url)); - _animLoading = true; std::weak_ptr weakSkeletonPtr = _animSkeleton; connect(_animLoader.get(), &AnimNodeLoader::success, [this, weakSkeletonPtr](AnimNode::Pointer nodeIn) { _animNode = nodeIn; @@ -1617,7 +1616,6 @@ void Rig::initAnimGraph(const QUrl& url) { auto roleState = roleAnimState.second; overrideRoleAnimation(roleState.role, roleState.url, roleState.fps, roleState.loop, roleState.firstFrame, roleState.lastFrame); } - _animLoading = false; emit onLoadComplete(); }); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index a7db86abf9..7230d05e2a 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -283,7 +283,6 @@ protected: std::shared_ptr _animNode; std::shared_ptr _animSkeleton; std::unique_ptr _animLoader; - bool _animLoading { false }; AnimVariantMap _animVars; enum class RigRole { Idle = 0, From 1a2533257574531b23c1af9994ca159d3ded2ffd Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 12 Feb 2018 10:59:25 -0800 Subject: [PATCH 15/25] fix indenting --- interface/src/avatar/MyAvatar.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 719a919721..d5cd7bdca1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1469,13 +1469,13 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { std::shared_ptr skeletonConnection = std::make_shared(); *skeletonConnection = QObject::connect(_skeletonModel.get(), &SkeletonModel::skeletonLoaded, [this, skeletonModelChangeCount, skeletonConnection]() { - if (skeletonModelChangeCount == _skeletonModelChangeCount) { - initHeadBones(); - _skeletonModel->setCauterizeBoneSet(_headBoneSet); - _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); - initAnimGraph(); - } - QObject::disconnect(*skeletonConnection); + if (skeletonModelChangeCount == _skeletonModelChangeCount) { + initHeadBones(); + _skeletonModel->setCauterizeBoneSet(_headBoneSet); + _fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl(); + initAnimGraph(); + } + QObject::disconnect(*skeletonConnection); }); saveAvatarUrl(); emit skeletonChanged(); From e15ab2ca6c49478f1b7006b829e2dcad840aa418 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 12 Feb 2018 13:32:48 -0800 Subject: [PATCH 16/25] CR --- domain-server/src/BackupSupervisor.cpp | 7 ++----- domain-server/src/BackupSupervisor.h | 3 +-- domain-server/src/DomainServer.h | 1 - libraries/networking/src/PacketReceiver.cpp | 2 +- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/domain-server/src/BackupSupervisor.cpp b/domain-server/src/BackupSupervisor.cpp index 1bf1e9e199..03ad5de558 100644 --- a/domain-server/src/BackupSupervisor.cpp +++ b/domain-server/src/BackupSupervisor.cpp @@ -108,6 +108,7 @@ bool BackupSupervisor::loadBackup(const QString& backupFile) { auto document = QJsonDocument::fromJson(file.readAll(), &error); if (document.isNull() || !document.isObject()) { qCritical() << "Could not parse backup file to JSON object:" << backupFile; + qCritical() << " Error:" << error.errorString(); backup.corruptedBackup = true; return false; } @@ -165,7 +166,6 @@ void BackupSupervisor::backupAssetServer() { }); startBackup(); - qDebug() << "Requesting mappings for backup!"; request->start(); } @@ -197,7 +197,7 @@ void BackupSupervisor::backupNextMissingFile() { if (request->getError() == AssetRequest::NoError) { qDebug() << "Got" << request->getHash(); - bool success = writeAssetFile(request->getHash(),request->getData()); + bool success = writeAssetFile(request->getHash(), request->getData()); if (!success) { qCritical() << "Failed to write asset file" << request->getHash(); } @@ -263,8 +263,6 @@ void BackupSupervisor::restoreAssetServer(int backupIndex) { auto request = assetClient->createGetAllMappingsRequest(); connect(request, &GetAllMappingsRequest::finished, this, [this, backupIndex](GetAllMappingsRequest* request) { - qDebug() << "Got" << request->getMappings().size() << "mappings!"; - if (request->getError() == MappingRequest::NoError) { const auto& newMappings = _backups.at(backupIndex).mappings; computeServerStateDifference(request->getMappings(), newMappings); @@ -278,7 +276,6 @@ void BackupSupervisor::restoreAssetServer(int backupIndex) { }); startRestore(); - qDebug() << "Requesting mappings for restore!"; request->start(); } diff --git a/domain-server/src/BackupSupervisor.h b/domain-server/src/BackupSupervisor.h index f01e389c39..067abdc25c 100644 --- a/domain-server/src/BackupSupervisor.h +++ b/domain-server/src/BackupSupervisor.h @@ -53,7 +53,6 @@ private: bool writeBackupFile(const AssetUtils::AssetMappings& mappings); bool writeAssetFile(const AssetUtils::AssetHash& hash, const QByteArray& data); - void startRestore() { _restoreInProgress = true; } void finishRestore() { _restoreInProgress = false; } void computeServerStateDifference(const AssetUtils::AssetMappings& currentMappings, @@ -75,7 +74,7 @@ private: bool _backupInProgress { false }; std::vector _assetsLeftToRequest; - // Internal storage for restor in progress + // Internal storage for restore in progress bool _restoreInProgress { false }; std::vector _assetsLeftToUpload; std::vector> _mappingsLeftToSet; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index f84a47d457..c7d779b394 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -253,7 +253,6 @@ private: bool _sendICEServerAddressToMetaverseAPIRedo { false }; QHash> _pendingOAuthConnections; - BackupSupervisor _backupSupervisor; QThread _assetClientThread; }; diff --git a/libraries/networking/src/PacketReceiver.cpp b/libraries/networking/src/PacketReceiver.cpp index 0834a55148..27b57ef26c 100644 --- a/libraries/networking/src/PacketReceiver.cpp +++ b/libraries/networking/src/PacketReceiver.cpp @@ -315,7 +315,7 @@ void PacketReceiver::handleVerifiedMessage(QSharedPointer recei } } else { qCDebug(networking).nospace() << "Listener for packet " << receivedMessage->getType() - << " has been destroyed. Removing from listener map."; + << " has been destroyed. Removing from listener map."; it = _messageListenerMap.erase(it); // if it exists, remove the listener from _directlyConnectedObjects From ddcee05b14637a342dd286c93482fba289300a0f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 13 Feb 2018 09:41:00 -0800 Subject: [PATCH 17/25] added control button for controller API --- interface/resources/controllers/keyboardMouse.json | 4 ++-- .../src/input-plugins/KeyboardMouseDevice.cpp | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json index 54d2467f78..b3f16a115e 100644 --- a/interface/resources/controllers/keyboardMouse.json +++ b/interface/resources/controllers/keyboardMouse.json @@ -88,8 +88,8 @@ ] }, - { "from": "Keyboard.W", "to": "Actions.LONGITUDINAL_FORWARD" }, - { "from": "Keyboard.S", "to": "Actions.LONGITUDINAL_BACKWARD" }, + { "from": "Keyboard.W", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_FORWARD" }, + { "from": "Keyboard.S", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.E", "to": "Actions.VERTICAL_UP" }, { "from": "Keyboard.Left", "when": "Keyboard.RightMouseButton", "to": "Actions.LATERAL_LEFT" }, diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index e9ec6d8910..ef7f482e44 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -54,11 +54,9 @@ void KeyboardMouseDevice::InputDevice::focusOutEvent() { void KeyboardMouseDevice::keyPressEvent(QKeyEvent* event) { auto input = _inputDevice->makeInput((Qt::Key) event->key()); - if (!(event->modifiers() & Qt::KeyboardModifier::ControlModifier)) { - auto result = _inputDevice->_buttonPressedMap.insert(input.getChannel()); - if (result.second) { - // key pressed again ? without catching the release event ? - } + auto result = _inputDevice->_buttonPressedMap.insert(input.getChannel()); + if (result.second) { + // key pressed again ? without catching the release event ? } } @@ -237,6 +235,7 @@ controller::Input::NamedVector KeyboardMouseDevice::InputDevice::getAvailableInp availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageUp), QKeySequence(Qt::Key_PageUp).toString())); availableInputs.append(Input::NamedPair(makeInput(Qt::Key_PageDown), QKeySequence(Qt::Key_PageDown).toString())); availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Tab), QKeySequence(Qt::Key_Tab).toString())); + availableInputs.append(Input::NamedPair(makeInput(Qt::Key_Control), "Control")); availableInputs.append(Input::NamedPair(makeInput(Qt::LeftButton), "LeftMouseButton")); availableInputs.append(Input::NamedPair(makeInput(Qt::MiddleButton), "MiddleMouseButton")); From 45f09dde96c55e8982840bdb7bea57f61dcdb21f Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 13 Feb 2018 10:32:15 -0800 Subject: [PATCH 18/25] address tony's requests --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/avatar/MyAvatar.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d5cd7bdca1..15ae1584f6 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1461,7 +1461,7 @@ void MyAvatar::clearJointsData() { void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _skeletonModelChangeCount++; - int skeletonModelChangeCount = _skeletonModelChangeCount; + int skeletonModelChangeCount = _skeletonModelChangeCount; Avatar::setSkeletonModelURL(skeletonModelURL); _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); _headBoneSet.clear(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3e063547d0..28af8b62fd 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -819,7 +819,6 @@ private: bool _enableDebugDrawIKConstraints { false }; bool _enableDebugDrawIKChains { false }; bool _enableDebugDrawDetailedCollision { false }; - bool _shouldInitHeadBones { true }; mutable bool _cauterizationNeedsUpdate; // do we need to scan children and update their "cauterized" state? From cf3d8e446376e4a4f4b9c3b637b8b835533c8892 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 13 Feb 2018 11:07:15 -0800 Subject: [PATCH 19/25] remove cached file --- interface/resources/qml/js/Utils.jsc | Bin 6516 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 interface/resources/qml/js/Utils.jsc diff --git a/interface/resources/qml/js/Utils.jsc b/interface/resources/qml/js/Utils.jsc deleted file mode 100644 index 8da68e4e192018ee2b4f3d835ec91f36f0161eca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6516 zcmcIoZDrF4*+OKP^~mxE_StR<97M?dYinHhXIH0prUNWm)BPSkkxI9zIccH zbDYc+&t`mYYoRZ%dcNJC7t6S;1kom{uKi%kZQQ*B-}@Ea#y#@Sit;ack*DT2py=+} zfuFX0y&bsG4t&xMe9-`o8bF@`3>v_=0VE9IX#==m0KYMS=MCVp0laDeYXyq{m#>ENBdlKi6Kn!P8Tz-gSf=^W4f1vJz z>OP?E{p$W>bw7z?g5MlwFfTkK{Y3k0%wPWl) z&?-R|Nd~OQ(pqO|>7zFD;=ilaYBV{~8D84z4za!=ysGK#f#f15cOtKd^CTCgW+(F3YvinYJCd&`a))r0Mo85U*Q-9!M*I7$0`-qB z_gRHiN|Dr;D9>%Ew0z6Wn-=@9$24G=wcYQAKr;$=G(+YT?S4gBPFhi3D=YPBjMwP(DtXg0@d zG_^09dbG0=GK0s0m5|xhXBFIQ_sX@rd#zip<)W#5p*M~l7I0kJ>Rx3@lVReJ;DNwB zDyZ3=2tQI@%!JdrBFuEc?sBA(9kgr3Y_aT2sk*B@nIUjOEkzeu#m^h8RqKk4g`M3sB#sj3Z zin4^&CHb`Bz^YaPh9305YFR;C*(6#-3l|K#%Uq~N?&pFYMV^-~(A@o8!1hi6=630V z=D8$YpkTiX7yMeo-YZonuRF86K3C#h$;)v~gtsnv`C8)2tn*te(mN*CdaZPdOV`he z*)_jyCu3zh886w%`HhxMf1eQDtm(Upqbj0Vx%OZr)gDguj!@-{XXzA|(w?PRE?x30 zEpTbky|hS!BgqTa0w)epy`_*v_84x=)^DWM#;N*^jM^Bf-(bR$)d{)5D$iF5i3b%r z#w^&U)1~N17geDbU5O$&)0=CYvjc#Aq(q)qH~AvR+Mm@cT4=hL1Xn8N@U?K^55MR2@%P2jgn8(i`O7~6 zxK$c)64LT_sgcZ&vec+z2H&rkC;mPWHh*!|K2jnUvlTP=pUo?u3hWUVoWmK4R^9)I zAzh!oRhDhE@4~X)XSJ_SUh|m1>hz)>Epi;v7^*bQ;}j93m2wi&RX?}-C7*gUq#NI@ zGOc58rVV>dQzIEaEO@PCVBLT$(j!F`RMAv8#^*$lYgTusRYURAwMF8EZetxI82B+s z`z+1wmz6ELSf7j!Xm+HgDrNgfDV*#t+ROb#9?Zyt{A%Rsvj0*NGhTn2Ds33J1MhAU zlsa=S4A+@{l}G8soHY(5De)+!Qogr%YCETuPj1^b!^~uX&&5@)|bMPIn zYR$nz?l-^k>yW^`7fQN$B&>{o^T;%79xpqkx?C&O8g-&Yt<(Ukr3_kWe<|r^QX-BN zry-R27SG-x}NZM;N{71_wRxwXjRK=*ls0BKHr)#V_Lkxd5bo6SDGTeHa_CrUP zBCi|1{m}7&DsBaO^KwJnp0@J-amzQ0+i%-y?QXk(T}a-t~cHo^z>QDFD)6)fXCSbJk% eP^J00or-VRsaUCE2A`?b=Mm4BnYXId>i+-+$aWzB From f64e5f2444343bd15a05dc0fee9fdb65477efc61 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 13 Feb 2018 13:06:26 -0800 Subject: [PATCH 20/25] Introducing the cull group --- .../src/avatars-renderer/Avatar.cpp | 2 +- libraries/render/src/render/CullTask.cpp | 24 +++++++++++++++++++ libraries/render/src/render/Item.cpp | 10 ++++++++ libraries/render/src/render/Item.h | 19 +++++++++++++++ .../src/render/RenderFetchCullSortTask.cpp | 4 ++-- 5 files changed, 56 insertions(+), 3 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 86635cd3bf..9cdd4e2d00 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -50,7 +50,7 @@ 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); + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withCullGroup(); } template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { return static_pointer_cast(avatar)->getBounds(); diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 4dec3030ef..467cf5adbf 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -227,6 +227,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); + if (item.getKey().isCullGroup()) { + item.fetchMetaSubItemBounds(outItems, (*scene)); + } } } } @@ -239,6 +242,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); + if (item.getKey().isCullGroup()) { + item.fetchMetaSubItemBounds(outItems, (*scene)); + } } } } @@ -251,6 +257,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); + if (item.getKey().isCullGroup()) { + item.fetchMetaSubItemBounds(outItems, (*scene)); + } } } } @@ -263,6 +272,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); + if (item.getKey().isCullGroup()) { + item.fetchMetaSubItemBounds(outItems, (*scene)); + } } } } @@ -277,6 +289,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); + if (item.getKey().isCullGroup()) { + item.fetchMetaSubItemBounds(outItems, (*scene)); + } } } } @@ -290,6 +305,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, ItemBound itemBound(id, item.getBound()); if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); + if (item.getKey().isCullGroup()) { + item.fetchMetaSubItemBounds(outItems, (*scene)); + } } } } @@ -304,6 +322,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, ItemBound itemBound(id, item.getBound()); if (test.frustumTest(itemBound.bound)) { outItems.emplace_back(itemBound); + if (item.getKey().isCullGroup()) { + item.fetchMetaSubItemBounds(outItems, (*scene)); + } } } } @@ -319,6 +340,9 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (test.frustumTest(itemBound.bound)) { if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); + if (item.getKey().isCullGroup()) { + item.fetchMetaSubItemBounds(outItems, (*scene)); + } } } } diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index 612dba076b..b8ca091c40 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -113,6 +113,16 @@ const ShapeKey Item::getShapeKey() const { return shapeKey; } +uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) const { + ItemIDs subItems; + auto numSubs = fetchMetaSubItems(subItems); + + for (auto id : subItems) { + subItemBounds.emplace_back(id, scene.getItem(id).getBound()); + } + return numSubs; +} + namespace render { template <> const ItemKey payloadGetKey(const PayloadProxyInterface::Pointer& payload) { if (!payload) { diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index ff4b3a0458..3c82e49e8d 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -78,11 +78,13 @@ public: INVISIBLE, // Visible or not in the scene? SHADOW_CASTER, // Item cast shadows LAYERED, // Item belongs to one of the layers different from the default layer + CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS, __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) + __META_CULLED, // Reserved bit for sub item of a meta render item to indicate that the culling is tied to the culling of the meta render item, not this one NUM_FLAGS, // Not a valid flag }; @@ -122,6 +124,7 @@ public: Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } Builder& withLayered() { _flags.set(LAYERED); return (*this); } + Builder& withCullGroup() { _flags.set(CULL_GROUP); return (*this); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } // Set ALL the tags in one call using the Tag bits @@ -132,6 +135,9 @@ public: static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); } static Builder light() { return Builder().withTypeLight(); } static Builder background() { return Builder().withViewSpace().withLayered(); } + + // Not meant to be public, part of the inner item / key / filter system + Builder& __withMetaCulled() { _flags.set(__META_CULLED); return (*this); } }; ItemKey(const Builder& builder) : ItemKey(builder._flags) {} @@ -159,6 +165,9 @@ public: bool isLayered() const { return _flags[LAYERED]; } bool isSpatial() const { return !isLayered(); } + bool isCullGroup() const { return _flags[CULL_GROUP]; } + void setCullGroup(bool cullGroup) { (cullGroup ? _flags.set(CULL_GROUP) : _flags.reset(CULL_GROUP)); } + bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } @@ -166,6 +175,9 @@ public: bool isSmall() const { return _flags[__SMALLER]; } void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); } + bool isMetaCulled() const { return _flags[__META_CULLED]; } + void setMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(__META_CULLED) : _flags.reset(__META_CULLED)); } + bool operator==(const ItemKey& key) { return (_flags == key._flags); } bool operator!=(const ItemKey& key) { return (_flags != key._flags); } }; @@ -221,6 +233,12 @@ public: Builder& withoutLayered() { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } Builder& withLayered() { _value.set(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } + Builder& withoutCullGroup() { _value.reset(ItemKey::CULL_GROUP); _mask.set(ItemKey::CULL_GROUP); return (*this); } + Builder& withCullGroup() { _value.set(ItemKey::CULL_GROUP); _mask.set(ItemKey::CULL_GROUP); return (*this); } + + Builder& withoutMetaCulled() { _value.reset(ItemKey::__META_CULLED); _mask.set(ItemKey::__META_CULLED); return (*this); } + Builder& withMetaCulled() { _value.set(ItemKey::__META_CULLED); _mask.set(ItemKey::__META_CULLED); return (*this); } + Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } // Set ALL the tags in one call using the Tag bits and the Tag bits touched @@ -420,6 +438,7 @@ public: // Meta Type Interface uint32_t fetchMetaSubItems(ItemIDs& subItems) const { return _payload->fetchMetaSubItems(subItems); } + uint32_t fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) const; // Access the status const StatusPointer& getStatus() const { return _payload->getStatus(); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 6fb9ba88aa..4fe5e2f1be 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -22,7 +22,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin // CPU jobs: // Fetch and cull the items from the scene - const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered().withTagBits(tagBits, tagMask); + const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered().withoutMetaCulled().withTagBits(tagBits, tagMask); const auto spatialFilter = render::Varying(filter); const auto fetchInput = FetchSpatialTree::Inputs(filter, glm::ivec2(0,0)).asVarying(); const auto spatialSelection = task.addJob("FetchSceneSelection", fetchInput); @@ -30,7 +30,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto culledSpatialSelection = task.addJob("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM); // Overlays are not culled - const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withTagBits(tagBits, tagMask); + const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withoutMetaCulled().withTagBits(tagBits, tagMask); const auto nonspatialFilter = render::Varying(overlayfilter); const auto nonspatialSelection = task.addJob("FetchOverlaySelection", nonspatialFilter); From 3e41229e8c674c1a568c16b4b199c5a0f1d8632f Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Tue, 13 Feb 2018 13:30:17 -0800 Subject: [PATCH 21/25] Commerce: Fix wrap mode for very long P2P memos --- interface/resources/qml/hifi/commerce/wallet/WalletHome.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index b980c13e3c..83c1a2035d 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -391,7 +391,7 @@ Item { anchors.topMargin: 15; width: 118; height: paintedHeight; - wrapMode: Text.WordWrap; + wrapMode: Text.Wrap; // Alignment horizontalAlignment: Text.AlignRight; } @@ -408,7 +408,7 @@ Item { height: paintedHeight; color: model.status === "invalidated" ? hifi.colors.redAccent : hifi.colors.baseGrayHighlight; linkColor: hifi.colors.blueAccent; - wrapMode: Text.WordWrap; + wrapMode: Text.Wrap; font.strikeout: model.status === "invalidated"; onLinkActivated: { From 1d3ae1b187cad4b2a48e5823ccfde3476e2106a1 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 13 Feb 2018 17:50:01 -0800 Subject: [PATCH 22/25] Work in progress to get the render items beeing tagged correctly for groupCulled --- interface/src/avatar/MyAvatar.cpp | 8 ++--- interface/src/ui/overlays/ModelOverlay.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 2 +- .../render-utils/src/MeshPartPayload.cpp | 12 +++++-- libraries/render-utils/src/MeshPartPayload.h | 4 +-- libraries/render-utils/src/Model.cpp | 36 ++++++++++--------- libraries/render-utils/src/Model.h | 6 +++- libraries/render/src/render/CullTask.cpp | 9 ++--- libraries/render/src/render/Item.cpp | 7 +++- libraries/render/src/render/Item.h | 5 ++- .../src/render/RenderFetchCullSortTask.cpp | 2 +- 11 files changed, 57 insertions(+), 36 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ba4d48fd3f..9c063b69fb 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1111,7 +1111,7 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { } void MyAvatar::setEnableMeshVisible(bool isEnabled) { - _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); + _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { @@ -1461,7 +1461,7 @@ void MyAvatar::clearJointsData() { void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { Avatar::setSkeletonModelURL(skeletonModelURL); - _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE); + _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); _headBoneSet.clear(); _cauterizationNeedsUpdate = true; saveAvatarUrl(); @@ -1808,7 +1808,7 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName, void MyAvatar::setVisibleInSceneIfReady(Model* model, const render::ScenePointer& scene, bool visible) { if (model->isActive() && model->isRenderable()) { - model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE); + model->setVisibleInScene(visible, scene, render::ItemKey::TAG_BITS_NONE, true); } } @@ -2008,7 +2008,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) { _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) { _attachmentModels[i]->setVisibleInScene(shouldDrawHead, qApp->getMain3DScene(), - render::ItemKey::TAG_BITS_NONE); + render::ItemKey::TAG_BITS_NONE, true); } } } diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 4847650163..2b2c1403ff 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -87,7 +87,7 @@ void ModelOverlay::update(float deltatime) { if (_visibleDirty) { _visibleDirty = false; // don't show overlays in mirrors - _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0); + _model->setVisibleInScene(getVisible(), scene, render::ItemKey::TAG_BITS_0, false); } if (_drawInFrontDirty) { _drawInFrontDirty = false; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 137203f475..f477283843 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1343,7 +1343,7 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state // so most of the time we don't do anything in this function. - model->setVisibleInScene(_visible, scene, viewTaskBits); + model->setVisibleInScene(_visible, scene, viewTaskBits, false); } // TODO? early exit here when not visible? diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 9655b60a78..e3d4818ec5 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -71,7 +71,7 @@ void MeshPartPayload::updateMaterial(graphics::MaterialPointer drawMaterial) { _drawMaterial = drawMaterial; } -void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) { +void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled) { ItemKey::Builder builder; builder.withTypeShape(); @@ -85,6 +85,10 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) builder.withLayered(); } + if (isGroupCulled) { + builder.withMetaCulled(); + } + if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); if (matKey.isTranslucent()) { @@ -403,7 +407,7 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render _worldBound.transform(boundTransform); } -void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits) { +void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled) { ItemKey::Builder builder; builder.withTypeShape(); @@ -417,6 +421,10 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag builder.withLayered(); } + if (isGroupCulled) { + builder.withMetaCulled(); + } + if (_isBlendShaped || _isSkinned) { builder.withDeformed(); } diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 21f9dc2e68..40efc67572 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -33,7 +33,7 @@ public: typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - virtual void updateKey(bool isVisible, bool isLayered, uint8_t tagBits); + virtual void updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled = false); virtual void updateMeshPart(const std::shared_ptr& drawMesh, int partIndex); @@ -99,7 +99,7 @@ public: using TransformType = glm::mat4; #endif - void updateKey(bool isVisible, bool isLayered, uint8_t tagBits) override; + void updateKey(bool isVisible, bool isLayered, uint8_t tagBits, bool isGroupCulled = false) override; void updateClusterBuffer(const std::vector& clusterTransforms); void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index b9ccc28c01..bb8353c746 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -271,6 +271,7 @@ void Model::updateRenderItems() { uint8_t viewTagBits = self->getViewTagBits(); bool isLayeredInFront = self->isLayeredInFront(); bool isLayeredInHUD = self->isLayeredInHUD(); + bool isGroupCulled = self->isGroupCulled(); render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -284,7 +285,7 @@ void Model::updateRenderItems() { transaction.updateItem(itemID, [modelTransform, clusterTransforms, invalidatePayloadShapeKey, isWireframe, isVisible, viewTagBits, isLayeredInFront, - isLayeredInHUD](ModelMeshPartPayload& data) { + isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { data.updateClusterBuffer(clusterTransforms); Transform renderTransform = modelTransform; @@ -300,7 +301,7 @@ void Model::updateRenderItems() { } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); data.setShapeKey(invalidatePayloadShapeKey, isWireframe); }); @@ -684,10 +685,11 @@ void Model::calculateTriangleSets() { } } -void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits) { - if (_isVisible != isVisible || _viewTagBits != viewTagBits) { +void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) { + if (_isVisible != isVisible || _viewTagBits != viewTagBits || _isGroupCulled != isGroupCulled) { _isVisible = isVisible; _viewTagBits = viewTagBits; + _isGroupCulled = isGroupCulled; bool isLayeredInFront = _isLayeredInFront; bool isLayeredInHUD = _isLayeredInHUD; @@ -695,14 +697,14 @@ void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, render::Transaction transaction; foreach (auto item, _modelMeshRenderItemsMap.keys()) { transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, - isLayeredInHUD](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); + isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, - isLayeredInHUD](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); + isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); }); } scene->enqueueTransaction(transaction); @@ -717,19 +719,20 @@ void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& bool isVisible = _isVisible; uint8_t viewTagBits = _viewTagBits; bool isLayeredInHUD = _isLayeredInHUD; + bool isGroupCulled = _isGroupCulled; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, - isLayeredInHUD](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); + isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, - isLayeredInHUD](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); + isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } @@ -744,19 +747,20 @@ void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& sce bool isVisible = _isVisible; uint8_t viewTagBits = _viewTagBits; bool isLayeredInFront = _isLayeredInFront; + bool isGroupCulled = _isGroupCulled; render::Transaction transaction; foreach(auto item, _modelMeshRenderItemsMap.keys()) { transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, - isLayeredInHUD](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); + isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } foreach(auto item, _collisionRenderItemsMap.keys()) { transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, - isLayeredInHUD](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits); + isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, viewTagBits, isGroupCulled); data.setLayer(isLayeredInFront, isLayeredInHUD); }); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index ca0904f334..57d2798a66 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -86,7 +86,7 @@ public: const QUrl& getURL() const { return _url; } // new Scene/Engine rendering support - void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits); + void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled); void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene); void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene); bool needsFixupInScene() const; @@ -109,6 +109,8 @@ public: bool isLayeredInFront() const { return _isLayeredInFront; } bool isLayeredInHUD() const { return _isLayeredInHUD; } + bool isGroupCulled() const { return _isGroupCulled; } + virtual void updateRenderItems(); void setRenderItemsNeedUpdate(); bool getRenderItemsNeedUpdate() { return _renderItemsNeedUpdate; } @@ -462,6 +464,8 @@ protected: bool _isLayeredInFront { false }; bool _isLayeredInHUD { false }; + bool _isGroupCulled{ false }; + bool shouldInvalidatePayloadShapeKey(int meshIndex); private: diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 467cf5adbf..b5ee251b5d 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -211,13 +211,14 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, outItems.clear(); outItems.reserve(inSelection.numItems()); - const auto filter = inputs.get1(); - if (!filter.selectsNothing()) { - // Now get the bound, and + const auto srcFilter = inputs.get1(); + if (!srcFilter.selectsNothing()) { + auto filter = render::ItemFilter::Builder(srcFilter).withoutMetaCulled().build(); + + // Now get the bound, and // filter individually against the _filter // visibility cull if partially selected ( octree cell contianing it was partial) // distance cull if was a subcell item ( octree cell is way bigger than the item bound itself, so now need to test per item) - if (_skipCulling) { // inside & fit items: filter only, culling is disabled { diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index b8ca091c40..ed052adf6e 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -118,7 +118,12 @@ uint32_t Item::fetchMetaSubItemBounds(ItemBounds& subItemBounds, Scene& scene) c auto numSubs = fetchMetaSubItems(subItems); for (auto id : subItems) { - subItemBounds.emplace_back(id, scene.getItem(id).getBound()); + auto& item = scene.getItem(id); + if (item.exist()) { + subItemBounds.emplace_back(id, item.getBound()); + } else { + numSubs--; + } } return numSubs; } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 3c82e49e8d..87ad25f4b2 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -125,6 +125,7 @@ public: Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } Builder& withLayered() { _flags.set(LAYERED); return (*this); } Builder& withCullGroup() { _flags.set(CULL_GROUP); return (*this); } + Builder& withMetaCulled() { _flags.set(__META_CULLED); return (*this); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } // Set ALL the tags in one call using the Tag bits @@ -135,9 +136,6 @@ public: static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); } static Builder light() { return Builder().withTypeLight(); } static Builder background() { return Builder().withViewSpace().withLayered(); } - - // Not meant to be public, part of the inner item / key / filter system - Builder& __withMetaCulled() { _flags.set(__META_CULLED); return (*this); } }; ItemKey(const Builder& builder) : ItemKey(builder._flags) {} @@ -205,6 +203,7 @@ public: ItemKey::Flags _mask{ 0 }; public: Builder() {} + Builder(const ItemFilter& srcFilter) : _value(srcFilter._value), _mask(srcFilter._mask) {} ItemFilter build() const { return ItemFilter(_value, _mask); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 4fe5e2f1be..14a5a632ad 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -22,7 +22,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin // CPU jobs: // Fetch and cull the items from the scene - const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered().withoutMetaCulled().withTagBits(tagBits, tagMask); + const ItemFilter filter = ItemFilter::Builder::visibleWorldItems().withoutLayered().withTagBits(tagBits, tagMask); const auto spatialFilter = render::Varying(filter); const auto fetchInput = FetchSpatialTree::Inputs(filter, glm::ivec2(0,0)).asVarying(); const auto spatialSelection = task.addJob("FetchSceneSelection", fetchInput); From 6357f36a97b4475c0d87fe69853f4d34837f26a1 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 14 Feb 2018 10:39:14 -0800 Subject: [PATCH 23/25] Fixing names --- .../src/avatars-renderer/Avatar.cpp | 2 +- .../render-utils/src/MeshPartPayload.cpp | 4 +-- libraries/render/src/render/CullTask.cpp | 18 ++++++------- libraries/render/src/render/Item.h | 26 +++++++++---------- .../src/render/RenderFetchCullSortTask.cpp | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 9cdd4e2d00..a2a23f2508 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -50,7 +50,7 @@ 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).withCullGroup(); + return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withMetaCullGroup(); } template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { return static_pointer_cast(avatar)->getBounds(); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index e3d4818ec5..da11535396 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -86,7 +86,7 @@ void MeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tagBits, } if (isGroupCulled) { - builder.withMetaCulled(); + builder.withSubMetaCulled(); } if (_drawMaterial) { @@ -422,7 +422,7 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, uint8_t tag } if (isGroupCulled) { - builder.withMetaCulled(); + builder.withSubMetaCulled(); } if (_isBlendShaped || _isSkinned) { diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index b5ee251b5d..f04427540a 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -213,7 +213,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, const auto srcFilter = inputs.get1(); if (!srcFilter.selectsNothing()) { - auto filter = render::ItemFilter::Builder(srcFilter).withoutMetaCulled().build(); + auto filter = render::ItemFilter::Builder(srcFilter).withoutSubMetaCulled().build(); // Now get the bound, and // filter individually against the _filter @@ -228,7 +228,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); - if (item.getKey().isCullGroup()) { + if (item.getKey().isMetaCullGroup()) { item.fetchMetaSubItemBounds(outItems, (*scene)); } } @@ -243,7 +243,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); - if (item.getKey().isCullGroup()) { + if (item.getKey().isMetaCullGroup()) { item.fetchMetaSubItemBounds(outItems, (*scene)); } } @@ -258,7 +258,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); - if (item.getKey().isCullGroup()) { + if (item.getKey().isMetaCullGroup()) { item.fetchMetaSubItemBounds(outItems, (*scene)); } } @@ -273,7 +273,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); - if (item.getKey().isCullGroup()) { + if (item.getKey().isMetaCullGroup()) { item.fetchMetaSubItemBounds(outItems, (*scene)); } } @@ -290,7 +290,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); - if (item.getKey().isCullGroup()) { + if (item.getKey().isMetaCullGroup()) { item.fetchMetaSubItemBounds(outItems, (*scene)); } } @@ -306,7 +306,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, ItemBound itemBound(id, item.getBound()); if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); - if (item.getKey().isCullGroup()) { + if (item.getKey().isMetaCullGroup()) { item.fetchMetaSubItemBounds(outItems, (*scene)); } } @@ -323,7 +323,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, ItemBound itemBound(id, item.getBound()); if (test.frustumTest(itemBound.bound)) { outItems.emplace_back(itemBound); - if (item.getKey().isCullGroup()) { + if (item.getKey().isMetaCullGroup()) { item.fetchMetaSubItemBounds(outItems, (*scene)); } } @@ -341,7 +341,7 @@ void CullSpatialSelection::run(const RenderContextPointer& renderContext, if (test.frustumTest(itemBound.bound)) { if (test.solidAngleTest(itemBound.bound)) { outItems.emplace_back(itemBound); - if (item.getKey().isCullGroup()) { + if (item.getKey().isMetaCullGroup()) { item.fetchMetaSubItemBounds(outItems, (*scene)); } } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 87ad25f4b2..e4dcc7ee03 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -78,13 +78,13 @@ public: INVISIBLE, // Visible or not in the scene? SHADOW_CASTER, // Item cast shadows LAYERED, // Item belongs to one of the layers different from the default layer - CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the + META_CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the view + SUB_META_CULLED, // As a sub item of a meta render item set as cull group, need to be set to my culling to the meta render it FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS, __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) - __META_CULLED, // Reserved bit for sub item of a meta render item to indicate that the culling is tied to the culling of the meta render item, not this one NUM_FLAGS, // Not a valid flag }; @@ -124,8 +124,8 @@ public: Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } Builder& withLayered() { _flags.set(LAYERED); return (*this); } - Builder& withCullGroup() { _flags.set(CULL_GROUP); return (*this); } - Builder& withMetaCulled() { _flags.set(__META_CULLED); return (*this); } + Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); } + Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } // Set ALL the tags in one call using the Tag bits @@ -163,8 +163,11 @@ public: bool isLayered() const { return _flags[LAYERED]; } bool isSpatial() const { return !isLayered(); } - bool isCullGroup() const { return _flags[CULL_GROUP]; } - void setCullGroup(bool cullGroup) { (cullGroup ? _flags.set(CULL_GROUP) : _flags.reset(CULL_GROUP)); } + bool isMetaCullGroup() const { return _flags[META_CULL_GROUP]; } + void setMetaCullGroup(bool cullGroup) { (cullGroup ? _flags.set(META_CULL_GROUP) : _flags.reset(META_CULL_GROUP)); } + + bool isSubMetaCulled() const { return _flags[SUB_META_CULLED]; } + void setSubMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(SUB_META_CULLED) : _flags.reset(SUB_META_CULLED)); } bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } @@ -173,9 +176,6 @@ public: bool isSmall() const { return _flags[__SMALLER]; } void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); } - bool isMetaCulled() const { return _flags[__META_CULLED]; } - void setMetaCulled(bool metaCulled) { (metaCulled ? _flags.set(__META_CULLED) : _flags.reset(__META_CULLED)); } - bool operator==(const ItemKey& key) { return (_flags == key._flags); } bool operator!=(const ItemKey& key) { return (_flags != key._flags); } }; @@ -232,11 +232,11 @@ public: Builder& withoutLayered() { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } Builder& withLayered() { _value.set(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } - Builder& withoutCullGroup() { _value.reset(ItemKey::CULL_GROUP); _mask.set(ItemKey::CULL_GROUP); return (*this); } - Builder& withCullGroup() { _value.set(ItemKey::CULL_GROUP); _mask.set(ItemKey::CULL_GROUP); return (*this); } + Builder& withoutMetaCullGroup() { _value.reset(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } + Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } - Builder& withoutMetaCulled() { _value.reset(ItemKey::__META_CULLED); _mask.set(ItemKey::__META_CULLED); return (*this); } - Builder& withMetaCulled() { _value.set(ItemKey::__META_CULLED); _mask.set(ItemKey::__META_CULLED); return (*this); } + Builder& withoutSubMetaCulled() { _value.reset(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } + Builder& withSubMetaCulled() { _value.set(ItemKey::SUB_META_CULLED); _mask.set(ItemKey::SUB_META_CULLED); return (*this); } Builder& withoutTag(ItemKey::Tag tagIndex) { _value.reset(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } Builder& withTag(ItemKey::Tag tagIndex) { _value.set(ItemKey::FIRST_TAG_BIT + tagIndex); _mask.set(ItemKey::FIRST_TAG_BIT + tagIndex); return (*this); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 14a5a632ad..7b9765dca1 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -30,7 +30,7 @@ void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varyin const auto culledSpatialSelection = task.addJob("CullSceneSelection", cullInputs, cullFunctor, RenderDetails::ITEM); // Overlays are not culled - const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withoutMetaCulled().withTagBits(tagBits, tagMask); + const ItemFilter overlayfilter = ItemFilter::Builder().withVisible().withoutSubMetaCulled().withTagBits(tagBits, tagMask); const auto nonspatialFilter = render::Varying(overlayfilter); const auto nonspatialSelection = task.addJob("FetchOverlaySelection", nonspatialFilter); From 8853bd63884450383ed3a5aeed6f310c3d54ca49 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 14 Feb 2018 11:11:28 -0800 Subject: [PATCH 24/25] Fix spectator camera crash --- interface/src/Application.cpp | 1 + .../display-plugins/OpenGLDisplayPlugin.cpp | 43 +++++++++++-------- .../src/display-plugins/OpenGLDisplayPlugin.h | 2 +- libraries/gl/src/gl/OffscreenGLCanvas.cpp | 27 ++++++++++++ libraries/gl/src/gl/OffscreenGLCanvas.h | 3 ++ .../qml/src/qml/impl/RenderEventHandler.cpp | 1 + plugins/openvr/src/OpenVrDisplayPlugin.cpp | 2 +- 7 files changed, 59 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0eb36173c2..5a340f471e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2338,6 +2338,7 @@ void Application::initializeGL() { qFatal("Unable to make offscreen context current"); } _offscreenContext->doneCurrent(); + _offscreenContext->setThreadContext(); _renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); // The UI can't be created until the primary OpenGL diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 40dcf1b8c7..9bd7d89634 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -130,14 +131,14 @@ public: CHECK_GL_ERROR(); _context->doneCurrent(); while (!_shutdown) { - if (_pendingMainThreadOperation) { + if (_pendingOtherThreadOperation) { PROFILE_RANGE(render, "MainThreadOp") { Lock lock(_mutex); _context->doneCurrent(); // Move the context to the main thread - _context->moveToThread(qApp->thread()); - _pendingMainThreadOperation = false; + _context->moveToThread(_targetOperationThread); + _pendingOtherThreadOperation = false; // Release the main thread to do it's action _condition.notify_one(); } @@ -146,7 +147,7 @@ public: { // Main thread does it's thing while we wait on the lock to release Lock lock(_mutex); - _condition.wait(lock, [&] { return _finishedMainThreadOperation; }); + _condition.wait(lock, [&] { return _finishedOtherThreadOperation; }); } } @@ -214,23 +215,25 @@ public: _condition.notify_one(); } - void withMainThreadContext(std::function f) { + void withOtherThreadContext(std::function f) { // Signal to the thread that there is work to be done on the main thread Lock lock(_mutex); - _pendingMainThreadOperation = true; - _finishedMainThreadOperation = false; - _condition.wait(lock, [&] { return !_pendingMainThreadOperation; }); + _targetOperationThread = QThread::currentThread(); + _pendingOtherThreadOperation = true; + _finishedOtherThreadOperation = false; + _condition.wait(lock, [&] { return !_pendingOtherThreadOperation; }); _context->makeCurrent(); f(); _context->doneCurrent(); + _targetOperationThread = nullptr; // Move the context back to the presentation thread _context->moveToThread(this); // restore control of the context to the presentation thread and signal // the end of the operation - _finishedMainThreadOperation = true; + _finishedOtherThreadOperation = true; lock.unlock(); _condition.notify_one(); } @@ -244,9 +247,11 @@ private: Mutex _mutex; // Used to allow the main thread to perform context operations Condition _condition; - bool _pendingMainThreadOperation { false }; - bool _finishedMainThreadOperation { false }; - QThread* _mainThread { nullptr }; + + + QThread* _targetOperationThread { nullptr }; + bool _pendingOtherThreadOperation { false }; + bool _finishedOtherThreadOperation { false }; std::queue _newPluginQueue; gl::Context* _context { nullptr }; }; @@ -744,10 +749,12 @@ void OpenGLDisplayPlugin::swapBuffers() { context->swapBuffers(); } -void OpenGLDisplayPlugin::withMainThreadContext(std::function f) const { +void OpenGLDisplayPlugin::withOtherThreadContext(std::function f) const { static auto presentThread = DependencyManager::get(); - presentThread->withMainThreadContext(f); - _container->makeRenderingContextCurrent(); + presentThread->withOtherThreadContext(f); + if (!OffscreenGLCanvas::restoreThreadContext()) { + qWarning("Unable to restore original OpenGL context"); + } } bool OpenGLDisplayPlugin::setDisplayTexture(const QString& name) { @@ -784,7 +791,7 @@ QImage OpenGLDisplayPlugin::getScreenshot(float aspectRatio) const { } auto glBackend = const_cast(*this).getGLBackend(); QImage screenshot(bestSize.x, bestSize.y, QImage::Format_ARGB32); - withMainThreadContext([&] { + withOtherThreadContext([&] { glBackend->downloadFramebuffer(_compositeFramebuffer, ivec4(corner, bestSize), screenshot); }); return screenshot.mirrored(false, true); @@ -797,7 +804,7 @@ QImage OpenGLDisplayPlugin::getSecondaryCameraScreenshot() const { auto glBackend = const_cast(*this).getGLBackend(); QImage screenshot(region.z, region.w, QImage::Format_ARGB32); - withMainThreadContext([&] { + withOtherThreadContext([&] { glBackend->downloadFramebuffer(secondaryCameraFramebuffer, region, screenshot); }); return screenshot.mirrored(false, true); @@ -886,7 +893,7 @@ void OpenGLDisplayPlugin::updateCompositeFramebuffer() { void OpenGLDisplayPlugin::copyTextureToQuickFramebuffer(NetworkTexturePointer networkTexture, QOpenGLFramebufferObject* target, GLsync* fenceSync) { #if !defined(USE_GLES) auto glBackend = const_cast(*this).getGLBackend(); - withMainThreadContext([&] { + withOtherThreadContext([&] { GLuint sourceTexture = glBackend->getTextureID(networkTexture->getGPUTexture()); GLuint targetTexture = target->texture(); GLuint fbo[2] {0, 0}; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h index 1176471b40..bf06486095 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.h @@ -119,7 +119,7 @@ protected: void renderFromTexture(gpu::Batch& batch, const gpu::TexturePointer texture, glm::ivec4 viewport, const glm::ivec4 scissor); virtual void updateFrameData(); - void withMainThreadContext(std::function f) const; + void withOtherThreadContext(std::function f) const; void present(); virtual void swapBuffers(); diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.cpp b/libraries/gl/src/gl/OffscreenGLCanvas.cpp index 380ba085cc..1bde9e289e 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.cpp +++ b/libraries/gl/src/gl/OffscreenGLCanvas.cpp @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -119,3 +120,29 @@ void OffscreenGLCanvas::moveToThreadWithContext(QThread* thread) { moveToThread(thread); _context->moveToThread(thread); } + +static const char* THREAD_CONTEXT_PROPERTY = "offscreenGlCanvas"; + +void OffscreenGLCanvas::setThreadContext() { + QThread::currentThread()->setProperty(THREAD_CONTEXT_PROPERTY, QVariant::fromValue(this)); +} + +bool OffscreenGLCanvas::restoreThreadContext() { + // Restore the rendering context for this thread + auto threadCanvasVariant = QThread::currentThread()->property(THREAD_CONTEXT_PROPERTY); + if (!threadCanvasVariant.isValid()) { + return false; + } + + auto threadCanvasObject = qvariant_cast(threadCanvasVariant); + auto threadCanvas = static_cast(threadCanvasObject); + if (!threadCanvas) { + return false; + } + + if (!threadCanvas->makeCurrent()) { + qFatal("Unable to restore Offscreen rendering context"); + } + + return true; +} diff --git a/libraries/gl/src/gl/OffscreenGLCanvas.h b/libraries/gl/src/gl/OffscreenGLCanvas.h index be0e0d9678..ed644b98fb 100644 --- a/libraries/gl/src/gl/OffscreenGLCanvas.h +++ b/libraries/gl/src/gl/OffscreenGLCanvas.h @@ -32,6 +32,9 @@ public: } QObject* getContextObject(); + void setThreadContext(); + static bool restoreThreadContext(); + private slots: void onMessageLogged(const QOpenGLDebugMessage &debugMessage); diff --git a/libraries/qml/src/qml/impl/RenderEventHandler.cpp b/libraries/qml/src/qml/impl/RenderEventHandler.cpp index cce1b68da9..6b66ce9314 100644 --- a/libraries/qml/src/qml/impl/RenderEventHandler.cpp +++ b/libraries/qml/src/qml/impl/RenderEventHandler.cpp @@ -58,6 +58,7 @@ void RenderEventHandler::onInitalize() { return; } + _canvas.setThreadContext(); if (!_canvas.makeCurrent()) { qFatal("Unable to make QML rendering context current on render thread"); } diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 4b5f0e6517..2949e72c74 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -485,7 +485,7 @@ bool OpenVrDisplayPlugin::internalActivate() { if (_threadedSubmit) { _submitThread = std::make_shared(*this); if (!_submitCanvas) { - withMainThreadContext([&] { + withOtherThreadContext([&] { _submitCanvas = std::make_shared(); _submitCanvas->create(); _submitCanvas->doneCurrent(); From e14f46101b47c55a4bd540060655ae8e9cadeed8 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 14 Feb 2018 13:49:43 -0800 Subject: [PATCH 25/25] fix tablet rotation when switching into and out of create mode --- scripts/system/libraries/WebTablet.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 05b4963280..a28de5abc2 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -47,7 +47,7 @@ function calcSpawnInfo(hand, landscape) { var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position; var headRot = (HMD.active && Camera.mode === "first person") ? HMD.orientation : Camera.orientation; - var forward = Quat.getForward(headRot); + var forward = Quat.getForward(Quat.cancelOutRollAndPitch(headRot)); var FORWARD_OFFSET = 0.5 * MyAvatar.sensorToWorldScale; finalPosition = Vec3.sum(headPos, Vec3.multiply(FORWARD_OFFSET, forward)); var orientation = Quat.lookAt({x: 0, y: 0, z: 0}, forward, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.UNIT_Y)); @@ -269,8 +269,9 @@ WebTablet.prototype.setLandscape = function(newLandscapeValue) { } this.landscape = newLandscapeValue; + var cameraOrientation = Quat.cancelOutRollAndPitch(Camera.orientation); Overlays.editOverlay(this.tabletEntityID, - { rotation: Quat.multiply(Camera.orientation, this.landscape ? ROT_LANDSCAPE : ROT_Y_180) }); + { rotation: Quat.multiply(cameraOrientation, this.landscape ? ROT_LANDSCAPE : ROT_Y_180) }); var tabletWidth = getTabletWidthFromSettings() * MyAvatar.sensorToWorldScale; var tabletScaleFactor = tabletWidth / TABLET_NATURAL_DIMENSIONS.x; @@ -278,7 +279,7 @@ WebTablet.prototype.setLandscape = function(newLandscapeValue) { var screenWidth = 0.82 * tabletWidth; var screenHeight = 0.81 * tabletHeight; Overlays.editOverlay(this.webOverlayID, { - rotation: Quat.multiply(Camera.orientation, ROT_LANDSCAPE_WINDOW), + rotation: Quat.multiply(cameraOrientation, ROT_LANDSCAPE_WINDOW), dimensions: {x: this.landscape ? screenHeight : screenWidth, y: this.landscape ? screenWidth : screenHeight, z: 0.1} }); };