From 72ed5f6d91852e0463e69f5876ceb9deb81adaca Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 23 Jan 2018 13:40:31 -0500 Subject: [PATCH 01/11] [Case 4315] Fixes OK button hard to use within HMD mode (details below). * Shape Color picker dynamically updates entity color. * This removes the OK button which was hard to interact with in HMD mode. The user no longer needs to click the OK button to submit changes to the color; rather the color of the entity updates as the user manipulates the color wheel and/or slider. Known Issue/TODO(s): * Color Picker's Color Preview area has a bug where the original/starting color preview is black as opposed to reflecting the entity's color upon clicking the color picker. * Color preview restore color functionality isn't working. Clicking the initial color preview doesn't restore the color. * In HMD Mode: While interacting with the picker the user is able to control scrolling navigation for the edit menu. For example, when moving up or down to change the hue the edit menu behind the picker will scroll up and down correlatively. * In HMD Mode: When the picker is dismissed (user clicks outside the picker), the RGB fields for the color still receive input. Tested in Desktop & HMD Modes. Changes Committed: modified: scripts/system/html/js/entityProperties.js --- scripts/system/html/js/entityProperties.js | 36 +++++++++++----------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 72092b66ca..3b6e207ccb 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -1040,9 +1040,9 @@ function loaded() { elZoneAmbientLightURL.value = properties.ambientLight.ambientURL; // Haze - elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit'); + elZoneHazeModeInherit.checked = (properties.hazeMode === 'inherit'); elZoneHazeModeDisabled.checked = (properties.hazeMode === 'disabled'); - elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled'); + elZoneHazeModeEnabled.checked = (properties.hazeMode === 'enabled'); elZoneHazeRange.value = properties.haze.hazeRange.toFixed(0); elZoneHazeColor.style.backgroundColor = "rgb(" + @@ -1308,15 +1308,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', + submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-color-control2').attr('active', 'true'); }, onHide: function(colpick) { $('#property-color-control2').attr('active', 'false'); }, - onSubmit: function(hsb, hex, rgb, el) { + onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); - $(el).colpickHide(); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); } })); @@ -1332,15 +1332,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', + submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-light-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-light-color').attr('active', 'false'); }, - onSubmit: function(hsb, hex, rgb, el) { + onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); - $(el).colpickHide(); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b); } })); @@ -1387,15 +1387,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', + submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-text-text-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-text-text-color').attr('active', 'false'); }, - onSubmit: function(hsb, hex, rgb, el) { + onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); - $(el).colpickHide(); $(el).attr('active', 'false'); emitColorPropertyUpdate('textColor', rgb.r, rgb.g, rgb.b); } @@ -1411,15 +1411,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', + submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-text-background-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-text-background-color').attr('active', 'false'); }, - onSubmit: function(hsb, hex, rgb, el) { + onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); - $(el).colpickHide(); emitColorPropertyUpdate('backgroundColor', rgb.r, rgb.g, rgb.b); } })); @@ -1436,15 +1436,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', + submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-zone-key-light-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-key-light-color').attr('active', 'false'); }, - onSubmit: function(hsb, hex, rgb, el) { + onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); - $(el).colpickHide(); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'keyLight'); } })); @@ -1505,15 +1505,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', + submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-zone-haze-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-haze-color').attr('active', 'false'); }, - onSubmit: function(hsb, hex, rgb, el) { + onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); - $(el).colpickHide(); emitColorPropertyUpdate('hazeColor', rgb.r, rgb.g, rgb.b, 'haze'); } })); @@ -1530,15 +1530,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', + submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-zone-haze-glare-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-haze-glare-color').attr('active', 'false'); }, - onSubmit: function(hsb, hex, rgb, el) { + onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); - $(el).colpickHide(); emitColorPropertyUpdate('hazeGlareColor', rgb.r, rgb.g, rgb.b, 'haze'); } })); @@ -1572,15 +1572,15 @@ function loaded() { colorScheme: 'dark', layout: 'hex', color: '000000', + submit: false, // We don't want to have a submission button onShow: function(colpick) { $('#property-zone-skybox-color').attr('active', 'true'); }, onHide: function(colpick) { $('#property-zone-skybox-color').attr('active', 'false'); }, - onSubmit: function(hsb, hex, rgb, el) { + onChange: function(hsb, hex, rgb, el) { $(el).css('background-color', '#' + hex); - $(el).colpickHide(); emitColorPropertyUpdate('color', rgb.r, rgb.g, rgb.b, 'skybox'); } })); From 4da7a1e65ae28a4927ceb5a20938625fc5ab5a18 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 23 Jan 2018 13:48:47 -0500 Subject: [PATCH 02/11] [Case 4315] ESLint pass on entityProperties.js. Re-ran after changes and issue count was 0. Changes Committed: modified: scripts/system/html/js/entityProperties.js --- scripts/system/html/js/entityProperties.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/system/html/js/entityProperties.js b/scripts/system/html/js/entityProperties.js index 3b6e207ccb..7008d0df66 100644 --- a/scripts/system/html/js/entityProperties.js +++ b/scripts/system/html/js/entityProperties.js @@ -653,16 +653,16 @@ function loaded() { var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y"); // Skybox - var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit"); + var elZoneSkyboxModeInherit = document.getElementById("property-zone-skybox-mode-inherit"); var elZoneSkyboxModeDisabled = document.getElementById("property-zone-skybox-mode-disabled"); - var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled"); + var elZoneSkyboxModeEnabled = document.getElementById("property-zone-skybox-mode-enabled"); // Ambient light var elCopySkyboxURLToAmbientURL = document.getElementById("copy-skybox-url-to-ambient-url"); - var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit"); + var elZoneAmbientLightModeInherit = document.getElementById("property-zone-ambient-light-mode-inherit"); var elZoneAmbientLightModeDisabled = document.getElementById("property-zone-ambient-light-mode-disabled"); - var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled"); + var elZoneAmbientLightModeEnabled = document.getElementById("property-zone-ambient-light-mode-enabled"); var elZoneAmbientLightIntensity = document.getElementById("property-zone-key-ambient-intensity"); var elZoneAmbientLightURL = document.getElementById("property-zone-key-ambient-url"); @@ -1013,9 +1013,9 @@ function loaded() { } else if (properties.type === "Zone") { // Key light - elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit'); + elZoneKeyLightModeInherit.checked = (properties.keyLightMode === 'inherit'); elZoneKeyLightModeDisabled.checked = (properties.keyLightMode === 'disabled'); - elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled'); + elZoneKeyLightModeEnabled.checked = (properties.keyLightMode === 'enabled'); elZoneKeyLightColor.style.backgroundColor = "rgb(" + properties.keyLight.color.red + "," + properties.keyLight.color.green + "," + properties.keyLight.color.blue + ")"; @@ -1027,14 +1027,14 @@ function loaded() { elZoneKeyLightDirectionY.value = properties.keyLight.direction.y.toFixed(2); // Skybox - elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit'); + elZoneSkyboxModeInherit.checked = (properties.skyboxMode === 'inherit'); elZoneSkyboxModeDisabled.checked = (properties.skyboxMode === 'disabled'); - elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled'); + elZoneSkyboxModeEnabled.checked = (properties.skyboxMode === 'enabled'); // Ambient light - elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit'); + elZoneAmbientLightModeInherit.checked = (properties.ambientLightMode === 'inherit'); elZoneAmbientLightModeDisabled.checked = (properties.ambientLightMode === 'disabled'); - elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled'); + elZoneAmbientLightModeEnabled.checked = (properties.ambientLightMode === 'enabled'); elZoneAmbientLightIntensity.value = properties.ambientLight.ambientIntensity.toFixed(2); elZoneAmbientLightURL.value = properties.ambientLight.ambientURL; From 180be18178139099b9e42662d8c1e9282b438238 Mon Sep 17 00:00:00 2001 From: LaShonda Hopper Date: Tue, 23 Jan 2018 14:02:31 -0500 Subject: [PATCH 03/11] [Case 4315] Fixes color picker issue in HMD mode (details below). Previously when in HMD mode, using the color picker to select a color via the gradient or hue areas would result in the page scrolling making it difficult to select the color or hue desired. This resolves the issue by turning off touch actions for the elements of the color picker that should have it when using the color picker. Tested in HMD & Desktop mode. Changes Committed: modified: scripts/system/html/css/colpick.css --- scripts/system/html/css/colpick.css | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/scripts/system/html/css/colpick.css b/scripts/system/html/css/colpick.css index 564f60cb3b..98417a5e9a 100644 --- a/scripts/system/html/css/colpick.css +++ b/scripts/system/html/css/colpick.css @@ -26,6 +26,7 @@ colpick Color Picker / colpick.com /*Color selection box with gradients*/ .colpick_color { position: absolute; + touch-action: none; left: 7px; top: 7px; width: 156px; @@ -84,6 +85,7 @@ colpick Color Picker / colpick.com /*Vertical hue bar*/ .colpick_hue { position: absolute; + touch-action: none; top: 6px; left: 175px; width: 19px; @@ -94,6 +96,7 @@ colpick Color Picker / colpick.com /*Hue bar sliding indicator*/ .colpick_hue_arrs { position: absolute; + touch-action: none; left: -8px; width: 35px; height: 7px; @@ -101,6 +104,7 @@ colpick Color Picker / colpick.com } .colpick_hue_larr { position:absolute; + touch-action: none; width: 0; height: 0; border-top: 6px solid transparent; @@ -109,6 +113,7 @@ colpick Color Picker / colpick.com } .colpick_hue_rarr { position:absolute; + touch-action: none; right:0; width: 0; height: 0; @@ -119,6 +124,7 @@ colpick Color Picker / colpick.com /*New color box*/ .colpick_new_color { position: absolute; + touch-action: none; left: 207px; top: 6px; width: 60px; @@ -129,6 +135,7 @@ colpick Color Picker / colpick.com /*Current color box*/ .colpick_current_color { position: absolute; + touch-action: none; left: 277px; top: 6px; width: 60px; @@ -139,6 +146,7 @@ colpick Color Picker / colpick.com /*Input field containers*/ .colpick_field, .colpick_hex_field { position: absolute; + touch-action: none; height: 20px; width: 60px; overflow:hidden; @@ -198,6 +206,7 @@ colpick Color Picker / colpick.com /*Text inputs*/ .colpick_field input, .colpick_hex_field input { position: absolute; + touch-action: none; right: 11px; margin: 0; padding: 0; @@ -217,6 +226,7 @@ colpick Color Picker / colpick.com /*Field up/down arrows*/ .colpick_field_arrs { position: absolute; + touch-action: none; top: 0; right: 0; width: 9px; @@ -225,6 +235,7 @@ colpick Color Picker / colpick.com } .colpick_field_uarr { position: absolute; + touch-action: none; top: 5px; width: 0; height: 0; @@ -234,6 +245,7 @@ colpick Color Picker / colpick.com } .colpick_field_darr { position: absolute; + touch-action: none; bottom:5px; width: 0; height: 0; @@ -244,6 +256,7 @@ colpick Color Picker / colpick.com /*Submit/Select button*/ .colpick_submit { position: absolute; + touch-action: none; left: 207px; top: 149px; width: 130px; From 579d9a864070f81043a1e1b5e2cde0c3dd0c3e68 Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Thu, 1 Feb 2018 00:48:03 +0300 Subject: [PATCH 04/11] fix slots invocation --- libraries/ui/src/QmlWindowClass.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/ui/src/QmlWindowClass.cpp b/libraries/ui/src/QmlWindowClass.cpp index 1209d39dcf..0825d238bc 100644 --- a/libraries/ui/src/QmlWindowClass.cpp +++ b/libraries/ui/src/QmlWindowClass.cpp @@ -227,7 +227,7 @@ bool QmlWindowClass::isVisible() { glm::vec2 QmlWindowClass::getPosition() { if (QThread::currentThread() != thread()) { vec2 result; - BLOCKING_INVOKE_METHOD(this, "getPosition", Q_RETURN_ARG(vec2, result)); + BLOCKING_INVOKE_METHOD(this, "getPosition", Q_RETURN_ARG(glm::vec2, result)); return result; } @@ -241,7 +241,7 @@ glm::vec2 QmlWindowClass::getPosition() { void QmlWindowClass::setPosition(const glm::vec2& position) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setPosition", Q_ARG(vec2, position)); + QMetaObject::invokeMethod(this, "setPosition", Q_ARG(const glm::vec2&, position)); return; } @@ -262,7 +262,7 @@ glm::vec2 toGlm(const QSizeF& size) { glm::vec2 QmlWindowClass::getSize() { if (QThread::currentThread() != thread()) { vec2 result; - BLOCKING_INVOKE_METHOD(this, "getSize", Q_RETURN_ARG(vec2, result)); + BLOCKING_INVOKE_METHOD(this, "getSize", Q_RETURN_ARG(glm::vec2, result)); return result; } @@ -275,7 +275,7 @@ glm::vec2 QmlWindowClass::getSize() { void QmlWindowClass::setSize(const glm::vec2& size) { if (QThread::currentThread() != thread()) { - QMetaObject::invokeMethod(this, "setSize", Q_ARG(vec2, size)); + QMetaObject::invokeMethod(this, "setSize", Q_ARG(const glm::vec2&, size)); return; } From 257932cedcd22d9979ccb5399cd18a715d65622f Mon Sep 17 00:00:00 2001 From: Triplelexx Date: Wed, 31 Jan 2018 22:00:30 +0000 Subject: [PATCH 05/11] remove cache buster --- scripts/tutorials/createTetherballStick.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/tutorials/createTetherballStick.js b/scripts/tutorials/createTetherballStick.js index 35f5fb0344..1b5bc36932 100644 --- a/scripts/tutorials/createTetherballStick.js +++ b/scripts/tutorials/createTetherballStick.js @@ -23,7 +23,7 @@ var BALL_DENSITY = 1000; var ACTION_DISTANCE = 0.35; var ACTION_TIMESCALE = 0.035; var MAX_DISTANCE_MULTIPLIER = 4; -var STICK_SCRIPT_URL = Script.resolvePath("./entity_scripts/tetherballStick.js?v=" + Date.now()); +var STICK_SCRIPT_URL = Script.resolvePath("./entity_scripts/tetherballStick.js"); var STICK_MODEL_URL = "http://hifi-content.s3.amazonaws.com/caitlyn/production/raveStick/newRaveStick2.fbx"; var COLLISION_SOUND_URL = "http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav"; From 1ed7d164c45dcb45be34d8a0633372bbe47502dc Mon Sep 17 00:00:00 2001 From: Alexander Ivash Date: Thu, 1 Feb 2018 01:15:03 +0300 Subject: [PATCH 06/11] FB11511 - position of log windows should be persistent between invocations of interface --- interface/src/ui/LogDialog.cpp | 12 ++++++- interface/src/ui/LogDialog.h | 4 +++ scripts/developer/debugging/debugWindow.js | 37 ++++++++++++++++++++-- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/LogDialog.cpp b/interface/src/ui/LogDialog.cpp index 00dc9be959..108edbfd39 100644 --- a/interface/src/ui/LogDialog.cpp +++ b/interface/src/ui/LogDialog.cpp @@ -38,7 +38,7 @@ const QString FATAL_TEXT = "[FATAL]"; const QString SUPPRESS_TEXT = "[SUPPRESS]"; const QString UNKNOWN_TEXT = "[UNKNOWN]"; -LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLogDialog(parent) { +LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLogDialog(parent), _windowGeometry("logDialogGeometry", QRect()) { _logger = logger; setWindowTitle("Log"); @@ -155,6 +155,11 @@ LogDialog::LogDialog(QWidget* parent, AbstractLoggerInterface* logger) : BaseLog _clearFilterButton->show(); connect(_clearFilterButton, &QPushButton::clicked, this, &LogDialog::handleClearFilterButton); handleClearFilterButton(); + + auto windowGeometry = _windowGeometry.get(); + if (windowGeometry.isValid()) { + setGeometry(windowGeometry); + } } void LogDialog::resizeEvent(QResizeEvent* event) { @@ -173,6 +178,11 @@ void LogDialog::resizeEvent(QResizeEvent* event) { ELEMENT_HEIGHT); } +void LogDialog::closeEvent(QCloseEvent* event) { + BaseLogDialog::closeEvent(event); + _windowGeometry.set(geometry()); +} + void LogDialog::handleRevealButton() { _logger->locateLog(); } diff --git a/interface/src/ui/LogDialog.h b/interface/src/ui/LogDialog.h index 5e4e084d5a..3cc7584fe8 100644 --- a/interface/src/ui/LogDialog.h +++ b/interface/src/ui/LogDialog.h @@ -13,6 +13,7 @@ #define hifi_LogDialog_h #include "BaseLogDialog.h" +#include class QCheckBox; class QPushButton; @@ -44,6 +45,8 @@ private slots: protected: void resizeEvent(QResizeEvent* event) override; + void closeEvent(QCloseEvent* event) override; + QString getCurrentLog() override; void printLogFile(); @@ -62,6 +65,7 @@ private: QString _filterSelection; AbstractLoggerInterface* _logger; + Setting::Handle _windowGeometry; }; #endif // hifi_LogDialog_h diff --git a/scripts/developer/debugging/debugWindow.js b/scripts/developer/debugging/debugWindow.js index 068efb351b..9522676007 100644 --- a/scripts/developer/debugging/debugWindow.js +++ b/scripts/developer/debugging/debugWindow.js @@ -22,14 +22,37 @@ if (scripts.length >= 2) { // Set up the qml ui var qml = Script.resolvePath('debugWindow.qml'); +var HMD_DEBUG_WINDOW_GEOMETRY_KEY = 'hmdDebugWindowGeometry'; +var hmdDebugWindowGeometryValue = Settings.getValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY) + +var windowWidth = 400; +var windowHeight = 900; + +var hasPosition = false; +var windowX = 0; +var windowY = 0; + +if (hmdDebugWindowGeometryValue !== '') { + var geometry = JSON.parse(hmdDebugWindowGeometryValue); + + windowWidth = geometry.width + windowHeight = geometry.height + windowX = geometry.x + windowY = geometry.y + hasPosition = true; +} + var window = new OverlayWindow({ title: 'Debug Window', source: qml, - width: 400, height: 900, + width: windowWidth, height: windowHeight, }); -window.setPosition(25, 50); -window.closed.connect(function() { Script.stop(); }); +if (hasPosition) { + window.setPosition(windowX, windowY); +} + +window.closed.connect(function () { Script.stop(); }); var getFormattedDate = function() { var date = new Date(); @@ -65,6 +88,14 @@ ScriptDiscoveryService.clearDebugWindow.connect(function() { }); Script.scriptEnding.connect(function () { + var geometry = JSON.stringify({ + x: window.position.x, + y: window.position.y, + width: window.size.x, + height: window.size.y + }) + + Settings.setValue(HMD_DEBUG_WINDOW_GEOMETRY_KEY, geometry); window.close(); }) From 4cd130dd63d21e3459d4b0e3d50a1309bf02db26 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 1 Feb 2018 13:39:57 +1300 Subject: [PATCH 07/11] Don't reparent model node with clusters if it's a root node --- libraries/fbx/src/FBXReader.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 14462e0558..14f12b5d1b 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1455,18 +1455,22 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS QSet remainingModels; for (QHash::const_iterator model = models.constBegin(); model != models.constEnd(); model++) { // models with clusters must be parented to the cluster top - foreach (const QString& deformerID, _connectionChildMap.values(model.key())) { - foreach (const QString& clusterID, _connectionChildMap.values(deformerID)) { - if (!clusters.contains(clusterID)) { - continue; + // Unless the model is a root node. + bool isARootNode = !modelIDs.contains(_connectionParentMap.value(model.key())); + if (!isARootNode) { + foreach(const QString& deformerID, _connectionChildMap.values(model.key())) { + foreach(const QString& clusterID, _connectionChildMap.values(deformerID)) { + if (!clusters.contains(clusterID)) { + continue; + } + QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url); + _connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key()); + _connectionParentMap.insert(model.key(), topID); + goto outerBreak; } - QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url); - _connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key()); - _connectionParentMap.insert(model.key(), topID); - goto outerBreak; } + outerBreak: ; } - outerBreak: // make sure the parent is in the child map QString parent = _connectionParentMap.value(model.key()); From a7ec4501e65396d4c7bf2316dd73188cea7a3c7d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 1 Feb 2018 13:43:14 +1300 Subject: [PATCH 08/11] FBX node IDs aren't alphanumerically ordered per logical structure --- libraries/fbx/src/FBXReader.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 14f12b5d1b..4ed1ca38dc 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1481,11 +1481,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } while (!remainingModels.isEmpty()) { QString first = *remainingModels.constBegin(); - foreach (const QString& id, remainingModels) { - if (id < first) { - first = id; - } - } QString topID = getTopModelID(_connectionParentMap, models, first, url); appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs, true); } From b23f98b31116dd3ea0da8f8f8d45dcd3c3b5a873 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 31 Jan 2018 17:56:33 -0800 Subject: [PATCH 09/11] Removal of hips offset shifting from AnimInverseKinematics node With the addition of the hips IK target, the hips offset shifting code is no longer necessary. This PR should not effect any behavior, but it removes this unused code from the animation system. --- interface/src/avatar/MyAvatar.cpp | 8 -- interface/src/avatar/MySkeletonModel.cpp | 2 - .../animation/src/AnimInverseKinematics.cpp | 108 ------------------ .../animation/src/AnimInverseKinematics.h | 7 -- libraries/animation/src/Rig.cpp | 12 -- libraries/animation/src/Rig.h | 1 - 6 files changed, 138 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 19a2d39a05..4ab741e32c 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3238,8 +3238,6 @@ bool MyAvatar::pinJoint(int index, const glm::vec3& position, const glm::quat& o slamPosition(position); setWorldOrientation(orientation); - _skeletonModel->getRig().setMaxHipsOffsetLength(0.05f); - auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index); if (it == _pinnedJoints.end()) { _pinnedJoints.push_back(index); @@ -3259,12 +3257,6 @@ bool MyAvatar::clearPinOnJoint(int index) { auto it = std::find(_pinnedJoints.begin(), _pinnedJoints.end(), index); if (it != _pinnedJoints.end()) { _pinnedJoints.erase(it); - - auto hipsIndex = getJointIndex("Hips"); - if (index == hipsIndex) { - _skeletonModel->getRig().setMaxHipsOffsetLength(FLT_MAX); - } - return true; } return false; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 9280899a1e..fd57657d33 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -43,8 +43,6 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { AnimPose result = AnimPose(worldToSensorMat * avatarTransform.getMatrix() * Matrices::Y_180); result.scale() = glm::vec3(1.0f, 1.0f, 1.0f); return result; - } else { - DebugDraw::getInstance().removeMarker("pinnedHips"); } glm::mat4 hipsMat = myAvatar->deriveBodyFromHMDSensor(); diff --git a/libraries/animation/src/AnimInverseKinematics.cpp b/libraries/animation/src/AnimInverseKinematics.cpp index e9f9f8818f..849ea5ee6b 100644 --- a/libraries/animation/src/AnimInverseKinematics.cpp +++ b/libraries/animation/src/AnimInverseKinematics.cpp @@ -880,25 +880,6 @@ const AnimPoseVec& AnimInverseKinematics::evaluate(const AnimVariantMap& animVar return _relativePoses; } -AnimPose AnimInverseKinematics::applyHipsOffset() const { - glm::vec3 hipsOffset = _hipsOffset; - AnimPose relHipsPose = _relativePoses[_hipsIndex]; - float offsetLength = glm::length(hipsOffset); - const float MIN_HIPS_OFFSET_LENGTH = 0.03f; - if (offsetLength > MIN_HIPS_OFFSET_LENGTH) { - float scaleFactor = ((offsetLength - MIN_HIPS_OFFSET_LENGTH) / offsetLength); - glm::vec3 scaledHipsOffset = scaleFactor * hipsOffset; - if (_hipsParentIndex == -1) { - relHipsPose.trans() = _relativePoses[_hipsIndex].trans() + scaledHipsOffset; - } else { - AnimPose absHipsPose = _skeleton->getAbsolutePose(_hipsIndex, _relativePoses); - absHipsPose.trans() += scaledHipsOffset; - relHipsPose = _skeleton->getAbsolutePose(_hipsParentIndex, _relativePoses).inverse() * absHipsPose; - } - } - return relHipsPose; -} - //virtual const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars, const AnimContext& context, float dt, Triggers& triggersOut, const AnimPoseVec& underPoses) { // allows solutionSource to be overridden by an animVar @@ -996,27 +977,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars _relativePoses[_hipsIndex] = parentAbsPose.inverse() * absPose; _relativePoses[_hipsIndex].scale() = glm::vec3(1.0f); - _hipsOffset = Vectors::ZERO; - - } else if (_hipsIndex >= 0) { - - // if there is no hips target, shift hips according to the _hipsOffset from the previous frame - AnimPose relHipsPose = applyHipsOffset(); - - // determine if we should begin interpolating the hips. - for (size_t i = 0; i < targets.size(); i++) { - if (_prevJointChainInfoVec[i].target.getIndex() == _hipsIndex) { - if (_prevJointChainInfoVec[i].timer > 0.0f) { - // smoothly lerp in hipsOffset - float alpha = (JOINT_CHAIN_INTERP_TIME - _prevJointChainInfoVec[i].timer) / JOINT_CHAIN_INTERP_TIME; - AnimPose prevRelHipsPose(_prevJointChainInfoVec[i].jointInfoVec[0].rot, _prevJointChainInfoVec[i].jointInfoVec[0].trans); - ::blend(1, &prevRelHipsPose, &relHipsPose, alpha, &relHipsPose); - } - break; - } - } - - _relativePoses[_hipsIndex] = relHipsPose; } // if there is an active jointChainInfo for the hips store the post shifted hips into it. @@ -1084,11 +1044,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars solve(context, targets, dt, jointChainInfoVec); } - - if (_hipsTargetIndex < 0) { - PROFILE_RANGE_EX(simulation_animation, "ik/measureHipsOffset", 0xffff00ff, 0); - _hipsOffset = computeHipsOffset(targets, underPoses, dt, _hipsOffset); - } } if (context.getEnableDebugDrawIKConstraints()) { @@ -1099,69 +1054,6 @@ const AnimPoseVec& AnimInverseKinematics::overlay(const AnimVariantMap& animVars return _relativePoses; } -glm::vec3 AnimInverseKinematics::computeHipsOffset(const std::vector& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const { - - // measure new _hipsOffset for next frame - // by looking for discrepancies between where a targeted endEffector is - // and where it wants to be (after IK solutions are done) - glm::vec3 hipsOffset = prevHipsOffset; - glm::vec3 newHipsOffset = Vectors::ZERO; - for (auto& target: targets) { - int targetIndex = target.getIndex(); - if (targetIndex == _headIndex && _headIndex != -1) { - // special handling for headTarget - if (target.getType() == IKTarget::Type::RotationOnly) { - // we want to shift the hips to bring the underPose closer - // to where the head happens to be (overpose) - glm::vec3 under = _skeleton->getAbsolutePose(_headIndex, underPoses).trans(); - glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans(); - const float HEAD_OFFSET_SLAVE_FACTOR = 0.65f; - newHipsOffset += HEAD_OFFSET_SLAVE_FACTOR * (actual - under); - } else if (target.getType() == IKTarget::Type::HmdHead) { - // we want to shift the hips to bring the head to its designated position - glm::vec3 actual = _skeleton->getAbsolutePose(_headIndex, _relativePoses).trans(); - hipsOffset += target.getTranslation() - actual; - // and ignore all other targets - newHipsOffset = hipsOffset; - break; - } else if (target.getType() == IKTarget::Type::RotationAndPosition) { - glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans(); - glm::vec3 targetPosition = target.getTranslation(); - newHipsOffset += targetPosition - actualPosition; - - // Add downward pressure on the hips - const float PRESSURE_SCALE_FACTOR = 0.95f; - const float PRESSURE_TRANSLATION_OFFSET = 1.0f; - newHipsOffset *= PRESSURE_SCALE_FACTOR; - newHipsOffset -= PRESSURE_TRANSLATION_OFFSET; - } - } else if (target.getType() == IKTarget::Type::RotationAndPosition) { - glm::vec3 actualPosition = _skeleton->getAbsolutePose(targetIndex, _relativePoses).trans(); - glm::vec3 targetPosition = target.getTranslation(); - newHipsOffset += targetPosition - actualPosition; - } - } - - // smooth transitions by relaxing hipsOffset toward the new value - const float HIPS_OFFSET_SLAVE_TIMESCALE = 0.10f; - float tau = dt < HIPS_OFFSET_SLAVE_TIMESCALE ? dt / HIPS_OFFSET_SLAVE_TIMESCALE : 1.0f; - hipsOffset += (newHipsOffset - hipsOffset) * tau; - - // clamp the hips offset - float hipsOffsetLength = glm::length(hipsOffset); - if (hipsOffsetLength > _maxHipsOffsetLength) { - hipsOffset *= _maxHipsOffsetLength / hipsOffsetLength; - } - - return hipsOffset; -} - -void AnimInverseKinematics::setMaxHipsOffsetLength(float maxLength) { - // manually adjust scale here - const float METERS_TO_CENTIMETERS = 100.0f; - _maxHipsOffsetLength = METERS_TO_CENTIMETERS * maxLength; -} - void AnimInverseKinematics::clearIKJointLimitHistory() { for (auto& pair : _constraints) { pair.second->clearHistory(); diff --git a/libraries/animation/src/AnimInverseKinematics.h b/libraries/animation/src/AnimInverseKinematics.h index bdfbad408d..ee1f9f43ad 100644 --- a/libraries/animation/src/AnimInverseKinematics.h +++ b/libraries/animation/src/AnimInverseKinematics.h @@ -57,8 +57,6 @@ public: void clearIKJointLimitHistory(); - void setMaxHipsOffsetLength(float maxLength); - float getMaxErrorOnLastSolve() { return _maxErrorOnLastSolve; } enum class SolutionSource { @@ -92,7 +90,6 @@ protected: void blendToPoses(const AnimPoseVec& targetPoses, const AnimPoseVec& underPose, float blendFactor); void preconditionRelativePosesToAvoidLimbLock(const AnimContext& context, const std::vector& targets); void setSecondaryTargets(const AnimContext& context); - AnimPose applyHipsOffset() const; // used to pre-compute information about each joint influeced by a spline IK target. struct SplineJointInfo { @@ -111,7 +108,6 @@ protected: void clearConstraints(); void initConstraints(); void initLimitCenterPoses(); - glm::vec3 computeHipsOffset(const std::vector& targets, const AnimPoseVec& underPoses, float dt, glm::vec3 prevHipsOffset) const; // no copies AnimInverseKinematics(const AnimInverseKinematics&) = delete; @@ -150,9 +146,6 @@ protected: mutable std::map> _splineJointInfoMap; - // experimental data for moving hips during IK - glm::vec3 _hipsOffset { Vectors::ZERO }; - float _maxHipsOffsetLength{ FLT_MAX }; int _headIndex { -1 }; int _hipsIndex { -1 }; int _hipsParentIndex { -1 }; diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 309bb59cff..a939db92aa 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -372,18 +372,6 @@ void Rig::clearIKJointLimitHistory() { } } -void Rig::setMaxHipsOffsetLength(float maxLength) { - _maxHipsOffsetLength = maxLength; - auto ikNode = getAnimInverseKinematicsNode(); - if (ikNode) { - ikNode->setMaxHipsOffsetLength(_maxHipsOffsetLength); - } -} - -float Rig::getMaxHipsOffsetLength() const { - return _maxHipsOffsetLength; -} - float Rig::getIKErrorOnLastSolve() const { float result = 0.0f; diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 87277af754..a7db86abf9 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -346,7 +346,6 @@ protected: bool _enabledAnimations { true }; mutable uint32_t _jointNameWarningCount { 0 }; - float _maxHipsOffsetLength { 1.0f }; bool _enableDebugDrawIKTargets { false }; bool _enableDebugDrawIKConstraints { false }; From a1b67afabfbf0f4da47805458445207462aad322 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 1 Feb 2018 11:57:50 -0800 Subject: [PATCH 10/11] Fix for rigidly bound mesh not being properly cauterized. For example, sometimes in first person view, you can see the back of your avatar's eyes or the brim of your avatar's hat. --- libraries/render-utils/src/CauterizedModel.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 0b8c636678..efca0c3267 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -238,9 +238,9 @@ void CauterizedModel::updateRenderItems() { renderTransform = modelTransform; if (clusterTransformsCauterized.size() == 1) { #if defined(SKIN_DQ) - Transform transform(clusterTransforms[0].getRotation(), - clusterTransforms[0].getScale(), - clusterTransforms[0].getTranslation()); + Transform transform(clusterTransformsCauterized[0].getRotation(), + clusterTransformsCauterized[0].getScale(), + clusterTransformsCauterized[0].getTranslation()); renderTransform = modelTransform.worldTransform(Transform(transform)); #else renderTransform = modelTransform.worldTransform(Transform(clusterTransformsCauterized[0])); From f46362906dfe344ab967ffcfa85129e0a004d565 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 2 Feb 2018 10:02:20 +1300 Subject: [PATCH 11/11] Bump avatar mixer packet version --- libraries/networking/src/udt/PacketHeaders.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index 0f69691bd5..d186ed41c3 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -248,7 +248,8 @@ enum class AvatarMixerPacketVersion : PacketVersion { IsReplicatedInAvatarIdentity, AvatarIdentityLookAtSnapping, UpdatedMannequinDefaultAvatar, - AvatarJointDefaultPoseFlags + AvatarJointDefaultPoseFlags, + FBXReaderNodeReparenting }; enum class DomainConnectRequestVersion : PacketVersion {