From 4830ba24aef5b793a81214c3c76303876af1a16f Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 28 Aug 2018 09:53:54 +1200 Subject: [PATCH 001/114] Highlight tablet when it is near-grabbable --- .../controllers/controllerDispatcher.js | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 7a916392b9..b1b41ded04 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -37,6 +37,20 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); PROFILE = true; } + var TABLET_GRABBABLE_SELECTION_NAME = "tabletGrabbableSelection"; + var TABLET_GRABBABLE_SELECTION_STYLE = { + outlineUnoccludedColor: { red: 0, green: 180, blue: 239 }, // #00b4ef + outlineUnoccludedAlpha: 1, + outlineOccludedColor: { red: 0, green: 0, blue: 0 }, + outlineOccludedAlpha: 0, + fillUnoccludedColor: { red: 0, green: 0, blue: 0 }, + fillUnoccludedAlpha: 0, + fillOccludedColor: { red: 0, green: 0, blue: 0 }, + fillOccludedAlpha: 0, + outlineWidth: 2, + isOutlineSmooth: false + }; + function ControllerDispatcher() { var _this = this; this.lastInterval = Date.now(); @@ -168,6 +182,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.setTimeout(_this.update, BASIC_TIMER_INTERVAL_MS); }; + this.isTabletNearGrabbable = false; + this.updateInternal = function () { if (PROFILE) { Script.beginProfileRange("dispatch.pre"); @@ -206,6 +222,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); // find 3d overlays near each hand var nearbyOverlayIDs = []; + var isTabletNearGrabbable = false; var h; for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { if (controllerLocations[h].valid) { @@ -218,12 +235,26 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var bDistance = Vec3.distance(bPosition, controllerLocations[h].position); return aDistance - bDistance; }); + if (HMD.tabletID && nearbyOverlays.indexOf(HMD.tabletID) !== -1) { + isTabletNearGrabbable = true; + } nearbyOverlayIDs.push(nearbyOverlays); } else { nearbyOverlayIDs.push([]); } } + // Highlight tablet if it is near-grabbable. + if (isTabletNearGrabbable !== _this.isTabletNearGrabbable) { + if (isTabletNearGrabbable) { + Selection.addToSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME, "overlay", HMD.tabletID); + } else { + Selection.removeFromSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME, "overlay", HMD.tabletID); + } + _this.isTabletNearGrabbable = isTabletNearGrabbable; + } + + // find entities near each hand var nearbyEntityProperties = [[], []]; var nearbyEntityPropertiesByID = {}; @@ -485,6 +516,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Selection.disableListHighlight(DISPATCHER_HOVERING_LIST); }; } + function mouseReleaseOnOverlay(overlayID, event) { if (HMD.homeButtonID && overlayID === HMD.homeButtonID && event.button === "Primary") { Messages.sendLocalMessage("home", overlayID); @@ -503,12 +535,29 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } } } + Overlays.mouseReleaseOnOverlay.connect(mouseReleaseOnOverlay); Overlays.mousePressOnOverlay.connect(mousePress); Entities.mousePressOnEntity.connect(mousePress); + + function onDisplayModeChanged() { + if (HMD.active) { + Selection.enableListHighlight(TABLET_GRABBABLE_SELECTION_NAME, TABLET_GRABBABLE_SELECTION_STYLE); + } else { + Selection.disableListHighlight(TABLET_GRABBABLE_SELECTION_NAME); + Selection.clearSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME); + } + } + + HMD.displayModeChanged.connect(onDisplayModeChanged); + HMD.mountedChanged.connect(onDisplayModeChanged); + var controllerDispatcher = new ControllerDispatcher(); Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); Messages.messageReceived.connect(controllerDispatcher.handleHandMessage); - Script.scriptEnding.connect(controllerDispatcher.cleanup); + Script.scriptEnding.connect(function () { + controllerDispatcher.cleanup(); + Selection.disableListHighlight(TABLET_GRABBABLE_SELECTION_NAME); + }); Script.setTimeout(controllerDispatcher.update, BASIC_TIMER_INTERVAL_MS); }()); From f84f3b20cdf79c2d75ff4703808838912a4c44d9 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 31 Aug 2018 10:25:12 +1200 Subject: [PATCH 002/114] Disable near and far lasers when tablet is grabbable --- .../controllerModules/farActionGrabEntity.js | 3 +- .../farActionGrabEntityDynOnly.js | 3 +- .../controllerModules/farParentGrabEntity.js | 3 +- .../controllerModules/nearTabletHighlight.js | 67 +++++++++++++++++++ .../controllerModules/webSurfaceLaserInput.js | 7 ++ .../system/controllers/controllerScripts.js | 3 +- 6 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 scripts/system/controllers/controllerModules/nearTabletHighlight.js diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 5e798ed680..b5141699f9 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -420,7 +420,8 @@ Script.include("/~/system/libraries/Xform.js"); this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay" + this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay", + this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight" ]; var nearGrabReadiness = []; diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js index 78abcb9b20..4fab0098b9 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntityDynOnly.js @@ -396,7 +396,8 @@ Script.include("/~/system/libraries/Xform.js"); this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay" + this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay", + this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight" ]; var nearGrabReadiness = []; diff --git a/scripts/system/controllers/controllerModules/farParentGrabEntity.js b/scripts/system/controllers/controllerModules/farParentGrabEntity.js index a9ec246a32..d58cbb9907 100644 --- a/scripts/system/controllers/controllerModules/farParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farParentGrabEntity.js @@ -442,7 +442,8 @@ Script.include("/~/system/libraries/Xform.js"); this.hand === RIGHT_HAND ? "RightFarTriggerEntity" : "LeftFarTriggerEntity", this.hand === RIGHT_HAND ? "RightNearActionGrabEntity" : "LeftNearActionGrabEntity", this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity", - this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay" + this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay", + this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight" ]; var nearGrabReadiness = []; diff --git a/scripts/system/controllers/controllerModules/nearTabletHighlight.js b/scripts/system/controllers/controllerModules/nearTabletHighlight.js new file mode 100644 index 0000000000..5f4dac232e --- /dev/null +++ b/scripts/system/controllers/controllerModules/nearTabletHighlight.js @@ -0,0 +1,67 @@ +// +// nearTabletHighlight.js +// +// Highlight the tablet if a hand is near enough to grab it. +// +// Created by David Rowe on 28 Aug 2018. +// 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 +// + +/* global LEFT_HAND, RIGHT_HAND, makeDispatcherModuleParameters, makeRunningValues, enableDispatcherModule, + * disableDispatcherModule */ + +Script.include("/~/system/libraries/controllerDispatcherUtils.js"); + +(function () { + + "use strict"; + + function NearTabletHighlight(hand) { + this.hand = hand; + + this.parameters = makeDispatcherModuleParameters( + 95, + this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], + [], + 100 + ); + + this.isNearTablet = function (controllerData) { + return HMD.tabletID && controllerData.nearbyOverlayIDs[this.hand].indexOf(HMD.tabletID) !== -1; + }; + + this.isReady = function (controllerData) { + if (this.isNearTablet(controllerData)) { + return makeRunningValues(true, [], []); + } + return makeRunningValues(false, [], []); + }; + + this.run = function (controllerData) { + if (!this.isNearTablet(controllerData)) { + return makeRunningValues(false, [], []); + } + + if (controllerData.triggerClicks[this.hand]) { + return makeRunningValues(false, [], []); + } + + return makeRunningValues(true, [], []); + }; + } + + var leftNearTabletHighlight = new NearTabletHighlight(LEFT_HAND); + var rightNearTabletHighlight = new NearTabletHighlight(RIGHT_HAND); + enableDispatcherModule("LeftNearTabletHighlight", leftNearTabletHighlight); + enableDispatcherModule("RightNearTabletHighlight", rightNearTabletHighlight); + + function cleanUp() { + disableDispatcherModule("LeftNearTabletHighlight"); + disableDispatcherModule("RightNearTabletHighlight"); + } + Script.scriptEnding.connect(cleanUp); + +}()); diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index a2fe0bfcd4..7ed9fd68b5 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -43,6 +43,13 @@ Script.include("/~/system/libraries/controllers.js"); } } } + + var nearTabletHighlightModule = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); + if (nearTabletHighlightModule) { + return nearTabletHighlightModule.isNearTablet(controllerData); + } + return false; }; diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index 6899577de2..8011c2b644 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -35,7 +35,8 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/scaleEntity.js", "controllerModules/highlightNearbyEntities.js", "controllerModules/nearGrabHyperLinkEntity.js", - "controllerModules/mouseHighlightEntities.js" + "controllerModules/mouseHighlightEntities.js", + "controllerModules/nearTabletHighlight.js" ]; if (Settings.getValue("useFarGrabJoints", false)) { From 9203bbc5d8ec265169d1293287614837c6e2043d Mon Sep 17 00:00:00 2001 From: David Rowe Date: Fri, 31 Aug 2018 11:02:36 +1200 Subject: [PATCH 003/114] Don't highlight tablet when it is grabbed --- .../controllers/controllerDispatcher.js | 48 +--------------- .../controllerModules/nearTabletHighlight.js | 55 ++++++++++++++++++- 2 files changed, 55 insertions(+), 48 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index b1b41ded04..a707050a9d 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -37,20 +37,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); PROFILE = true; } - var TABLET_GRABBABLE_SELECTION_NAME = "tabletGrabbableSelection"; - var TABLET_GRABBABLE_SELECTION_STYLE = { - outlineUnoccludedColor: { red: 0, green: 180, blue: 239 }, // #00b4ef - outlineUnoccludedAlpha: 1, - outlineOccludedColor: { red: 0, green: 0, blue: 0 }, - outlineOccludedAlpha: 0, - fillUnoccludedColor: { red: 0, green: 0, blue: 0 }, - fillUnoccludedAlpha: 0, - fillOccludedColor: { red: 0, green: 0, blue: 0 }, - fillOccludedAlpha: 0, - outlineWidth: 2, - isOutlineSmooth: false - }; - function ControllerDispatcher() { var _this = this; this.lastInterval = Date.now(); @@ -182,8 +168,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.setTimeout(_this.update, BASIC_TIMER_INTERVAL_MS); }; - this.isTabletNearGrabbable = false; - this.updateInternal = function () { if (PROFILE) { Script.beginProfileRange("dispatch.pre"); @@ -222,7 +206,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); // find 3d overlays near each hand var nearbyOverlayIDs = []; - var isTabletNearGrabbable = false; var h; for (h = LEFT_HAND; h <= RIGHT_HAND; h++) { if (controllerLocations[h].valid) { @@ -235,26 +218,12 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var bDistance = Vec3.distance(bPosition, controllerLocations[h].position); return aDistance - bDistance; }); - if (HMD.tabletID && nearbyOverlays.indexOf(HMD.tabletID) !== -1) { - isTabletNearGrabbable = true; - } nearbyOverlayIDs.push(nearbyOverlays); } else { nearbyOverlayIDs.push([]); } } - // Highlight tablet if it is near-grabbable. - if (isTabletNearGrabbable !== _this.isTabletNearGrabbable) { - if (isTabletNearGrabbable) { - Selection.addToSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME, "overlay", HMD.tabletID); - } else { - Selection.removeFromSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME, "overlay", HMD.tabletID); - } - _this.isTabletNearGrabbable = isTabletNearGrabbable; - } - - // find entities near each hand var nearbyEntityProperties = [[], []]; var nearbyEntityPropertiesByID = {}; @@ -540,24 +509,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Overlays.mousePressOnOverlay.connect(mousePress); Entities.mousePressOnEntity.connect(mousePress); - function onDisplayModeChanged() { - if (HMD.active) { - Selection.enableListHighlight(TABLET_GRABBABLE_SELECTION_NAME, TABLET_GRABBABLE_SELECTION_STYLE); - } else { - Selection.disableListHighlight(TABLET_GRABBABLE_SELECTION_NAME); - Selection.clearSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME); - } - } - - HMD.displayModeChanged.connect(onDisplayModeChanged); - HMD.mountedChanged.connect(onDisplayModeChanged); - var controllerDispatcher = new ControllerDispatcher(); Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); Messages.messageReceived.connect(controllerDispatcher.handleHandMessage); - Script.scriptEnding.connect(function () { - controllerDispatcher.cleanup(); - Selection.disableListHighlight(TABLET_GRABBABLE_SELECTION_NAME); - }); + Script.scriptEnding.connect(controllerDispatcher.cleanup); Script.setTimeout(controllerDispatcher.update, BASIC_TIMER_INTERVAL_MS); }()); diff --git a/scripts/system/controllers/controllerModules/nearTabletHighlight.js b/scripts/system/controllers/controllerModules/nearTabletHighlight.js index 5f4dac232e..d436bad458 100644 --- a/scripts/system/controllers/controllerModules/nearTabletHighlight.js +++ b/scripts/system/controllers/controllerModules/nearTabletHighlight.js @@ -1,7 +1,7 @@ // // nearTabletHighlight.js // -// Highlight the tablet if a hand is near enough to grab it. +// Highlight the tablet if a hand is near enough to grab it and it isn't grabbed. // // Created by David Rowe on 28 Aug 2018. // Copyright 2018 High Fidelity, Inc. @@ -19,6 +19,43 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); "use strict"; + var TABLET_GRABBABLE_SELECTION_NAME = "tabletGrabbableSelection"; + var TABLET_GRABBABLE_SELECTION_STYLE = { + outlineUnoccludedColor: { red: 0, green: 180, blue: 239 }, // #00b4ef + outlineUnoccludedAlpha: 1, + outlineOccludedColor: { red: 0, green: 0, blue: 0 }, + outlineOccludedAlpha: 0, + fillUnoccludedColor: { red: 0, green: 0, blue: 0 }, + fillUnoccludedAlpha: 0, + fillOccludedColor: { red: 0, green: 0, blue: 0 }, + fillOccludedAlpha: 0, + outlineWidth: 2, + isOutlineSmooth: false + }; + + var isTabletNearGrabbable = [false, false]; + var isTabletHighlighted = false; + + function setTabletNearGrabbable(hand, enabled) { + if (enabled === isTabletNearGrabbable[hand]) { + return; + } + + isTabletNearGrabbable[hand] = enabled; + + if (isTabletNearGrabbable[LEFT_HAND] || isTabletNearGrabbable[RIGHT_HAND]) { + if (!isTabletHighlighted) { + Selection.addToSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME, "overlay", HMD.tabletID); + isTabletHighlighted = true; + } + } else { + if (isTabletHighlighted) { + Selection.removeFromSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME, "overlay", HMD.tabletID); + isTabletHighlighted = false; + } + } + } + function NearTabletHighlight(hand) { this.hand = hand; @@ -37,18 +74,22 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (this.isNearTablet(controllerData)) { return makeRunningValues(true, [], []); } + setTabletNearGrabbable(this.hand, false); return makeRunningValues(false, [], []); }; this.run = function (controllerData) { if (!this.isNearTablet(controllerData)) { + setTabletNearGrabbable(this.hand, false); return makeRunningValues(false, [], []); } if (controllerData.triggerClicks[this.hand]) { + setTabletNearGrabbable(this.hand, false); return makeRunningValues(false, [], []); } + setTabletNearGrabbable(this.hand, true); return makeRunningValues(true, [], []); }; } @@ -58,9 +99,21 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); enableDispatcherModule("LeftNearTabletHighlight", leftNearTabletHighlight); enableDispatcherModule("RightNearTabletHighlight", rightNearTabletHighlight); + function onDisplayModeChanged() { + if (HMD.active) { + Selection.enableListHighlight(TABLET_GRABBABLE_SELECTION_NAME, TABLET_GRABBABLE_SELECTION_STYLE); + } else { + Selection.disableListHighlight(TABLET_GRABBABLE_SELECTION_NAME); + Selection.clearSelectedItemsList(TABLET_GRABBABLE_SELECTION_NAME); + } + } + HMD.displayModeChanged.connect(onDisplayModeChanged); + HMD.mountedChanged.connect(onDisplayModeChanged); + function cleanUp() { disableDispatcherModule("LeftNearTabletHighlight"); disableDispatcherModule("RightNearTabletHighlight"); + Selection.disableListHighlight(TABLET_GRABBABLE_SELECTION_NAME); } Script.scriptEnding.connect(cleanUp); From daae3f50c8080b1e03b6e81155d43c5efcc12cd4 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 6 Sep 2018 09:09:30 +1200 Subject: [PATCH 004/114] Increase tablet highlight outline width --- .../system/controllers/controllerModules/nearTabletHighlight.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/nearTabletHighlight.js b/scripts/system/controllers/controllerModules/nearTabletHighlight.js index d436bad458..7738f48561 100644 --- a/scripts/system/controllers/controllerModules/nearTabletHighlight.js +++ b/scripts/system/controllers/controllerModules/nearTabletHighlight.js @@ -29,7 +29,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); fillUnoccludedAlpha: 0, fillOccludedColor: { red: 0, green: 0, blue: 0 }, fillOccludedAlpha: 0, - outlineWidth: 2, + outlineWidth: 4, isOutlineSmooth: false }; From f23d93add3f0f9489e2a2cdaf65cabdf47e79cf6 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 6 Sep 2018 09:17:00 +1200 Subject: [PATCH 005/114] Fix grabbing tablet with grip not working --- .../system/controllers/controllerModules/nearTabletHighlight.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/nearTabletHighlight.js b/scripts/system/controllers/controllerModules/nearTabletHighlight.js index 7738f48561..2b02bf3aed 100644 --- a/scripts/system/controllers/controllerModules/nearTabletHighlight.js +++ b/scripts/system/controllers/controllerModules/nearTabletHighlight.js @@ -84,7 +84,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); return makeRunningValues(false, [], []); } - if (controllerData.triggerClicks[this.hand]) { + if (controllerData.triggerClicks[this.hand] || controllerData.secondaryValues[this.hand]) { setTabletNearGrabbable(this.hand, false); return makeRunningValues(false, [], []); } From 16a94f827df1c4406f0750c1b1e62fdac84bcf67 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 11 Sep 2018 09:51:28 +1200 Subject: [PATCH 006/114] Fix tablet highlight not working with stylus --- .../system/controllers/controllerModules/stylusInput.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/stylusInput.js b/scripts/system/controllers/controllerModules/stylusInput.js index a512fd89db..a60ea596e9 100644 --- a/scripts/system/controllers/controllerModules/stylusInput.js +++ b/scripts/system/controllers/controllerModules/stylusInput.js @@ -70,7 +70,13 @@ Script.include("/~/system/libraries/controllers.js"); var farGrabModuleName = this.hand === RIGHT_HAND ? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity"; var farGrabModule = getEnabledModuleByName(farGrabModuleName); var farGrabModuleReady = farGrabModule ? farGrabModule.isReady(controllerData) : makeRunningValues(false, [], []); - return grabOverlayModuleReady.active || farGrabModuleReady.active || grabEntityModuleReady.active; + var nearTabletHighlightModuleName = + this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"; + var nearTabletHighlightModule = getEnabledModuleByName(nearTabletHighlightModuleName); + var nearTabletHighlightModuleReady = nearTabletHighlightModule + ? nearTabletHighlightModule.isReady(controllerData) : makeRunningValues(false, [], []); + return grabOverlayModuleReady.active || farGrabModuleReady.active || grabEntityModuleReady.active + || nearTabletHighlightModuleReady.active; }; this.overlayLaserActive = function(controllerData) { From 992b9f847ca9eb85adc5430fc4cddf959a96c581 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 11 Sep 2018 09:58:19 +1200 Subject: [PATCH 007/114] Reduce near grab distance of tablet so that stylus works on tablet --- scripts/system/controllers/controllerDispatcher.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index a707050a9d..69b1b27035 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -26,6 +26,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); (function() { Script.include("/~/system/libraries/pointersUtils.js"); var NEAR_MAX_RADIUS = 0.1; + var NEAR_TABLET_MAX_RADIUS = 0.05; var TARGET_UPDATE_HZ = 60; // 50hz good enough, but we're using update var BASIC_TIMER_INTERVAL_MS = 1000 / TARGET_UPDATE_HZ; @@ -211,6 +212,17 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (controllerLocations[h].valid) { var nearbyOverlays = Overlays.findOverlays(controllerLocations[h].position, NEAR_MAX_RADIUS * sensorScaleFactor); + + // Tablet must be within NEAR_TABLET_MAX_RADIUS in order to be grabbed. + var tabletIndex = nearbyOverlays.indexOf(HMD.tabletID); + if (tabletIndex !== -1) { + var closebyOverlays = + Overlays.findOverlays(controllerLocations[h].position, NEAR_TABLET_MAX_RADIUS * sensorScaleFactor); + if (tabletIndex !== -1 && closebyOverlays.indexOf(HMD.tabletID) === -1) { + nearbyOverlays.splice(tabletIndex, 1); + } + } + nearbyOverlays.sort(function (a, b) { var aPosition = Overlays.getProperty(a, "position"); var aDistance = Vec3.distance(aPosition, controllerLocations[h].position); From ff0d938d3793e80d9e5c699115981ea96af453ba Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 17 Sep 2018 16:53:15 -0700 Subject: [PATCH 008/114] initial changes to stop the squatty potty from happening when users are sitting down in vr mode --- interface/resources/qml/AnimStats.qml | 2 +- interface/src/avatar/MyAvatar.cpp | 84 +++++++++++++++++++++--- interface/src/avatar/MyAvatar.h | 6 +- interface/src/avatar/MySkeletonModel.cpp | 2 +- 4 files changed, 81 insertions(+), 13 deletions(-) diff --git a/interface/resources/qml/AnimStats.qml b/interface/resources/qml/AnimStats.qml index 35ed3799a6..fd0a280dad 100644 --- a/interface/resources/qml/AnimStats.qml +++ b/interface/resources/qml/AnimStats.qml @@ -53,7 +53,7 @@ Item { ListView { width: firstCol.width height: root.animStateMachines.length * 15 - visible: root.animStateMchines.length > 0; + visible: root.animStateMachines.length > 0; model: root.animStateMachines delegate: StatText { text: { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c47cfdb383..b626fb6c2a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3589,9 +3589,11 @@ glm::vec3 MyAvatar::computeCounterBalance() { // if the height is higher than default hips, clamp to default hips counterBalancedCg.y = tposeHips.y + 0.05f; } else if (counterBalancedCg.y < sitSquatThreshold) { - //do a height reset + // do a height reset setResetMode(true); _follow.activate(FollowHelper::Vertical); + // disable cg behaviour in this case. + _isInSittingState = true; } return counterBalancedCg; } @@ -3832,6 +3834,10 @@ bool MyAvatar::getIsInWalkingState() const { return _isInWalkingState; } +bool MyAvatar::getIsInSittingState() const { + return _isInSittingState; +} + float MyAvatar::getWalkSpeed() const { return _walkSpeed.get() * _walkSpeedScalar; } @@ -3852,6 +3858,10 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { _isInWalkingState = isWalking; } +void MyAvatar::setIsInSittingState(bool isSitting) { + _isInSittingState = isSitting; +} + void MyAvatar::setWalkSpeed(float value) { _walkSpeed.set(value); } @@ -4029,6 +4039,33 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; } +bool MyAvatar::FollowHelper::shouldActivateHorizontalSitting(MyAvatar& myAvatar) const { + + // get the current readings + controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); + controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); + controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); + + bool stepDetected = false; + float myScale = myAvatar.getAvatarScale(); + + if (!withinBaseOfSupport(currentHeadPose)) { + // a step is detected + stepDetected = true; + } else { + glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); + glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); + glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); + float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); + if (!isActive(Horizontal) && + (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { + myAvatar.setResetMode(true); + stepDetected = true; + } + } + return stepDetected; +} + bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const { // get the current readings @@ -4072,33 +4109,60 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons return stepDetected; } -bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { +bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; + const float SITTING_BOTTOM = -0.02f; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + if (myAvatar.getIsInSittingState()) { + if (offset.y < SITTING_BOTTOM) { + // we recenter when sitting. + return true; + } else if (offset.y > CYLINDER_TOP) { + // if we recenter upwards then no longer in sitting state + myAvatar.setIsInSittingState(false); + return true; + } else { + return false; + } + } else { + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + } } void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { - if (myAvatar.getHMDLeanRecenterEnabled() && - qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { + qCDebug(interfaceapp) << "in sitting state: " << myAvatar.getIsInSittingState(); + + if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { - if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { - activate(Horizontal); - if (myAvatar.getEnableStepResetRotation()) { - activate(Rotation); - myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); + if (!(myAvatar.getIsInSittingState())) { + if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { + activate(Horizontal); + if (myAvatar.getEnableStepResetRotation()) { + activate(Rotation); + myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); + } + } + } else { + // you are in the sitting state with cg model enabled + if (!isActive(Horizontal) && (shouldActivateHorizontalSitting(myAvatar) || hasDriveInput)) { + activate(Horizontal); + if (myAvatar.getEnableStepResetRotation()) { + activate(Rotation); + myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); + } } } } else { + // center of gravity model is not enabled if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Horizontal); if (myAvatar.getEnableStepResetRotation()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 139f1f6ea2..a7fdf964d0 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1094,6 +1094,8 @@ public: void setIsInWalkingState(bool isWalking); bool getIsInWalkingState() const; + void setIsInSittingState(bool isSitting); + bool getIsInSittingState() const; void setWalkSpeed(float value); float getWalkSpeed() const; void setWalkBackwardSpeed(float value); @@ -1708,9 +1710,10 @@ private: float getMaxTimeRemaining() const; void decrementTimeRemaining(float dt); bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; - bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; + bool shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const; + bool shouldActivateHorizontalSitting(MyAvatar& myAvatar) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation() const; @@ -1800,6 +1803,7 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; + bool _isInSittingState{ false }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 3084542472..42ec582c47 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { } glm::mat4 hipsMat; - if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState())) { + if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState())) { // then we use center of gravity model hipsMat = myAvatar->deriveBodyUsingCgModel(); } else { From 14fb7e1d44f8e52fbc91f8810f48d78b776b3005 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 17 Sep 2018 17:53:08 -0700 Subject: [PATCH 009/114] removed redundant code --- interface/src/avatar/MyAvatar.cpp | 52 ++++++------------------------- 1 file changed, 9 insertions(+), 43 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b626fb6c2a..d4168616c3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4039,33 +4039,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; } -bool MyAvatar::FollowHelper::shouldActivateHorizontalSitting(MyAvatar& myAvatar) const { - - // get the current readings - controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); - controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); - controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); - - bool stepDetected = false; - float myScale = myAvatar.getAvatarScale(); - - if (!withinBaseOfSupport(currentHeadPose)) { - // a step is detected - stepDetected = true; - } else { - glm::vec3 defaultHipsPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - glm::vec3 defaultHeadPosition = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); - glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); - float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); - if (!isActive(Horizontal) && - (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { - myAvatar.setResetMode(true); - stepDetected = true; - } - } - return stepDetected; -} - bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const { // get the current readings @@ -4078,6 +4051,10 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons if (myAvatar.getIsInWalkingState()) { stepDetected = true; + } else if (myAvatar.getIsInSittingState()) { + if (!withinBaseOfSupport(currentHeadPose)) { + stepDetected = true; + } } else { if (!withinBaseOfSupport(currentHeadPose) && headAngularVelocityBelowThreshold(currentHeadPose) && @@ -4143,22 +4120,11 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { - if (!(myAvatar.getIsInSittingState())) { - if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { - activate(Horizontal); - if (myAvatar.getEnableStepResetRotation()) { - activate(Rotation); - myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); - } - } - } else { - // you are in the sitting state with cg model enabled - if (!isActive(Horizontal) && (shouldActivateHorizontalSitting(myAvatar) || hasDriveInput)) { - activate(Horizontal); - if (myAvatar.getEnableStepResetRotation()) { - activate(Rotation); - myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); - } + if (!isActive(Horizontal) && (shouldActivateHorizontalCG(myAvatar) || hasDriveInput)) { + activate(Horizontal); + if (myAvatar.getEnableStepResetRotation()) { + activate(Rotation); + myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } } } else { From 96da9b7e54ddaec7e976527059e878d0e3e27b89 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 18 Sep 2018 10:31:19 -0700 Subject: [PATCH 010/114] cleaned up code for squatty fix --- interface/resources/qml/AnimStats.qml | 2 +- interface/src/avatar/MyAvatar.cpp | 6 +++--- interface/src/avatar/MyAvatar.h | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/AnimStats.qml b/interface/resources/qml/AnimStats.qml index fd0a280dad..35ed3799a6 100644 --- a/interface/resources/qml/AnimStats.qml +++ b/interface/resources/qml/AnimStats.qml @@ -53,7 +53,7 @@ Item { ListView { width: firstCol.width height: root.animStateMachines.length * 15 - visible: root.animStateMachines.length > 0; + visible: root.animStateMchines.length > 0; model: root.animStateMachines delegate: StatText { text: { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d4168616c3..8eceb19e09 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4074,6 +4074,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons glm::vec3 currentHeadPosition = currentHeadPose.getTranslation(); float anatomicalHeadToHipsDistance = glm::length(defaultHeadPosition - defaultHipsPosition); if (!isActive(Horizontal) && + (!isActive(Vertical)) && (glm::length(currentHeadPosition - defaultHipsPosition) > (anatomicalHeadToHipsDistance + (DEFAULT_AVATAR_SPINE_STRETCH_LIMIT * anatomicalHeadToHipsDistance)))) { myAvatar.setResetMode(true); stepDetected = true; @@ -4112,9 +4113,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput) { - qCDebug(interfaceapp) << "in sitting state: " << myAvatar.getIsInSittingState(); - - if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { + if (myAvatar.getHMDLeanRecenterEnabled() && + qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a7fdf964d0..6f3858c5bf 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1713,7 +1713,6 @@ private: bool shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const; - bool shouldActivateHorizontalSitting(MyAvatar& myAvatar) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation() const; @@ -1803,7 +1802,7 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; - bool _isInSittingState{ false }; + bool _isInSittingState { false }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From 42e248ef84ca8207ca92885f04768935e8457062 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 18 Sep 2018 17:37:44 -0700 Subject: [PATCH 011/114] maded more changes to support sitting state to do: add option for stuck pose reset --- interface/src/avatar/MyAvatar.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8eceb19e09..bf684ccd9a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -453,6 +453,16 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); + // qCDebug(interfaceapp) << "sitting state is " << getIsInSittingState(); + // debug setting for sitting state if you start in the chair. + // if the head is close to the floor in sensor space + // and the up of the head is close to sensor up then try switching us to sitting state. + auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); + glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); + float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { + qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; + } // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { @@ -3593,7 +3603,7 @@ glm::vec3 MyAvatar::computeCounterBalance() { setResetMode(true); _follow.activate(FollowHelper::Vertical); // disable cg behaviour in this case. - _isInSittingState = true; + setIsInSittingState(true); } return counterBalancedCg; } @@ -4049,6 +4059,12 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons bool stepDetected = false; float myScale = myAvatar.getAvatarScale(); + + // debug head hips angle + //glm::vec3 hipsPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); + //glm::vec3 headHipsBody = currentHeadPose.getTranslation() - hipsPos; + //qCDebug(interfaceapp) << "head in sensor space " << withinBaseOfSupport(currentHeadPose); + if (myAvatar.getIsInWalkingState()) { stepDetected = true; } else if (myAvatar.getIsInSittingState()) { @@ -4094,6 +4110,12 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); + glm::vec3 headWorldSpace = myAvatar.getHead()->getPosition(); + glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar.getSensorToWorldMatrix()); + glm::vec3 headSensorSpace = transformVectorFast(myAvatar.getSensorToWorldMatrix(), headWorldSpace); + //qCDebug(interfaceapp) << "sensor space position " << extractTranslation(currentBodyMatrix) << " head position sensor " << sensorHeadPose.getTranslation(); + if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. From 0381630e73ccfdcb4afc6dd6833109409720d356 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 20 Sep 2018 16:07:24 -0700 Subject: [PATCH 012/114] update some server-console dependencies after npm audit --- server-console/package-lock.json | 1907 ++++++++++++++---------------- server-console/package.json | 11 +- server-console/src/main.js | 13 +- 3 files changed, 906 insertions(+), 1025 deletions(-) diff --git a/server-console/package-lock.json b/server-console/package-lock.json index 4f12f2fa00..e27c3815f6 100644 --- a/server-console/package-lock.json +++ b/server-console/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "@types/node": { - "version": "8.10.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.2.tgz", - "integrity": "sha512-A6Uv1anbsCvrRDtaUXS2xZ5tlzD+Kg7yMRlSLFDy3z0r7KlGXDzL14vELXIAgpk2aJbU3XeZZQRcEkLkowT92g==", + "version": "8.10.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.10.29.tgz", + "integrity": "sha512-zbteaWZ2mdduacm0byELwtRyhYE40aK+pAanQk415gr1eRuu67x7QGOLmn8jz5zI8LDK7d0WI/oT6r5Trz4rzQ==", "dev": true }, "abbrev": { @@ -21,10 +21,10 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" + "co": "^4.6.0", + "fast-deep-equal": "^1.0.0", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.3.0" } }, "always-tail": { @@ -32,7 +32,14 @@ "resolved": "https://registry.npmjs.org/always-tail/-/always-tail-0.2.0.tgz", "integrity": "sha1-M5sa9E1QJQqgeg6H7Mw6JOxET/4=", "requires": { - "debug": "0.7.4" + "debug": "~0.7.2" + }, + "dependencies": { + "debug": { + "version": "0.7.4", + "resolved": "http://registry.npmjs.org/debug/-/debug-0.7.4.tgz", + "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + } } }, "ansi-regex": { @@ -47,70 +54,48 @@ "dev": true }, "asar": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/asar/-/asar-0.14.2.tgz", - "integrity": "sha512-eKo4ywQDq9dC/0Pu6UJsX4PxNi5ZlC4/NQ1JORUW4xkMRrEWpoLPpkngmQ6K7ZkioVjE2ZafLMmHPAQKMO0BdA==", + "version": "0.14.3", + "resolved": "https://registry.npmjs.org/asar/-/asar-0.14.3.tgz", + "integrity": "sha512-+hNnVVDmYbv05We/a9knj/98w171+A94A9DNHj+3kXUr3ENTQoSEcfbJRvBBRHyOh4vukBYWujmHvvaMmQoQbg==", "dev": true, "requires": { - "chromium-pickle-js": "0.2.0", - "commander": "2.9.0", - "cuint": "0.2.2", - "glob": "6.0.4", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "mksnapshot": "0.3.1", + "chromium-pickle-js": "^0.2.0", + "commander": "^2.9.0", + "cuint": "^0.2.1", + "glob": "^6.0.4", + "minimatch": "^3.0.3", + "mkdirp": "^0.5.0", + "mksnapshot": "^0.3.0", "tmp": "0.0.28" }, "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, "glob": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", "dev": true, "requires": { - "inflight": "1.0.4", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.3.3", - "path-is-absolute": "1.0.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "1.1.11" + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } } } }, "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } }, "assert-plus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", - "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "asynckit": { "version": "0.4.0", @@ -129,9 +114,15 @@ "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" }, "aws4": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.7.0.tgz", - "integrity": "sha512-32NDda82rhwD9/JBCCkB+MRYDp0oSvlo2IL6rQWA10PQi7tDUM3eqMSltXmY+Oyl/7N3P3qNtAlv7X0d9bI28w==" + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true }, "base64-js": { "version": "1.2.0", @@ -139,14 +130,23 @@ "integrity": "sha1-o5mS1yNYSBGYK+XikLtqU9hnAPE=", "dev": true }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, "binary": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", "dev": true, "requires": { - "buffers": "0.1.1", - "chainsaw": "0.1.0" + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" } }, "bl": { @@ -154,7 +154,7 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz", "integrity": "sha1-/cqHGplxOqANGeO7ukHER4emU5g=", "requires": { - "readable-stream": "2.0.6" + "readable-stream": "~2.0.5" }, "dependencies": { "isarray": { @@ -167,20 +167,20 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.1", - "isarray": "1.0.0", - "process-nextick-args": "1.0.6", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } } } }, "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.2.tgz", + "integrity": "sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg==", "dev": true }, "boolbase": { @@ -188,14 +188,44 @@ "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "requires": { - "hoek": "4.2.1" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, "buffers": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", @@ -219,8 +249,8 @@ "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", "dev": true, "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" } }, "caseless": { @@ -234,19 +264,30 @@ "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", "dev": true, "requires": { - "traverse": "0.3.9" + "traverse": ">=0.3.0 <0.4" } }, "cheerio": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz", - "integrity": "sha1-dy5wFfLuKZZQltcepBdbdas1SSU=", + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz", + "integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=", "requires": { - "css-select": "1.0.0", - "dom-serializer": "0.1.0", - "entities": "1.1.1", - "htmlparser2": "3.8.3", - "lodash": "3.10.1" + "css-select": "~1.2.0", + "dom-serializer": "~0.1.0", + "entities": "~1.1.1", + "htmlparser2": "^3.9.1", + "lodash.assignin": "^4.0.9", + "lodash.bind": "^4.1.4", + "lodash.defaults": "^4.0.1", + "lodash.filter": "^4.4.0", + "lodash.flatten": "^4.2.0", + "lodash.foreach": "^4.3.0", + "lodash.map": "^4.4.0", + "lodash.merge": "^4.4.0", + "lodash.pick": "^4.2.1", + "lodash.reduce": "^4.4.0", + "lodash.reject": "^4.4.0", + "lodash.some": "^4.4.0" } }, "chromium-pickle-js": { @@ -260,9 +301,9 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", "requires": { - "string-width": "1.0.1", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.0.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" } }, "co": { @@ -275,25 +316,22 @@ "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.0.0.tgz", "integrity": "sha1-9psZLT99keOC5Lcb3bd4eGGasMY=", "requires": { - "number-is-nan": "1.0.0" + "number-is-nan": "^1.0.0" } }, "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", + "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } }, "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "dev": true, - "requires": { - "graceful-readlink": "1.0.1" - } + "version": "2.18.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.18.0.tgz", + "integrity": "sha512-6CYPa+JP2ftfRU2qkDK+UTVeQYosOg/2GbcjIcKPHfinyOLPVGXu/ovN86RP49Re5ndJK1N0kuiidFFuepc4ZQ==", + "dev": true }, "compare-version": { "version": "0.1.2", @@ -308,34 +346,57 @@ "dev": true }, "concat-stream": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.0.tgz", - "integrity": "sha1-U/fUPFHF5D+ByP3QMyHGMb5o1hE=", + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", "dev": true, "requires": { - "inherits": "2.0.1", - "readable-stream": "2.0.6", - "typedarray": "0.0.6" + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" }, "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, "readable-stream": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", - "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.1", - "isarray": "1.0.0", - "process-nextick-args": "1.0.6", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" } } } @@ -345,39 +406,21 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.2.1" - } - } - } - }, "css-select": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz", - "integrity": "sha1-sRIcpRhI3SZOIkTQWM7iVN7rRLA=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", + "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", "requires": { - "boolbase": "1.0.0", - "css-what": "1.0.0", - "domutils": "1.4.3", - "nth-check": "1.0.1" + "boolbase": "~1.0.0", + "css-what": "2.1", + "domutils": "1.5.1", + "nth-check": "~1.0.1" } }, "css-what": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz", - "integrity": "sha1-18wt9FGAZm+Z0rFEYmOUaeAPc2w=" + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", + "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=" }, "cuint": { "version": "0.2.2", @@ -386,24 +429,27 @@ "dev": true }, "dashdash": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.0.tgz", - "integrity": "sha1-parm/Z2OFWYk6w3ZJZ6xK6JFOFo=", + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } + "assert-plus": "^1.0.0" } }, "debug": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz", - "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=" + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.0.1.tgz", + "integrity": "sha512-K23FHJ/Mt404FSlp6gSZCevIbTMLX0j3fmHhUEhQ3Wq0FMODW3+cUSoLdy1Gx4polAf4t/lphhmHH35BB8cLYw==", + "requires": { + "ms": "^2.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } }, "decamelize": { "version": "1.2.0", @@ -416,19 +462,19 @@ "integrity": "sha1-rjvLfjTGWHmt/nfhnDD4ZgK0vbA=", "dev": true, "requires": { - "binary": "0.3.0", - "graceful-fs": "4.1.3", - "mkpath": "0.1.0", - "nopt": "3.0.6", - "q": "1.5.1", - "readable-stream": "1.1.14", + "binary": "^0.3.0", + "graceful-fs": "^4.1.3", + "mkpath": "^0.1.0", + "nopt": "^3.0.1", + "q": "^1.1.2", + "readable-stream": "^1.1.8", "touch": "0.0.3" } }, "deep-extend": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.1.tgz", - "integrity": "sha1-7+QRPQgIX05vlod1mBD4B0aeIlM=", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", "dev": true }, "delayed-stream": { @@ -441,8 +487,8 @@ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" + "domelementtype": "~1.1.1", + "entities": "~1.1.1" }, "dependencies": { "domelementtype": { @@ -458,95 +504,109 @@ "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=" }, "domhandler": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz", + "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==", "requires": { - "domelementtype": "1.3.0" + "domelementtype": "1" } }, "domutils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz", - "integrity": "sha1-CGVRN5bGswYDGFDhdVFrr4C3Km8=", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", "requires": { - "domelementtype": "1.3.0" + "dom-serializer": "0", + "domelementtype": "1" } }, "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", "optional": true, "requires": { - "jsbn": "0.1.0" + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" } }, "electron": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/electron/-/electron-1.8.4.tgz", - "integrity": "sha512-2f1cx0G3riMFODXFftF5AHXy+oHfhpntZHTDN66Hxtl09gmEr42B3piNEod9MEmw72f75LX2JfeYceqq1PF8cA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-3.0.0.tgz", + "integrity": "sha512-QN9X5vYa4kzJKniwhXlJwioX9qw2fDehdqxN/00KCLz/qnOz/IHLAHGikFjRwfEF2xnkmHxf61F8wn2LePPXXQ==", "dev": true, "requires": { - "@types/node": "8.10.2", - "electron-download": "3.3.0", - "extract-zip": "1.5.0" + "@types/node": "^8.0.24", + "electron-download": "^4.1.0", + "extract-zip": "^1.0.3" } }, "electron-download": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz", - "integrity": "sha1-LP1U1pZsAZxNSa1l++Zcyc3vaMg=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.1.tgz", + "integrity": "sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg==", "dev": true, "requires": { - "debug": "2.6.9", - "fs-extra": "0.30.0", - "home-path": "1.0.5", - "minimist": "1.2.0", - "nugget": "2.0.1", - "path-exists": "2.1.0", - "rc": "1.1.6", - "semver": "5.5.0", - "sumchecker": "1.3.1" + "debug": "^3.0.0", + "env-paths": "^1.0.0", + "fs-extra": "^4.0.1", + "minimist": "^1.2.0", + "nugget": "^2.0.1", + "path-exists": "^3.0.0", + "rc": "^1.2.1", + "semver": "^5.4.1", + "sumchecker": "^2.0.2" }, "dependencies": { "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "fs-extra": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz", - "integrity": "sha1-8jP/zAjU2n1DLapEl3aYnbHfk/A=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "jsonfile": "2.2.3", - "klaw": "1.3.1", - "path-is-absolute": "1.0.0", - "rimraf": "2.6.2" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, + "optional": true + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, - "sumchecker": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-1.3.1.tgz", - "integrity": "sha1-ebs7RFbdBPGOvbwNcDodHa7FEF0=", - "dev": true, - "requires": { - "debug": "2.6.9", - "es6-promise": "4.2.4" - } + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true } } }, @@ -556,17 +616,17 @@ "integrity": "sha1-DboCXtM9DkW/j0DG6b487i+YbCg=" }, "electron-osx-sign": { - "version": "0.4.8", - "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.8.tgz", - "integrity": "sha1-8Ln63e2eHlTsNfqJh3tcbDTHvEA=", + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/electron-osx-sign/-/electron-osx-sign-0.4.10.tgz", + "integrity": "sha1-vk87ibKnWh3F8eckkIGrKSnKOiY=", "dev": true, "requires": { - "bluebird": "3.5.1", - "compare-version": "0.1.2", - "debug": "2.6.9", - "isbinaryfile": "3.0.2", - "minimist": "1.2.0", - "plist": "2.1.0" + "bluebird": "^3.5.0", + "compare-version": "^0.1.2", + "debug": "^2.6.8", + "isbinaryfile": "^3.0.2", + "minimist": "^1.2.0", + "plist": "^2.1.0" }, "dependencies": { "debug": { @@ -577,89 +637,75 @@ "requires": { "ms": "2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, "electron-packager": { - "version": "12.0.0", - "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-12.0.0.tgz", - "integrity": "sha1-uC0k14ovIUA7v9FmpbFWmJTVzQw=", + "version": "12.1.2", + "resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-12.1.2.tgz", + "integrity": "sha512-7UiTNquZqhQm+L0Oqn7bR/7Ry/7zGO/PKwFpSNqHbWxydoN2aNahKyWjOPhcxHCAz+C1uu+tdyRe7wEN0BaJsA==", "dev": true, "requires": { - "asar": "0.14.2", - "debug": "3.1.0", - "electron-download": "4.1.0", - "electron-osx-sign": "0.4.8", - "extract-zip": "1.5.0", - "fs-extra": "5.0.0", - "galactus": "0.2.0", - "get-package-info": "1.0.0", - "nodeify": "1.0.1", - "parse-author": "2.0.0", - "pify": "3.0.0", - "plist": "2.1.0", - "rcedit": "1.0.0", - "resolve": "1.5.0", - "sanitize-filename": "1.6.1", - "semver": "5.5.0", - "yargs-parser": "9.0.2" + "asar": "^0.14.0", + "debug": "^3.0.0", + "electron-download": "^4.1.1", + "electron-osx-sign": "^0.4.1", + "extract-zip": "^1.0.3", + "fs-extra": "^5.0.0", + "galactus": "^0.2.1", + "get-package-info": "^1.0.0", + "nodeify": "^1.0.1", + "parse-author": "^2.0.0", + "pify": "^3.0.0", + "plist": "^2.0.0", + "rcedit": "^1.0.0", + "resolve": "^1.1.6", + "sanitize-filename": "^1.6.0", + "semver": "^5.3.0", + "yargs-parser": "^10.0.0" }, "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, "electron-download": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.0.tgz", - "integrity": "sha1-v5MsdG8vh//MCdHdRy8v9rkYeEU=", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.1.tgz", + "integrity": "sha512-FjEWG9Jb/ppK/2zToP+U5dds114fM1ZOJqMAR4aXXL5CvyPE9fiqBK/9YcwC9poIFQTEJk/EM/zyRwziziRZrg==", "dev": true, "requires": { - "debug": "2.6.9", - "env-paths": "1.0.0", - "fs-extra": "2.1.2", - "minimist": "1.2.0", - "nugget": "2.0.1", - "path-exists": "3.0.0", - "rc": "1.1.6", - "semver": "5.5.0", - "sumchecker": "2.0.2" + "debug": "^3.0.0", + "env-paths": "^1.0.0", + "fs-extra": "^4.0.1", + "minimist": "^1.2.0", + "nugget": "^2.0.1", + "path-exists": "^3.0.0", + "rc": "^1.2.1", + "semver": "^5.4.1", + "sumchecker": "^2.0.2" }, "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, "fs-extra": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-2.1.2.tgz", - "integrity": "sha1-BGxwFjzvmq1GsOSn+kZ/si1x3jU=", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "jsonfile": "2.2.3" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } } } @@ -670,63 +716,35 @@ "integrity": "sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ==", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "jsonfile": "4.0.0", - "universalify": "0.1.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" }, "dependencies": { - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "dev": true, - "requires": { - "graceful-fs": "4.1.11" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true, - "optional": true - } - } + "optional": true } } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true }, - "nugget": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nugget/-/nugget-2.0.1.tgz", - "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=", - "dev": true, - "requires": { - "debug": "2.6.9", - "minimist": "1.2.0", - "pretty-bytes": "1.0.4", - "progress-stream": "1.2.0", - "request": "2.85.0", - "single-line-log": "1.1.2", - "throttleit": "0.0.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", @@ -739,41 +757,29 @@ "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "dev": true }, - "rcedit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/rcedit/-/rcedit-1.0.0.tgz", - "integrity": "sha512-W7DNa34x/3OgWyDHsI172AG/Lr/lZ+PkavFkHj0QhhkBRcV9QTmRJE1tDKrWkx8XHPSBsmZkNv9OKue6pncLFQ==", - "dev": true + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", "dev": true }, - "single-line-log": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/single-line-log/-/single-line-log-1.1.2.tgz", - "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=", - "dev": true, - "requires": { - "string-width": "1.0.1" - } - }, - "throttleit": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-0.0.2.tgz", - "integrity": "sha1-z+34jmDADdlpe2H90qg0OptoDq8=", + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true - }, - "yargs-parser": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz", - "integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=", - "dev": true, - "requires": { - "camelcase": "4.1.0" - } } } }, @@ -782,7 +788,7 @@ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.1.0.tgz", "integrity": "sha1-6TUyWLqpEIll78QcsO+K3i88+wc=", "requires": { - "once": "1.3.3" + "once": "~1.3.0" } }, "entities": { @@ -802,58 +808,46 @@ "integrity": "sha1-5ntD8+gsluo6WE/+4Ln8MyXYAtk=", "dev": true, "requires": { - "is-arrayish": "0.2.1" + "is-arrayish": "^0.2.1" } }, - "es6-promise": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.4.tgz", - "integrity": "sha512-/NdNZVJg+uZgtm9eS3O6lrOLYmQag2DjdEXuPaHlZ6RuVqgqaVZfgYCepEIKsLqwdQArOPtC3XzRLqGGfT8KQQ==", - "dev": true - }, "extend": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz", "integrity": "sha1-WkdDU7nzNT3dgXbf03uRyDpG8dQ=" }, "extract-zip": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.5.0.tgz", - "integrity": "sha1-ksz22B73Cp+kwXRxFMzvbYaIpsQ=", + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.6.7.tgz", + "integrity": "sha1-qEC0uK9kAyZMjbV/Txp0Mz74H+k=", "dev": true, "requires": { - "concat-stream": "1.5.0", - "debug": "0.7.4", - "mkdirp": "0.5.0", + "concat-stream": "1.6.2", + "debug": "2.6.9", + "mkdirp": "0.5.1", "yauzl": "2.4.1" }, "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - }, - "mkdirp": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", - "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "requires": { - "minimist": "0.0.8" + "ms": "2.0.0" } } } }, "extsprintf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", - "integrity": "sha1-4QgOBljjALBilJkMxw4VAiNf1VA=" + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, "fast-deep-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" }, "fast-json-stable-stringify": { "version": "2.0.0", @@ -866,7 +860,7 @@ "integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=", "dev": true, "requires": { - "pend": "1.2.0" + "pend": "~1.2.0" } }, "find-up": { @@ -875,8 +869,8 @@ "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "dev": true, "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { "path-exists": { @@ -885,28 +879,28 @@ "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "dev": true, "requires": { - "pinkie-promise": "2.0.1" + "pinkie-promise": "^2.0.0" } } } }, "flora-colossus": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/flora-colossus/-/flora-colossus-0.0.2.tgz", - "integrity": "sha1-fRvimh8X+k8isb1hSC+Gw04HuQE=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/flora-colossus/-/flora-colossus-1.0.0.tgz", + "integrity": "sha1-VHKcNh7ezuAU3UQWeeGjfB13OkU=", "dev": true, "requires": { - "debug": "3.1.0", - "fs-extra": "4.0.3" + "debug": "^3.1.0", + "fs-extra": "^4.0.0" }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "fs-extra": { @@ -915,9 +909,9 @@ "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "jsonfile": "4.0.0", - "universalify": "0.1.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "jsonfile": { @@ -926,7 +920,7 @@ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.6" }, "dependencies": { "graceful-fs": { @@ -939,9 +933,9 @@ } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true } } @@ -956,9 +950,9 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.2.tgz", "integrity": "sha1-SXBJi+YEwgwAXU9cI67NIda0kJk=", "requires": { - "asynckit": "0.4.0", + "asynckit": "^0.4.0", "combined-stream": "1.0.6", - "mime-types": "2.1.18" + "mime-types": "^2.1.12" }, "dependencies": { "combined-stream": { @@ -966,19 +960,37 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.6.tgz", "integrity": "sha1-cj599ugBrFYTETp+RFqbactjKBg=", "requires": { - "delayed-stream": "1.0.0" + "delayed-stream": "~1.0.0" } } } }, "fs-extra": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz", - "integrity": "sha1-zTzl9+fLYUWIP8rjGR6Yd/hYeVA=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz", + "integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==", "requires": { - "graceful-fs": "4.1.3", - "jsonfile": "2.2.3", - "klaw": "1.3.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "dependencies": { + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "optional": true + } + } + } } }, "fs.realpath": { @@ -988,23 +1000,23 @@ "dev": true }, "galactus": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/galactus/-/galactus-0.2.0.tgz", - "integrity": "sha1-w9Y7pVAkZv5A6mfMaJCFs90kqPw=", + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/galactus/-/galactus-0.2.1.tgz", + "integrity": "sha1-y+0tIKQMH1Z5o1kI4rlBVzPnjbk=", "dev": true, "requires": { - "debug": "3.1.0", - "flora-colossus": "0.0.2", - "fs-extra": "4.0.3" + "debug": "^3.1.0", + "flora-colossus": "^1.0.0", + "fs-extra": "^4.0.0" }, "dependencies": { "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", "dev": true, "requires": { - "ms": "2.0.0" + "ms": "^2.1.1" } }, "fs-extra": { @@ -1013,9 +1025,9 @@ "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "jsonfile": "4.0.0", - "universalify": "0.1.1" + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" } }, "jsonfile": { @@ -1024,7 +1036,7 @@ "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", "dev": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.6" }, "dependencies": { "graceful-fs": { @@ -1037,9 +1049,9 @@ } }, "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", "dev": true } } @@ -1050,10 +1062,10 @@ "integrity": "sha1-ZDJ5ZWPigRPNlHTbvQAFKYWkmZw=", "dev": true, "requires": { - "bluebird": "3.5.1", - "debug": "2.6.9", - "lodash.get": "4.4.2", - "read-pkg-up": "2.0.0" + "bluebird": "^3.1.1", + "debug": "^2.2.0", + "lodash.get": "^4.0.0", + "read-pkg-up": "^2.0.0" }, "dependencies": { "debug": { @@ -1071,7 +1083,7 @@ "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", "dev": true, "requires": { - "locate-path": "2.0.0" + "locate-path": "^2.0.0" } }, "load-json-file": { @@ -1080,25 +1092,19 @@ "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" } }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", "dev": true, "requires": { - "pify": "2.3.0" + "pify": "^2.0.0" } }, "read-pkg": { @@ -1107,9 +1113,9 @@ "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", "dev": true, "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.3.5", - "path-type": "2.0.0" + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" } }, "read-pkg-up": { @@ -1118,8 +1124,8 @@ "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", "dev": true, "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" + "find-up": "^2.0.0", + "read-pkg": "^2.0.0" } }, "strip-bom": { @@ -1136,18 +1142,26 @@ "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", "dev": true }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, "glob": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", "dev": true, "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.4", - "inherits": "2.0.1", - "minimatch": "3.0.4", - "once": "1.3.3", - "path-is-absolute": "1.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "dependencies": { "balanced-match": { @@ -1162,7 +1176,7 @@ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "balanced-match": "1.0.0", + "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, @@ -1172,7 +1186,7 @@ "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "dev": true, "requires": { - "brace-expansion": "1.1.11" + "brace-expansion": "^1.1.7" } } } @@ -1182,12 +1196,6 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz", "integrity": "sha1-kgM84RETxB4mKNYf36QLwQ3AFVw=" }, - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", - "dev": true - }, "growly": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", @@ -1199,36 +1207,14 @@ "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz", + "integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==", "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" + "ajv": "^5.3.0", + "har-schema": "^2.0.0" } }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.1", - "sntp": "2.1.0" - } - }, - "hoek": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.1.tgz", - "integrity": "sha512-QLg82fGkfnJ/4iy1xZ81/9SIJiq1NGFUMGs6ParyjBZr6jW2Ufj/snDqTHixNlHdPNwN2RLVD0Pi3igeK9+JfA==" - }, - "home-path": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/home-path/-/home-path-1.0.5.tgz", - "integrity": "sha1-eIspgVsS1Tus9XVkhHbm+QQdEz8=", - "dev": true - }, "hosted-git-info": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.4.tgz", @@ -1236,30 +1222,56 @@ "dev": true }, "htmlparser2": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz", + "integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=", "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.3.0", - "domutils": "1.5.1", - "entities": "1.0.0", - "readable-stream": "1.1.14" + "domelementtype": "^1.3.0", + "domhandler": "^2.3.0", + "domutils": "^1.5.1", + "entities": "^1.1.1", + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" }, "dependencies": { - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } } }, - "entities": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=" + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } } } }, @@ -1268,16 +1280,9 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.2.2", - "sshpk": "1.7.4" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - } + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" } }, "indent-string": { @@ -1286,7 +1291,7 @@ "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", "dev": true, "requires": { - "repeating": "2.0.1" + "repeating": "^2.0.0" }, "dependencies": { "repeating": { @@ -1295,7 +1300,7 @@ "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", "dev": true, "requires": { - "is-finite": "1.0.1" + "is-finite": "^1.0.0" } } } @@ -1306,8 +1311,8 @@ "integrity": "sha1-bLtFIevVHODsCpNr/XZX736bFyo=", "dev": true, "requires": { - "once": "1.3.3", - "wrappy": "1.0.1" + "once": "^1.3.0", + "wrappy": "1" } }, "inherits": { @@ -1338,7 +1343,7 @@ "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { - "builtin-modules": "1.1.1" + "builtin-modules": "^1.0.0" } }, "is-finite": { @@ -1347,7 +1352,7 @@ "integrity": "sha1-ZDhgPq6+J5OUj/SkJi7I2z1iWXs=", "dev": true, "requires": { - "number-is-nan": "1.0.0" + "number-is-nan": "^1.0.0" } }, "is-fullwidth-code-point": { @@ -1355,7 +1360,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "requires": { - "number-is-nan": "1.0.0" + "number-is-nan": "^1.0.0" } }, "is-promise": { @@ -1378,13 +1383,17 @@ "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true }, "isbinaryfile": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.2.tgz", - "integrity": "sha1-Sj6XTsDLqQBNP8bN5yCeppNopiE=", - "dev": true + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-3.0.3.tgz", + "integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==", + "dev": true, + "requires": { + "buffer-alloc": "^1.2.0" + } }, "isexe": { "version": "2.0.0", @@ -1396,25 +1405,16 @@ "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, - "jodid25519": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz", - "integrity": "sha1-BtSRIlUJNBlHfUJWM2BuDpB4KWc=", - "optional": true, - "requires": { - "jsbn": "0.1.0" - } - }, "jsbn": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz", - "integrity": "sha1-ZQmH2g3XT06/WhE3eiqi0nPpff0=", + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", "optional": true }, "json-schema": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz", - "integrity": "sha1-UDVPGfYDkXxpX3C4Wvp3w7DyNQY=" + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-traverse": { "version": "0.3.1", @@ -1429,30 +1429,34 @@ "jsonfile": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.2.3.tgz", - "integrity": "sha1-4lK5mmr5AdPsQfMyWJyQUJp7xgU=" + "integrity": "sha1-4lK5mmr5AdPsQfMyWJyQUJp7xgU=", + "dev": true }, "jsprim": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz", - "integrity": "sha1-8gyQaskqvVjjt5rIvHCkiDJRLaE=", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", "requires": { - "extsprintf": "1.0.2", - "json-schema": "0.2.2", - "verror": "1.3.6" + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" } }, "klaw": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz", "integrity": "sha1-QIhDO0azsbolnXh4XY6W9zugJDk=", + "dev": true, "requires": { - "graceful-fs": "4.1.11" + "graceful-fs": "^4.1.9" }, "dependencies": { "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true, "optional": true } } @@ -1462,7 +1466,7 @@ "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", "requires": { - "invert-kv": "1.0.0" + "invert-kv": "^1.0.0" } }, "load-json-file": { @@ -1471,11 +1475,11 @@ "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" } }, "locate-path": { @@ -1484,8 +1488,8 @@ "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", "dev": true, "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" }, "dependencies": { "path-exists": { @@ -1496,10 +1500,35 @@ } } }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" + "lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=" + }, + "lodash.bind": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz", + "integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU=" + }, + "lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "lodash.filter": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz", + "integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4=" + }, + "lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "lodash.foreach": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz", + "integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM=" }, "lodash.get": { "version": "4.4.2", @@ -1507,14 +1536,44 @@ "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", "dev": true }, + "lodash.map": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz", + "integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=" + }, + "lodash.merge": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", + "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==" + }, + "lodash.pick": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz", + "integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=" + }, + "lodash.reduce": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz", + "integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs=" + }, + "lodash.reject": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz", + "integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU=" + }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=" + }, "loud-rejection": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.3.0.tgz", "integrity": "sha1-8omjkvF9K6rPGU0KZzAEOUQzsRU=", "dev": true, "requires": { - "array-find-index": "1.0.1", - "signal-exit": "2.1.2" + "array-find-index": "^1.0.0", + "signal-exit": "^2.1.2" } }, "map-obj": { @@ -1529,29 +1588,38 @@ "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", "dev": true, "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.3.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.3.5", - "object-assign": "4.0.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" } }, "mime-db": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", - "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" + "version": "1.36.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.36.0.tgz", + "integrity": "sha512-L+xvyD9MkoYMXb1jAmzI/lWYAxAMCPvIBSWur0PZ5nOf5euahRLVqH//FKW9mWp2lkqUgYiXPgkzfMUFi4zVDw==" }, "mime-types": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", - "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", + "version": "2.1.20", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.20.tgz", + "integrity": "sha512-HrkrPaP9vGuWbLK1B1FfgAkbqNjIuy4eHlIYnFi7kamZyLLrGlo2mpcx0bBmNpKqBtYtAfGbodDddIgddSJC2A==", "requires": { - "mime-db": "1.33.0" + "mime-db": "~1.36.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" } }, "minimist": { @@ -1589,220 +1657,21 @@ "requires": { "decompress-zip": "0.3.0", "fs-extra": "0.26.7", - "request": "2.83.0" + "request": "^2.79.0" }, "dependencies": { - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", - "dev": true - }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "dev": true, - "requires": { - "hoek": "4.2.0" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "dev": true, - "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "dev": true, - "requires": { - "hoek": "4.2.0" - } - } - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", - "dev": true - }, - "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", - "dev": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", "integrity": "sha1-muH92UiXeY7at20JGM9C0MMYT6k=", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "jsonfile": "2.2.3", - "klaw": "1.3.1", - "path-is-absolute": "1.0.0", - "rimraf": "2.6.2" + "graceful-fs": "^4.1.2", + "jsonfile": "^2.1.0", + "klaw": "^1.0.0", + "path-is-absolute": "^1.0.0", + "rimraf": "^2.2.8" } - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "dev": true, - "requires": { - "ajv": "5.5.2", - "har-schema": "2.0.0" - } - }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "dev": true, - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.0", - "sntp": "2.1.0" - } - }, - "hoek": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", - "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==", - "dev": true - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.2.2", - "sshpk": "1.7.4" - } - }, - "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", - "dev": true - }, - "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "dev": true, - "requires": { - "mime-db": "1.30.0" - } - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", - "dev": true - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==", - "dev": true - }, - "request": { - "version": "2.83.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz", - "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==", - "dev": true, - "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.1", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.3", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" - } - }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "dev": true, - "requires": { - "hoek": "4.2.0" - } - }, - "tough-cookie": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", - "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", - "dev": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "5.1.1" - } - }, - "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", - "dev": true } } }, @@ -1817,10 +1686,10 @@ "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.2.1.tgz", "integrity": "sha512-MIBs+AAd6dJ2SklbbE8RUDRlIVhU8MaNLh1A9SUZDUHPiZkWLFde6UNwG41yQHZEToHgJMXqyVZ9UcS/ReOVTg==", "requires": { - "growly": "1.3.0", - "semver": "5.5.0", - "shellwords": "0.1.1", - "which": "1.3.0" + "growly": "^1.3.0", + "semver": "^5.4.1", + "shellwords": "^0.1.1", + "which": "^1.3.0" }, "dependencies": { "semver": { @@ -1836,8 +1705,8 @@ "integrity": "sha1-ZKtpp7268DzhB7TwM1yHwLnpGx0=", "dev": true, "requires": { - "is-promise": "1.0.1", - "promise": "1.3.0" + "is-promise": "~1.0.0", + "promise": "~1.3.0" } }, "nopt": { @@ -1846,7 +1715,7 @@ "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", "dev": true, "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } }, "normalize-package-data": { @@ -1855,10 +1724,10 @@ "integrity": "sha1-jZJPFClg4Xd+f/4XBUNjHMfLAt8=", "dev": true, "requires": { - "hosted-git-info": "2.1.4", - "is-builtin-module": "1.0.0", - "semver": "5.1.0", - "validate-npm-package-license": "3.0.1" + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, "nth-check": { @@ -1866,7 +1735,7 @@ "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", "requires": { - "boolbase": "1.0.0" + "boolbase": "~1.0.0" } }, "nugget": { @@ -1875,12 +1744,12 @@ "integrity": "sha1-IBCVpIfhrTYIGzQy+jytpPjQcbA=", "dev": true, "requires": { - "debug": "2.6.9", - "minimist": "1.2.0", - "pretty-bytes": "1.0.4", - "progress-stream": "1.2.0", - "request": "2.85.0", - "single-line-log": "1.1.2", + "debug": "^2.1.3", + "minimist": "^1.1.0", + "pretty-bytes": "^1.0.2", + "progress-stream": "^1.1.0", + "request": "^2.45.0", + "single-line-log": "^1.1.2", "throttleit": "0.0.2" }, "dependencies": { @@ -1907,9 +1776,9 @@ "integrity": "sha1-wCD1KcUoKt/dIz2R1LGBw9aG3Es=" }, "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-assign": { "version": "4.0.1", @@ -1928,7 +1797,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", "requires": { - "wrappy": "1.0.1" + "wrappy": "1" } }, "os-homedir": { @@ -1941,7 +1810,7 @@ "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", "requires": { - "lcid": "1.0.0" + "lcid": "^1.0.0" } }, "os-tmpdir": { @@ -1951,12 +1820,12 @@ "dev": true }, "p-limit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", - "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", "dev": true, "requires": { - "p-try": "1.0.0" + "p-try": "^1.0.0" } }, "p-locate": { @@ -1965,7 +1834,7 @@ "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", "dev": true, "requires": { - "p-limit": "1.2.0" + "p-limit": "^1.1.0" } }, "p-try": { @@ -1980,7 +1849,7 @@ "integrity": "sha1-00YL8d3Q367tQtp1QkLmX7aEqB8=", "dev": true, "requires": { - "author-regex": "1.0.0" + "author-regex": "^1.0.0" } }, "parse-json": { @@ -1989,17 +1858,14 @@ "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", "dev": true, "requires": { - "error-ex": "1.3.0" + "error-ex": "^1.2.0" } }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "2.0.1" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true }, "path-is-absolute": { "version": "1.0.0", @@ -2008,9 +1874,9 @@ "dev": true }, "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", "dev": true }, "path-type": { @@ -2019,9 +1885,9 @@ "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", "dev": true, "requires": { - "graceful-fs": "4.1.3", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" } }, "pend": { @@ -2053,7 +1919,7 @@ "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", "dev": true, "requires": { - "pinkie": "2.0.4" + "pinkie": "^2.0.0" } }, "plist": { @@ -2064,7 +1930,7 @@ "requires": { "base64-js": "1.2.0", "xmlbuilder": "8.2.2", - "xmldom": "0.1.27" + "xmldom": "0.1.x" } }, "pretty-bytes": { @@ -2073,8 +1939,8 @@ "integrity": "sha1-CiLoIQYJrTVUL4yNXSFZr/B1HIQ=", "dev": true, "requires": { - "get-stdin": "4.0.1", - "meow": "3.7.0" + "get-stdin": "^4.0.1", + "meow": "^3.1.0" } }, "process-nextick-args": { @@ -2088,8 +1954,8 @@ "integrity": "sha1-LNPP6jO6OonJwSHsM0er6asSX3c=", "dev": true, "requires": { - "speedometer": "0.1.4", - "through2": "0.2.3" + "speedometer": "~0.1.2", + "through2": "~0.2.3" } }, "promise": { @@ -2098,16 +1964,21 @@ "integrity": "sha1-5cyaTIJ45GZP/twBx9qEhCsEAXU=", "dev": true, "requires": { - "is-promise": "1.0.1" + "is-promise": "~1" } }, + "psl": { + "version": "1.1.29", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", + "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" + }, "pump": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.1.tgz", "integrity": "sha1-8fFAn7m9EIW721drQ7hOxLXq3Bo=", "requires": { - "end-of-stream": "1.1.0", - "once": "1.3.3" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "punycode": { @@ -2122,31 +1993,37 @@ "dev": true }, "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, "rc": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.1.6.tgz", - "integrity": "sha1-Q2UbdrauU7XIAvEVH6P8OwWZack=", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", "dev": true, "requires": { - "deep-extend": "0.4.1", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "1.0.4" + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" } }, + "rcedit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/rcedit/-/rcedit-1.1.0.tgz", + "integrity": "sha512-JkXJ0IrUcdupLoIx6gE4YcFaMVSGtu7kQf4NJoDJUnfBZGuATmJ2Yal2v55KTltp+WV8dGr7A0RtOzx6jmtM6Q==", + "dev": true + }, "read-pkg": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", "dev": true, "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.3.5", - "path-type": "1.1.0" + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" } }, "read-pkg-up": { @@ -2155,19 +2032,20 @@ "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", "dev": true, "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" } }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.1", + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", "isarray": "0.0.1", - "string_decoder": "0.10.31" + "string_decoder": "~0.10.x" } }, "redent": { @@ -2176,43 +2054,41 @@ "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", "dev": true, "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" } }, "request": { - "version": "2.85.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.85.0.tgz", - "integrity": "sha512-8H7Ehijd4js+s6wuVPLjwORxD4zeuyjYugprdOXlPSqaApmL/QOy+EB/beICHVCHkGMKNh5rvihb5ov+IDw4mg==", + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.7.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.2", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.18", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.4", - "tunnel-agent": "0.6.0", - "uuid": "3.2.1" + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" }, "dependencies": { "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" } } }, @@ -2221,16 +2097,16 @@ "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-1.0.2.tgz", "integrity": "sha1-XUBvCBMJ32G0qKqDzVc032Pxi/U=", "requires": { - "throttleit": "1.0.0" + "throttleit": "^1.0.0" } }, "resolve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", - "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", "dev": true, "requires": { - "path-parse": "1.0.5" + "path-parse": "^1.0.5" } }, "rimraf": { @@ -2239,13 +2115,18 @@ "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", "dev": true, "requires": { - "glob": "7.1.2" + "glob": "^7.0.5" } }, "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "sanitize-filename": { "version": "1.6.1", @@ -2253,7 +2134,7 @@ "integrity": "sha1-YS2hyWRz+gLczaktzVtKsWSmdyo=", "dev": true, "requires": { - "truncate-utf8-bytes": "1.0.2" + "truncate-utf8-bytes": "^1.0.0" } }, "semver": { @@ -2279,15 +2160,7 @@ "integrity": "sha1-wvg/Jzo+GhbtsJlWYdoO1e8DM2Q=", "dev": true, "requires": { - "string-width": "1.0.1" - } - }, - "sntp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz", - "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==", - "requires": { - "hoek": "4.2.1" + "string-width": "^1.0.1" } }, "spdx-correct": { @@ -2296,7 +2169,7 @@ "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", "dev": true, "requires": { - "spdx-license-ids": "1.2.1" + "spdx-license-ids": "^1.0.2" } }, "spdx-exceptions": { @@ -2311,8 +2184,8 @@ "integrity": "sha1-1SsUtelnB3FECvIlvLVjEirEUvY=", "dev": true, "requires": { - "spdx-exceptions": "1.0.4", - "spdx-license-ids": "1.2.1" + "spdx-exceptions": "^1.0.4", + "spdx-license-ids": "^1.0.0" } }, "spdx-license-ids": { @@ -2328,17 +2201,19 @@ "dev": true }, "sshpk": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.4.tgz", - "integrity": "sha1-rXtH3vymHIQV2WQkO2KwzmD7yjg=", + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.14.2.tgz", + "integrity": "sha1-xvxhZIo9nE52T9P8306hBeSSupg=", "requires": { - "asn1": "0.2.3", - "assert-plus": "0.2.0", - "dashdash": "1.13.0", - "ecc-jsbn": "0.1.1", - "jodid25519": "1.0.2", - "jsbn": "0.1.0", - "tweetnacl": "0.14.3" + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" } }, "string-width": { @@ -2346,9 +2221,9 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.1.tgz", "integrity": "sha1-ySEptvHX9SrPmvQkom44ZKBc6wo=", "requires": { - "code-point-at": "1.0.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" } }, "string_decoder": { @@ -2356,17 +2231,12 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, "strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "requires": { - "ansi-regex": "2.0.0" + "ansi-regex": "^2.0.0" } }, "strip-bom": { @@ -2375,7 +2245,7 @@ "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", "dev": true, "requires": { - "is-utf8": "0.2.1" + "is-utf8": "^0.2.0" } }, "strip-indent": { @@ -2384,13 +2254,13 @@ "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", "dev": true, "requires": { - "get-stdin": "4.0.1" + "get-stdin": "^4.0.1" } }, "strip-json-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, "sumchecker": { @@ -2399,7 +2269,7 @@ "integrity": "sha1-D0LBDl0F2l1C7qPlbDOZo31sWz4=", "dev": true, "requires": { - "debug": "2.6.9" + "debug": "^2.2.0" }, "dependencies": { "debug": { @@ -2410,12 +2280,6 @@ "requires": { "ms": "2.0.0" } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true } } }, @@ -2424,9 +2288,9 @@ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.12.0.tgz", "integrity": "sha1-pqgFU9ilTHPeHQrg553ncDVgXh0=", "requires": { - "mkdirp": "0.5.1", - "pump": "1.0.1", - "tar-stream": "1.5.1" + "mkdirp": "^0.5.0", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" } }, "tar-stream": { @@ -2434,10 +2298,10 @@ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.5.1.tgz", "integrity": "sha1-UWx00b6j4THMC5NIkpyag/CirRE=", "requires": { - "bl": "1.1.2", - "end-of-stream": "1.1.0", - "readable-stream": "2.0.6", - "xtend": "4.0.1" + "bl": "^1.0.0", + "end-of-stream": "^1.0.0", + "readable-stream": "^2.0.0", + "xtend": "^4.0.0" }, "dependencies": { "isarray": { @@ -2450,12 +2314,12 @@ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz", "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=", "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.1", - "isarray": "1.0.0", - "process-nextick-args": "1.0.6", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "~1.0.0", + "process-nextick-args": "~1.0.6", + "string_decoder": "~0.10.x", + "util-deprecate": "~1.0.1" } } } @@ -2471,8 +2335,8 @@ "integrity": "sha1-6zKE2k6jEbbMis42U3SKUqvyWj8=", "dev": true, "requires": { - "readable-stream": "1.1.14", - "xtend": "2.1.2" + "readable-stream": "~1.1.9", + "xtend": "~2.1.1" }, "dependencies": { "xtend": { @@ -2481,7 +2345,7 @@ "integrity": "sha1-bv7MKk2tjmlixJAbM3znuoe10os=", "dev": true, "requires": { - "object-keys": "0.4.0" + "object-keys": "~0.4.0" } } } @@ -2492,7 +2356,7 @@ "integrity": "sha1-Fyc1t/YU6nrzlmT6hM8N5OUV0SA=", "dev": true, "requires": { - "os-tmpdir": "1.0.2" + "os-tmpdir": "~1.0.1" } }, "touch": { @@ -2501,7 +2365,7 @@ "integrity": "sha1-Ua7z1ElXHU8oel2Hyci0kYGg2x0=", "dev": true, "requires": { - "nopt": "1.0.10" + "nopt": "~1.0.10" }, "dependencies": { "nopt": { @@ -2510,17 +2374,18 @@ "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, "requires": { - "abbrev": "1.1.1" + "abbrev": "1" } } } }, "tough-cookie": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", "requires": { - "punycode": "1.4.1" + "psl": "^1.1.24", + "punycode": "^1.4.1" } }, "traverse": { @@ -2541,7 +2406,7 @@ "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", "dev": true, "requires": { - "utf8-byte-length": "1.0.4" + "utf8-byte-length": "^1.0.1" } }, "tunnel-agent": { @@ -2549,13 +2414,13 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", "requires": { - "safe-buffer": "5.1.1" + "safe-buffer": "^5.0.1" } }, "tweetnacl": { - "version": "0.14.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.3.tgz", - "integrity": "sha1-PaOC9nDyXe1417PReSEZvKC3Ey0=", + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", "optional": true }, "typedarray": { @@ -2567,8 +2432,7 @@ "universalify": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=", - "dev": true + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" }, "utf8-byte-length": { "version": "1.0.4", @@ -2582,9 +2446,9 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, "uuid": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", - "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "validate-npm-package-license": { "version": "3.0.1", @@ -2592,16 +2456,18 @@ "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", "dev": true, "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.2" + "spdx-correct": "~1.0.0", + "spdx-expression-parse": "~1.0.0" } }, "verror": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", - "integrity": "sha1-z/XfEpRtKX0rqu+qJoniW+AcAFw=", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", "requires": { - "extsprintf": "1.0.2" + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" } }, "which": { @@ -2609,7 +2475,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", "requires": { - "isexe": "2.0.0" + "isexe": "^2.0.0" } }, "window-size": { @@ -2622,7 +2488,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.0.0.tgz", "integrity": "sha1-fTD4+HP5pbvDpk2ryNF34HGuQm8=", "requires": { - "string-width": "1.0.1" + "string-width": "^1.0.1" } }, "wrappy": { @@ -2657,13 +2523,30 @@ "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", "requires": { - "camelcase": "2.1.1", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "os-locale": "1.4.0", - "string-width": "1.0.1", - "window-size": "0.1.4", - "y18n": "3.2.1" + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + }, + "yargs-parser": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", + "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", + "dev": true, + "requires": { + "camelcase": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true + } } }, "yauzl": { @@ -2672,7 +2555,7 @@ "integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=", "dev": true, "requires": { - "fd-slicer": "1.0.1" + "fd-slicer": "~1.0.1" } } } diff --git a/server-console/package.json b/server-console/package.json index 565658702b..7a93d0faa5 100644 --- a/server-console/package.json +++ b/server-console/package.json @@ -8,8 +8,8 @@ "" ], "devDependencies": { - "electron-packager": "^12.0.0", - "electron": "1.8.4" + "electron": "^3.0.0", + "electron-packager": "^12.1.2" }, "repository": { "type": "git", @@ -23,14 +23,15 @@ "packager": "node packager.js" }, "dependencies": { - "always-tail": "0.2.0", - "cheerio": "^0.19.0", + "always-tail": "^0.2.0", + "cheerio": "^0.22.0", + "debug": "^4.0.1", "electron-log": "1.1.1", "extend": "^3.0.0", "fs-extra": "^6.0.0", "node-notifier": "^5.2.1", "os-homedir": "^1.0.1", - "request": "^2.85.0", + "request": "^2.88.0", "request-progress": "1.0.2", "tar-fs": "^1.12.0", "yargs": "^3.30.0" diff --git a/server-console/src/main.js b/server-console/src/main.js index 92ebdbf36c..3316730971 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -266,15 +266,12 @@ process.on('uncaughtException', function(err) { log.error(err.stack); }); -var shouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) { - // Someone tried to run a second instance, focus the window (if there is one) - return true; -}); +const gotTheLock = app.requestSingleInstanceLock() -if (shouldQuit) { - log.warn("Another instance of the Sandbox is already running - this instance will quit."); - app.exit(0); - return; +if (!gotTheLock) { + log.warn("Another instance of the Sandbox is already running - this instance will quit."); + app.exit(0); + return; } // Check command line arguments to see how to find binaries From ad6bbc7ff6954461c35da6ddbdef7b71bf7c5c55 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 25 Sep 2018 11:22:44 -0700 Subject: [PATCH 013/114] latest squatty changes --- interface/src/avatar/MyAvatar.cpp | 25 +++++++++++++++++-------- interface/src/avatar/MyAvatar.h | 1 + plugins/oculus/src/OculusHelpers.cpp | 6 ++++++ 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bf684ccd9a..c52e029d94 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -463,6 +463,7 @@ void MyAvatar::update(float deltaTime) { if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; } + // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { @@ -3601,9 +3602,9 @@ glm::vec3 MyAvatar::computeCounterBalance() { } else if (counterBalancedCg.y < sitSquatThreshold) { // do a height reset setResetMode(true); - _follow.activate(FollowHelper::Vertical); + //_follow.activate(FollowHelper::Vertical); // disable cg behaviour in this case. - setIsInSittingState(true); + //setIsInSittingState(true); } return counterBalancedCg; } @@ -4059,12 +4060,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons bool stepDetected = false; float myScale = myAvatar.getAvatarScale(); - - // debug head hips angle - //glm::vec3 hipsPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - //glm::vec3 headHipsBody = currentHeadPose.getTranslation() - hipsPos; - //qCDebug(interfaceapp) << "head in sensor space " << withinBaseOfSupport(currentHeadPose); - if (myAvatar.getIsInWalkingState()) { stepDetected = true; } else if (myAvatar.getIsInSittingState()) { @@ -4137,6 +4132,20 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { + + // debug head hips angle + glm::vec3 headDefaultPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); + if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.05f)) { + _squatCount++; + if ((_squatCount > 300) && !isActive(Vertical) && !isActive(Horizontal)) { + activate(Horizontal); + activate(Vertical); + _squatCount = 0; + } + } else { + _squatCount = 0; + } + if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6f3858c5bf..78dc6307e8 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1727,6 +1727,7 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; + int _squatCount{ 0 }; }; FollowHelper _follow; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 511984c657..e543d3ca00 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -79,6 +79,12 @@ private: if (!OVR_SUCCESS(ovr_Initialize(&initParams))) { qCWarning(oculusLog) << "Failed to initialze Oculus SDK" << ovr::getError(); return; + } else { + qCWarning(oculusLog) << "successful init of oculus!!!!!!!!"; + ovrTrackingOrigin fred; + fred = ovr_GetTrackingOriginType(session); + qCWarning(oculusLog) << (int)fred; + } ovrGraphicsLuid luid; From fa9abf0fff45ba8205a8647bdb28f18bc068e676 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 26 Sep 2018 18:08:00 -0700 Subject: [PATCH 014/114] added the floor at 0.0 in sensor space for oculus. to do: vive --- interface/src/avatar/MyAvatar.cpp | 35 ++++++++++++++++++++-------- interface/src/avatar/MyAvatar.h | 5 ++-- plugins/oculus/src/OculusHelpers.cpp | 13 ++++++----- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6394631484..2152c12b64 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -477,10 +477,20 @@ void MyAvatar::update(float deltaTime) { auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { - qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; + //qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; } - + if (!_lastFrameHMDMode && qApp->isHMDMode()) { + // we have entered hmd mode, so make the best guess about sitting or standing + if (sensorHeadPoseDebug.getTranslation().y < 1.3f) { + // then we are sitting. + // setIsInSittingState(true); + } else { + // setIsInSittingState(false); + } + } + // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { @@ -3575,9 +3585,9 @@ glm::vec3 MyAvatar::computeCounterBalance() { } else if (counterBalancedCg.y < sitSquatThreshold) { // do a height reset setResetMode(true); - //_follow.activate(FollowHelper::Vertical); + // _follow.activate(FollowHelper::Vertical); // disable cg behaviour in this case. - //setIsInSittingState(true); + // setIsInSittingState(true); } return counterBalancedCg; } @@ -4090,7 +4100,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl return true; } else if (offset.y > CYLINDER_TOP) { // if we recenter upwards then no longer in sitting state - myAvatar.setIsInSittingState(false); + // myAvatar.setIsInSittingState(false); return true; } else { return false; @@ -4110,15 +4120,20 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat glm::vec3 headDefaultPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.05f)) { _squatCount++; - if ((_squatCount > 300) && !isActive(Vertical) && !isActive(Horizontal)) { - activate(Horizontal); - activate(Vertical); - _squatCount = 0; + if ((_squatCount > 600) && !isActive(Vertical) && !isActive(Horizontal)) { + if (myAvatar.getIsInSittingState()) { + // activate(Horizontal); + activate(Vertical); + _squatCount = 0; + } else { + activate(Horizontal); + _squatCount = 0; + } } } else { _squatCount = 0; } - + if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1dabe38116..4ccb1a8d75 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1728,7 +1728,7 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; - int _squatCount{ 0 }; + int _squatCount { 0 }; }; FollowHelper _follow; @@ -1760,6 +1760,7 @@ private: glm::quat _customListenOrientation; AtRestDetector _hmdAtRestDetector; + bool _lastFrameHMDMode { false } ; bool _lastIsMoving { false }; // all poses are in sensor-frame @@ -1804,7 +1805,7 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; - bool _isInSittingState { false }; + bool _isInSittingState { true }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index e543d3ca00..38d93d088d 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -79,18 +79,19 @@ private: if (!OVR_SUCCESS(ovr_Initialize(&initParams))) { qCWarning(oculusLog) << "Failed to initialze Oculus SDK" << ovr::getError(); return; - } else { - qCWarning(oculusLog) << "successful init of oculus!!!!!!!!"; - ovrTrackingOrigin fred; - fred = ovr_GetTrackingOriginType(session); - qCWarning(oculusLog) << (int)fred; - } ovrGraphicsLuid luid; if (!OVR_SUCCESS(ovr_Create(&session, &luid))) { qCWarning(oculusLog) << "Failed to acquire Oculus session" << ovr::getError(); return; + } else { + qCWarning(oculusLog) << "successful init of oculus!!!!!!!!"; + ovrTrackingOrigin fred; + //fred = ovr_GetTrackingOriginType(session); + ovrResult retTrackingType = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel); + fred = ovr_GetTrackingOriginType(session); + qCWarning(oculusLog) << OVR_SUCCESS(retTrackingType) << (int)fred; } } From 52355e53f1e69ff4032813c13b229c04c6cfdb0d Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 27 Sep 2018 16:44:55 -0700 Subject: [PATCH 015/114] adding the menu item to the avatar app for the sit state. --- interface/resources/qml/hifi/AvatarApp.qml | 1 + .../resources/qml/hifi/avatarapp/Settings.qml | 57 +- interface/src/avatar/MyAvatar.cpp | 14 +- interface/src/avatar/MyAvatar.h | 9 + .../src/avatars-renderer/Avatar.cpp | 1 + scripts/developer/objectOrientedStep.js | 688 ++++++++++++++++++ scripts/system/avatarapp.js | 15 +- 7 files changed, 778 insertions(+), 7 deletions(-) create mode 100644 scripts/developer/objectOrientedStep.js diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index aea5931627..b06a2ca67c 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -252,6 +252,7 @@ Rectangle { var avatarSettings = { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, + sittingEnabled : settings.avatarSittingOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index 71bfbb084d..af76ba04d6 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -20,6 +20,7 @@ Rectangle { property real scaleValue: scaleSlider.value / 10 property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked + property alias avatarSittingOn: sitRadiobutton.checked property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -45,6 +46,12 @@ Rectangle { collisionsDisabledRadioButton.checked = true; } + if (settings.sittingEnabled) { + sitRadiobutton.checked = true; + } else { + standRadioButton.checked = true; + } + avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; @@ -289,8 +296,56 @@ Rectangle { text: "OFF" boxSize: 20 } - } + + // TextStyle9 + + RalewaySemiBold { + size: 17; + Layout.row: 2 + Layout.column: 0 + + text: "Sitting State" + } + + ButtonGroup { + id: sitStand + } + + HifiControlsUit.RadioButton { + id: sitRadiobutton + + Layout.row: 2 + Layout.column: 1 + Layout.leftMargin: -40 + + ButtonGroup.group: sitStand + checked: true + + colorScheme: hifi.colorSchemes.light + fontSize: 17 + letterSpacing: 1.4 + text: "Sit" + boxSize: 20 + } + + HifiControlsUit.RadioButton { + id: standRadioButton + + Layout.row: 2 + Layout.column: 2 + Layout.rightMargin: 20 + + ButtonGroup.group: sitStand + + colorScheme: hifi.colorSchemes.light + fontSize: 17 + letterSpacing: 1.4 + text: "Stand" + boxSize: 20 + } + } + ColumnLayout { id: avatarAnimationLayout anchors.top: handAndCollisions.bottom diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2152c12b64..631a4b0670 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -477,7 +477,7 @@ void MyAvatar::update(float deltaTime) { auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); - qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; + // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { //qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; } @@ -3854,6 +3854,7 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { void MyAvatar::setIsInSittingState(bool isSitting) { _isInSittingState = isSitting; + emit sittingEnabledChanged(isSitting); } void MyAvatar::setWalkSpeed(float value) { @@ -4098,9 +4099,9 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (offset.y > CYLINDER_TOP) { + } else if (offset.y > 2.0*CYLINDER_TOP) { // if we recenter upwards then no longer in sitting state - // myAvatar.setIsInSittingState(false); + myAvatar.setIsInSittingState(false); return true; } else { return false; @@ -4126,7 +4127,12 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat activate(Vertical); _squatCount = 0; } else { - activate(Horizontal); + if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.20f)) { + myAvatar.setIsInSittingState(true); + activate(Vertical); + } else { + activate(Horizontal); + } _squatCount = 0; } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 4ccb1a8d75..d9744e93fe 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -239,6 +239,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float walkSpeed READ getWalkSpeed WRITE setWalkSpeed); Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed); Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed); + Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState); const QString DOMINANT_LEFT_HAND = "left"; const QString DOMINANT_RIGHT_HAND = "right"; @@ -1506,6 +1507,14 @@ signals: */ void disableHandTouchForIDChanged(const QUuid& entityID, bool disable); + /**jsdoc + * Triggered when the sit state is enabled or disabled + * @function MyAvatar.sittingEnabledChanged + * @param {boolean} enabled + * @returns {Signal} + */ + void sittingEnabledChanged(bool enabled); + private slots: void leaveDomain(); void updateCollisionCapsuleCache(); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 914a3b7c6e..51c51b6a20 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -1618,6 +1618,7 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) { glm::vec3 Avatar::getWorldFeetPosition() { ShapeInfo shapeInfo; + computeShapeInfo(shapeInfo); glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight glm::vec3 localFeet(0.0f, shapeInfo.getOffset().y - halfExtents.y - halfExtents.x, 0.0f); diff --git a/scripts/developer/objectOrientedStep.js b/scripts/developer/objectOrientedStep.js new file mode 100644 index 0000000000..a5c27e36b9 --- /dev/null +++ b/scripts/developer/objectOrientedStep.js @@ -0,0 +1,688 @@ +/* jslint bitwise: true */ + +/* global Script, Vec3, MyAvatar, Tablet, Messages, Quat, +DebugDraw, Mat4, Entities, Xform, Controller, Camera, console, document*/ + +Script.registerValue("STEPAPP", true); +var CENTIMETERSPERMETER = 100.0; +var LEFT = 0; +var RIGHT = 1; +var INCREASING = 1.0; +var DECREASING = -1.0; +var DEFAULT_AVATAR_HEIGHT = 1.64; +var TABLET_BUTTON_NAME = "STEP"; +var CHANGE_OF_BASIS_ROTATION = { x: 0, y: 1, z: 0, w: 0 }; +// in meters (mostly) +var DEFAULT_ANTERIOR = 0.04; +var DEFAULT_POSTERIOR = 0.06; +var DEFAULT_LATERAL = 0.10; +var DEFAULT_HEIGHT_DIFFERENCE = 0.02; +var DEFAULT_ANGULAR_VELOCITY = 0.3; +var DEFAULT_HAND_VELOCITY = 0.4; +var DEFAULT_ANGULAR_HAND_VELOCITY = 3.3; +var DEFAULT_HEAD_VELOCITY = 0.14; +var DEFAULT_LEVEL_PITCH = 7; +var DEFAULT_LEVEL_ROLL = 7; +var DEFAULT_DIFF = 0.0; +var DEFAULT_DIFF_EULERS = { x: 0.0, y: 0.0, z: 0.0 }; +var DEFAULT_HIPS_POSITION; +var DEFAULT_HEAD_POSITION; +var DEFAULT_TORSO_LENGTH; +var SPINE_STRETCH_LIMIT = 0.02; + +var VELOCITY_EPSILON = 0.02; +var AVERAGING_RATE = 0.03; +var HEIGHT_AVERAGING_RATE = 0.01; +var STEP_TIME_SECS = 0.2; +var MODE_SAMPLE_LENGTH = 100; +var RESET_MODE = false; +var HEAD_TURN_THRESHOLD = 25.0; +var NO_SHARED_DIRECTION = -0.98; +var LOADING_DELAY = 500; +var FAILSAFE_TIMEOUT = 2.5; + +var debugDrawBase = true; +var activated = false; +var documentLoaded = false; +var failsafeFlag = false; +var failsafeSignalTimer = -1.0; +var stepTimer = -1.0; + + +var modeArray = new Array(MODE_SAMPLE_LENGTH); +var modeHeight = -10.0; + +var handPosition; +var handOrientation; +var hands = []; +var hipToHandAverage = []; +var handDotHead = []; +var headAverageOrientation = MyAvatar.orientation; +var headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; +var averageHeight = 1.0; +var headEulers = { x: 0.0, y: 0.0, z: 0.0 }; +var headAverageEulers = { x: 0.0, y: 0.0, z: 0.0 }; +var headAveragePosition = { x: 0, y: 0.4, z: 0 }; +var frontLeft = { x: -DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; +var frontRight = { x: DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; +var backLeft = { x: -DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; +var backRight = { x: DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; + + +// define state readings constructor +function StateReading(headPose, rhandPose, lhandPose, backLength, diffFromMode, diffFromAverageHeight, diffFromAveragePosition, + diffFromAverageEulers) { + this.headPose = headPose; + this.rhandPose = rhandPose; + this.lhandPose = lhandPose; + this.backLength = backLength; + this.diffFromMode = diffFromMode; + this.diffFromAverageHeight = diffFromAverageHeight; + this.diffFromAveragePosition = diffFromAveragePosition; + this.diffFromAverageEulers = diffFromAverageEulers; +} + +// define current state readings object for holding tracker readings and current differences from averages +var currentStateReadings = new StateReading(Controller.getPoseValue(Controller.Standard.Head), + Controller.getPoseValue(Controller.Standard.RightHand), Controller.getPoseValue(Controller.Standard.LeftHand), + DEFAULT_TORSO_LENGTH, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF_EULERS); + +// declare the checkbox constructor +function AppCheckbox(type,id,eventType,isChecked) { + this.type = type; + this.id = id; + this.eventType = eventType; + this.data = {value: isChecked}; +} + +// define the checkboxes in the html file +var usingAverageHeight = new AppCheckbox("checkboxtick", "runningAverageHeightCheck", "onRunningAverageHeightCheckBox", + false); +var usingModeHeight = new AppCheckbox("checkboxtick","modeCheck","onModeCheckBox",true); +var usingBaseOfSupport = new AppCheckbox("checkboxtick","baseOfSupportCheck","onBaseOfSupportCheckBox",true); +var usingAverageHeadPosition = new AppCheckbox("checkboxtick", "headAveragePositionCheck", "onHeadAveragePositionCheckBox", + false); + +var checkBoxArray = new Array(usingAverageHeight,usingModeHeight,usingBaseOfSupport,usingAverageHeadPosition); + +// declare the html slider constructor +function AppProperty(name, type, eventType, signalType, setFunction, initValue, convertToThreshold, convertToSlider, signalOn) { + this.name = name; + this.type = type; + this.eventType = eventType; + this.signalType = signalType; + this.setValue = setFunction; + this.value = initValue; + this.get = function () { + return this.value; + }; + this.convertToThreshold = convertToThreshold; + this.convertToSlider = convertToSlider; + this.signalOn = signalOn; +} + +// define the sliders +var frontBaseProperty = new AppProperty("#anteriorBase-slider", "slider", "onAnteriorBaseSlider", "frontSignal", + setAnteriorDistance, DEFAULT_ANTERIOR, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + },true); +var backBaseProperty = new AppProperty("#posteriorBase-slider", "slider", "onPosteriorBaseSlider", "backSignal", + setPosteriorDistance, DEFAULT_POSTERIOR, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + }, true); +var lateralBaseProperty = new AppProperty("#lateralBase-slider", "slider", "onLateralBaseSlider", "lateralSignal", + setLateralDistance, DEFAULT_LATERAL, function (num) { + return convertToMeters(num); + }, function (num) { + return convertToCentimeters(num); + }, true); +var headAngularVelocityProperty = new AppProperty("#angularVelocityHead-slider", "slider", "onAngularVelocitySlider", + "angularHeadSignal", setAngularThreshold, DEFAULT_ANGULAR_VELOCITY, function (num) { + var base = 4; + var shift = 2; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 4; + var shift = 2; + return convertLog(base, num, DECREASING, shift); + }, true); +var heightDifferenceProperty = new AppProperty("#heightDifference-slider", "slider", "onHeightDifferenceSlider", "heightSignal", + setHeightThreshold, DEFAULT_HEIGHT_DIFFERENCE, function (num) { + return convertToMeters(-num); + }, function (num) { + return convertToCentimeters(-num); + }, true); +var handsVelocityProperty = new AppProperty("#handsVelocity-slider", "slider", "onHandsVelocitySlider", "handVelocitySignal", + setHandVelocityThreshold, DEFAULT_HAND_VELOCITY, function (num) { + return num; + }, function (num) { + return num; + }, true); +var handsAngularVelocityProperty = new AppProperty("#handsAngularVelocity-slider", "slider", "onHandsAngularVelocitySlider", + "handAngularSignal", setHandAngularVelocityThreshold, DEFAULT_ANGULAR_HAND_VELOCITY, function (num) { + var base = 7; + var shift = 2; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 7; + var shift = 2; + return convertLog(base, num, DECREASING, shift); + }, true); +var headVelocityProperty = new AppProperty("#headVelocity-slider", "slider", "onHeadVelocitySlider", "headVelocitySignal", + setHeadVelocityThreshold, DEFAULT_HEAD_VELOCITY, function (num) { + var base = 2; + var shift = 0; + return convertExponential(base, num, INCREASING, shift); + }, function (num) { + var base = 2; + var shift = 0; + return convertLog(base, num, INCREASING, shift); + }, true); +var headPitchProperty = new AppProperty("#headPitch-slider", "slider", "onHeadPitchSlider", "headPitchSignal", + setHeadPitchThreshold, DEFAULT_LEVEL_PITCH, function (num) { + var base = 2.5; + var shift = 5; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 2.5; + var shift = 5; + return convertLog(base, num, DECREASING, shift); + }, true); +var headRollProperty = new AppProperty("#headRoll-slider", "slider", "onHeadRollSlider", "headRollSignal", setHeadRollThreshold, + DEFAULT_LEVEL_ROLL, function (num) { + var base = 2.5; + var shift = 5; + return convertExponential(base, num, DECREASING, shift); + }, function (num) { + var base = 2.5; + var shift = 5; + return convertLog(base, num, DECREASING, shift); + }, true); + +var propArray = new Array(frontBaseProperty, backBaseProperty, lateralBaseProperty, headAngularVelocityProperty, + heightDifferenceProperty, handsVelocityProperty, handsAngularVelocityProperty, headVelocityProperty, headPitchProperty, + headRollProperty); + +// var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepApp.html"); +var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepAppExtra.html"); +var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + +function manageClick() { + if (activated) { + tablet.gotoHomeScreen(); + } else { + tablet.gotoWebScreen(HTML_URL); + } +} + +var tabletButton = tablet.addButton({ + text: TABLET_BUTTON_NAME, + icon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg"), + activeIcon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg") +}); + +function drawBase() { + // transform corners into world space, for rendering. + var worldPointLf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontLeft)); + var worldPointRf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontRight)); + var worldPointLb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backLeft)); + var worldPointRb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backRight)); + + var GREEN = { r: 0, g: 1, b: 0, a: 1 }; + // draw border + DebugDraw.drawRay(worldPointLf, worldPointRf, GREEN); + DebugDraw.drawRay(worldPointRf, worldPointRb, GREEN); + DebugDraw.drawRay(worldPointRb, worldPointLb, GREEN); + DebugDraw.drawRay(worldPointLb, worldPointLf, GREEN); +} + +function onKeyPress(event) { + if (event.text === "'") { + // when the sensors are reset, then reset the mode. + RESET_MODE = false; + } +} + +function onWebEventReceived(msg) { + var message = JSON.parse(msg); + print(" we have a message from html dialog " + message.type); + propArray.forEach(function (prop) { + if (prop.eventType === message.type) { + prop.setValue(prop.convertToThreshold(message.data.value)); + print("message from " + prop.name); + // break; + } + }); + checkBoxArray.forEach(function(cbox) { + if (cbox.eventType === message.type) { + cbox.data.value = message.data.value; + // break; + } + }); + if (message.type === "onCreateStepApp") { + print("document loaded"); + documentLoaded = true; + Script.setTimeout(initAppForm, LOADING_DELAY); + } +} + +function initAppForm() { + print("step app is loaded: " + documentLoaded); + if (documentLoaded === true) { + propArray.forEach(function (prop) { + tablet.emitScriptEvent(JSON.stringify({ + "type": "trigger", + "id": prop.signalType, + "data": { "value": "green" } + })); + tablet.emitScriptEvent(JSON.stringify({ + "type": "slider", + "id": prop.name, + "data": { "value": prop.convertToSlider(prop.value) } + })); + }); + checkBoxArray.forEach(function (cbox) { + tablet.emitScriptEvent(JSON.stringify({ + "type": "checkboxtick", + "id": cbox.id, + "data": { "value": cbox.data.value } + })); + }); + } +} + +function updateSignalColors() { + + // force the updates by running the threshold comparisons + withinBaseOfSupport(currentStateReadings.headPose.translation); + withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode); + headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity); + handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose); + handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose); + headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)); + headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition); + headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight); + isHeadLevel(currentStateReadings.diffFromAverageEulers); + + propArray.forEach(function (prop) { + if (prop.signalOn) { + tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "green" } })); + } else { + tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "red" } })); + } + }); +} + +function onScreenChanged(type, url) { + print("Screen changed"); + if (type === "Web" && url === HTML_URL) { + if (!activated) { + // hook up to event bridge + tablet.webEventReceived.connect(onWebEventReceived); + print("after connect web event"); + MyAvatar.hmdLeanRecenterEnabled = false; + + } + activated = true; + } else { + if (activated) { + // disconnect from event bridge + tablet.webEventReceived.disconnect(onWebEventReceived); + documentLoaded = false; + } + activated = false; + } +} + +function getLog(x, y) { + return Math.log(y) / Math.log(x); +} + +function noConversion(num) { + return num; +} + +function convertLog(base, num, direction, shift) { + return direction * getLog(base, (num + 1.0)) + shift; +} + +function convertExponential(base, num, direction, shift) { + return Math.pow(base, (direction*num + shift)) - 1.0; +} + +function convertToCentimeters(num) { + return num * CENTIMETERSPERMETER; +} + +function convertToMeters(num) { + print("convert to meters " + num); + return num / CENTIMETERSPERMETER; +} + +function isInsideLine(a, b, c) { + return (((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0); +} + +function setAngularThreshold(num) { + headAngularVelocityProperty.value = num; + print("angular threshold " + headAngularVelocityProperty.get()); +} + +function setHeadRollThreshold(num) { + headRollProperty.value = num; + print("head roll threshold " + headRollProperty.get()); +} + +function setHeadPitchThreshold(num) { + headPitchProperty.value = num; + print("head pitch threshold " + headPitchProperty.get()); +} + +function setHeightThreshold(num) { + heightDifferenceProperty.value = num; + print("height threshold " + heightDifferenceProperty.get()); +} + +function setLateralDistance(num) { + lateralBaseProperty.value = num; + frontLeft.x = -lateralBaseProperty.get(); + frontRight.x = lateralBaseProperty.get(); + backLeft.x = -lateralBaseProperty.get(); + backRight.x = lateralBaseProperty.get(); + print("lateral distance " + lateralBaseProperty.get()); +} + +function setAnteriorDistance(num) { + frontBaseProperty.value = num; + frontLeft.z = -frontBaseProperty.get(); + frontRight.z = -frontBaseProperty.get(); + print("anterior distance " + frontBaseProperty.get()); +} + +function setPosteriorDistance(num) { + backBaseProperty.value = num; + backLeft.z = backBaseProperty.get(); + backRight.z = backBaseProperty.get(); + print("posterior distance " + backBaseProperty.get()); +} + +function setHandAngularVelocityThreshold(num) { + handsAngularVelocityProperty.value = num; + print("hand angular velocity threshold " + handsAngularVelocityProperty.get()); +} + +function setHandVelocityThreshold(num) { + handsVelocityProperty.value = num; + print("hand velocity threshold " + handsVelocityProperty.get()); +} + +function setHeadVelocityThreshold(num) { + headVelocityProperty.value = num; + print("headvelocity threshold " + headVelocityProperty.get()); +} + +function withinBaseOfSupport(pos) { + var userScale = 1.0; + frontBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontLeft), Vec3.multiply(userScale, frontRight), pos)); + backBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, backRight), Vec3.multiply(userScale, backLeft), pos)); + lateralBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontRight), Vec3.multiply(userScale, backRight), pos) + && isInsideLine(Vec3.multiply(userScale, backLeft), Vec3.multiply(userScale, frontLeft), pos)); + return (!frontBaseProperty.signalOn && !backBaseProperty.signalOn && !lateralBaseProperty.signalOn); +} + +function withinThresholdOfStandingHeightMode(heightDiff) { + if (usingModeHeight.data.value) { + heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); + return heightDifferenceProperty.signalOn; + } else { + return true; + } +} + +function headAngularVelocityBelowThreshold(headAngularVelocity) { + var angVel = Vec3.length({ x: headAngularVelocity.x, y: 0, z: headAngularVelocity.z }); + headAngularVelocityProperty.signalOn = angVel < headAngularVelocityProperty.get(); + return headAngularVelocityProperty.signalOn; +} + +function handDirectionMatchesHeadDirection(lhPose, rhPose) { + handsVelocityProperty.signalOn = ((handsVelocityProperty.get() < NO_SHARED_DIRECTION) || + ((!lhPose.valid || ((handDotHead[LEFT] > handsVelocityProperty.get()) && + (Vec3.length(lhPose.velocity) > VELOCITY_EPSILON))) && + (!rhPose.valid || ((handDotHead[RIGHT] > handsVelocityProperty.get()) && + (Vec3.length(rhPose.velocity) > VELOCITY_EPSILON))))); + return handsVelocityProperty.signalOn; +} + +function handAngularVelocityBelowThreshold(lhPose, rhPose) { + var xzRHandAngularVelocity = Vec3.length({ x: rhPose.angularVelocity.x, y: 0.0, z: rhPose.angularVelocity.z }); + var xzLHandAngularVelocity = Vec3.length({ x: lhPose.angularVelocity.x, y: 0.0, z: lhPose.angularVelocity.z }); + handsAngularVelocityProperty.signalOn = ((!rhPose.valid ||(xzRHandAngularVelocity < handsAngularVelocityProperty.get())) + && (!lhPose.valid || (xzLHandAngularVelocity < handsAngularVelocityProperty.get()))); + return handsAngularVelocityProperty.signalOn; +} + +function headVelocityGreaterThanThreshold(headVel) { + headVelocityProperty.signalOn = (headVel > headVelocityProperty.get()) || (headVelocityProperty.get() < VELOCITY_EPSILON); + return headVelocityProperty.signalOn; +} + +function headMovedAwayFromAveragePosition(headDelta) { + return !withinBaseOfSupport(headDelta) || !usingAverageHeadPosition.data.value; +} + +function headLowerThanHeightAverage(heightDiff) { + if (usingAverageHeight.data.value) { + print("head lower than height average"); + heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); + return heightDifferenceProperty.signalOn; + } else { + return true; + } +} + +function isHeadLevel(diffEulers) { + headRollProperty.signalOn = Math.abs(diffEulers.z) < headRollProperty.get(); + headPitchProperty.signalOn = Math.abs(diffEulers.x) < headPitchProperty.get(); + return (headRollProperty.signalOn && headPitchProperty.signalOn); +} + +function findAverage(arr) { + var sum = arr.reduce(function (acc, val) { + return acc + val; + },0); + return sum / arr.length; +} + +function addToModeArray(arr,num) { + for (var i = 0 ;i < (arr.length - 1); i++) { + arr[i] = arr[i+1]; + } + arr[arr.length - 1] = (Math.floor(num*CENTIMETERSPERMETER))/CENTIMETERSPERMETER; +} + +function findMode(ary, currentMode, backLength, defaultBack, currentHeight) { + var numMapping = {}; + var greatestFreq = 0; + var mode; + ary.forEach(function (number) { + numMapping[number] = (numMapping[number] || 0) + 1; + if ((greatestFreq < numMapping[number]) || ((numMapping[number] === MODE_SAMPLE_LENGTH) && (number > currentMode) )) { + greatestFreq = numMapping[number]; + mode = number; + } + }); + if (mode > currentMode) { + return Number(mode); + } else { + if (!RESET_MODE && HMD.active) { + print("resetting the mode............................................. "); + print("resetting the mode............................................. "); + RESET_MODE = true; + var correction = 0.02; + return currentHeight - correction; + } else { + return currentMode; + } + } +} + +function update(dt) { + if (debugDrawBase) { + drawBase(); + } + // Update current state information + currentStateReadings.headPose = Controller.getPoseValue(Controller.Standard.Head); + currentStateReadings.rhandPose = Controller.getPoseValue(Controller.Standard.RightHand); + currentStateReadings.lhandPose = Controller.getPoseValue(Controller.Standard.LeftHand); + + // back length + var headMinusHipLean = Vec3.subtract(currentStateReadings.headPose.translation, DEFAULT_HIPS_POSITION); + currentStateReadings.backLength = Vec3.length(headMinusHipLean); + // print("back length and default " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); + + // mode height + addToModeArray(modeArray, currentStateReadings.headPose.translation.y); + modeHeight = findMode(modeArray, modeHeight, currentStateReadings.backLength, DEFAULT_TORSO_LENGTH, + currentStateReadings.headPose.translation.y); + currentStateReadings.diffFromMode = modeHeight - currentStateReadings.headPose.translation.y; + + // hand direction + var leftHandLateralPoseVelocity = currentStateReadings.lhandPose.velocity; + leftHandLateralPoseVelocity.y = 0.0; + var rightHandLateralPoseVelocity = currentStateReadings.rhandPose.velocity; + rightHandLateralPoseVelocity.y = 0.0; + var headLateralPoseVelocity = currentStateReadings.headPose.velocity; + headLateralPoseVelocity.y = 0.0; + handDotHead[LEFT] = Vec3.dot(Vec3.normalize(leftHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); + handDotHead[RIGHT] = Vec3.dot(Vec3.normalize(rightHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); + + // average head position + headAveragePosition = Vec3.mix(headAveragePosition, currentStateReadings.headPose.translation, AVERAGING_RATE); + currentStateReadings.diffFromAveragePosition = Vec3.subtract(currentStateReadings.headPose.translation, + headAveragePosition); + + // average height + averageHeight = currentStateReadings.headPose.translation.y * HEIGHT_AVERAGING_RATE + + averageHeight * (1.0 - HEIGHT_AVERAGING_RATE); + currentStateReadings.diffFromAverageHeight = Math.abs(currentStateReadings.headPose.translation.y - averageHeight); + + // eulers diff + headEulers = Quat.safeEulerAngles(currentStateReadings.headPose.rotation); + headAverageOrientation = Quat.slerp(headAverageOrientation, currentStateReadings.headPose.rotation, AVERAGING_RATE); + headAverageEulers = Quat.safeEulerAngles(headAverageOrientation); + currentStateReadings.diffFromAverageEulers = Vec3.subtract(headAverageEulers, headEulers); + + // headpose rig space is for determining when to recenter rotation. + var headPoseRigSpace = Quat.multiply(CHANGE_OF_BASIS_ROTATION, currentStateReadings.headPose.rotation); + headPoseAverageOrientation = Quat.slerp(headPoseAverageOrientation, headPoseRigSpace, AVERAGING_RATE); + var headPoseAverageEulers = Quat.safeEulerAngles(headPoseAverageOrientation); + + // make the signal colors reflect the current thresholds that have been crossed + updateSignalColors(); + + SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; + + //print("the spine stretch limit is " + SPINE_STRETCH_LIMIT + " head avatar space is " + currentStateReadings.headPose.translation.y); + //print("the current back length is " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); + // Conditions for taking a step. + // 1. off the base of support. front, lateral, back edges. + // 2. head is not lower than the height mode value by more than the maxHeightChange tolerance + // 3. the angular velocity of the head is not greater than the threshold value + // ie this reflects the speed the head is rotating away from having up = (0,1,0) in Avatar frame.. + // 4. the hands velocity vector has the same direction as the head, within the given tolerance + // the tolerance is an acos value, -1 means the hands going in any direction will not block translating + // up to 1 where the hands velocity direction must exactly match that of the head. -1 threshold disables this condition. + // 5. the angular velocity xz magnitude for each hand is below the threshold value + // ie here this reflects the speed that each hand is rotating away from having up = (0,1,0) in Avatar frame. + // 6. head velocity is below step threshold + // 7. head has moved further than the threshold from the running average position of the head. + // 8. head height is not lower than the running average head height with a difference of maxHeightChange. + // 9. head's rotation in avatar space is not pitching or rolling greater than the pitch or roll thresholds + if (!withinBaseOfSupport(currentStateReadings.headPose.translation) && + withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode) && + headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity) && + handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && + handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && + headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)) && + headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition) && + headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight) && + isHeadLevel(currentStateReadings.diffFromAverageEulers)) { + + if (stepTimer < 0.0) { //!MyAvatar.isRecenteringHorizontally() + print("trigger recenter========================================================"); + MyAvatar.triggerHorizontalRecenter(); + stepTimer = STEP_TIME_SECS; + } + } else if ((currentStateReadings.backLength > (DEFAULT_TORSO_LENGTH + SPINE_STRETCH_LIMIT)) && + (failsafeSignalTimer < 0.0) && HMD.active) { + // do the failsafe recenter. + // failsafeFlag stops repeated setting of failsafe button color. + // RESET_MODE false forces a reset of the height + RESET_MODE = false; + failsafeFlag = true; + failsafeSignalTimer = FAILSAFE_TIMEOUT; + MyAvatar.triggerHorizontalRecenter(); + tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "green" } })); + // in fail safe we debug print the values that were blocking us. + print("failsafe debug---------------------------------------------------------------"); + propArray.forEach(function (prop) { + print(prop.name); + if (!prop.signalOn) { + print(prop.signalType + " contributed to failsafe call"); + } + }); + print("end failsafe debug---------------------------------------------------------------"); + + } + + if ((failsafeSignalTimer < 0.0) && failsafeFlag) { + failsafeFlag = false; + tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "orange" } })); + } + + stepTimer -= dt; + failsafeSignalTimer -= dt; + + if (!HMD.active) { + RESET_MODE = false; + } + + if (Math.abs(headPoseAverageEulers.y) > HEAD_TURN_THRESHOLD) { + // Turn feet + // MyAvatar.triggerRotationRecenter(); + // headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; + } +} + +function shutdownTabletApp() { + // GlobalDebugger.stop(); + tablet.removeButton(tabletButton); + if (activated) { + tablet.webEventReceived.disconnect(onWebEventReceived); + tablet.gotoHomeScreen(); + } + tablet.screenChanged.disconnect(onScreenChanged); +} + +tabletButton.clicked.connect(manageClick); +tablet.screenChanged.connect(onScreenChanged); + +Script.setTimeout(function() { + DEFAULT_HIPS_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); + DEFAULT_HEAD_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); + DEFAULT_TORSO_LENGTH = Vec3.length(Vec3.subtract(DEFAULT_HEAD_POSITION, DEFAULT_HIPS_POSITION)); + SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; +},(4*LOADING_DELAY)); + +Script.update.connect(update); +Controller.keyPressEvent.connect(onKeyPress); +Script.scriptEnding.connect(function () { + MyAvatar.hmdLeanRecenterEnabled = true; + Script.update.disconnect(update); + shutdownTabletApp(); +}); diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 10ccb66d96..ee4c6736a2 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -63,7 +63,8 @@ function getMyAvatar() { function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), - collisionsEnabled : MyAvatar.getCollisionsEnabled(), + collisionsEnabled: MyAvatar.getCollisionsEnabled(), + sittingEnabled: MyAvatar.isInSittingState, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -136,6 +137,13 @@ function onCollisionsEnabledChanged(enabled) { } } +function onSittingEnabledChanged(isSitting) { + if (currentAvatarSettings.sittingEnabled !== isSitting) { + currentAvatarSettings.sittingEnabled = isSitting; + sendToQml({ 'method': 'settingChanged', 'name': 'sittingEnabled', 'value': isSitting }) + } +} + function onNewCollisionSoundUrl(url) { if(currentAvatarSettings.collisionSoundUrl !== url) { currentAvatarSettings.collisionSoundUrl = url; @@ -314,9 +322,10 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); + MyAvatar.isInSittingState = message.settings.sittingEnabled; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); - + print("save settings"); settings = getMyAvatarSettings(); break; default: @@ -507,6 +516,7 @@ function off() { MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); + MyAvatar.sittingEnabledChanged.disconnect(onSittingEnabledChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -521,6 +531,7 @@ function on() { MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); + MyAvatar.sittingEnabledChanged.connect(onSittingEnabledChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 42cb8a7ef0159f130c65d6a424bf8b54ae14323e Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 27 Sep 2018 16:59:54 -0700 Subject: [PATCH 016/114] avatar app changes --- interface/src/avatar/MyAvatar.cpp | 2 +- scripts/system/avatarapp.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 631a4b0670..d54616f245 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -477,7 +477,7 @@ void MyAvatar::update(float deltaTime) { auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); - // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; + // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { //qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; } diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index ee4c6736a2..16761f29a6 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -140,6 +140,7 @@ function onCollisionsEnabledChanged(enabled) { function onSittingEnabledChanged(isSitting) { if (currentAvatarSettings.sittingEnabled !== isSitting) { currentAvatarSettings.sittingEnabled = isSitting; + print("emit sitting changed"); sendToQml({ 'method': 'settingChanged', 'name': 'sittingEnabled', 'value': isSitting }) } } From 884ad66a146541fba08975af43e8cbfe1e46cd16 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 28 Sep 2018 17:18:24 -0700 Subject: [PATCH 017/114] added sensor space detection of height of the user in MyAvatar.cpp 1.2 * average sensor space height changes to standing. .833 sensorspace height changes to sitting. there is also a manual override in the avatar app settings now --- interface/src/avatar/MyAvatar.cpp | 38 +++++++++++++++++++++++++------ interface/src/avatar/MyAvatar.h | 4 +++- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d54616f245..819778b1e7 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -475,6 +475,12 @@ void MyAvatar::update(float deltaTime) { // if the head is close to the floor in sensor space // and the up of the head is close to sensor up then try switching us to sitting state. auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (sensorHeadPoseDebug.isValid()) { + _sumUserHeightSensorSpace += sensorHeadPoseDebug.getTranslation().y; + _averageUserHeightCount++; + } + qCDebug(interfaceapp) << sensorHeadPoseDebug.isValid() << " valid. sensor space average " << (_sumUserHeightSensorSpace / _averageUserHeightCount) << " head position sensor y value " << sensorHeadPoseDebug.getTranslation().y; + glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; @@ -3854,6 +3860,9 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { void MyAvatar::setIsInSittingState(bool isSitting) { _isInSittingState = isSitting; + controller::Pose sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); + _sumUserHeightSensorSpace = sensorHeadPoseDebug.getTranslation().y; + _averageUserHeightCount = 1; emit sittingEnabledChanged(isSitting); } @@ -4093,21 +4102,36 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 headWorldSpace = myAvatar.getHead()->getPosition(); glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar.getSensorToWorldMatrix()); glm::vec3 headSensorSpace = transformVectorFast(myAvatar.getSensorToWorldMatrix(), headWorldSpace); - //qCDebug(interfaceapp) << "sensor space position " << extractTranslation(currentBodyMatrix) << " head position sensor " << sensorHeadPose.getTranslation(); + //get the mode. + //put it in sensor space. + // if we are 20% higher switch to standing. + // 16.6% lower then switch to sitting. + // add this !!!! And the head is upright. + float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (offset.y > 2.0*CYLINDER_TOP) { + } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); + //myAvatar._sumUserHeightSensorSpace = 1.2f * averageSensorSpaceHeight; + // myAvatar._averageUserHeightCount = 1; return true; } else { return false; } } else { - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // in the standing state + if (sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) { + myAvatar.setIsInSittingState(true); + // myAvatar._sumUserHeightSensorSpace = 0.83f * averageSensorSpaceHeight; + // myAvatar._averageUserHeightCount = 1; + return true; + } else { + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + } } } @@ -4124,14 +4148,14 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if ((_squatCount > 600) && !isActive(Vertical) && !isActive(Horizontal)) { if (myAvatar.getIsInSittingState()) { // activate(Horizontal); - activate(Vertical); + //activate(Vertical); _squatCount = 0; } else { if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.20f)) { - myAvatar.setIsInSittingState(true); - activate(Vertical); + //myAvatar.setIsInSittingState(true); + //activate(Vertical); } else { - activate(Horizontal); + //activate(Horizontal); } _squatCount = 0; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d9744e93fe..628c358202 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1805,6 +1805,8 @@ private: // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; + float _sumUserHeightSensorSpace { DEFAULT_AVATAR_HEIGHT }; + int _averageUserHeightCount { 1 }; void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); @@ -1814,7 +1816,7 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; - bool _isInSittingState { true }; + bool _isInSittingState { false }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From 3a2a8fe4f8d4dfa7eb965fa4dff59d2914b207d3 Mon Sep 17 00:00:00 2001 From: amantley Date: Sat, 29 Sep 2018 15:49:11 -0700 Subject: [PATCH 018/114] adjusted openvr to use 0.0 for the floor instead of -1.6 --- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index fae2144caf..1638a17631 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -463,7 +463,7 @@ bool OpenVrDisplayPlugin::internalActivate() { auto chaperone = vr::VRChaperone(); if (chaperone) { float const UI_RADIUS = 1.0f; - float const UI_HEIGHT = 1.6f; + float const UI_HEIGHT = 0.0f; float const UI_Z_OFFSET = 0.5; float xSize, zSize; From 9e400459270ad90fd896d75025ca7cf5c60a109d Mon Sep 17 00:00:00 2001 From: amantley Date: Sun, 30 Sep 2018 17:13:34 -0700 Subject: [PATCH 019/114] added criteria to stop false positive for sit down --- interface/src/avatar/MyAvatar.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 02ea49cda0..f281d8c87d 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4079,13 +4079,21 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl // if we are 20% higher switch to standing. // 16.6% lower then switch to sitting. // add this !!!! And the head is upright. + glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); + float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); + glm::vec3 worldHips = transformVectorFast(myAvatar.getTransform().getMatrix(),avatarHips); + glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; + // we could add a counting here to make sure that a lean forward doesn't accidentally put you in sitting mode. + // but maybe so what. + // the real test is... can I pick something up in standing mode? if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { + } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); //myAvatar._sumUserHeightSensorSpace = 1.2f * averageSensorSpaceHeight; @@ -4096,7 +4104,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } } else { // in the standing state - if (sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) { + if ((sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) && (acosHead > 0.98f) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight)) { myAvatar.setIsInSittingState(true); // myAvatar._sumUserHeightSensorSpace = 0.83f * averageSensorSpaceHeight; // myAvatar._averageUserHeightCount = 1; From fe7c14e5cf3523beb1be9cb1d5b0feb23188deb5 Mon Sep 17 00:00:00 2001 From: amantley Date: Sun, 30 Sep 2018 17:15:07 -0700 Subject: [PATCH 020/114] removed extraneous script --- scripts/developer/objectOrientedStep.js | 688 ------------------------ 1 file changed, 688 deletions(-) delete mode 100644 scripts/developer/objectOrientedStep.js diff --git a/scripts/developer/objectOrientedStep.js b/scripts/developer/objectOrientedStep.js deleted file mode 100644 index a5c27e36b9..0000000000 --- a/scripts/developer/objectOrientedStep.js +++ /dev/null @@ -1,688 +0,0 @@ -/* jslint bitwise: true */ - -/* global Script, Vec3, MyAvatar, Tablet, Messages, Quat, -DebugDraw, Mat4, Entities, Xform, Controller, Camera, console, document*/ - -Script.registerValue("STEPAPP", true); -var CENTIMETERSPERMETER = 100.0; -var LEFT = 0; -var RIGHT = 1; -var INCREASING = 1.0; -var DECREASING = -1.0; -var DEFAULT_AVATAR_HEIGHT = 1.64; -var TABLET_BUTTON_NAME = "STEP"; -var CHANGE_OF_BASIS_ROTATION = { x: 0, y: 1, z: 0, w: 0 }; -// in meters (mostly) -var DEFAULT_ANTERIOR = 0.04; -var DEFAULT_POSTERIOR = 0.06; -var DEFAULT_LATERAL = 0.10; -var DEFAULT_HEIGHT_DIFFERENCE = 0.02; -var DEFAULT_ANGULAR_VELOCITY = 0.3; -var DEFAULT_HAND_VELOCITY = 0.4; -var DEFAULT_ANGULAR_HAND_VELOCITY = 3.3; -var DEFAULT_HEAD_VELOCITY = 0.14; -var DEFAULT_LEVEL_PITCH = 7; -var DEFAULT_LEVEL_ROLL = 7; -var DEFAULT_DIFF = 0.0; -var DEFAULT_DIFF_EULERS = { x: 0.0, y: 0.0, z: 0.0 }; -var DEFAULT_HIPS_POSITION; -var DEFAULT_HEAD_POSITION; -var DEFAULT_TORSO_LENGTH; -var SPINE_STRETCH_LIMIT = 0.02; - -var VELOCITY_EPSILON = 0.02; -var AVERAGING_RATE = 0.03; -var HEIGHT_AVERAGING_RATE = 0.01; -var STEP_TIME_SECS = 0.2; -var MODE_SAMPLE_LENGTH = 100; -var RESET_MODE = false; -var HEAD_TURN_THRESHOLD = 25.0; -var NO_SHARED_DIRECTION = -0.98; -var LOADING_DELAY = 500; -var FAILSAFE_TIMEOUT = 2.5; - -var debugDrawBase = true; -var activated = false; -var documentLoaded = false; -var failsafeFlag = false; -var failsafeSignalTimer = -1.0; -var stepTimer = -1.0; - - -var modeArray = new Array(MODE_SAMPLE_LENGTH); -var modeHeight = -10.0; - -var handPosition; -var handOrientation; -var hands = []; -var hipToHandAverage = []; -var handDotHead = []; -var headAverageOrientation = MyAvatar.orientation; -var headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; -var averageHeight = 1.0; -var headEulers = { x: 0.0, y: 0.0, z: 0.0 }; -var headAverageEulers = { x: 0.0, y: 0.0, z: 0.0 }; -var headAveragePosition = { x: 0, y: 0.4, z: 0 }; -var frontLeft = { x: -DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; -var frontRight = { x: DEFAULT_LATERAL, y: 0, z: -DEFAULT_ANTERIOR }; -var backLeft = { x: -DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; -var backRight = { x: DEFAULT_LATERAL, y: 0, z: DEFAULT_POSTERIOR }; - - -// define state readings constructor -function StateReading(headPose, rhandPose, lhandPose, backLength, diffFromMode, diffFromAverageHeight, diffFromAveragePosition, - diffFromAverageEulers) { - this.headPose = headPose; - this.rhandPose = rhandPose; - this.lhandPose = lhandPose; - this.backLength = backLength; - this.diffFromMode = diffFromMode; - this.diffFromAverageHeight = diffFromAverageHeight; - this.diffFromAveragePosition = diffFromAveragePosition; - this.diffFromAverageEulers = diffFromAverageEulers; -} - -// define current state readings object for holding tracker readings and current differences from averages -var currentStateReadings = new StateReading(Controller.getPoseValue(Controller.Standard.Head), - Controller.getPoseValue(Controller.Standard.RightHand), Controller.getPoseValue(Controller.Standard.LeftHand), - DEFAULT_TORSO_LENGTH, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF, DEFAULT_DIFF_EULERS); - -// declare the checkbox constructor -function AppCheckbox(type,id,eventType,isChecked) { - this.type = type; - this.id = id; - this.eventType = eventType; - this.data = {value: isChecked}; -} - -// define the checkboxes in the html file -var usingAverageHeight = new AppCheckbox("checkboxtick", "runningAverageHeightCheck", "onRunningAverageHeightCheckBox", - false); -var usingModeHeight = new AppCheckbox("checkboxtick","modeCheck","onModeCheckBox",true); -var usingBaseOfSupport = new AppCheckbox("checkboxtick","baseOfSupportCheck","onBaseOfSupportCheckBox",true); -var usingAverageHeadPosition = new AppCheckbox("checkboxtick", "headAveragePositionCheck", "onHeadAveragePositionCheckBox", - false); - -var checkBoxArray = new Array(usingAverageHeight,usingModeHeight,usingBaseOfSupport,usingAverageHeadPosition); - -// declare the html slider constructor -function AppProperty(name, type, eventType, signalType, setFunction, initValue, convertToThreshold, convertToSlider, signalOn) { - this.name = name; - this.type = type; - this.eventType = eventType; - this.signalType = signalType; - this.setValue = setFunction; - this.value = initValue; - this.get = function () { - return this.value; - }; - this.convertToThreshold = convertToThreshold; - this.convertToSlider = convertToSlider; - this.signalOn = signalOn; -} - -// define the sliders -var frontBaseProperty = new AppProperty("#anteriorBase-slider", "slider", "onAnteriorBaseSlider", "frontSignal", - setAnteriorDistance, DEFAULT_ANTERIOR, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - },true); -var backBaseProperty = new AppProperty("#posteriorBase-slider", "slider", "onPosteriorBaseSlider", "backSignal", - setPosteriorDistance, DEFAULT_POSTERIOR, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - }, true); -var lateralBaseProperty = new AppProperty("#lateralBase-slider", "slider", "onLateralBaseSlider", "lateralSignal", - setLateralDistance, DEFAULT_LATERAL, function (num) { - return convertToMeters(num); - }, function (num) { - return convertToCentimeters(num); - }, true); -var headAngularVelocityProperty = new AppProperty("#angularVelocityHead-slider", "slider", "onAngularVelocitySlider", - "angularHeadSignal", setAngularThreshold, DEFAULT_ANGULAR_VELOCITY, function (num) { - var base = 4; - var shift = 2; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 4; - var shift = 2; - return convertLog(base, num, DECREASING, shift); - }, true); -var heightDifferenceProperty = new AppProperty("#heightDifference-slider", "slider", "onHeightDifferenceSlider", "heightSignal", - setHeightThreshold, DEFAULT_HEIGHT_DIFFERENCE, function (num) { - return convertToMeters(-num); - }, function (num) { - return convertToCentimeters(-num); - }, true); -var handsVelocityProperty = new AppProperty("#handsVelocity-slider", "slider", "onHandsVelocitySlider", "handVelocitySignal", - setHandVelocityThreshold, DEFAULT_HAND_VELOCITY, function (num) { - return num; - }, function (num) { - return num; - }, true); -var handsAngularVelocityProperty = new AppProperty("#handsAngularVelocity-slider", "slider", "onHandsAngularVelocitySlider", - "handAngularSignal", setHandAngularVelocityThreshold, DEFAULT_ANGULAR_HAND_VELOCITY, function (num) { - var base = 7; - var shift = 2; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 7; - var shift = 2; - return convertLog(base, num, DECREASING, shift); - }, true); -var headVelocityProperty = new AppProperty("#headVelocity-slider", "slider", "onHeadVelocitySlider", "headVelocitySignal", - setHeadVelocityThreshold, DEFAULT_HEAD_VELOCITY, function (num) { - var base = 2; - var shift = 0; - return convertExponential(base, num, INCREASING, shift); - }, function (num) { - var base = 2; - var shift = 0; - return convertLog(base, num, INCREASING, shift); - }, true); -var headPitchProperty = new AppProperty("#headPitch-slider", "slider", "onHeadPitchSlider", "headPitchSignal", - setHeadPitchThreshold, DEFAULT_LEVEL_PITCH, function (num) { - var base = 2.5; - var shift = 5; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 2.5; - var shift = 5; - return convertLog(base, num, DECREASING, shift); - }, true); -var headRollProperty = new AppProperty("#headRoll-slider", "slider", "onHeadRollSlider", "headRollSignal", setHeadRollThreshold, - DEFAULT_LEVEL_ROLL, function (num) { - var base = 2.5; - var shift = 5; - return convertExponential(base, num, DECREASING, shift); - }, function (num) { - var base = 2.5; - var shift = 5; - return convertLog(base, num, DECREASING, shift); - }, true); - -var propArray = new Array(frontBaseProperty, backBaseProperty, lateralBaseProperty, headAngularVelocityProperty, - heightDifferenceProperty, handsVelocityProperty, handsAngularVelocityProperty, headVelocityProperty, headPitchProperty, - headRollProperty); - -// var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepApp.html"); -var HTML_URL = Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/stepAppExtra.html"); -var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); - -function manageClick() { - if (activated) { - tablet.gotoHomeScreen(); - } else { - tablet.gotoWebScreen(HTML_URL); - } -} - -var tabletButton = tablet.addButton({ - text: TABLET_BUTTON_NAME, - icon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg"), - activeIcon: Script.resolvePath("http://hifi-content.s3.amazonaws.com/angus/stepApp/foot.svg") -}); - -function drawBase() { - // transform corners into world space, for rendering. - var worldPointLf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontLeft)); - var worldPointRf = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, frontRight)); - var worldPointLb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backLeft)); - var worldPointRb = Vec3.sum(MyAvatar.position,Vec3.multiplyQbyV(MyAvatar.orientation, backRight)); - - var GREEN = { r: 0, g: 1, b: 0, a: 1 }; - // draw border - DebugDraw.drawRay(worldPointLf, worldPointRf, GREEN); - DebugDraw.drawRay(worldPointRf, worldPointRb, GREEN); - DebugDraw.drawRay(worldPointRb, worldPointLb, GREEN); - DebugDraw.drawRay(worldPointLb, worldPointLf, GREEN); -} - -function onKeyPress(event) { - if (event.text === "'") { - // when the sensors are reset, then reset the mode. - RESET_MODE = false; - } -} - -function onWebEventReceived(msg) { - var message = JSON.parse(msg); - print(" we have a message from html dialog " + message.type); - propArray.forEach(function (prop) { - if (prop.eventType === message.type) { - prop.setValue(prop.convertToThreshold(message.data.value)); - print("message from " + prop.name); - // break; - } - }); - checkBoxArray.forEach(function(cbox) { - if (cbox.eventType === message.type) { - cbox.data.value = message.data.value; - // break; - } - }); - if (message.type === "onCreateStepApp") { - print("document loaded"); - documentLoaded = true; - Script.setTimeout(initAppForm, LOADING_DELAY); - } -} - -function initAppForm() { - print("step app is loaded: " + documentLoaded); - if (documentLoaded === true) { - propArray.forEach(function (prop) { - tablet.emitScriptEvent(JSON.stringify({ - "type": "trigger", - "id": prop.signalType, - "data": { "value": "green" } - })); - tablet.emitScriptEvent(JSON.stringify({ - "type": "slider", - "id": prop.name, - "data": { "value": prop.convertToSlider(prop.value) } - })); - }); - checkBoxArray.forEach(function (cbox) { - tablet.emitScriptEvent(JSON.stringify({ - "type": "checkboxtick", - "id": cbox.id, - "data": { "value": cbox.data.value } - })); - }); - } -} - -function updateSignalColors() { - - // force the updates by running the threshold comparisons - withinBaseOfSupport(currentStateReadings.headPose.translation); - withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode); - headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity); - handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose); - handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose); - headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)); - headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition); - headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight); - isHeadLevel(currentStateReadings.diffFromAverageEulers); - - propArray.forEach(function (prop) { - if (prop.signalOn) { - tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "green" } })); - } else { - tablet.emitScriptEvent(JSON.stringify({ "type": "trigger", "id": prop.signalType, "data": { "value": "red" } })); - } - }); -} - -function onScreenChanged(type, url) { - print("Screen changed"); - if (type === "Web" && url === HTML_URL) { - if (!activated) { - // hook up to event bridge - tablet.webEventReceived.connect(onWebEventReceived); - print("after connect web event"); - MyAvatar.hmdLeanRecenterEnabled = false; - - } - activated = true; - } else { - if (activated) { - // disconnect from event bridge - tablet.webEventReceived.disconnect(onWebEventReceived); - documentLoaded = false; - } - activated = false; - } -} - -function getLog(x, y) { - return Math.log(y) / Math.log(x); -} - -function noConversion(num) { - return num; -} - -function convertLog(base, num, direction, shift) { - return direction * getLog(base, (num + 1.0)) + shift; -} - -function convertExponential(base, num, direction, shift) { - return Math.pow(base, (direction*num + shift)) - 1.0; -} - -function convertToCentimeters(num) { - return num * CENTIMETERSPERMETER; -} - -function convertToMeters(num) { - print("convert to meters " + num); - return num / CENTIMETERSPERMETER; -} - -function isInsideLine(a, b, c) { - return (((b.x - a.x)*(c.z - a.z) - (b.z - a.z)*(c.x - a.x)) > 0); -} - -function setAngularThreshold(num) { - headAngularVelocityProperty.value = num; - print("angular threshold " + headAngularVelocityProperty.get()); -} - -function setHeadRollThreshold(num) { - headRollProperty.value = num; - print("head roll threshold " + headRollProperty.get()); -} - -function setHeadPitchThreshold(num) { - headPitchProperty.value = num; - print("head pitch threshold " + headPitchProperty.get()); -} - -function setHeightThreshold(num) { - heightDifferenceProperty.value = num; - print("height threshold " + heightDifferenceProperty.get()); -} - -function setLateralDistance(num) { - lateralBaseProperty.value = num; - frontLeft.x = -lateralBaseProperty.get(); - frontRight.x = lateralBaseProperty.get(); - backLeft.x = -lateralBaseProperty.get(); - backRight.x = lateralBaseProperty.get(); - print("lateral distance " + lateralBaseProperty.get()); -} - -function setAnteriorDistance(num) { - frontBaseProperty.value = num; - frontLeft.z = -frontBaseProperty.get(); - frontRight.z = -frontBaseProperty.get(); - print("anterior distance " + frontBaseProperty.get()); -} - -function setPosteriorDistance(num) { - backBaseProperty.value = num; - backLeft.z = backBaseProperty.get(); - backRight.z = backBaseProperty.get(); - print("posterior distance " + backBaseProperty.get()); -} - -function setHandAngularVelocityThreshold(num) { - handsAngularVelocityProperty.value = num; - print("hand angular velocity threshold " + handsAngularVelocityProperty.get()); -} - -function setHandVelocityThreshold(num) { - handsVelocityProperty.value = num; - print("hand velocity threshold " + handsVelocityProperty.get()); -} - -function setHeadVelocityThreshold(num) { - headVelocityProperty.value = num; - print("headvelocity threshold " + headVelocityProperty.get()); -} - -function withinBaseOfSupport(pos) { - var userScale = 1.0; - frontBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontLeft), Vec3.multiply(userScale, frontRight), pos)); - backBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, backRight), Vec3.multiply(userScale, backLeft), pos)); - lateralBaseProperty.signalOn = !(isInsideLine(Vec3.multiply(userScale, frontRight), Vec3.multiply(userScale, backRight), pos) - && isInsideLine(Vec3.multiply(userScale, backLeft), Vec3.multiply(userScale, frontLeft), pos)); - return (!frontBaseProperty.signalOn && !backBaseProperty.signalOn && !lateralBaseProperty.signalOn); -} - -function withinThresholdOfStandingHeightMode(heightDiff) { - if (usingModeHeight.data.value) { - heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); - return heightDifferenceProperty.signalOn; - } else { - return true; - } -} - -function headAngularVelocityBelowThreshold(headAngularVelocity) { - var angVel = Vec3.length({ x: headAngularVelocity.x, y: 0, z: headAngularVelocity.z }); - headAngularVelocityProperty.signalOn = angVel < headAngularVelocityProperty.get(); - return headAngularVelocityProperty.signalOn; -} - -function handDirectionMatchesHeadDirection(lhPose, rhPose) { - handsVelocityProperty.signalOn = ((handsVelocityProperty.get() < NO_SHARED_DIRECTION) || - ((!lhPose.valid || ((handDotHead[LEFT] > handsVelocityProperty.get()) && - (Vec3.length(lhPose.velocity) > VELOCITY_EPSILON))) && - (!rhPose.valid || ((handDotHead[RIGHT] > handsVelocityProperty.get()) && - (Vec3.length(rhPose.velocity) > VELOCITY_EPSILON))))); - return handsVelocityProperty.signalOn; -} - -function handAngularVelocityBelowThreshold(lhPose, rhPose) { - var xzRHandAngularVelocity = Vec3.length({ x: rhPose.angularVelocity.x, y: 0.0, z: rhPose.angularVelocity.z }); - var xzLHandAngularVelocity = Vec3.length({ x: lhPose.angularVelocity.x, y: 0.0, z: lhPose.angularVelocity.z }); - handsAngularVelocityProperty.signalOn = ((!rhPose.valid ||(xzRHandAngularVelocity < handsAngularVelocityProperty.get())) - && (!lhPose.valid || (xzLHandAngularVelocity < handsAngularVelocityProperty.get()))); - return handsAngularVelocityProperty.signalOn; -} - -function headVelocityGreaterThanThreshold(headVel) { - headVelocityProperty.signalOn = (headVel > headVelocityProperty.get()) || (headVelocityProperty.get() < VELOCITY_EPSILON); - return headVelocityProperty.signalOn; -} - -function headMovedAwayFromAveragePosition(headDelta) { - return !withinBaseOfSupport(headDelta) || !usingAverageHeadPosition.data.value; -} - -function headLowerThanHeightAverage(heightDiff) { - if (usingAverageHeight.data.value) { - print("head lower than height average"); - heightDifferenceProperty.signalOn = heightDiff < heightDifferenceProperty.get(); - return heightDifferenceProperty.signalOn; - } else { - return true; - } -} - -function isHeadLevel(diffEulers) { - headRollProperty.signalOn = Math.abs(diffEulers.z) < headRollProperty.get(); - headPitchProperty.signalOn = Math.abs(diffEulers.x) < headPitchProperty.get(); - return (headRollProperty.signalOn && headPitchProperty.signalOn); -} - -function findAverage(arr) { - var sum = arr.reduce(function (acc, val) { - return acc + val; - },0); - return sum / arr.length; -} - -function addToModeArray(arr,num) { - for (var i = 0 ;i < (arr.length - 1); i++) { - arr[i] = arr[i+1]; - } - arr[arr.length - 1] = (Math.floor(num*CENTIMETERSPERMETER))/CENTIMETERSPERMETER; -} - -function findMode(ary, currentMode, backLength, defaultBack, currentHeight) { - var numMapping = {}; - var greatestFreq = 0; - var mode; - ary.forEach(function (number) { - numMapping[number] = (numMapping[number] || 0) + 1; - if ((greatestFreq < numMapping[number]) || ((numMapping[number] === MODE_SAMPLE_LENGTH) && (number > currentMode) )) { - greatestFreq = numMapping[number]; - mode = number; - } - }); - if (mode > currentMode) { - return Number(mode); - } else { - if (!RESET_MODE && HMD.active) { - print("resetting the mode............................................. "); - print("resetting the mode............................................. "); - RESET_MODE = true; - var correction = 0.02; - return currentHeight - correction; - } else { - return currentMode; - } - } -} - -function update(dt) { - if (debugDrawBase) { - drawBase(); - } - // Update current state information - currentStateReadings.headPose = Controller.getPoseValue(Controller.Standard.Head); - currentStateReadings.rhandPose = Controller.getPoseValue(Controller.Standard.RightHand); - currentStateReadings.lhandPose = Controller.getPoseValue(Controller.Standard.LeftHand); - - // back length - var headMinusHipLean = Vec3.subtract(currentStateReadings.headPose.translation, DEFAULT_HIPS_POSITION); - currentStateReadings.backLength = Vec3.length(headMinusHipLean); - // print("back length and default " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); - - // mode height - addToModeArray(modeArray, currentStateReadings.headPose.translation.y); - modeHeight = findMode(modeArray, modeHeight, currentStateReadings.backLength, DEFAULT_TORSO_LENGTH, - currentStateReadings.headPose.translation.y); - currentStateReadings.diffFromMode = modeHeight - currentStateReadings.headPose.translation.y; - - // hand direction - var leftHandLateralPoseVelocity = currentStateReadings.lhandPose.velocity; - leftHandLateralPoseVelocity.y = 0.0; - var rightHandLateralPoseVelocity = currentStateReadings.rhandPose.velocity; - rightHandLateralPoseVelocity.y = 0.0; - var headLateralPoseVelocity = currentStateReadings.headPose.velocity; - headLateralPoseVelocity.y = 0.0; - handDotHead[LEFT] = Vec3.dot(Vec3.normalize(leftHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); - handDotHead[RIGHT] = Vec3.dot(Vec3.normalize(rightHandLateralPoseVelocity), Vec3.normalize(headLateralPoseVelocity)); - - // average head position - headAveragePosition = Vec3.mix(headAveragePosition, currentStateReadings.headPose.translation, AVERAGING_RATE); - currentStateReadings.diffFromAveragePosition = Vec3.subtract(currentStateReadings.headPose.translation, - headAveragePosition); - - // average height - averageHeight = currentStateReadings.headPose.translation.y * HEIGHT_AVERAGING_RATE + - averageHeight * (1.0 - HEIGHT_AVERAGING_RATE); - currentStateReadings.diffFromAverageHeight = Math.abs(currentStateReadings.headPose.translation.y - averageHeight); - - // eulers diff - headEulers = Quat.safeEulerAngles(currentStateReadings.headPose.rotation); - headAverageOrientation = Quat.slerp(headAverageOrientation, currentStateReadings.headPose.rotation, AVERAGING_RATE); - headAverageEulers = Quat.safeEulerAngles(headAverageOrientation); - currentStateReadings.diffFromAverageEulers = Vec3.subtract(headAverageEulers, headEulers); - - // headpose rig space is for determining when to recenter rotation. - var headPoseRigSpace = Quat.multiply(CHANGE_OF_BASIS_ROTATION, currentStateReadings.headPose.rotation); - headPoseAverageOrientation = Quat.slerp(headPoseAverageOrientation, headPoseRigSpace, AVERAGING_RATE); - var headPoseAverageEulers = Quat.safeEulerAngles(headPoseAverageOrientation); - - // make the signal colors reflect the current thresholds that have been crossed - updateSignalColors(); - - SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; - - //print("the spine stretch limit is " + SPINE_STRETCH_LIMIT + " head avatar space is " + currentStateReadings.headPose.translation.y); - //print("the current back length is " + currentStateReadings.backLength + " " + DEFAULT_TORSO_LENGTH); - // Conditions for taking a step. - // 1. off the base of support. front, lateral, back edges. - // 2. head is not lower than the height mode value by more than the maxHeightChange tolerance - // 3. the angular velocity of the head is not greater than the threshold value - // ie this reflects the speed the head is rotating away from having up = (0,1,0) in Avatar frame.. - // 4. the hands velocity vector has the same direction as the head, within the given tolerance - // the tolerance is an acos value, -1 means the hands going in any direction will not block translating - // up to 1 where the hands velocity direction must exactly match that of the head. -1 threshold disables this condition. - // 5. the angular velocity xz magnitude for each hand is below the threshold value - // ie here this reflects the speed that each hand is rotating away from having up = (0,1,0) in Avatar frame. - // 6. head velocity is below step threshold - // 7. head has moved further than the threshold from the running average position of the head. - // 8. head height is not lower than the running average head height with a difference of maxHeightChange. - // 9. head's rotation in avatar space is not pitching or rolling greater than the pitch or roll thresholds - if (!withinBaseOfSupport(currentStateReadings.headPose.translation) && - withinThresholdOfStandingHeightMode(currentStateReadings.diffFromMode) && - headAngularVelocityBelowThreshold(currentStateReadings.headPose.angularVelocity) && - handDirectionMatchesHeadDirection(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && - handAngularVelocityBelowThreshold(currentStateReadings.lhandPose, currentStateReadings.rhandPose) && - headVelocityGreaterThanThreshold(Vec3.length(currentStateReadings.headPose.velocity)) && - headMovedAwayFromAveragePosition(currentStateReadings.diffFromAveragePosition) && - headLowerThanHeightAverage(currentStateReadings.diffFromAverageHeight) && - isHeadLevel(currentStateReadings.diffFromAverageEulers)) { - - if (stepTimer < 0.0) { //!MyAvatar.isRecenteringHorizontally() - print("trigger recenter========================================================"); - MyAvatar.triggerHorizontalRecenter(); - stepTimer = STEP_TIME_SECS; - } - } else if ((currentStateReadings.backLength > (DEFAULT_TORSO_LENGTH + SPINE_STRETCH_LIMIT)) && - (failsafeSignalTimer < 0.0) && HMD.active) { - // do the failsafe recenter. - // failsafeFlag stops repeated setting of failsafe button color. - // RESET_MODE false forces a reset of the height - RESET_MODE = false; - failsafeFlag = true; - failsafeSignalTimer = FAILSAFE_TIMEOUT; - MyAvatar.triggerHorizontalRecenter(); - tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "green" } })); - // in fail safe we debug print the values that were blocking us. - print("failsafe debug---------------------------------------------------------------"); - propArray.forEach(function (prop) { - print(prop.name); - if (!prop.signalOn) { - print(prop.signalType + " contributed to failsafe call"); - } - }); - print("end failsafe debug---------------------------------------------------------------"); - - } - - if ((failsafeSignalTimer < 0.0) && failsafeFlag) { - failsafeFlag = false; - tablet.emitScriptEvent(JSON.stringify({ "type": "failsafe", "id": "failsafeSignal", "data": { "value": "orange" } })); - } - - stepTimer -= dt; - failsafeSignalTimer -= dt; - - if (!HMD.active) { - RESET_MODE = false; - } - - if (Math.abs(headPoseAverageEulers.y) > HEAD_TURN_THRESHOLD) { - // Turn feet - // MyAvatar.triggerRotationRecenter(); - // headPoseAverageOrientation = { x: 0, y: 0, z: 0, w: 1 }; - } -} - -function shutdownTabletApp() { - // GlobalDebugger.stop(); - tablet.removeButton(tabletButton); - if (activated) { - tablet.webEventReceived.disconnect(onWebEventReceived); - tablet.gotoHomeScreen(); - } - tablet.screenChanged.disconnect(onScreenChanged); -} - -tabletButton.clicked.connect(manageClick); -tablet.screenChanged.connect(onScreenChanged); - -Script.setTimeout(function() { - DEFAULT_HIPS_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Hips")); - DEFAULT_HEAD_POSITION = MyAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(MyAvatar.getJointIndex("Head")); - DEFAULT_TORSO_LENGTH = Vec3.length(Vec3.subtract(DEFAULT_HEAD_POSITION, DEFAULT_HIPS_POSITION)); - SPINE_STRETCH_LIMIT = (0.04) * DEFAULT_TORSO_LENGTH * MyAvatar.scale; -},(4*LOADING_DELAY)); - -Script.update.connect(update); -Controller.keyPressEvent.connect(onKeyPress); -Script.scriptEnding.connect(function () { - MyAvatar.hmdLeanRecenterEnabled = true; - Script.update.disconnect(update); - shutdownTabletApp(); -}); From 1a0e2c6ea181bbae814554967ed8b60729eb56b8 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 1 Oct 2018 08:30:51 -0700 Subject: [PATCH 021/114] clean up for pr --- interface/resources/qml/hifi/avatarapp/Settings.qml | 3 +-- interface/src/avatar/MyAvatar.cpp | 12 ------------ 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index af76ba04d6..c4289ca650 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -296,7 +296,6 @@ Rectangle { text: "OFF" boxSize: 20 } - // TextStyle9 @@ -345,7 +344,7 @@ Rectangle { boxSize: 20 } } - + ColumnLayout { id: avatarAnimationLayout anchors.top: handAndCollisions.bottom diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index f281d8c87d..1bd8d4b2f0 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -485,18 +485,6 @@ void MyAvatar::update(float deltaTime) { glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; - if ((acosHead > 0.98f) && !getIsInSittingState() && (sensorHeadPoseDebug.getTranslation().y < -0.5f)) { - //qCDebug(interfaceapp) << "we are going to sitting state because it looks like we should" << sensorHeadPoseDebug.getTranslation().y; - } - if (!_lastFrameHMDMode && qApp->isHMDMode()) { - // we have entered hmd mode, so make the best guess about sitting or standing - if (sensorHeadPoseDebug.getTranslation().y < 1.3f) { - // then we are sitting. - // setIsInSittingState(true); - } else { - // setIsInSittingState(false); - } - } // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter From 90feeffa9db5076f3ca7e2bf8012d60ad11b2c1e Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 1 Oct 2018 14:21:00 -0700 Subject: [PATCH 022/114] cleaning up. putting squat fix in vertical recenter --- interface/src/avatar/MyAvatar.cpp | 70 +++++++++++++--------------- interface/src/avatar/MyAvatar.h | 6 +-- plugins/oculus/src/OculusHelpers.cpp | 10 ++-- scripts/system/avatarapp.js | 6 +-- 4 files changed, 43 insertions(+), 49 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1bd8d4b2f0..278d2703ab 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -484,6 +484,19 @@ void MyAvatar::update(float deltaTime) { glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + + glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head")); + glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2")); + glm::vec3 headCurrentPositionAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation(); + glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f); + float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); + if (headCurrentPositionAvatarSpace.y < (headDefaultPositionAvatarSpace.y - 0.05) && (angleSpine2 > 0.98f)) { + _squatCount++; + } else { + _squatCount = 0; + } + + // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; // put the average hand azimuth into sensor space. @@ -3795,7 +3808,7 @@ bool MyAvatar::getIsInWalkingState() const { } bool MyAvatar::getIsInSittingState() const { - return _isInSittingState; + return _isInSittingState.get(); } float MyAvatar::getWalkSpeed() const { @@ -3819,7 +3832,7 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { - _isInSittingState = isSitting; + _isInSittingState.set(isSitting); controller::Pose sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); _sumUserHeightSensorSpace = sensorHeadPoseDebug.getTranslation().y; _averageUserHeightCount = 1; @@ -4064,8 +4077,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 headSensorSpace = transformVectorFast(myAvatar.getSensorToWorldMatrix(), headWorldSpace); //get the mode. //put it in sensor space. - // if we are 20% higher switch to standing. - // 16.6% lower then switch to sitting. + // if we are 20% higher switch to standing. + // 16.6% lower then switch to sitting. // add this !!!! And the head is upright. glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); @@ -4074,8 +4087,9 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; // we could add a counting here to make sure that a lean forward doesn't accidentally put you in sitting mode. - // but maybe so what. + // but maybe so what. // the real test is... can I pick something up in standing mode? + if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { @@ -4084,22 +4098,27 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); - //myAvatar._sumUserHeightSensorSpace = 1.2f * averageSensorSpaceHeight; - // myAvatar._averageUserHeightCount = 1; return true; } else { return false; } } else { - // in the standing state - if ((sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) && (acosHead > 0.98f) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight)) { - myAvatar.setIsInSittingState(true); - // myAvatar._sumUserHeightSensorSpace = 0.83f * averageSensorSpaceHeight; - // myAvatar._averageUserHeightCount = 1; - return true; + // in the standing state + if ((sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) && (acosHead > 0.98f) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + myAvatar._sitStandStateCount++; + if (myAvatar._sitStandStateCount > 300) { + myAvatar.setIsInSittingState(true); + myAvatar._sitStandStateCount = 0; + myAvatar._squatCount = 0; + return true; + } } else { - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + if (myAvatar._squatCount > 600) { + return true; + myAvatar._squatCount = 0; + } } + return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } } @@ -4109,29 +4128,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { - // debug head hips angle - glm::vec3 headDefaultPos = myAvatar.getAbsoluteDefaultJointTranslationInObjectFrame(myAvatar.getJointIndex("Head")); - if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.05f)) { - _squatCount++; - if ((_squatCount > 600) && !isActive(Vertical) && !isActive(Horizontal)) { - if (myAvatar.getIsInSittingState()) { - // activate(Horizontal); - //activate(Vertical); - _squatCount = 0; - } else { - if (myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPos.y - 0.20f)) { - //myAvatar.setIsInSittingState(true); - //activate(Vertical); - } else { - //activate(Horizontal); - } - _squatCount = 0; - } - } - } else { - _squatCount = 0; - } - if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 62ba8d68b1..c7f6fa89ae 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1737,7 +1737,6 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; - int _squatCount { 0 }; }; FollowHelper _follow; @@ -1770,7 +1769,6 @@ private: glm::quat _customListenOrientation; AtRestDetector _hmdAtRestDetector; - bool _lastFrameHMDMode { false } ; bool _lastIsMoving { false }; // all poses are in sensor-frame @@ -1817,7 +1815,9 @@ private: ThreadSafeValueCache _sprintSpeed { AVATAR_SPRINT_SPEED_SCALAR }; float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; - bool _isInSittingState { false }; + ThreadSafeValueCache _isInSittingState { false }; + int _sitStandStateCount { 0 }; + int _squatCount { 0 }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 38d93d088d..402b05f39c 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -86,12 +86,10 @@ private: qCWarning(oculusLog) << "Failed to acquire Oculus session" << ovr::getError(); return; } else { - qCWarning(oculusLog) << "successful init of oculus!!!!!!!!"; - ovrTrackingOrigin fred; - //fred = ovr_GetTrackingOriginType(session); - ovrResult retTrackingType = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel); - fred = ovr_GetTrackingOriginType(session); - qCWarning(oculusLog) << OVR_SUCCESS(retTrackingType) << (int)fred; + ovrResult setFloorLevelOrigin = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel); + if (!OVR_SUCCESS(setFloorLevelOrigin)) { + qCWarning(oculusLog) << "Failed to set the Oculus tracking origin to floor level" << ovr::getError(); + } } } diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 16761f29a6..faf624392a 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -63,8 +63,8 @@ function getMyAvatar() { function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), - collisionsEnabled: MyAvatar.getCollisionsEnabled(), - sittingEnabled: MyAvatar.isInSittingState, + collisionsEnabled : MyAvatar.getCollisionsEnabled(), + sittingEnabled : MyAvatar.isInSittingState, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -326,7 +326,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See MyAvatar.isInSittingState = message.settings.sittingEnabled; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); - print("save settings"); + settings = getMyAvatarSettings(); break; default: From f0676d796c74a8464954bf1a8b7aae3e40df00a0 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 1 Oct 2018 17:57:00 -0700 Subject: [PATCH 023/114] added constants and tipping point for running average. this should be replaced by the mode --- interface/src/avatar/MyAvatar.cpp | 86 +++++++++++++------------------ interface/src/avatar/MyAvatar.h | 2 + 2 files changed, 38 insertions(+), 50 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 278d2703ab..4f28ae8e90 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -471,34 +471,6 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - // qCDebug(interfaceapp) << "sitting state is " << getIsInSittingState(); - // debug setting for sitting state if you start in the chair. - // if the head is close to the floor in sensor space - // and the up of the head is close to sensor up then try switching us to sitting state. - auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); - if (sensorHeadPoseDebug.isValid()) { - _sumUserHeightSensorSpace += sensorHeadPoseDebug.getTranslation().y; - _averageUserHeightCount++; - } - qCDebug(interfaceapp) << sensorHeadPoseDebug.isValid() << " valid. sensor space average " << (_sumUserHeightSensorSpace / _averageUserHeightCount) << " head position sensor y value " << sensorHeadPoseDebug.getTranslation().y; - - glm::vec3 upHead = transformVectorFast(sensorHeadPoseDebug.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); - float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); - - glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head")); - glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2")); - glm::vec3 headCurrentPositionAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation(); - glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f); - float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); - if (headCurrentPositionAvatarSpace.y < (headDefaultPositionAvatarSpace.y - 0.05) && (angleSpine2 > 0.98f)) { - _squatCount++; - } else { - _squatCount = 0; - } - - - // qCDebug(interfaceapp) << "sensor space head pos " << sensorHeadPoseDebug.getTranslation().y; - // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { @@ -527,6 +499,29 @@ void MyAvatar::update(float deltaTime) { setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD))); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); + // if the head tracker reading is valid then add it to the running average. + auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (sensorHeadPoseDebug.isValid()) { + _sumUserHeightSensorSpace += sensorHeadPoseDebug.getTranslation().y; + _averageUserHeightCount++; + } + + // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. + const float SQUAT_THRESHOLD = 0.05f; + const float COSINE_TEN_DEGREES = 0.98f; + glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head")); + glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2")); + glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f); + if (glm::length(upSpine2) > 0.0f) { + upSpine2 = glm::normalize(upSpine2); + } + float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); + if (newHeightReading < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) { + _squatCount++; + } else { + _squatCount = 0; + } + if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation()); @@ -3561,12 +3556,6 @@ glm::vec3 MyAvatar::computeCounterBalance() { if (counterBalancedCg.y > (tposeHips.y + 0.05f)) { // if the height is higher than default hips, clamp to default hips counterBalancedCg.y = tposeHips.y + 0.05f; - } else if (counterBalancedCg.y < sitSquatThreshold) { - // do a height reset - setResetMode(true); - // _follow.activate(FollowHelper::Vertical); - // disable cg behaviour in this case. - // setIsInSittingState(true); } return counterBalancedCg; } @@ -4068,34 +4057,29 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; + const float STANDING_HEIGHT_MULTIPLE = 1.2f; + const float SITTING_HEIGHT_MULTIPLE = 0.833f; + const float COSINE_TEN_DEGREES = 0.98f; + const int SITTING_COUNT_THRESHOLD = 300; + const int SQUATTY_COUNT_THRESHOLD = 600; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); - glm::vec3 headWorldSpace = myAvatar.getHead()->getPosition(); - glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar.getSensorToWorldMatrix()); - glm::vec3 headSensorSpace = transformVectorFast(myAvatar.getSensorToWorldMatrix(), headWorldSpace); - //get the mode. - //put it in sensor space. - // if we are 20% higher switch to standing. - // 16.6% lower then switch to sitting. - // add this !!!! And the head is upright. glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); glm::vec3 worldHips = transformVectorFast(myAvatar.getTransform().getMatrix(),avatarHips); glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); + float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; - // we could add a counting here to make sure that a lean forward doesn't accidentally put you in sitting mode. - // but maybe so what. - // the real test is... can I pick something up in standing mode? - if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (sensorHeadPose.getTranslation().y > (1.2f * averageSensorSpaceHeight)) { + } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); return true; @@ -4104,16 +4088,18 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } } else { // in the standing state - if ((sensorHeadPose.getTranslation().y < (0.83f * averageSensorSpaceHeight)) && (acosHead > 0.98f) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) myAvatar._sitStandStateCount++; - if (myAvatar._sitStandStateCount > 300) { + if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(true); + myAvatar._tippingPoint = averageSensorSpaceHeight; myAvatar._sitStandStateCount = 0; myAvatar._squatCount = 0; return true; } } else { - if (myAvatar._squatCount > 600) { + myAvatar._tippingPoint = averageSensorSpaceHeight; + if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { return true; myAvatar._squatCount = 0; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c7f6fa89ae..6fe5aeda47 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -140,6 +140,7 @@ class MyAvatar : public Avatar { * @property {number} walkSpeed * @property {number} walkBackwardSpeed * @property {number} sprintSpeed + * @property {number} isInSittingState * * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the * registration point of the 3D model. @@ -1818,6 +1819,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; + float _tippingPoint { DEFAULT_AVATAR_HEIGHT }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From 8a0fbc3fe9049e3322fd88e42024d698ae344d18 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 2 Oct 2018 17:47:56 -0700 Subject: [PATCH 024/114] changed the height to use the mode . to do fix sensor space bug. --- interface/src/avatar/MyAvatar.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4f28ae8e90..4892f98da1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4074,12 +4074,18 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; + glm::vec3 modeWorldSpace = myAvatar.getTransform().getRotation() * glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f); + glm::vec3 modeSensorSpace = extractRotation(myAvatar.getSensorToWorldMatrix()) * modeWorldSpace; + glm::vec3 bodyInSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), myAvatar.getTransform().getTranslation()); + modeSensorSpace.y = modeSensorSpace.y + bodyInSensorSpace.y; + qCDebug(interfaceapp) << "mode world sensor " << myAvatar.getCurrentStandingHeight() << " " << modeWorldSpace << " " << modeSensorSpace << " " << bodyInSensorSpace; if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. return true; - } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { + // } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { + } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { // if we recenter upwards then no longer in sitting state myAvatar.setIsInSittingState(false); return true; @@ -4088,10 +4094,12 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } } else { // in the standing state - if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) + // if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) + if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * modeSensorSpace.y)) && (acosHead > COSINE_TEN_DEGREES)) { myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(true); + myAvatar.setResetMode(true); myAvatar._tippingPoint = averageSensorSpaceHeight; myAvatar._sitStandStateCount = 0; myAvatar._squatCount = 0; From 809ca0e51266ee8b25edb2ceeb5ce4e8b5491cd0 Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 3 Oct 2018 18:05:30 -0700 Subject: [PATCH 025/114] vive hmd input is implemented. not using mode --- interface/src/avatar/MyAvatar.cpp | 45 ++++++++++++++++++------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4892f98da1..9db07347c3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3821,10 +3821,14 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { - _isInSittingState.set(isSitting); + _sitStandStateCount = 0; + _squatCount = 0; controller::Pose sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); _sumUserHeightSensorSpace = sensorHeadPoseDebug.getTranslation().y; + _tippingPoint = sensorHeadPoseDebug.getTranslation().y; _averageUserHeightCount = 1; + setResetMode(true); + _isInSittingState.set(isSitting); emit sittingEnabledChanged(isSitting); } @@ -4070,45 +4074,48 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - glm::vec3 worldHips = transformVectorFast(myAvatar.getTransform().getMatrix(),avatarHips); - glm::vec3 sensorHips = transformVectorFast(myAvatar.getSensorToWorldMatrix(), worldHips); + glm::vec3 worldHips = transformPoint(myAvatar.getTransform().getMatrix(),avatarHips); + glm::vec3 sensorHips = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), worldHips); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; - glm::vec3 modeWorldSpace = myAvatar.getTransform().getRotation() * glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f); - glm::vec3 modeSensorSpace = extractRotation(myAvatar.getSensorToWorldMatrix()) * modeWorldSpace; - glm::vec3 bodyInSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), myAvatar.getTransform().getTranslation()); - modeSensorSpace.y = modeSensorSpace.y + bodyInSensorSpace.y; - qCDebug(interfaceapp) << "mode world sensor " << myAvatar.getCurrentStandingHeight() << " " << modeWorldSpace << " " << modeSensorSpace << " " << bodyInSensorSpace; + glm::vec3 modeWorldSpace = transformPoint(myAvatar.getTransform().getMatrix(), glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f)); + glm::vec3 modeSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), modeWorldSpace); + //qCDebug(interfaceapp) << "mode reading avatar " << myAvatar.getCurrentStandingHeight() << "mode w " << modeWorldSpace << "mode s " << modeSensorSpace << "sensor pose " < (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { - } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { + } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { + // } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { // if we recenter upwards then no longer in sitting state - myAvatar.setIsInSittingState(false); - return true; + //myAvatar._sitStandStateCount++; + //if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { + myAvatar.setIsInSittingState(false); + return true; + //} } else { + myAvatar._sitStandStateCount = 0; + myAvatar._tippingPoint = averageSensorSpaceHeight; return false; } } else { // in the standing state // if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) - if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * modeSensorSpace.y)) && (acosHead > COSINE_TEN_DEGREES)) { + if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint))) { myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(true); - myAvatar.setResetMode(true); - myAvatar._tippingPoint = averageSensorSpaceHeight; - myAvatar._sitStandStateCount = 0; - myAvatar._squatCount = 0; return true; } } else { myAvatar._tippingPoint = averageSensorSpaceHeight; + myAvatar._sitStandStateCount = 0; if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { - return true; + // return true; myAvatar._squatCount = 0; } } @@ -4145,7 +4152,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - activate(Vertical); + //activate(Vertical); } } else { if (!isActive(Rotation) && getForceActivateRotation()) { From acce675efc4280740508d8e3562e6d39ea85bf40 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 4 Oct 2018 14:53:51 -0700 Subject: [PATCH 026/114] added snap for recentering with sit stand state change. using average height with tipping point for thresholds --- interface/src/avatar/MyAvatar.cpp | 41 ++++++++++++++++++++----------- interface/src/avatar/MyAvatar.h | 1 + 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9db07347c3..55536748c7 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4081,26 +4081,26 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 modeWorldSpace = transformPoint(myAvatar.getTransform().getMatrix(), glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f)); glm::vec3 modeSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), modeWorldSpace); - //qCDebug(interfaceapp) << "mode reading avatar " << myAvatar.getCurrentStandingHeight() << "mode w " << modeWorldSpace << "mode s " << modeSensorSpace << "sensor pose " < (STANDING_HEIGHT_MULTIPLE * averageSensorSpaceHeight)) { + //returnValue = true; + } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) { // } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { // if we recenter upwards then no longer in sitting state - //myAvatar._sitStandStateCount++; - //if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { + myAvatar._sitStandStateCount++; + if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(false); - return true; - //} + myAvatar._sitStandStateChange = true; + returnValue = true; + } } else { myAvatar._sitStandStateCount = 0; myAvatar._tippingPoint = averageSensorSpaceHeight; - return false; } } else { // in the standing state @@ -4109,7 +4109,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { myAvatar.setIsInSittingState(true); - return true; + myAvatar._sitStandStateChange = true; + returnValue = true; } } else { myAvatar._tippingPoint = averageSensorSpaceHeight; @@ -4119,8 +4120,9 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl myAvatar._squatCount = 0; } } - return (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } + return returnValue; } void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, @@ -4152,7 +4154,9 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - //activate(Vertical); + activate(Vertical); + _timeRemaining[(int)Vertical] = 0.1f; + qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; } } else { if (!isActive(Rotation) && getForceActivateRotation()) { @@ -4209,6 +4213,9 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co // apply follow displacement to the body matrix. glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement(); + if (worldLinearDisplacement.y > 0.0001f) { + qCDebug(interfaceapp) << "linear displacement " << worldLinearDisplacement << " time remaining " << getMaxTimeRemaining(); + } glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement(); glm::mat4 sensorToWorldMatrix = myAvatar.getSensorToWorldMatrix(); @@ -4219,6 +4226,12 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); + if (isActive(Vertical)) { + deactivate(Vertical); + return myAvatar.deriveBodyFromHMDSensor(); + } else { + return newBodyMat; + } return newBodyMat; } else { return currentBodyMatrix; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 6fe5aeda47..7854f5cb41 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1807,6 +1807,7 @@ private: ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; float _sumUserHeightSensorSpace { DEFAULT_AVATAR_HEIGHT }; int _averageUserHeightCount { 1 }; + bool _sitStandStateChange { false }; void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); From 82f8c6743678527e6c14ae8b13b66038f2bc6143 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 4 Oct 2018 15:37:01 -0700 Subject: [PATCH 027/114] put the mode in sensor space for cg --- interface/src/avatar/MyAvatar.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 55536748c7..db37b5003b 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -493,7 +493,7 @@ void MyAvatar::update(float deltaTime) { _smoothOrientationTimer += deltaTime; } - float newHeightReading = getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y; + float newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD).getTranslation().y; int newHeightReadingInCentimeters = glm::floor(newHeightReading * CENTIMETERS_PER_METER); _recentModeReadings.insert(newHeightReadingInCentimeters); setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD))); @@ -4015,6 +4015,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); controller::Pose currentLeftHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND); controller::Pose currentRightHandPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND); + controller::Pose currentHeadSensorPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); bool stepDetected = false; float myScale = myAvatar.getAvatarScale(); @@ -4028,7 +4029,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons } else { if (!withinBaseOfSupport(currentHeadPose) && headAngularVelocityBelowThreshold(currentHeadPose) && - isWithinThresholdHeightMode(currentHeadPose, myAvatar.getCurrentStandingHeight(), myScale) && + isWithinThresholdHeightMode(currentHeadSensorPose, myAvatar.getCurrentStandingHeight(), myScale) && handDirectionMatchesHeadDirection(currentLeftHandPose, currentRightHandPose, currentHeadPose) && handAngularVelocityBelowThreshold(currentLeftHandPose, currentRightHandPose) && headVelocityGreaterThanThreshold(currentHeadPose) && @@ -4083,7 +4084,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl // qCDebug(interfaceapp) << "mode reading avatar " << myAvatar.getCurrentStandingHeight() << "mode w " << modeWorldSpace << "mode s " << modeSensorSpace << "sensor pose " < Date: Thu, 4 Oct 2018 18:05:05 -0700 Subject: [PATCH 028/114] changed pre physics to use cg for desired body when in cg mode --- interface/src/avatar/MyAvatar.cpp | 58 +++++++++++++------------------ interface/src/avatar/MyAvatar.h | 4 +-- 2 files changed, 27 insertions(+), 35 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index db37b5003b..09896e66c3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -493,17 +493,14 @@ void MyAvatar::update(float deltaTime) { _smoothOrientationTimer += deltaTime; } - float newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD).getTranslation().y; - int newHeightReadingInCentimeters = glm::floor(newHeightReading * CENTIMETERS_PER_METER); - _recentModeReadings.insert(newHeightReadingInCentimeters); - setCurrentStandingHeight(computeStandingHeightMode(getControllerPoseInAvatarFrame(controller::Action::HEAD))); - setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); - - // if the head tracker reading is valid then add it to the running average. - auto sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); - if (sensorHeadPoseDebug.isValid()) { - _sumUserHeightSensorSpace += sensorHeadPoseDebug.getTranslation().y; + controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (newHeightReading.isValid()) { + int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER); + _sumUserHeightSensorSpace += newHeightReading.getTranslation().y; _averageUserHeightCount++; + _recentModeReadings.insert(newHeightReadingInCentimeters); + setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); + setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); } // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. @@ -516,7 +513,7 @@ void MyAvatar::update(float deltaTime) { upSpine2 = glm::normalize(upSpine2); } float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); - if (newHeightReading < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) { + if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) { _squatCount++; } else { _squatCount = 0; @@ -2031,6 +2028,11 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setPositionAndOrientation(getWorldPosition(), getWorldOrientation()); auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD); if (headPose.isValid()) { + if (getCenterOfGravityModelEnabled() && !getIsInSittingState()) { + _follow.prePhysicsUpdate(*this, deriveBodyUsingCgModel(), _bodySensorMatrix, hasDriveInput()); + } else { + _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); + } _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); } else { _follow.deactivate(); @@ -3823,9 +3825,11 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { void MyAvatar::setIsInSittingState(bool isSitting) { _sitStandStateCount = 0; _squatCount = 0; - controller::Pose sensorHeadPoseDebug = getControllerPoseInSensorFrame(controller::Action::HEAD); - _sumUserHeightSensorSpace = sensorHeadPoseDebug.getTranslation().y; - _tippingPoint = sensorHeadPoseDebug.getTranslation().y; + controller::Pose sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); + if (sensorHeadPose.isValid()) { + _sumUserHeightSensorSpace = sensorHeadPose.getTranslation().y; + _tippingPoint = sensorHeadPose.getTranslation().y; + } _averageUserHeightCount = 1; setResetMode(true); _isInSittingState.set(isSitting); @@ -4077,21 +4081,14 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); glm::vec3 worldHips = transformPoint(myAvatar.getTransform().getMatrix(),avatarHips); glm::vec3 sensorHips = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), worldHips); - + //qCDebug(interfaceapp) << " current mode " << myAvatar.getCurrentStandingHeight() << " " << sensorHeadPose.getTranslation().y << " state " << myAvatar.getIsInSittingState(); float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; - glm::vec3 modeWorldSpace = transformPoint(myAvatar.getTransform().getMatrix(), glm::vec3(0.0f,myAvatar.getCurrentStandingHeight(),0.0f)); - glm::vec3 modeSensorSpace = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), modeWorldSpace); - - // qCDebug(interfaceapp) << "mode reading avatar " << myAvatar.getCurrentStandingHeight() << "mode w " << modeWorldSpace << "mode s " << modeSensorSpace << "sensor pose " < (STANDING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) { - // } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * modeSensorSpace.y)) { // if we recenter upwards then no longer in sitting state myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { @@ -4105,7 +4102,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } } else { // in the standing state - // if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) + // && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint))) { myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { @@ -4114,14 +4111,14 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl returnValue = true; } } else { - myAvatar._tippingPoint = averageSensorSpaceHeight; + myAvatar._tippingPoint = myAvatar.getCurrentStandingHeight(); myAvatar._sitStandStateCount = 0; if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { // return true; myAvatar._squatCount = 0; } } - // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); } return returnValue; } @@ -4156,7 +4153,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); - _timeRemaining[(int)Vertical] = 0.1f; qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; } } else { @@ -4214,9 +4210,6 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co // apply follow displacement to the body matrix. glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement(); - if (worldLinearDisplacement.y > 0.0001f) { - qCDebug(interfaceapp) << "linear displacement " << worldLinearDisplacement << " time remaining " << getMaxTimeRemaining(); - } glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement(); glm::mat4 sensorToWorldMatrix = myAvatar.getSensorToWorldMatrix(); @@ -4228,10 +4221,9 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); if (isActive(Vertical)) { + // myAvatar._sitStandStateChange = false; deactivate(Vertical); - return myAvatar.deriveBodyFromHMDSensor(); - } else { - return newBodyMat; + newBodyMat = myAvatar.deriveBodyFromHMDSensor(); } return newBodyMat; } else { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 7854f5cb41..0c6b1b01a5 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1805,7 +1805,7 @@ private: // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; - float _sumUserHeightSensorSpace { DEFAULT_AVATAR_HEIGHT }; + float _sumUserHeightSensorSpace { 0.0f }; int _averageUserHeightCount { 1 }; bool _sitStandStateChange { false }; @@ -1820,7 +1820,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; - float _tippingPoint { DEFAULT_AVATAR_HEIGHT }; + float _tippingPoint { 0.0f }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From cbe638bfdb18d1420dacc470d46671ee4bb8c79e Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 4 Oct 2018 18:16:39 -0700 Subject: [PATCH 029/114] added flag for vertical recentering that is state change, snap, versus the usual .5 second recentering --- interface/src/avatar/MyAvatar.cpp | 6 +++--- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 09896e66c3..8756f1bbd8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4203,7 +4203,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat myAvatar.getCharacterController()->setFollowParameters(followWorldPose, getMaxTimeRemaining()); } -glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) { +glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix) { if (isActive()) { float dt = myAvatar.getCharacterController()->getFollowTime(); decrementTimeRemaining(dt); @@ -4220,8 +4220,8 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); - if (isActive(Vertical)) { - // myAvatar._sitStandStateChange = false; + if (myAvatar._sitStandStateChange) { + myAvatar._sitStandStateChange = false; deactivate(Vertical); newBodyMat = myAvatar.deriveBodyFromHMDSensor(); } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0c6b1b01a5..072ea04ee7 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1725,7 +1725,7 @@ private: bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); - glm::mat4 postPhysicsUpdate(const MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); + glm::mat4 postPhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& currentBodyMatrix); bool getForceActivateRotation() const; void setForceActivateRotation(bool val); bool getForceActivateVertical() const; From ad46b7196634e301f9fdd5d5f8d0e11342959446 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 5 Oct 2018 13:04:14 -0700 Subject: [PATCH 030/114] before moving the step state counting to myavatar::update() --- interface/src/avatar/MyAvatar.cpp | 28 ++++++++++++++++++++++------ interface/src/avatar/MyAvatar.h | 1 + 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8756f1bbd8..c5defe3d72 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -4103,6 +4103,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl } else { // in the standing state // && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) + if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint))) { myAvatar._sitStandStateCount++; if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { @@ -4111,14 +4112,15 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl returnValue = true; } } else { + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); myAvatar._tippingPoint = myAvatar.getCurrentStandingHeight(); myAvatar._sitStandStateCount = 0; if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { - // return true; + // returnValue = true; myAvatar._squatCount = 0; } } - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + } return returnValue; } @@ -4151,10 +4153,20 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - activate(Vertical); - qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; + + qCDebug(interfaceapp) << "velocity of headset " << glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()); + + if (_velocityCount > 60) { + if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { + activate(Vertical); + qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; + } + } else { + if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) { + _velocityCount++; + } } + } else { if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); @@ -4223,7 +4235,11 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const gl if (myAvatar._sitStandStateChange) { myAvatar._sitStandStateChange = false; deactivate(Vertical); - newBodyMat = myAvatar.deriveBodyFromHMDSensor(); + + qCDebug(interfaceapp) << "before snap " << extractTranslation(newBodyMat); + //newBodyMat = myAvatar.deriveBodyFromHMDSensor(); + setTranslation(newBodyMat, extractTranslation(myAvatar.deriveBodyFromHMDSensor())); + qCDebug(interfaceapp) << "after snap " << extractTranslation(newBodyMat); } return newBodyMat; } else { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 072ea04ee7..24a58745a3 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1738,6 +1738,7 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; + int _velocityCount { 0 }; }; FollowHelper _follow; From 96872f841202f4a60fc8b3b2a77f9632d0197ce8 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 5 Oct 2018 14:55:32 -0700 Subject: [PATCH 031/114] moved all the state update for sit and stand to myavatar::update() also made it so that sit horizontal reset is handled in non-cg recentering. to do: revisit what should be sent for desired body in prephysics update call --- interface/src/avatar/MyAvatar.cpp | 143 ++++++++++++++++++------------ 1 file changed, 87 insertions(+), 56 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c5defe3d72..58a0ef4046 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -467,6 +467,11 @@ void MyAvatar::update(float deltaTime) { // update moving average of HMD facing in xz plane. const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength(); const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders + const float STANDING_HEIGHT_MULTIPLE = 1.2f; + const float SITTING_HEIGHT_MULTIPLE = 0.833f; + const float COSINE_TEN_DEGREES = 0.98f; + const int SITTING_COUNT_THRESHOLD = 300; + const int SQUATTY_COUNT_THRESHOLD = 600; float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); @@ -505,7 +510,6 @@ void MyAvatar::update(float deltaTime) { // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. const float SQUAT_THRESHOLD = 0.05f; - const float COSINE_TEN_DEGREES = 0.98f; glm::vec3 headDefaultPositionAvatarSpace = getAbsoluteDefaultJointTranslationInObjectFrame(getJointIndex("Head")); glm::quat spine2OrientationAvatarSpace = getAbsoluteJointRotationInObjectFrame(getJointIndex("Spine2")); glm::vec3 upSpine2 = spine2OrientationAvatarSpace * glm::vec3(0.0f, 1.0f, 0.0f); @@ -519,6 +523,65 @@ void MyAvatar::update(float deltaTime) { _squatCount = 0; } + float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; + //auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); + //glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); + //float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); + + glm::vec3 avatarHips = getAbsoluteJointTranslationInObjectFrame(getJointIndex("Hips")); + glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); + glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); + + // put update sit stand state counts here + if (getIsInSittingState()) { + if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setResetMode(true); + setIsInSittingState(false); + setCenterOfGravityModelEnabled(true); + _sitStandStateChange = true; + } + } else { + _sitStandStateCount = 0; + // tipping point is average height when sitting. + _tippingPoint = averageSensorSpaceHeight; + } + } else { + // in the standing state + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setResetMode(true); + setIsInSittingState(true); + setCenterOfGravityModelEnabled(false); + _sitStandStateChange = true; + } + } else { + // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; + } + + } + + if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation()); @@ -2028,10 +2091,10 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setPositionAndOrientation(getWorldPosition(), getWorldOrientation()); auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD); if (headPose.isValid()) { - if (getCenterOfGravityModelEnabled() && !getIsInSittingState()) { - _follow.prePhysicsUpdate(*this, deriveBodyUsingCgModel(), _bodySensorMatrix, hasDriveInput()); + if (getCenterOfGravityModelEnabled()) { + //_follow.prePhysicsUpdate(*this, deriveBodyUsingCgModel(), _bodySensorMatrix, hasDriveInput()); } else { - _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); + //_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); } _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); } else { @@ -3995,6 +4058,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, // x axis of currentBodyMatrix in world space. glm::vec3 right = glm::normalize(glm::vec3(currentBodyMatrix[0][0], currentBodyMatrix[1][0], currentBodyMatrix[2][0])); glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + controller::Pose currentHeadPose = myAvatar.getControllerPoseInAvatarFrame(controller::Action::HEAD); float forwardLeanAmount = glm::dot(forward, offset); float lateralLeanAmount = glm::dot(right, offset); @@ -4003,14 +4067,19 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const float MAX_FORWARD_LEAN = 0.15f; const float MAX_BACKWARD_LEAN = 0.1f; - - if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { - return true; + bool stepDetected = false; + if (myAvatar.getIsInSittingState()) { + if (!withinBaseOfSupport(currentHeadPose)) { + stepDetected = true; + } + } else if (forwardLeanAmount > 0 && forwardLeanAmount > MAX_FORWARD_LEAN) { + stepDetected = true; } else if (forwardLeanAmount < 0 && forwardLeanAmount < -MAX_BACKWARD_LEAN) { - return true; + stepDetected = true; + } else { + stepDetected = fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; } - - return fabs(lateralLeanAmount) > MAX_LATERAL_LEAN; + return stepDetected; } bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) const { @@ -4026,10 +4095,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons if (myAvatar.getIsInWalkingState()) { stepDetected = true; - } else if (myAvatar.getIsInSittingState()) { - if (!withinBaseOfSupport(currentHeadPose)) { - stepDetected = true; - } } else { if (!withinBaseOfSupport(currentHeadPose) && headAngularVelocityBelowThreshold(currentHeadPose) && @@ -4066,61 +4131,27 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; - const float STANDING_HEIGHT_MULTIPLE = 1.2f; - const float SITTING_HEIGHT_MULTIPLE = 0.833f; - const float COSINE_TEN_DEGREES = 0.98f; - const int SITTING_COUNT_THRESHOLD = 300; const int SQUATTY_COUNT_THRESHOLD = 600; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - - auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); - glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); - float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); - - glm::vec3 avatarHips = myAvatar.getAbsoluteJointTranslationInObjectFrame(myAvatar.getJointIndex("Hips")); - glm::vec3 worldHips = transformPoint(myAvatar.getTransform().getMatrix(),avatarHips); - glm::vec3 sensorHips = transformPoint(glm::inverse(myAvatar.getSensorToWorldMatrix()), worldHips); //qCDebug(interfaceapp) << " current mode " << myAvatar.getCurrentStandingHeight() << " " << sensorHeadPose.getTranslation().y << " state " << myAvatar.getIsInSittingState(); - float averageSensorSpaceHeight = myAvatar._sumUserHeightSensorSpace / myAvatar._averageUserHeightCount; + bool returnValue = false; + if (myAvatar._sitStandStateChange) { + returnValue = true; + } if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. returnValue = true; - } else if (sensorHeadPose.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * myAvatar._tippingPoint)) { - // if we recenter upwards then no longer in sitting state - myAvatar._sitStandStateCount++; - if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { - myAvatar.setIsInSittingState(false); - myAvatar._sitStandStateChange = true; - returnValue = true; - } - } else { - myAvatar._sitStandStateCount = 0; - myAvatar._tippingPoint = averageSensorSpaceHeight; } } else { // in the standing state - // && (acosHead > COSINE_TEN_DEGREES)) { //&& !(sensorHips.y > (0.4f * averageSensorSpaceHeight) - - if ((sensorHeadPose.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * myAvatar._tippingPoint))) { - myAvatar._sitStandStateCount++; - if (myAvatar._sitStandStateCount > SITTING_COUNT_THRESHOLD) { - myAvatar.setIsInSittingState(true); - myAvatar._sitStandStateChange = true; - returnValue = true; - } - } else { - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); - myAvatar._tippingPoint = myAvatar.getCurrentStandingHeight(); - myAvatar._sitStandStateCount = 0; - if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { - // returnValue = true; - myAvatar._squatCount = 0; - } + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { + myAvatar._squatCount = 0; + returnValue = true; } - } return returnValue; } From 3517905435d5b0fa2c276f9c313de8de5460712e Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 5 Oct 2018 16:22:30 -0700 Subject: [PATCH 032/114] added getter and setter for sitstandstatechange bool --- interface/src/avatar/MyAvatar.cpp | 50 ++++++++++--------------------- interface/src/avatar/MyAvatar.h | 18 ++++++----- 2 files changed, 27 insertions(+), 41 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 58a0ef4046..995126f3ca 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -524,14 +524,11 @@ void MyAvatar::update(float deltaTime) { } float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; - //auto sensorHeadPose = myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD); - //glm::vec3 upHead = transformVectorFast(sensorHeadPose.getMatrix(), glm::vec3(0.0f, 1.0f, 0.0f)); - //float acosHead = glm::dot(upHead, glm::vec3(0.0f, 1.0f, 0.0f)); glm::vec3 avatarHips = getAbsoluteJointTranslationInObjectFrame(getJointIndex("Hips")); glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); - + // put update sit stand state counts here if (getIsInSittingState()) { if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { @@ -548,11 +545,11 @@ void MyAvatar::update(float deltaTime) { setResetMode(true); setIsInSittingState(false); setCenterOfGravityModelEnabled(true); - _sitStandStateChange = true; + setSitStandStateChange(true); } } else { _sitStandStateCount = 0; - // tipping point is average height when sitting. + // tipping point is average height when sitting. _tippingPoint = averageSensorSpaceHeight; } } else { @@ -570,7 +567,7 @@ void MyAvatar::update(float deltaTime) { setResetMode(true); setIsInSittingState(true); setCenterOfGravityModelEnabled(false); - _sitStandStateChange = true; + setSitStandStateChange(true); } } else { // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); @@ -2091,11 +2088,6 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setPositionAndOrientation(getWorldPosition(), getWorldOrientation()); auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD); if (headPose.isValid()) { - if (getCenterOfGravityModelEnabled()) { - //_follow.prePhysicsUpdate(*this, deriveBodyUsingCgModel(), _bodySensorMatrix, hasDriveInput()); - } else { - //_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); - } _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); } else { _follow.deactivate(); @@ -3886,15 +3878,6 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { - _sitStandStateCount = 0; - _squatCount = 0; - controller::Pose sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); - if (sensorHeadPose.isValid()) { - _sumUserHeightSensorSpace = sensorHeadPose.getTranslation().y; - _tippingPoint = sensorHeadPose.getTranslation().y; - } - _averageUserHeightCount = 1; - setResetMode(true); _isInSittingState.set(isSitting); emit sittingEnabledChanged(isSitting); } @@ -3915,6 +3898,14 @@ float MyAvatar::getSprintSpeed() const { return _sprintSpeed.get(); } +void MyAvatar::setSitStandStateChange(bool stateChanged) { + _sitStandStateChange = stateChanged; +} + +float MyAvatar::getSitStandStateChange() const { + return _sitStandStateChange; +} + QVector MyAvatar::getScriptUrls() { QVector scripts = _skeletonModel->isLoaded() ? _skeletonModel->getFBXGeometry().scripts : QVector(); return scripts; @@ -4134,10 +4125,8 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const int SQUATTY_COUNT_THRESHOLD = 600; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - //qCDebug(interfaceapp) << " current mode " << myAvatar.getCurrentStandingHeight() << " " << sensorHeadPose.getTranslation().y << " state " << myAvatar.getIsInSittingState(); - bool returnValue = false; - if (myAvatar._sitStandStateChange) { + if (myAvatar.getSitStandStateChange()) { returnValue = true; } if (myAvatar.getIsInSittingState()) { @@ -4184,13 +4173,10 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - - qCDebug(interfaceapp) << "velocity of headset " << glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()); - + if (_velocityCount > 60) { if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); - qCDebug(interfaceapp) << "recenter vertically!!!!!! " << hasDriveInput; } } else { if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) { @@ -4263,14 +4249,10 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(MyAvatar& myAvatar, const gl glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix), sensorLinearDisplacement + extractTranslation(currentBodyMatrix)); - if (myAvatar._sitStandStateChange) { - myAvatar._sitStandStateChange = false; + if (myAvatar.getSitStandStateChange()) { + myAvatar.setSitStandStateChange(false); deactivate(Vertical); - - qCDebug(interfaceapp) << "before snap " << extractTranslation(newBodyMat); - //newBodyMat = myAvatar.deriveBodyFromHMDSensor(); setTranslation(newBodyMat, extractTranslation(myAvatar.deriveBodyFromHMDSensor())); - qCDebug(interfaceapp) << "after snap " << extractTranslation(newBodyMat); } return newBodyMat; } else { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 24a58745a3..54aa015aff 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1105,6 +1105,8 @@ public: float getWalkBackwardSpeed() const; void setSprintSpeed(float value); float getSprintSpeed() const; + void setSitStandStateChange(bool stateChanged); + float getSitStandStateChange() const; QVector getScriptUrls(); @@ -1804,14 +1806,16 @@ private: std::mutex _pinnedJointsMutex; std::vector _pinnedJoints; - // height of user in sensor space, when standing erect. - ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; - float _sumUserHeightSensorSpace { 0.0f }; - int _averageUserHeightCount { 1 }; - bool _sitStandStateChange { false }; - void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); + const float DEFAULT_FLOOR_HEIGHT = 0.0f; + + // height of user in sensor space, when standing erect. + ThreadSafeValueCache _userHeight{ DEFAULT_AVATAR_HEIGHT }; + float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; + int _averageUserHeightCount{ 1 }; + bool _sitStandStateChange{ false }; + // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; ThreadSafeValueCache _walkBackwardSpeed { DEFAULT_AVATAR_MAX_WALKING_BACKWARD_SPEED }; @@ -1821,7 +1825,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; - float _tippingPoint { 0.0f }; + float _tippingPoint { DEFAULT_FLOOR_HEIGHT }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From ea8229fca49862635cf90e396815d795567fa46d Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Mon, 8 Oct 2018 13:10:41 -0700 Subject: [PATCH 033/114] adding fix for length check --- .../system/controllers/controllerModules/farActionGrabEntity.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 2e73526728..2fe98ae673 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -317,7 +317,7 @@ Script.include("/~/system/libraries/Xform.js"); }; this.restoreIgnoredEntities = function() { - for (var i = 0; i < this.ignoredEntities; i++) { + for (var i = 0; i < this.ignoredEntities.length; i++) { var data = { action: 'remove', id: this.ignoredEntities[i] From 6f9593dabd4dc06b48faeb04f4d5d2869b21660a Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Mon, 8 Oct 2018 16:59:39 -0700 Subject: [PATCH 034/114] adding fix for far action grab --- .../controllerModules/farActionGrabEntity.js | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 2fe98ae673..4e9ce44d64 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -336,15 +336,6 @@ Script.include("/~/system/libraries/Xform.js"); if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web") || intersection.type === Picks.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) { return true; - } else if (intersection.type === Picks.INTERSECTED_ENTITY && !Window.isPhysicsEnabled()) { - // add to ignored items. - var data = { - action: 'add', - id: intersection.objectID - }; - Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); - this.ignoredEntities.push(intersection.objectID); - } return false; }; @@ -405,7 +396,6 @@ Script.include("/~/system/libraries/Xform.js"); this.isReady = function (controllerData) { if (HMD.active) { if (this.notPointingAtEntity(controllerData)) { - this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } @@ -417,17 +407,28 @@ Script.include("/~/system/libraries/Xform.js"); return makeRunningValues(true, [], []); } else { this.destroyContextOverlay(); - this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); } } - this.restoreIgnoredEntities(); return makeRunningValues(false, [], []); }; this.run = function (controllerData) { + + var intersection = controllerData.rayPicks[this.hand]; + if (intersection.type === Picks.INTERSECTED_ENTITY && !Window.isPhysicsEnabled()) { + // add to ignored items. + if (this.ignoredEntities.indexOf(intersection.objectID) === -1) { + var data = { + action: 'add', + id: intersection.objectID + }; + Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); + this.ignoredEntities.push(intersection.objectID); + } + } if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || - this.notPointingAtEntity(controllerData) || this.targetIsNull()) { + (this.notPointingAtEntity(controllerData) && Window.isPhysicsEnabled()) || this.targetIsNull()) { this.endFarGrabAction(); Selection.removeFromSelectedItemsList(DISPATCHER_HOVERING_LIST, "entity", this.highlightedEntity); From 296ea8a5af821e5f8bfeaac3e85c6eb002813189 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 10 Oct 2018 12:00:58 -0700 Subject: [PATCH 035/114] fix overlay issues during interstitial mode --- .../controllerModules/webSurfaceLaserInput.js | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 2412e2fa1c..cf61693dfd 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -20,6 +20,7 @@ Script.include("/~/system/libraries/controllers.js"); this.hand = hand; this.otherHand = this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND; this.running = false; + this.ignoredOverlays = []; this.parameters = makeDispatcherModuleParameters( 160, @@ -67,6 +68,42 @@ Script.include("/~/system/libraries/controllers.js"); return this.hand === RIGHT_HAND ? leftOverlayLaserInput : rightOverlayLaserInput; }; + this.addOverlayToIgnoreList = function(controllerData) { + if (Window.interstitialModeEnabled && !Window.isPhysicsEnabled()) { + var intersection = controllerData.rayPicks[this.hand]; + var objectID = intersection.objectID; + + if (intersection.type === Picks.INTERSECTED_OVERLAY) { + var overlayIndex = this.ignoredOverlays.indexOf(objectID); + + if (overlayIndex === -1) { + var overlayName = Overlays.getProperty(objectID, "name"); + if (overlayName !== "Loading-Destination-Card-Text" && overlayName !== "Loading-Destination-Card-GoTo-Image" && + overlayName !== "Loading-Destination-Card-GoTo-Image-Hover") { + var data = { + action: 'add', + id: objectID + }; + Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); + this.ignoredOverlays.push(objectID); + } + } + } + } + }; + + this.restoreIgnoredOverlays = function() { + for (var index = 0; index < this.ignoredOverlays.length; index++) { + var data = { + action: 'remove', + id: this.ignoredOverlays[index] + }; + Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); + } + + this.ignoredOverlays = []; + }; + this.isPointingAtTriggerable = function(controllerData, triggerPressed, checkEntitiesOnly) { // allow pointing at tablet, unlocked web entities, or web overlays automatically without pressing trigger, // but for pointing at locked web entities or non-web overlays user must be pressing trigger @@ -143,6 +180,7 @@ Script.include("/~/system/libraries/controllers.js"); var allowThisModule = !otherModuleRunning && !grabModuleNeedsToRun; var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE; var laserOn = isTriggerPressed || this.parameters.handLaser.allwaysOn; + this.addOverlayToIgnoreList(controllerData); if (allowThisModule) { if (isTriggerPressed && !this.isPointingAtTriggerable(controllerData, isTriggerPressed, true)) { // if trigger is down + not pointing at a web entity, keep running web surface laser @@ -156,6 +194,7 @@ Script.include("/~/system/libraries/controllers.js"); this.deleteContextOverlay(); this.running = false; this.dominantHandOverride = false; + this.restoreIgnoredOverlays(); return makeRunningValues(false, [], []); } } @@ -163,6 +202,7 @@ Script.include("/~/system/libraries/controllers.js"); this.deleteContextOverlay(); this.running = false; this.dominantHandOverride = false; + this.restoreIgnoredOverlays(); return makeRunningValues(false, [], []); }; } From a47a1c03e6b68492003aac9c3aa237bbc40dc6c3 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 10 Oct 2018 14:08:47 -0700 Subject: [PATCH 036/114] ignore web entities --- .../controllerModules/webSurfaceLaserInput.js | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index cf61693dfd..898164dc99 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -20,7 +20,7 @@ Script.include("/~/system/libraries/controllers.js"); this.hand = hand; this.otherHand = this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND; this.running = false; - this.ignoredOverlays = []; + this.ignoredObjects = []; this.parameters = makeDispatcherModuleParameters( 160, @@ -68,35 +68,43 @@ Script.include("/~/system/libraries/controllers.js"); return this.hand === RIGHT_HAND ? leftOverlayLaserInput : rightOverlayLaserInput; }; - this.addOverlayToIgnoreList = function(controllerData) { + this.addObjectToIgnoreList = function(controllerData) { if (Window.interstitialModeEnabled && !Window.isPhysicsEnabled()) { var intersection = controllerData.rayPicks[this.hand]; var objectID = intersection.objectID; if (intersection.type === Picks.INTERSECTED_OVERLAY) { - var overlayIndex = this.ignoredOverlays.indexOf(objectID); + var overlayIndex = this.ignoredObjects.indexOf(objectID); - if (overlayIndex === -1) { - var overlayName = Overlays.getProperty(objectID, "name"); - if (overlayName !== "Loading-Destination-Card-Text" && overlayName !== "Loading-Destination-Card-GoTo-Image" && - overlayName !== "Loading-Destination-Card-GoTo-Image-Hover") { - var data = { - action: 'add', - id: objectID - }; - Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); - this.ignoredOverlays.push(objectID); - } + var overlayName = Overlays.getProperty(objectID, "name"); + if (overlayName !== "Loading-Destination-Card-Text" && overlayName !== "Loading-Destination-Card-GoTo-Image" && + overlayName !== "Loading-Destination-Card-GoTo-Image-Hover") { + var data = { + action: 'add', + id: objectID + }; + Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); + this.ignoredObjects.push(objectID); } + } else if (intersection.type === Picks.INTERSECTED_ENTITY) { + var entityIndex = this.ignoredObjects.indexOf(objectID); + var data = { + action: 'add', + id: objectID + }; + print("ignoreing entity " + entityIndex); + Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); + this.ignoredObjects.push(objectID); } } }; - this.restoreIgnoredOverlays = function() { - for (var index = 0; index < this.ignoredOverlays.length; index++) { + this.restoreIgnoredObjects = function() { + for (var index = 0; index < this.ignoredObjects.length; index++) { + print("removing"); var data = { action: 'remove', - id: this.ignoredOverlays[index] + id: this.ignoredObjects[index] }; Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); } @@ -168,6 +176,10 @@ Script.include("/~/system/libraries/controllers.js"); return makeRunningValues(true, [], []); } } + + if (Window.interstitialModeEnabled && Window.isPhysicsEnabled()) { + this.restoreIgnoredObjects(); + } return makeRunningValues(false, [], []); }; @@ -180,7 +192,7 @@ Script.include("/~/system/libraries/controllers.js"); var allowThisModule = !otherModuleRunning && !grabModuleNeedsToRun; var isTriggerPressed = controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE; var laserOn = isTriggerPressed || this.parameters.handLaser.allwaysOn; - this.addOverlayToIgnoreList(controllerData); + this.addObjectToIgnoreList(controllerData); if (allowThisModule) { if (isTriggerPressed && !this.isPointingAtTriggerable(controllerData, isTriggerPressed, true)) { // if trigger is down + not pointing at a web entity, keep running web surface laser @@ -194,7 +206,6 @@ Script.include("/~/system/libraries/controllers.js"); this.deleteContextOverlay(); this.running = false; this.dominantHandOverride = false; - this.restoreIgnoredOverlays(); return makeRunningValues(false, [], []); } } @@ -202,7 +213,6 @@ Script.include("/~/system/libraries/controllers.js"); this.deleteContextOverlay(); this.running = false; this.dominantHandOverride = false; - this.restoreIgnoredOverlays(); return makeRunningValues(false, [], []); }; } From be8f4256c3478094805b8142a4461a8a0ceb1ce3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 28 Sep 2017 16:45:39 -0700 Subject: [PATCH 037/114] Add ccache support for Linux and Mac --- cmake/compiler.cmake | 4 +++ cmake/macros/ConfigureCCache.cmake | 45 ++++++++++++++++++++++++++++++ cmake/templates/launch-c.in | 12 ++++++++ cmake/templates/launch-cxx.in | 12 ++++++++ 4 files changed, 73 insertions(+) create mode 100644 cmake/macros/ConfigureCCache.cmake create mode 100644 cmake/templates/launch-c.in create mode 100644 cmake/templates/launch-cxx.in diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake index 6ff6fce1d8..927871773d 100644 --- a/cmake/compiler.cmake +++ b/cmake/compiler.cmake @@ -6,6 +6,10 @@ if (NOT "${CMAKE_SIZEOF_VOID_P}" EQUAL "8") message( FATAL_ERROR "Only 64 bit builds supported." ) endif() +if (USE_CCACHE OR "$ENV{USE_CCACHE}") + configure_ccache() +endif() + if (WIN32) add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS) diff --git a/cmake/macros/ConfigureCCache.cmake b/cmake/macros/ConfigureCCache.cmake new file mode 100644 index 0000000000..6107faaa21 --- /dev/null +++ b/cmake/macros/ConfigureCCache.cmake @@ -0,0 +1,45 @@ +# +# ConfigureCCache.cmake +# cmake/macros +# +# Created by Clement Brisset on 10/10/18. +# Copyright 2018 High Fidelity, Inc. +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http:#www.apache.org/licenses/LICENSE-2.0.html +# + +macro(configure_ccache) + find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) + message(STATUS "Configuring ccache") + + # Set up wrapper scripts + set(C_LAUNCHER "${CCACHE_PROGRAM}") + set(CXX_LAUNCHER "${CCACHE_PROGRAM}") + + set(LAUNCH_C_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/launch-c.in") + set(LAUNCH_CXX_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/launch-cxx.in") + set(LAUNCH_C "${CMAKE_BINARY_DIR}/CMakeFiles/launch-c") + set(LAUNCH_CXX "${CMAKE_BINARY_DIR}/CMakeFiles/launch-cxx") + + configure_file(${LAUNCH_C_IN} ${LAUNCH_C}) + configure_file(${LAUNCH_CXX_IN} ${LAUNCH_CXX}) + execute_process(COMMAND chmod a+rx ${LAUNCH_C} ${LAUNCH_CXX}) + + if(CMAKE_GENERATOR STREQUAL "Xcode") + # Set Xcode project attributes to route compilation and linking + # through our scripts + set(CMAKE_XCODE_ATTRIBUTE_CC ${LAUNCH_C}) + set(CMAKE_XCODE_ATTRIBUTE_CXX ${LAUNCH_CXX}) + set(CMAKE_XCODE_ATTRIBUTE_LD ${LAUNCH_C}) + set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS ${LAUNCH_CXX}) + else() + # Support Unix Makefiles and Ninja + set(CMAKE_C_COMPILER_LAUNCHER ${LAUNCH_C}) + set(CMAKE_CXX_COMPILER_LAUNCHER ${LAUNCH_CXX}) + endif() + else() + message(WARNING "Could not find ccache") + endif() +endmacro() diff --git a/cmake/templates/launch-c.in b/cmake/templates/launch-c.in new file mode 100644 index 0000000000..6c91d96dd9 --- /dev/null +++ b/cmake/templates/launch-c.in @@ -0,0 +1,12 @@ +#!/bin/sh + +# Xcode generator doesn't include the compiler as the +# first argument, Ninja and Makefiles do. Handle both cases. +if [[ "$1" = "${CMAKE_C_COMPILER}" ]] ; then + shift +fi + +export CCACHE_CPP2=true +export CCACHE_HARDLINK=true +export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches +exec "${C_LAUNCHER}" "${CMAKE_C_COMPILER}" "$@" diff --git a/cmake/templates/launch-cxx.in b/cmake/templates/launch-cxx.in new file mode 100644 index 0000000000..4215d89c80 --- /dev/null +++ b/cmake/templates/launch-cxx.in @@ -0,0 +1,12 @@ +#!/bin/sh + +# Xcode generator doesn't include the compiler as the +# first argument, Ninja and Makefiles do. Handle both cases. +if [[ "$1" = "${CMAKE_CXX_COMPILER}" ]] ; then + shift +fi + +export CCACHE_CPP2=true +export CCACHE_HARDLINK=true +export CCACHE_SLOPPINESS=file_macro,time_macros,include_file_mtime,include_file_ctime,file_stat_matches +exec "${CXX_LAUNCHER}" "${CMAKE_CXX_COMPILER}" "$@" From 5faf26abd104b0db6d4539b5e074aee4f201bf82 Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 11 Oct 2018 10:38:59 -0700 Subject: [PATCH 038/114] turned off shoulder rotation when we don't have hmd lean recentering on. this temporarily fixes the behavior of the shoulders in this mode. todo: use the spine2 position to determine azimuth of hands, then they will work in all conditions --- interface/src/avatar/MyAvatar.cpp | 7 +++++++ interface/src/avatar/MySkeletonModel.cpp | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1f38971ab4..77c66d062f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -591,8 +591,15 @@ void MyAvatar::update(float deltaTime) { // draw hand azimuth vector glm::vec3 handAzimuthMidpoint = transformPoint(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); + + } + // temp: draw spine 2 position for hand azimuth purposes. + int spine2Index = getJointIndex("Spine2"); + glm::vec3 spine2WorldPosition = transformPoint(getTransform().getMatrix(), getAbsoluteJointTranslationInObjectFrame(spine2Index)); + DebugDraw::getInstance().addMarker("spine2 location", Quaternions::IDENTITY, spine2WorldPosition, glm::vec4(1)); + if (_goToPending) { setWorldPosition(_goToPosition); setWorldOrientation(_goToOrientation); diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 42ec582c47..1f97ce03f8 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -239,7 +239,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; // set spine2 if we have hand controllers - if (myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && + if (myAvatar->getHMDLeanRecenterEnabled() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { @@ -250,6 +250,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { bool headExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Head"), currentHeadPose); bool hipsExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Hips"), currentHipsPose); if (spine2Exists && headExists && hipsExists) { + // qCDebug(interfaceapp) << "hips forward direction "<< (currentHipsPose.rot() * glm::vec3(0.0f, 0.0f, 1.0f)); AnimPose rigSpaceYaw(myAvatar->getSpine2RotationRigSpace()); glm::vec3 u, v, w; glm::vec3 fwd = rigSpaceYaw.rot() * glm::vec3(0.0f, 0.0f, 1.0f); From 451142f9a3e15d555a7318a469298d88b1153355 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 11 Oct 2018 11:33:19 -0700 Subject: [PATCH 039/114] fixing some more interstittial issues --- scripts/system/controllers/controllerModules/teleport.js | 4 ++++ scripts/system/interstitialPage.js | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index bf5022cdaf..bccdd9007c 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -701,6 +701,10 @@ Script.include("/~/system/libraries/controllers.js"); }; this.isReady = function(controllerData, deltaTime) { + if (Window.interstitialModeEnabled && !Window.isPhysicsEnabled()) { + return makeRunningValues(false, [], []); + } + var otherModule = this.getOtherModule(); if (!this.disabled && this.buttonValue !== 0 && !otherModule.active) { this.active = true; diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index 19e603b4ab..040128ffcf 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -545,7 +545,11 @@ MyAvatar.sensorToWorldScaleChanged.connect(scaleInterstitialPage); MyAvatar.sessionUUIDChanged.connect(function() { var avatarSessionUUID = MyAvatar.sessionUUID; - Overlays.editOverlay(loadingSphereID, { parentID: avatarSessionUUID }); + Overlays.editOverlay(loadingSphereID, { + position: Vec3.sum(Vec3.sum(MyAvatar.position, {x: 0.0, y: -1.0, z: 0.0}), Vec3.multiplyQbyV(MyAvatar.orientation, {x: 0, y: 0.95, z: 0})), + orientation: Quat.multiply(Quat.fromVec3Degrees({x: 0, y: 180, z: 0}), MyAvatar.orientation), + parentID: avatarSessionUUID + }); }); var toggle = true; From f73d974ad77b62a41b4d540e60b1cc1c584db98f Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 11 Oct 2018 15:14:04 -0700 Subject: [PATCH 040/114] added a lock state so you can lock sit or stand state, also made the hand azimuth relative to the spine2 location in avatar space. This stops the arms from behaving badly when the hands are in front of the chest but behind the root position of the avatar --- interface/src/avatar/MyAvatar.cpp | 119 ++++++++++++++--------- interface/src/avatar/MyAvatar.h | 1 + interface/src/avatar/MySkeletonModel.cpp | 3 +- 3 files changed, 75 insertions(+), 48 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 77c66d062f..6b4459e97c 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -531,52 +531,57 @@ void MyAvatar::update(float deltaTime) { glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); // put update sit stand state counts here - if (getIsInSittingState()) { - if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + if (!_lockSitStandState) { + if (getIsInSittingState()) { + if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setResetMode(true); + setIsInSittingState(false); + setCenterOfGravityModelEnabled(true); + setSitStandStateChange(true); } - _averageUserHeightCount = 1; - setResetMode(true); - setIsInSittingState(false); - setCenterOfGravityModelEnabled(true); - setSitStandStateChange(true); + qCDebug(interfaceapp) << "going to stand state"; + } else { + _sitStandStateCount = 0; + // tipping point is average height when sitting. + _tippingPoint = averageSensorSpaceHeight; } } else { - _sitStandStateCount = 0; - // tipping point is average height when sitting. - _tippingPoint = averageSensorSpaceHeight; - } - } else { - // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - setResetMode(true); - setIsInSittingState(true); - setCenterOfGravityModelEnabled(false); - setSitStandStateChange(true); - } - } else { - // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; - } + // in the standing state + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setResetMode(true); + setIsInSittingState(true); + setCenterOfGravityModelEnabled(false); + setSitStandStateChange(true); + } + qCDebug(interfaceapp) << "going to sit state"; + } else { + // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; + } + + } } @@ -939,6 +944,15 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { // Find the vector halfway between the hip to hand azimuth vectors // This midpoint hand azimuth is in Avatar space glm::vec2 MyAvatar::computeHandAzimuth() const { + int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); + glm::vec3 azimuthOrigin(0.0f,0.0f,0.0f); + if (!(spine2Index < 0)) { + // use the spine for the azimuth origin. + azimuthOrigin = getAbsoluteJointTranslationInObjectFrame(spine2Index); + } else { + // use the avatar root as the azimuth origin. + } + controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD); @@ -946,11 +960,13 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { glm::vec2 latestHipToHandController = _hipToHandController; if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid()) { + glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - azimuthOrigin; + glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - azimuthOrigin; // we need the old azimuth reading to prevent flipping the facing direction 180 // in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart. glm::vec2 oldAzimuthReading = _hipToHandController; - if ((glm::length(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)) > 0.0f) && (glm::length(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)) > 0.0f)) { - latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)), glm::normalize(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)), HALFWAY); + if ((glm::length(glm::vec2(rightHandOffset.x, rightHandOffset.z)) > 0.0f) && (glm::length(glm::vec2(leftHandOffset.x, leftHandOffset.z)) > 0.0f)) { + latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandOffset.x, rightHandOffset.z)), glm::normalize(glm::vec2(leftHandOffset.x, leftHandOffset.z)), HALFWAY); } else { latestHipToHandController = glm::vec2(0.0f, -1.0f); } @@ -4134,21 +4150,29 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const int SQUATTY_COUNT_THRESHOLD = 600; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); + bool returnValue = false; + returnValue = (offset.y > CYLINDER_TOP);// || (offset.y < CYLINDER_BOTTOM); + if (myAvatar.getSitStandStateChange()) { + qCDebug(interfaceapp) << "sit state change"; returnValue = true; } if (myAvatar.getIsInSittingState()) { if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. + qCDebug(interfaceapp) << "lean back sitting "; returnValue = true; } } else { // in the standing state - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { myAvatar._squatCount = 0; - returnValue = true; + qCDebug(interfaceapp) << "squatting "; + // returnValue = true; + } + if (returnValue == true) { + qCDebug(interfaceapp) << "above or below capsule in standing"; } } return returnValue; @@ -4182,7 +4206,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - + if (_velocityCount > 60) { if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); @@ -4192,6 +4216,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat _velocityCount++; } } + } else { if (!isActive(Rotation) && getForceActivateRotation()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f268a05a15..f026f39493 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1824,6 +1824,7 @@ private: float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; int _averageUserHeightCount{ 1 }; bool _sitStandStateChange{ false }; + bool _lockSitStandState { true }; // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 1f97ce03f8..ce8fefa0c5 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -239,7 +239,8 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; // set spine2 if we have hand controllers - if (myAvatar->getHMDLeanRecenterEnabled() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && + // myAvatar->getHMDLeanRecenterEnabled() && + if (myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { From 1bcbda7ad6454988e4fba25c2e1f389109ba701d Mon Sep 17 00:00:00 2001 From: Clement Date: Thu, 11 Oct 2018 16:16:24 -0700 Subject: [PATCH 041/114] Prevent race on internal client traits members --- assignment-client/src/Agent.h | 1 - interface/src/avatar/MyAvatar.cpp | 1 + interface/src/avatar/MyAvatar.h | 1 - libraries/avatars/src/ClientTraitsHandler.cpp | 23 +++++++++++++++++++ libraries/avatars/src/ClientTraitsHandler.h | 19 +++++++-------- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 2b5ff51b49..7d47c8e713 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -21,7 +21,6 @@ #include #include -#include #include #include #include diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b347963cf1..5418410dd4 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 16b765711a..c99fd3bce6 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/libraries/avatars/src/ClientTraitsHandler.cpp b/libraries/avatars/src/ClientTraitsHandler.cpp index a06b53da7c..f8247d9e52 100644 --- a/libraries/avatars/src/ClientTraitsHandler.cpp +++ b/libraries/avatars/src/ClientTraitsHandler.cpp @@ -31,7 +31,27 @@ ClientTraitsHandler::ClientTraitsHandler(AvatarData* owningAvatar) : nodeList->getPacketReceiver().registerListener(PacketType::SetAvatarTraits, this, "processTraitOverride"); } +void ClientTraitsHandler::markTraitUpdated(AvatarTraits::TraitType updatedTrait) { + Lock lock(_traitLock); + _traitStatuses[updatedTrait] = Updated; + _hasChangedTraits = true; +} + +void ClientTraitsHandler::markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID) { + Lock lock(_traitLock); + _traitStatuses.instanceInsert(traitType, updatedInstanceID, Updated); + _hasChangedTraits = true; +} + +void ClientTraitsHandler::markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID) { + Lock lock(_traitLock); + _traitStatuses.instanceInsert(traitType, deleteInstanceID, Deleted); + _hasChangedTraits = true; +} + void ClientTraitsHandler::resetForNewMixer() { + Lock lock(_traitLock); + // re-set the current version to 0 _currentTraitVersion = AvatarTraits::DEFAULT_TRAIT_VERSION; @@ -46,6 +66,8 @@ void ClientTraitsHandler::resetForNewMixer() { } void ClientTraitsHandler::sendChangedTraitsToMixer() { + Lock lock(_traitLock); + if (hasChangedTraits() || _shouldPerformInitialSend) { // we have at least one changed trait to send @@ -113,6 +135,7 @@ void ClientTraitsHandler::sendChangedTraitsToMixer() { void ClientTraitsHandler::processTraitOverride(QSharedPointer message, SharedNodePointer sendingNode) { if (sendingNode->getType() == NodeType::AvatarMixer) { + Lock lock(_traitLock); while (message->getBytesLeftToRead()) { AvatarTraits::TraitType traitType; message->readPrimitive(&traitType); diff --git a/libraries/avatars/src/ClientTraitsHandler.h b/libraries/avatars/src/ClientTraitsHandler.h index 27ba58d46b..3900268101 100644 --- a/libraries/avatars/src/ClientTraitsHandler.h +++ b/libraries/avatars/src/ClientTraitsHandler.h @@ -26,14 +26,11 @@ public: void sendChangedTraitsToMixer(); - bool hasChangedTraits() { return _hasChangedTraits; } + bool hasChangedTraits() const { return _hasChangedTraits; } - void markTraitUpdated(AvatarTraits::TraitType updatedTrait) - { _traitStatuses[updatedTrait] = Updated; _hasChangedTraits = true; } - void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID) - { _traitStatuses.instanceInsert(traitType, updatedInstanceID, Updated); _hasChangedTraits = true; } - void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID) - { _traitStatuses.instanceInsert(traitType, deleteInstanceID, Deleted); _hasChangedTraits = true; } + void markTraitUpdated(AvatarTraits::TraitType updatedTrait); + void markInstancedTraitUpdated(AvatarTraits::TraitType traitType, QUuid updatedInstanceID); + void markInstancedTraitDeleted(AvatarTraits::TraitType traitType, QUuid deleteInstanceID); void resetForNewMixer(); @@ -41,17 +38,21 @@ public slots: void processTraitOverride(QSharedPointer message, SharedNodePointer sendingNode); private: + using Mutex = std::recursive_mutex; + using Lock = std::lock_guard; + enum ClientTraitStatus { Unchanged, Updated, Deleted }; - AvatarData* _owningAvatar; + AvatarData* const _owningAvatar; + Mutex _traitLock; AvatarTraits::AssociatedTraitValues _traitStatuses; - AvatarTraits::TraitVersion _currentTraitVersion { AvatarTraits::DEFAULT_TRAIT_VERSION }; + AvatarTraits::TraitVersion _currentTraitVersion { AvatarTraits::DEFAULT_TRAIT_VERSION }; AvatarTraits::TraitVersion _currentSkeletonVersion { AvatarTraits::NULL_TRAIT_VERSION }; bool _shouldPerformInitialSend { false }; From a6339bbe859a00a0406b83be62d5b09522f8a3fa Mon Sep 17 00:00:00 2001 From: Liv Erickson Date: Thu, 11 Oct 2018 17:26:05 -0700 Subject: [PATCH 042/114] bug fix and new menu content --- cmake/externals/serverless-content/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/externals/serverless-content/CMakeLists.txt b/cmake/externals/serverless-content/CMakeLists.txt index 12e2b7a4c6..8bb49f0973 100644 --- a/cmake/externals/serverless-content/CMakeLists.txt +++ b/cmake/externals/serverless-content/CMakeLists.txt @@ -4,8 +4,8 @@ set(EXTERNAL_NAME serverless-content) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC73.zip - URL_MD5 0c5edfb63cafb042311d3cf25261fbf2 + URL http://cdn.highfidelity.com/content-sets/serverless-tutorial-RC75.zip + URL_MD5 b4225d058952e17976ac228330ce8d51 CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" From 67afc862224dcb753acdf62b4a8d77f276806b8c Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 11 Oct 2018 18:39:44 -0700 Subject: [PATCH 043/114] cleanup --- interface/resources/qml/hifi/AvatarApp.qml | 1 + .../resources/qml/hifi/avatarapp/Settings.qml | 19 ++++++++++++ interface/src/avatar/MyAvatar.cpp | 29 +++++++++---------- interface/src/avatar/MyAvatar.h | 13 ++++++++- interface/src/avatar/MySkeletonModel.cpp | 3 +- scripts/system/avatarapp.js | 14 ++++++++- 6 files changed, 60 insertions(+), 19 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index b06a2ca67c..bf647b65bb 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -253,6 +253,7 @@ Rectangle { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, sittingEnabled : settings.avatarSittingOn, + lockStateEnabled : settings.avatarLockSitStandStateOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index c4289ca650..8749079940 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -21,6 +21,7 @@ Rectangle { property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked property alias avatarSittingOn: sitRadiobutton.checked + property alias avatarLockSitStandStateOn: lockSitStandStateCheckbox.checked property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -52,6 +53,12 @@ Rectangle { standRadioButton.checked = true; } + if (settings.lockStateEnabled) { + lockSitStandStateCheckbox.checked = true; + } else { + lockSitStandStateCheckbox.checked = false; + } + avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; @@ -343,6 +350,18 @@ Rectangle { text: "Stand" boxSize: 20 } + + // "Lock State" Checkbox + + HifiControlsUit.CheckBox { + id: lockSitStandStateCheckbox; + visible: activeTab == "nearbyTab"; + anchors.right: reloadNearbyContainer.left; + anchors.rightMargin: 20; + checked: settings.lockStateEnabled; + text: "lock"; + boxSize: 24; + } } ColumnLayout { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6b4459e97c..745705f7b8 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -531,7 +531,7 @@ void MyAvatar::update(float deltaTime) { glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); // put update sit stand state counts here - if (!_lockSitStandState) { + if (getIsSitStandStateLocked()) { if (getIsInSittingState()) { if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we recenter upwards then no longer in sitting state @@ -584,7 +584,6 @@ void MyAvatar::update(float deltaTime) { } } - if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); glm::vec3 worldHeadPos = transformPoint(getSensorToWorldMatrix(), sensorHeadPose.getTranslation()); @@ -595,16 +594,9 @@ void MyAvatar::update(float deltaTime) { // draw hand azimuth vector glm::vec3 handAzimuthMidpoint = transformPoint(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); - DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); - - + DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); } - // temp: draw spine 2 position for hand azimuth purposes. - int spine2Index = getJointIndex("Spine2"); - glm::vec3 spine2WorldPosition = transformPoint(getTransform().getMatrix(), getAbsoluteJointTranslationInObjectFrame(spine2Index)); - DebugDraw::getInstance().addMarker("spine2 location", Quaternions::IDENTITY, spine2WorldPosition, glm::vec4(1)); - if (_goToPending) { setWorldPosition(_goToPosition); setWorldOrientation(_goToOrientation); @@ -949,8 +941,6 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { if (!(spine2Index < 0)) { // use the spine for the azimuth origin. azimuthOrigin = getAbsoluteJointTranslationInObjectFrame(spine2Index); - } else { - // use the avatar root as the azimuth origin. } controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); @@ -3882,6 +3872,10 @@ bool MyAvatar::getIsInSittingState() const { return _isInSittingState.get(); } +bool MyAvatar::getIsSitStandStateLocked() const { + return _lockSitStandState.get(); +} + float MyAvatar::getWalkSpeed() const { return _walkSpeed.get() * _walkSpeedScalar; } @@ -3907,6 +3901,11 @@ void MyAvatar::setIsInSittingState(bool isSitting) { emit sittingEnabledChanged(isSitting); } +void MyAvatar::setIsSitStandStateLocked(bool isLocked) { + _lockSitStandState.set(isLocked); + emit sitStandStateLockEnabledChanged(isLocked); +} + void MyAvatar::setWalkSpeed(float value) { _walkSpeed.set(value); } @@ -4152,7 +4151,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); bool returnValue = false; - returnValue = (offset.y > CYLINDER_TOP);// || (offset.y < CYLINDER_BOTTOM); + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); if (myAvatar.getSitStandStateChange()) { qCDebug(interfaceapp) << "sit state change"; @@ -4206,7 +4205,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - + if (_velocityCount > 60) { if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); @@ -4216,7 +4215,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat _velocityCount++; } } - + } else { if (!isActive(Rotation) && getForceActivateRotation()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index f026f39493..674d4b8b70 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -244,6 +244,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed); Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed); Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState); + Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked); const QString DOMINANT_LEFT_HAND = "left"; const QString DOMINANT_RIGHT_HAND = "right"; @@ -1105,6 +1106,8 @@ public: bool getIsInWalkingState() const; void setIsInSittingState(bool isSitting); bool getIsInSittingState() const; + void setIsSitStandStateLocked(bool isLocked); + bool getIsSitStandStateLocked() const; void setWalkSpeed(float value); float getWalkSpeed() const; void setWalkBackwardSpeed(float value); @@ -1526,6 +1529,14 @@ signals: */ void sittingEnabledChanged(bool enabled); + /**jsdoc + * Triggered when the sit state is enabled or disabled + * @function MyAvatar.sitStandStateLockEnabledChanged + * @param {boolean} enabled + * @returns {Signal} + */ + void sitStandStateLockEnabledChanged(bool enabled); + private slots: void leaveDomain(); void updateCollisionCapsuleCache(); @@ -1824,7 +1835,7 @@ private: float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; int _averageUserHeightCount{ 1 }; bool _sitStandStateChange{ false }; - bool _lockSitStandState { true }; + ThreadSafeValueCache _lockSitStandState { true }; // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index ce8fefa0c5..78c5c03cc9 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -239,7 +239,6 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { params.primaryControllerFlags[Rig::PrimaryControllerType_Hips] = (uint8_t)Rig::ControllerFlags::Enabled | (uint8_t)Rig::ControllerFlags::Estimated; // set spine2 if we have hand controllers - // myAvatar->getHMDLeanRecenterEnabled() && if (myAvatar->getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid() && myAvatar->getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && !(params.primaryControllerFlags[Rig::PrimaryControllerType_Spine2] & (uint8_t)Rig::ControllerFlags::Enabled)) { @@ -251,7 +250,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { bool headExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Head"), currentHeadPose); bool hipsExists = _rig.getAbsoluteJointPoseInRigFrame(_rig.indexOfJoint("Hips"), currentHipsPose); if (spine2Exists && headExists && hipsExists) { - // qCDebug(interfaceapp) << "hips forward direction "<< (currentHipsPose.rot() * glm::vec3(0.0f, 0.0f, 1.0f)); + AnimPose rigSpaceYaw(myAvatar->getSpine2RotationRigSpace()); glm::vec3 u, v, w; glm::vec3 fwd = rigSpaceYaw.rot() * glm::vec3(0.0f, 0.0f, 1.0f); diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index faf624392a..4a25ab9551 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -64,7 +64,8 @@ function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), collisionsEnabled : MyAvatar.getCollisionsEnabled(), - sittingEnabled : MyAvatar.isInSittingState, + sittingEnabled: MyAvatar.isInSittingState, + lockStateEnabled: MyAvatar.isSitStandStateLocked, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -145,6 +146,14 @@ function onSittingEnabledChanged(isSitting) { } } +function onSitStandStateLockedEnabledChanged(isLocked) { + if (currentAvatarSettings.lockStateEnabled !== isLocked) { + currentAvatarSettings.lockStateEnabled = isLocked; + print("emit lock sit stand state changed"); + sendToQml({ 'method': 'settingChanged', 'name': 'lockStateEnabled', 'value': isLocked }) + } +} + function onNewCollisionSoundUrl(url) { if(currentAvatarSettings.collisionSoundUrl !== url) { currentAvatarSettings.collisionSoundUrl = url; @@ -324,6 +333,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); MyAvatar.isInSittingState = message.settings.sittingEnabled; + MyAvatar.isSitStandStateLocked = message.settings.lockStateEnabled; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); @@ -518,6 +528,7 @@ function off() { MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); MyAvatar.sittingEnabledChanged.disconnect(onSittingEnabledChanged); + MyAvatar.sitStandStateLockEnabledChanged.disconnect(onSitStandStateLockedEnabledChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -533,6 +544,7 @@ function on() { MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); MyAvatar.sittingEnabledChanged.connect(onSittingEnabledChanged); + MyAvatar.sitStandStateLockEnabledChanged.connect(onSitStandStateLockedEnabledChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From d7dc69129aed97cb6808101e504d92d5a478e6e7 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 12 Oct 2018 11:43:03 -0700 Subject: [PATCH 044/114] improve loading bar progress --- .../resources/sounds/crystals_and_voices.mp3 | Bin 0 -> 337547 bytes scripts/system/interstitialPage.js | 23 +++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 interface/resources/sounds/crystals_and_voices.mp3 diff --git a/interface/resources/sounds/crystals_and_voices.mp3 b/interface/resources/sounds/crystals_and_voices.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..b5bee31381639f66aaf6c2ba0724ea7fa9620268 GIT binary patch literal 337547 zcmeF2=UWrqyYD9?K!6ZJ57kf&J@kNx2_2+_rhup+6lu~Cu#wQ4NGBAP4k9QBs1z~u zu7DJ!NKp|G6$=&+=3G4cxA)oS4><3h@2hoXX4b4VpX>hK_ga}TH&TZJ0011h=6j0q~z=aDeHb*5Ngn z|8?Hs(Zg#w0S54Ydwm5w`k$T%Kmb4n$p6pr|9!3)PzZR?6D;085=xj_D4v=7v z*J0%i5eRP@h_dqfvb1#N^XJd&NoSsjln?*_fZ6PGGXW49jrK%efb~T_YZrrnf+4Rr zTs;DV0E9IR3<6v|!ungED|VTR`2vF9!R5pnV$c&-*wFWGK@IPDBc%n-Mby3aCk+4u zo|KgSWt|EDWHOl?uzRe%z5Nb1H#av3f?xy+gMuOX4tqthc5Pohk=(U?6%_%3`O#nu z0H7|j@btiq{AfuNyDUtWHNr%6iJK)n6@xe)i$S8v9vV)xxCW$@9RteL2%&Y2DhFA! zzO-8xHT^E>y<>J!<)(q997;`7@`j{h+sQY(vbX1m_Z_bUQe1xEQduJPi{Ypt7m4N*F$20IEv*zE`IfrR;^S zR-JM^d{qCX?dRRgU8T*41v4hr4Bdt&%)n|6Gjo?G!GjzA!z7JGoWA`qzGUm*=f@7t>DPYaC7p<+aZX`o6i9 z7V`8%yYCmDp;j*=RZjinlZ)rqj^0{)^)}NK=@~ll{5GY~y(#*?2Lt|XmgQroGf^(6 z3AGxS=n~+B1S3B5)vKsW##)jvxcxDUh;wkx@2Bnwk`yA6UNuGc{SxM>LavP_5V~$F zvT?oOr(h`dz)gy!NCQ zKbtt4vq;=j;!&8k(73##7&XT~4yW|j8zbRK|0X=mP(RY>u3CKEs9_zBJi-*mmG2(- zYa#0ll-(xq;ImeacfF$=zgFQ7&e{7@MfN91r`g#lI_naQ3&Byz;|U>9^un@R88M0J zkPrfZ#)x*s7Pyd(#|#FALh%Uc^KhikQHV6V8*NN_nG*+eHFHGPzOx^Ee*we&x3fd$ zU^hx%xT4eHAw%1{I6F~$uRLAZUY=GueXC-cl05B1FLt)*d?ek_B<}Nmh6L}!ri{~R zoJZ_m7`tq~kh^R4Yu2T=d~pUwKZ1_0`YtO)amGxik`(UXrwkF-n`^?u0VHSlGnKlTXR8d!bx6krr zy5)%IB5m z;SN8w;`I|gO({SA;;>^%l|jW%?mj3XME-r5?T~B6UWEkE8hDfgKK7L=H|(p&7Wt8| z`lYDvw{xF8{}Qhd5}qKvB)b04&ujRIi^vH&*mCR9gY)YX_rS-2AlCWDs8@HeL*p&p zHO`jo6P8!Kfh2fVgT$l^JZ!r@5IWWsL_NyupNG7kJOdnv#5WAi|3M+o*!Qtig$ zsDY_zoztC{=fsao{94$UsvGvUs@_(#7acq)bV>qk#t&o=YIfNiIu+=>Qxe{D$sAm< z2k3ia+ENYZoBRzn!cA4jj*i|-klounuW}Of8gP9a(OC$B=N^5U-U92PPC;kRg?0?h z6jYsTrpM`fZqreGiZzz8t)UgBy$uj*aRc=$gsY;yTF+jszRU4SytbdeTAGY&`AGTL zuS*l{-?N)ChfNiACz;QZdQzsuTJ3&!r(?@6)*mYxy5$yyxtu!Cknju$>#MtYt*}P5 z_v#JRv==5ga}kn;yBjU$*hzPYj&ObulDg;s0BcqhS?>F2TH=o-2xXeQ8;sc*(SoPR&T)CgbOL%elOyx{K$b%~j zhlErCsGeANY~f|niEeLds5zb!5ei4X-yjO5Q;1^{*b6f|gQR3iEZxQ7607QyLa!4x zVt9;u#x{0vd+i-^*qR5`Igt2b*f9I_(hVtXP0K6l&3*O;Ok`N4M_AHzU|pJ6T3xPdyoF=z78A8ffBlyh|U^k%pX|#ML&CV>(QytdYu9(ukFh<_f*d4 z*u7;pPnS5M6AJJ5EYE@x;`!zYVSjE>5v-zK7>uCvGWM8#fBNZ9>P7d!%PX>2)~2`Y zPnAzUYj3=LFZKMxr9qT(PDkL0wHzoARb0}IFDRRqFe zrQl%=5ka8{q|XKsl1?FxwqR?t$BsooBm`qrX1)l1Uq?{>ZBH4E_EQvI_k>(yc)!F-8$F{85{u$PTDdHGJj7 z;s$S9)?oO$vg1PaMkQ-LGu2dEP%0 z=yel3Xqi3#XD@sT#GwMPa~ZtHdn|4BG_cKBBWZXV(|lu$1S7U~l4jg9hShaYdd^yK zSNwA*7{70>IBsiGw=eBexl3e-hR}w) zV-7sNvR@EZPTqnl7FSLU{EUl6EaQ(C?FO8d`FJ0$scS*Sq(IfpKB>$0YGh8S!w(6a z0iY(L-LY+#NqSIvNhsXHDkGR3xsgodODiKT>MbLH%qlTpO&S*ePFMW~E)kmnu=9@M zfK@C;P%>DF6|i|U<~;J*p3##r(SHnqD*lvs{Y8KA)2kb0AC6_y>0(i{E7j9-RSSLl zOV(vq#;p9y8b&^TaTh;fK@UoT;2bS91z@xloV^uAxJtuwIb_@8Iramsz_dm$LRsYf{OP_0OP91E}7frC2Z z1kTBiBcX~LCJ6*RWlJo%`*T=cvSQ>p*|>xt7jj*P!_(MzD)T~XV*WwB+r-P6ro7Ez z%{tsYrk4><94d?39A^r~%nGlabKekKpEiwndhN`Kh4!a%(R81f7m22W=sBDx+s2cg z1cXXqM)&(O<7N*P1#XwaEyTT7ApC84=rZST176j>MQcuR$ldy<()$m@uLio$_*vte zM({&bYK!aYm;BVPy5X8daERl=ddoc~7@b_^c1yB(YDR-HUXLAliXIi9XB~G?dq^mN z3MGgdLfgAZCk*iop*DESv|t4C(*_ZRq|ip|v2T`mz)7qS8uPjEo>pV=>V48<4ehSD zP@{;-zEjyhcWY-}^4u{_f8F#a=kl{H2VWjC&S&!Tfc}+&Nh1pJYjSLyIj$x*IbL0$ zh&|y+GN8*Aqn24rtrl}mI%YSrMDQH?NoD$K-`WwHdsh3!F`J)DPM*o)Zf+}|+gZK7 z++tG;wF}ae_dvCJXDoYs7iIR>cXBt$MA@q8tig|;V)>(k`@!`j;RLR1w%q$;aHYs~ zv~0h0kM5gbdNAf;JA0>m?o(!qiKzqdGhRVgkSqPl{Q;t_2kw4=z!TD{R@;2A*rvP z1?8m{jzk~iE*mh@;r>Dyx#(maAy#prVo|h_c7ZrwJP;PH_UX8IWTgaC4q6f?Kq92K z1$56Cl?JbE*k0vU0CP-BV&G=kHM`~MjHCr4Y~=d*fR)(egPY%S1=L-@5Bnm~;31)S zDpW+Y=P(bMOGRdcs^AeG)kx&K4H`O~LR%=s-rL^=Pd*%sgT9U{>tdWtPDyD^?kb>C zR^o}OGyv+PYAHV^Jk;S$p^EsWWv6yUwG+^rlq+q}07aU_*CR@~@LZzC`BJv{IIBJXA3p#21MuOC z+Vpz-zL(i~RUy8SnOHsR8{(|E$f-V}gj;WkL-u`bLD@<*JmrjH#PN9R$HJECw;I2b zZ(ZJ&xj#SZs-`hp6J8)u>a*{7acayN*p~KfXYx2(;~RqX#is#g2xBhGcqVfiBNnpB z@yNuRDrH2GX0)4A6A9fVQ|mI}FMI6Tu4zd>+Rv9b&K0u%yJ`9++AXM09lq;6<9GF> z4@#pwueFr4OhHwslt){vHb-xkMh<{Y)*CRXKR3#q`z)gJD8Y#s2u-@i0gyW+R6vEg ziuOR;FO!ViYf3^DEI8@W|HKgQ4N2O9;&RVGn&@#(`!u8gF?Nn>7G6a2p(kmWfzEsd zXHrbOet{7OF&_o-;nBOg>)=6&z3n(ajzV=_&~^0EZA{4JHbLg~3qh+S*f=9wOjDTp zMYz+8WLqH(l#R6bL5bG&LeHkNS`7~hO|Op8n&bU~qmx_Fey`}E{>tce@6|UY16R&H z-9aCGH~<4*zWQQ%`qRE$UXtMX0$8nEvP7D6Y4>+_zR}w}b`B;inHT4tGbKpIRi$-j z1XcdwG9znwOdbExvwmholVHyO;m4QIeUry6k{{aaOr9Nl0e=X_88D+2*^Bhv7M&)c z6SRt)lv`y5QL+N86@UrcA=GfV9GOdGj)!4PMQh0ASr7o`+G?SFE&);XDWqPFa38un zUML^@LCCDWz^sVZi$g(@X7}=5{vQ!zf83WQ@Zi?p4y)^B9Xl(UNJkA4hd-yXk_MM<3l+LbdM zO)tx43Eu>@8ovt|*8DQQ!!GFhp+)Y+Tk-zr$p>I%U8OB8w`%)Ffg4^lMx7eei22Cr4e|v_$hERaD0AikPrd(6o%1<)w}C*C79qpU&#%7Wa!#epm-gvxN9Cjt&cor?`IW6igy!j2nTr5IIYE zAb-&EsoBH0QReC% z(j~EUG{4assD$p-olKwCF?yu>ztX(cV-#LgTQp4-i77uqabk~aBy+zgNcxpsyF zod#JpFUM;%bioD4Qd7ZnToBF9lS9`pa+I8fmykh}K+-VwQd>QRew%1!`BA0~)4m+8 z0KYD4%_qLo( zzje)BuBC!%1GlrJ1RxT~rOyMfw?3By8{cG0Y1& z#h7VW9fxKV&u9XKk3S|6${zQ|M>FKfmGL*#9^47P z4uW8r#%|Wp^l4=+Y+P8c-UEJd^s2;Ki5noHeA9QB$4Uf)%60FNsRu^wldhj;vq7H! zrCEFvB6{qRW0fc*wWSne)SHhxcviQyCptQ!I14nqklyMcdGwTwcK2Av)hx%(l(OH= zWU*l87-Pjn5|6T^OoBvb>JAXuT~S-W>kXE7G# z5a1(wA}ZxAWK3`QrMh+kEb)uYqN8Mbp~}|1{qs$`AIqa{?k>9YqjJPbNEb^n zG|@m3TNWF+i8iW~IYzA*$#UYlg{}i4*mhB<7<1$)OK{?tS?sH=qPRGPs2;XF@alpTPZ-q#Hkj0ch>OG&0 zvlif$hoH@{jA8Z?o?zt3b5lJCyHRtgviI=I8kWvO-+wH$p6PVROce48*w8Uc<#io^aJ7R^S4UuCI{vKJSZ5)} z4GeI~lL?d8^j}Zl%DT?@G!@hY?BJK*gFgQT--^uRG>35YrqRm5#A4H0h4#w3r#v-bm)UWf`L#)aVK^<+GTswK2N zt}WXaGh(;>N>z>tE{u7vM*5o@A-T2{V^%-78lH1V=pz-HF4=SFa;Dvp4WTM{WN$W- zE5L`Si7e|HZNUcZzSPwJAlH^Ip5roEpkVj;N1e#8u;>lL8W4QFQ4kQTpxQlpH-A+q zwxlLZnc__$FQs~Q4?vZGkxOuPUIR*YY^emfl} z&!)|+Ar%r5n7}*X(hz4PIAwXb_*>KqH74sTbSFIjjH$mQjMSAzjduhf9YMgnQL^PvJ#K!T&qs`2g>5W0l z^Y+)y$~$GvII2yADZOHESTdd=ox4k`)jcG%1wa`xJ+bqJBr6YmLxhqA5|xTl@iiwZ zbGtK-mSSf-T+Z^VH|ffnz!KsI>86%aAFUm?et`R@mq2jC!-&db$vvUU(v?PUw(yW( zFvh#3NOs~{l&#C@V`WJX%yLajD>*uRw`)-oA+1-0qeADCEMzZxSTL#mbk_O%qWX;P z+4fs_+WwL_nS`Z`iC^)tbYs8dIpNEqh%hjsc5f5aTn**__P+71B(dGl$4eV{NTyW` z#RxIM`7o|u?5op?;E;FSCy>tt*c(-*o`pQ!Uwm`=;>WYo3kuU8R{pleYqchz15aJv z2)(nj@2quw)0-YCQLMJykGJ&#sA~xjDv(5ArJrKa{94@o!>YxIFV8OK5f8gvQlMSD za(*F(aWtS2Q{hbdq7B)8)ulVi`9bXS{Q=U)aHS006y?{k-Wb8429(=#wM$>FUfJ66 ze3x;7>OjGUDH<^Y89{0l_|>UpKTnn~X$=FWmCx6M@4_SDqGq3rgklUAp1d&66{4dE zM;dl(`s6Gps)kjyEIy!=1@^BLRBXHqKP0pXKuaWhq4Qa!lSWRAP$dg1Og<0tBOB3x zXSHjgMNTr{+SJ~&8Bp{KcyRy4K^Bw4dXg_oSnO@1Rj;Fv2T=Fev+hQSMQS(7> zcs|Wph+$>!u6N#Y!6&OjkQ*dD1~vsk!FeujHt4r zc(?9=+FhlJhvkFP&z(h^FamZ;?}pl~kPqM7@T$if-JH2hv3Y3i>op{zWUS80W0YIj z@^SXHXw%xk(li(d?#8jZtn$@#xjU@F5JQ>cgPA!!w!I8M5y$5jbDF+N{6fsQCxC(d z2_`IUo23#t_>*}=?qw^^M~GkGU?C^O(-!$Bz7UbU!yLwsALdblhNQtADg=;aie-^- zU%P6R0N*n)v-K)WUqfaukD~`L7&BsaNZ^R_BNSFB6eIeFNi$Ap+{pls;3kL|UgHr; zUvQEVG%Hev3c?O7>1tWNGasz~i6JV~L8dpgy^v)2uBIzg&BCU*0HqR;Oti_AVqO@+ zN`JhdtSM$W<03sdspZ`BmCLjpJPm>;|Mpt4;?s_?qzh6I;yPA=z$i@Mg(eYF^ZVVZ z%i#I9%(D6gtP5p~6YqfMxy5a;!I*cX_ouF$Tr|1IY|3VNNniHPe(T?(%+fkLWMb=sVDX_oh|Vu2Mvgl z0UhC8Wp~xiFKMBog7~-4Srv>;ZUN6oNnJ^^z^1nL(uQ(ot@UOojQIlA2Hac!XJgcD zaE@#~eu3>>=#S6t8Q0y|YRKbpEUKf&nI=Zxc+32va9~seplaH`F+4#X99u1Nu2v^k z{|p9>m=a69tN~GMLDQu1hR?mawd&fPyS(gdO5R1Tw@!dl<~(F}oF#|4+{zM;aMDm{ zyG+%L6$6JS!lPm`;Hud;*FlxcW-@QW_C42A!t6Sm6{6fAKcDo*cT}d0a?QPLudS#j z5EkZ1jf?pFXXkC3Tn`C-0HDXEjSlmWC6o7f1Rig-Rm8*PYff~}mh4*S!{R?R-Z^5| z(Yf+wCZJWXg}YS_1nr_h@H03o98Hk2EnX{q9HtuoA-IdW64yI^OahbZWLolT?D!6x z)5ZKM@ceu}IR{c8nlWu)LBAMRo*&E6oPx~Y%}l!8!f|Xm;+9CY;rmtAwuG-5qpUH@ z1KYWyl>&9$`1hl3G`=KuOHIZUV;pTqm(Nh%41bHSO3X;}(fMUP^v=vKZrPbR+d{!D z$l8c@t$BX;mR%E`uLmxbW;1d?jy`8?cq#h+(lIUl4f8z}Z9Z)0GcaJc69f;w?3U)6 z)vycAv59#`Wh2%k#n<533^zhAj&mHMe!TDYK*>wiL{mwizoNK>eIE`BLau#q*tT3yoYG#(){JCb1wi&Hb@ zb~BrfGyWb;%i8>MAedWe0?lg8cIXS0et{?TtgQ3T(*xjiZx~t`LGlR|iZm`IrL zNZofct6ej!q`UR9dO_Uv$d}kkW9cQbL0j&D(u7{1Kduuki-G85WX_d0 z%>5NIXVDfJ!GP4S?KKz~0Yp#1SCYJ8QY)+XTvFf<><8Mc9jD$plWawTv)*3=f9-tW z2f^R=S2j3&w`fY-iPWHg$N=b(|KP zJ%V%%7YxX7T`oDaQAW;t361(S$rV>Z-8(r)v*cg<_iG z0(vAJ{}V&@vc?>*%Sg86NfQxj7Ra1x6xT&I+RR4mTU=RI-C?LM*MUd06 zyrUakgUyUw1j7r?@1Evf$cn;qZqG-Mwc27 zN=gxxj=KbKmkg=qvp~flxT5d6*-n*&&?BP4cvOK9NkAnhK@_Egp|h*l^` z@L+jC9-A1)>H=!-&WI`(7UIY^eVAjrDJN3e+v#@}3&ST&PJ7{vY&qPP_9^WTzA2Z! zppXN@JvVMhOxKNN_LY(nL8^&}#yRqj33jcLmo*KO{BH+Dqk^5( zj%5$W%t4)$<-|4aUM{$}E_S^=Ouvl=Ty$N=jJlaKh07v*>Vht)DpCdq-6h~;GylSb z+(XKVP>uZ$O=d&?PM%`yTh0hhS+_}V!Bz-*83C{(4@DCw%q&sc21)EeP7g8`ejl9`nU8`-(JX2vy7@wRj zZUVtA!&wjns~mRY2l~y+g}Mjb!-L>?9w><{Y0YnFOf9lUv(VhKN99<#(e0znI8eH3 zP>6gH7)#6vM5#rk^nESYG5V$wVY=&d7rKezkOXEmiqP3i4^Kj6&12x5bVSTH9%H*c zXlyuZOl2W6zCJB>))jZq{!f z(y0sI4HFPsR`EO^pOTNI3gh?N&Edt$SAx#zE zwk)z?_uz7<4IYUP<>3lsBkHA>6Gx9@ZHOn-!sR}i&(v#ODGSguFlmkk_t`)YEO(86 z%mOUSp;zDb_S@k{0H6&h`CEc4&LtjkD z2>Tv1u>uDBjDUX|%YCk(r zLv~$=pw?41B-Cha2~HUs~f59|P_%p6!1 zkE+b&XEDSQAyv~Es*-7jCsQ(MM#Md_Q37aG#@nVFdKl(O)Vm1%VE=W$apMk$Utdr7 zmkHmyZa)>dsVFBnQL4fH+i{|!9L`?AP(3IgcU<^8lz_zf0}Psp^`9iZjn5&qS}5!K^K2L zjpL%JTBn{A+D&%ec?pzl+#(4BUVx#Q*QyPRb0XEPP}L-}q|MC%&BD5@OrBz@k`ub| z2yC7JcojL{aNNVkX7V3pi%HA1dy7DZHMx=bq$JaPSXbW;w|~M$ipp!6YpbbR@$#3% zEH0**cdzm*%?yX@-mkc9akj9}af}O^ma{Yq?iGO`xT9l1A?FO02b+X)qh}nvx7p%n zRxbC{+m*BPWPB!gu9jcr#U`=tkjy>I9b@kSE?yXz%CJ!DwO56W4ojaO96Y2JJ)DOXm2{SIqHC2`w zcgBF!3n6q-4ewBK4iYsuIE?dpv*|Ry2vC~fER`{r+jaWoomgRTiEa31ykjjUr)8Qg&wIB znwE||-?qrD^TN4YO#mD`RuPIfETF=V36tnPsSo?;5AxUwe!HR#VT0pvG@0s_&mI|a z%ho&{Cpwqr*~4ZvA4J0q;dXbY^^`o za_%abS+M$^8m(}=e82tlsb+6=`J(#UUd}5oUV|Vb|42x!wZB;nWlGkK%0Ta+^K66- z3*FRX2dAIf5JqK~Nd}3JRgm%BXnW*?<1tRxjVs{;(K+L7t=Vi?;7i z<%*LhPJ^F>F#^9!I4#9YJ0^^btrD$72MBwkas(_v)eBleK*GNRI0Oz4ZE}q_9GUY# z+!v0Q?$OXBmU{;UQfZEtwK$mi=FN-`e%C|N8J z#+<{GIP(g6Ky{iSUcPFyq*@TaF3UKI2o1Z?0duO3h`Hg?H{m?<bvP$i`2fwaa5J6F)V{}75j(#J8ELNbdP{2GDBbHOKgRD3vS+8plj zhcOhAIKpNfhkE2)lKIh4==i7i^Fn(EpO!wnezYg{F?`3ap?&We2%6D=vK8g9DXvht zpO)ulwVwEQt-f^4slFPhJ35zRK3M6-)dI#W zUo(9hH+BH-D|ku*JUBs}Y!&@IC9| z&wJRC!zLlwoJ$)*idrt7uBGxBNo*r18tisIsvK@v#>PM6xr-PTJ8$5ojVYMs7msrzReK-A!^{zZ1Fv)hfPvJ2L)-VA~?`XtwHg$Dj zH^bSsCh;xxj+o$;sU8}36w`_UjJ^(9CsG(V`~~haRdvwbypAMeiGHPdZTTFUQ}zxM2a zK9$4*0J6~7ensnQr=tlsmrTO2vLD%2fJ_?1Io%*R7;!1PB)F(tt{M4Ykyk?TrP7U9 zW62T+CSJRA8gT!UM?c^+tk1;IU`}#Ez%0^V=6^u+RXtYRtv*YTo`}6&rvAX9@iitR zBr%2ML=7QLLa{f=aQ_MuKHZvSIZ?`JZ0a7 zQj7?aFJ%nj%wkM1%n2#U6*gJ8#(QabLIw+fEs0DS2>ctw$oEY4H#$q4wHK>5Dn1z~ z>V=#UjF5Yl_^m_|s`np4d1}VIZ3fFH-IJLjI4wAHLiv<8Hi#I62lJ@j@>K#qQY67f zb^{W|74$Au14b~>xf2b72Njju+%!v7@-dd*^UtN^b%;#c-EKF#uzHIGd+{r|kqSe7 zS$!ir6bX6fZ?ZZH36wcg%0M3PXtc$hg)fiIny$>wpBEl|4uS_c(r8J3`qyJeZYc>B zSc)l=iV>RhCn7@neCP^(G=QLMIf>;nCJbT_!#~_4^u4Dbi*<<$XnqE+)NxPWs&7B) zB+YDfMwH*g0*|054tk1&oi`mM(*aUa0Ac${h@_5^)>`8~mSP`( zAh;yw=x0V1P>9pmK(D7}s~t<5gW-74(O%fPARdRtiB}`%^ZH%*WV;K_=)$g)le5<> z{G;@>u=}YNpPVs2AS4bam;4N zOd6fO4Ne{s`b33xiuA_L4>8PolD0#+EV!=DqLAzNXfhn-U88!-#xLk4-oe813hGV9fV%NGb`~zc zsC(H^BLPj7s&{o!suV7ZecE4XWOa&%-a&|kaDU~W?Yr{1g>|-e3H<9A#SADiny(?| zPFD1OGeL5HFPUrWw-l5U|u}##jfYdpceA zkkAGdIw;!*ohu}n_23U{Ii$uk-=WLNrb%^;=`FhhuUl-p*1wO(R=Kz9KYQ?e|A&dr znw;v74vxcJNa_3vDhv`upZalCzM!U-g_$jurz)qq!yk{;DKYdqZ-(p3isEKU7!h>t z_NKerb=jtk_bq6m`FcGg@)CFd%*GzPn`CRZe(^JUu93iugF&IpSsZF-)SLLE3{!HO9?Fj06_s#WmXOI2FBfNV{yG z6xNUzRE0ga8tW#ABv1a=R|_kz;?^8@EfZ{q{O2^Be<~$$X1V=2q_kzx9ZN6~rrc_T zUkHFacu(vjNoZK8SN5kPevev9Z%dy(QrdNLTJoORGQUv{PBcI+P1{~h;h6+U0~1p& z*cszCD3@^a*#mI?2Y{0B0sua;zNPGu?m3?-|0>-i965`Yt-<76>(d6xB?>Qv22|$}Qdt>Ky zmrp{?{vp&G%*W-&MwI1{>Ka{M?i~Cm_d4j#sm&jm7JD-)KYr7{4s^3`>J^;!_3NP; zUIY&fF9|8%h>p~VSaWWvFL6pn=`oDl$U#K@OGVGQ_|m%{&o)SfoolXYQEW_~RN~Mv zq`vXiyFrjd@F_;%PPi`p{rjLTh>ivy%g}qD$eocLq8r=I~Pa63)FZi%B8lrvATm4b$p`<1ZQ0C){!Go zvKOHUzgjsKL3kczMod-&qoE|O3q4htkY zf{*J08&RCY!yga1v!AkksW);vUYx z3%%Gi@(d+n-m<_Hx-dtRuN4G|h}&dhPF2#PS?c*D1!9=4a;gRzX3$|5d%VM39b0;i z6)LQE#j*4Y_>6?^UC-U;ldG6fIXHYrdj@mNybN-S8M?+}QDB7jXS}AdR%P7KEXm*c zW_mqD=^VmhKwL+-fKzz_IqiNQT`RtS9A#;xd*PAvsq1AtSB$%FRD&S6dH!w!nLspA zV7&3n7D<3tz4M&JB(U{_ktNwoI2n8t)}lcv(-?^6OAYRG%!~pOi(;IXCCmho!Nexf zClEbAYj&d=F-lyl4Y8-(>~#>nRtiex1y=v$AprV7+!#9FO|p?fFGo1xkqe;$Di=41 zqN(qUNA;HF%KG|q1_MsbQd-~VFE!4v!g&?K_)Ftvw^ABSZa2CRp7Y+G1eNV!Bb!j`YcGN2MWJ(;5C~_qZsO{!QlOL`C;vz~1ntZK;%! zX;7}}g&n8yo#Py@-sB@K?^VLz?T(u`9&2!kcZ+aWad%P_8*LSTY`s0|{J8FIq^GT0 zTnT=}15UZK{_0K1OQXXD9eAK~a6uLtbY-7;Un^$$^hA;t%1Ty3?rH#%Tgv=yQO45A z$%7iT+-+?yUzt?SD(UI&wa=z!J}9a3?t8viSq{H1Jc5npH||l)HDnu1vN4mT)#-Tc)r)h^=SBW;IVyDN$UiGq3(6nhFb|=^1rA+~4dFrT&|A({ zX}P*r{~_=V=Tn82k;-RZURK3=t{zqh;CQm%Uq@refY;Tx1yA1@bEup9&pm}szG74o z#P`@Kb1LeV>*BiU(&On`D|-A&91kPT73!w`9@S4XI`0~P`CQhU(Vt*sdPsG5;mJBO zoJkh?PS36TW`9sM-K`gy5XsmiZ;Bhg#;E{OF!(1$T)wc`rdq&v<_|I^N&@FPC@fe! zHxU=}vHEInx7OW$tBy|0*}mR%zi-I}F>E@v9b+4THQHC47d{-@TRZ>e&Eu=p0VX~YrckMv99>i z4WRks#3i;TAEUI>OVkIxD#xuHLoeJ>3E#L`|GRM13VoKsx)TlR|0#UsMZmK5726DM(O{?lOUax4$b+o$!~a*DKF8%Rk>R9IlPa0Pu-BO z`jF5^09r2Ecj$7KP#qvb1&<^I3mm?TC4#7cEZ~+u?E5U701?lMKau51J@1QDZ+_Y5 zkQWZ-I-I3ZpVRVS*g&aaRTDz^ycWqL2+stxeg&-*2>Gpp@havd7k_H#X`d|xvl_$~yy9T?SNRGz8 zniys(lNFWas=A2~%qEm4p%h0^P`-k$6sB~3tdZUky>Yk2pWX0O&w?wHGIdo!*{`y^ zU%bSGTh@3U^M11Ld$I|#U0y5;BN%+d2keeI+`bY1BiUfXZ2#~R%e~%P72LU&UT<}^ z)5el`d2d(>oQWJ7aN_%x`}nz8PPn45v_ZS~_3}7PafJudvqJvGOXM)^G#OrK))sB7 zId-_el-9MEv^4>Oe+~SMU*nV@p<=u+4OM|2K{a07FQ`2$DhJ2R?9N7>K3;Pe`DA ztSC^3ltOyg=DUrHvkW^-tC-WQ?i$+PMP{DRlI)s}mzWbyG4UxWFcj^<{wIc}CHi9L zyGf=!$*52^3ob$+A6FnNL>}?adT5Pr=W&9z%9i?p5ocM0(Sn?7>+LUT`+Nfty1!;ub$YumfI734+>pN?NVH|w}xqpFiLJpHJ1ax0lr&A9fDU5j*dC(Jxi z6dv~;eOXI7@pHIH=wzZW7#;WkJXg5))GDMrhNb;*5<7Ewh$n?#8z+Yf%-l{or_~&b z%l3!f*3pMtX3Gt~4Nd8gLHWLmM5#4$>8z54t~?iFO<5nnvP=6jCtol7+b$?;q`VMl z{|p4{tRw&=**754#>mgiA`sK*FV{xKEh~m`*z8knBGV@Lf`rVbn9}-%pLX$=N4_(f}Q0FiYaXI}F z;PU@SlTE9Dbm%Rs2?;}K_n!08($k6_l7dEu&mP||0{5To`sl3=p8e;OHKRx3FqxuK zNb}hOYDRGswJerN&nPNupSP;^Xx$M)`lyQbM#myz_JMV!QDdR+6O~3m3vaA~SsCfY z<29N`A@4sm!t$vkvZR3*MXJGP8^@wlIp~36V&QZ@v_d9r$A}0RB4|MoBaQAHvitR9t4*bIvH4yN^S4`wHG+4>-N=b?9P>ODhp!Y`Z zm+NE)zP4K&%v6^|lZRDBqyYW(+flF78rD?qLAM$#(u3ZdOIJ2~cjW{K{;q*@)H*@mwJXP4Q%mI$iQBlM2C9Qxx2>a&Yh^~h-Y*%*s-M3(=!G6!KI`wnB0 zg@HYskpu@`Kq9k#2J9Vm+*JIzz%n1b=6g}>KYY+*@K^E`nN$ix|H-Q+=78DDURTS4 zIu&J1~-E|kxC6w&Fa*XEThJAGL8&_e9X1O5Eb;&k2yj0h z$At#)BEve^XS%0x41HGqXjI>*l7O3{mxOwZT{v9BCAoHrNPMp?&z#LI#iQz@K`^bbwj>wHP8 zmukH#@eCMWp)D(qLWNkiEoJ0_0+BWkD~K_nnS}r@0HCO&z>wmQscmJtkoqT>F!5G3 zCJ>evSHKopV9QQZH=LxYZ_<}qSL4v^|EJob(Z1>op(6r#T5#aZAF}Fe1VmVyF{A&l zhS;*bi9PaY8M>1%(p^nr>Gy4t<54W1vCD1W=xIimK2B2iXYQq&d+Qprrce2)SeD}Q zgDahrQ+MuRDmi~5oqCbc^3teqhy1mpj=zT7zb8%aHT$`5FlTJ8_6NO%Oom^(q}*+ zyquukD%-?OL2(yf(N4BcBw8D2iGT?C{S!>PBQw|bsTneUb9m#4Pv$cRwi`Q&5py4; z9)9^a2D5%G_wMl5pZ4EZ)ZS75CHuEAg{S;#CgPLxipvK-c}(QpkFNp(Q6*VqS+x)G z#OuzV?DMZlPES(n!b@ELDb6seqDtvyVtA#WEprYynT| zr`b5eB_F%+iFpj#Q`I*!<%#$Eegw&NoO`T$0B{<=VZur*&Pcxzc~(P-CFfmEJX`cE zrXZZmsn@gs=d){KYw^|OdhFHpT4+}&2&EJ1Cc>6^iAr63j^44;6bBY1<5PBthP!^{ z_^KzelC*%zHpGHkxLl{TE--qYuEWrpft0F0JAXVDMIMn$V!YWc8N~f<=25Oat1aEO z+>4!m|Be}+lUV>3Y{Mp#<)#+*a8BcD-^MF+Z<1N$GXdmCvOjDBoQ)n2bt=onyC2lX zj4mM;)8rT5nDV%-c}k}{*RnBX2}$l$2?MqEwcb8l>g>LGf&OIf3M%VibGM^$3ZJ26 zI-d!y@>gCS-7%H=#S+|N_u7N#HC-){cPDD2*m$I1J&jn|mTRJ<&_;%b+W42P(=&2A zpuAgD?9`^KV=iZR7ilj!JyBAZwXT%CYi$hrQNQ?^LE^?{V6&RMl?jxk01pR;gye=r`XbGKnb*0y6- zfNa8YQd{TJGt4c_KO&r`qy4`w*C~8nLnitq$Q#UNOxPF%v(LV+a<;ebnl_rrhg>{J zOLi>l4sZO@cKYGv=X-&U801#pcroIRz1u#Ox+ENMoMwvjF@PyskSV5%RK>E0Gg?^X<_Q5v#)K4{Aw5sU{!+M7;zboBC*WQS)}#jS@pZ#?-J zcQnf1sqN>>bnAaip;_4IOqVkiX++(Cn=uhmxR?X>b@|TbkUSb)WM6&dirReH4F#-| zGYxO>ADF%KN8^9*sAelLon$>H5KEPXe2wNU(iqS#2AqjR16p6YvFc+7F1h>WyP2La zsi{P9+%@Z?{0_e+5!v&wz;e4k@M+a!+pf;G-mme7Kk8hv>f!((Kn%g;kaW?7y;8?85VC8`)&*6R`?FS7Lm^AdW3+&jjWo`+|%MqSX5TR5gt z_t6*1EyfW1unD+|g=&TcooHVL4&%*5GeV3;hFMu09u;CDzHrZC>tlqBP6w;=Ua1~- zS;eH^^Kp{#j#1bs4)1t#ul2-5zn-@)`!^ZN4NzmiEX%1~j8gloqhjx=8VM0qU;rRK zr*c5Bwa0}){#IbFa_r*FK0mj% zv~gz$?GwP|0_XdX*;Wk88QV6=I7di4+nczmjjpn678Y@Y_pS7&yLHC z1W9I0vg5z>^^lE)rA#TxB}X1Yb%tt!j%Z0VnE(foc!7xA^1G_2vhiGmTSfUJ0O_{~ z$yJ&p%uu}4OP~D&=+Tb^Rb)gQ;xb6nKJo`Ch>J0XLl^a^KB@_l!7v>;<;RrKKI zV3XG6!lwo_Ve|@!kSLT@+1%v;&n>}rImUf1*j-pG50$!~ZowInOPsMf0p=vQRqG2* zKNid&uwrP~b6rhTZ&^Q{3~TE2d74)UQld3gPwfG<&eQTWQjmIX0sguoI;;^%lWCJC_J=L#7M7CE?K z$wD-*I@l&p19WfA-LhFxD>el1MbU92KCz9jb!23vFW1cin(D2WRG!bF_W-bipixFw zFV1qSk@c+0kuwmo$NRbl*|mnNFVGtAoXJ+qGvD1s26fnSF3JBB%aRmjqTk$dHrLAV zr#|~9h73>b)h6j-15>Nkxd*S9b7)woh&bpitNSU5btiww0*c4=s>Nf%JcD7tk&VWv zLl&jRoAu=}=6tOiS3xJ=siClm&%_S?gE+{BQ?E3kLeK zvilFpKU2-`IqkmNuKlj}E!l@g*mekns(RVQ`G)$hjxN3?2tc4;yvaj@VK7)QXXj}g z(yixZmEH6o16)MVjKNGwl7z%xq%TbUq)4`AUW$(J`zWB;Udos&d_%eC{^R122eY@; z6<e*r<*Q!oDCR#m?oWu7p4<X>H49RwCj_8M z6eP-NS&NO=J>huLO@5k07;|LE|{nBLrTPM$TgbEf8t#}_M_ zTDq1cP_1)fdSZSrZoQ)R$=%o1zZ?7OHTApf<8>0f2aR(&;yQnb0MGDvz5EV>1mI#R zt@egH0ot`jADc*AUT73?ST>s`_ddOe6drAI{2=w4d0Rq^aRCva&~6R?hke5yEd9N3 zBvcrS!##)MYg@yb_I&68ftwBCp8`E9Ej-m$@NI$IqT!P4CQh5Eek(iNi(SO?6J@$E zBi(^S4;XCXzH9svMQp>SUWo>rwDP8&fvz@N@eeoG7~{3vg0n#50RS8&HVE$O#hE9h zvD{!bW2PzLlJle2mCCA38rND+W){_x2$y54?!Nf@)wM4l?00+jStJO@re=EYjH%rZ zip3$ekPD!)ay*>~uR}d8A|4B2p-quE0aVh+I+!@K`@mdcXOQ}q6BjRkcpAj!GWr5) zU?C{jq^>%t`Mg|I$3b|jQ-<%hu?CbOpOyyBf7{|(sMSruamCM!1>EDptVsr#uwt-4 zq#u^;Mm1}Txy~yi3KNoO1`s{Oh0P8!blY+MP3@?7e_*Sys9oGO9T!?2uoo7ha^3r~ zyz_YT%5~|q0Z=c6<%Z;L{`bkHIO^};y-p-nle%)`=;ZQY0`8E7NxyKj(NOj*0SDrO5gaP_5QX)54PqY=fKlrLT>6r}k z<2eL_IfP@K8-in_J;Hds{p}G7B@hOtcyUf<-?sWt+G2)&C6aJo#Yub=8ijJKexAnl zZ5it}deko2^_`@z)`aOEb!@rzL>_K-*Vw<(x7{g{mhbw;|HjZuVZ(&3UYv>k2ulRq z%(5~9A$v%FHinYM<$ zoWXQ83>@^qbKuAem{c`P{LhBY&0KK*_V6kKc=)sXaOiA8RuSTP;<4*AytzD{Hj7m`Ky?T{v{+OO zlBk!6^Wrdy|EuM{DCFSWnK;chiTiu&uhQQ~*F>yxXGeK|ms>PT*Qdob`_DJR>Cl(2 z&Hl0u^z;)NirKk2O34@&tU5ZqNu>^Qh*5XA1DO#4T;Z_x8I*YETFD+Sw;&)Ip$!^xkcCdO;mwfzR&Yu-Lewa!Mf1`%G;YY$ZL-50cH^og#6t;-cYhc z0bov|6ZU_Z3X2)Vt)Y-U+P)bwLe#91-ceE*fSvuQUOv!Rpyc_CM5{=FSUqjf7=4^x2;wbPND*nHqvSHNF^w&(|TQ)vR-A zTQYlFcU)e=*WLyhRqYyWE-#})mugxyz*?)u+8tt#A7Zp16MR=<4Ow%~{iEOIY(gQtCUmf(%= zTH22thY|kvJ%7h&MK3xeipCDa0RU>gQ-bIblxlmGMZ^#&1eS0FfRIPb1$7#Qsn=>0ClJOHI{n>E2UWZP z1GDvrOJ<`#S_;EIM!pFGk`)!FO6 z%V`8S$fVeOAXU9kRcj9BC42XrR0jmzQZ&_xNEqI@aj)t_-3P3vWU~`cgn{@AW2&DZ z%Kk+@k`@g8BqRt+03*?^*jem{w3q*~q|qG0>2l@#X0bM4Is5D@>2ju@`qY_Jb~kqG zb111r6b1ipQuC(EY2#-#bVvY?i47!lkK!!BBbW$!Gp4^KymCSGx~LrQfpHl$XN9hA zY{x*+@k*M{-Hqq>f)X0;zg9j1@M z2yLFhlHzn`u^x}w#pMaH_)tz?0KOC-NfTT!sxFTDzx+cwe`C2o#ae6^Zg>R;sO{BplTUEo>M^^*mc zj~{*=tnEMkRzsyyzi4KH;{9GlR}4#ghwnd52I}b&DZPEhqP@BCS7PFnUD|EKr3cmGv9_I2no;IwycVzC(^ekIg z)#gYhxGDiPl2-*gQf{zXic*?~H>h1Ufw4i2M)T({dj;Mtd$RLdgyj9D+$TU|>Qb8e zTYB%1zT^oxPii-t%9k^Q-UGme;zsAOZLfW71cRA1ycoe8B%v$GyiFO`mf*aIx*sR4 zS9erYhJNv?PiC}0>p@r2#dG_M%Y`ou0H9ob+JBR=N!hgTXo`39)p7&2Jig%H?R@zda{l3Rp*r4S&hWW<~kg4n7Y8#v&K_E0C zyx_~Er7qH7J!Wczq#oZ$Xro6c6NTG}S>WEKFUO!{&45*Z&-GkmVxG|wi38}eHg}Nl z2CRGafHK*Xs33f=N5Q%AJ{Nc4{S%c7+Hxf|Paf63_4irtDA?)wmE|gvY;0Kj_4Lda zIt?w18~-^+hyaciHacSpW(keR2xc>@@(kXyE{Dz$rHsEoOXg3)2E$9R{tEjq1kx8c zan?e_jbJP+W8?W^A2UsUX%ajd9Zt*hjqvsVFj)+Fr5o3VFZcFb)S=FotFW<*Wx< znFful_n9pK0&po>vhf}^{tYSo*hd~HTsCE@UlLs9nwCa}h4hqky^mH~T8Z9o`me(o z1(qnhktXaop_T4WKlgZ{foW1n!ru4MM5JsfNsmwGzL3Pn>e{%kRO-JM%3i(A>Zv30 zMN@fM7upPBxj~f5u3yPn9GUs+!xB-wYi)8@`7&!asvz9;t_ z#Lf^p0D#-XjLy~}i-b;=8**lr7KT@O;IvAu?;@ZLB9LBI#Z47 z7k0uKGU28zK-gF2oENKP{x!1Wq$NP0?$d7~00 zDR8196D6`ooRJh(^0RpHGCEgwQxkZH%hBMAMeE`Xt|O|+12e@moaN}cWJ^O38<*Em zDeKp7M^|MXFe0y;u@O}~YbpSlJR;UP#kYMwT=z}~PcLUojjlwx2NGYZ)t#Fx_v?sb zhU19iv@TmgWy}~fYw+1&PjD{yrD}tDfALse+(q-Bd2G8}l7}x!fTD zTrPax<*dLX$Ot(zCYmhXvug_G%-g!FFC-xJ7RoVuF3)GQup}friNo4UIBohF)sIU3 zBN>41p}%f{WY1c70KZIcaUDF40F2Yp&=H$_@Wh_-xQr(5Gz3pa2KyZbR`Q@WP1KW- z=zd42Nk0BJBX171d)K%-0aEI^(=sWCe`nhAvaOm7qlYoi-h+S9%;clM^%%#k(BydC zTqH=B7iXg7(c#24+QfsN&fy2ARn8xMnCW>KQI>ND22XWN1hiN@Mzk3mo(~>0t{(sA)xuQ}Km}rmy z)Fl%>*T-8Vlkgn7GzP064FbOo=EK+qv-D1>)DNEhh~pfDZPf*@R_~mwfPlsi9qE&K zS+vytpA$V7yA5#-Ko+`~Dw8{;KMd`e{vjl3VgPZ^07@j2NiZV0zV%a>u1v!^Ybji* zYPyC|*bpX4jO709ss!=G zb`}VLV^x|>1d}_<2XCA?nHATYG#}w7;gmR40rCM$fg;+v8tMJ8$K31oLgD=(7B^Q! z>_oDBeuWOUw|;NptyqHq5PNJ0U=ID=K+O{FQs)%;trGQwMgqc!#2ODwtfVRC*#7h} z+sG{JpHwP0j(Iphe$(@AiibIe2VvSyTiO7In+IjyiC-F~VTZpTk<4Nw?c2%b?V;N^ zB}_Mpw{NZDGCp3;S>2LCzM@|F6Gx>6GBJhQ>`{Em*RemB7I6dqKPfEhWR~dXjciv4 zIIwaR|7f)@*gsO+yf3yn<Ve zWC?=dV2D0&dVN2En2x@EB@Cs`#8CTnX3_`rt|rxK^2v#nQnP78;z(<80vG=mZ1DWW zRfe&8#eTsLMf}e}Tk-f*<>Z~MU9Z+4Bfbqheg-xOtn|k_fs-CeLqRKZXag<|h1`0a zM(xw7LbH}O35?>)B`*&9N$@T6g%r}d?j^%iUpIG)&-lN#?hlrOZ0B;7zt6~{yr238 z+m9~BIbOW?gK4scs`o0>{1uf7%D;W7GZFN880e9nCZ7@(lTQ4ZD#=TO#j<_lzuP(D zHS)^L1b{A7KZNF6J6F`FdvxASnu~i?BugS4NFa|9w7E z-p+@Nr*Dh$7OIK0FTyUjNKw&6x+?#hLmk3KXIDKuUOj(&-WpTY;VeHyF^__ zj4u2!lNo=ATSZgh!%pjK#|>pG71SS8-j7sjyZ6w(iy_vOh)!wX;fZ_@IRGS+eQCvN z&8+Tk0znVrL`-$wcj(1iI>!bGw*>Z&M}6NwdNovtfGn3|ds6rqYwg^hd``u8@wM$G z*F5_q3(y1b(SYO=c`1Ah$-qKk29iFANW?RcnB$=UsHp)E6VHgTug5%`$%0s>sl*5q z3L4GftiSl3y^R#Y86@0IN?Xwv7`q2RZR6t3_U+%Ud$1f{cYDY0GwqMs zC5Gj#-2PPE3v2&UXZ7^ECnm{ZveeVNp z9pJEIa%=Z^bb(wAFhz=9y(L6Fct)lEV(P1>y~Zz4fv;|Fx?Zh^(*@9&$pcUphVB|; z7+9%kse%Z(n;X-Ku%ge|-Pz9a?-JO2sEx z8j`ks(_2Sb+#2wkmL7m+BIy%hjihhBU+zR0+ueai6Ky;?B(;>uFb2w3nQb$bv3H%h z$lQfE=mYhnM$u$Gv&HtYk=V$#?p&*W`Gb-}C7YKk&t2vah;crj4~IYYRn6aC{CyV9 zp$2B|T`vTtTBPvUm1tQ-n3(4D>Uv?YTD^Lz5*${E*NnkQnRXD^Y^&MhTkh)0rnG-@ z0Mt{P0RH8d|4G;F>;FIm&exg0j|}hhAJ%_MCCEY>U_c|K;mDLpJ?5i+ zzyHN(?4By|d=3G?nMk9A@|iQerL)*mi%p z-9wF%aoD&+=wy+#Gp2S^|6DxXpCHpDSPWJwDOim4^hLmF^gTV((t2V2_(;06eJ^^o zx28sh)zxJa3q_P!R;^YC+IAG;t|I>1PdP>#`BX*e!hKz-zKQ=lHDiY@5x^}#-YEtx zu4oe3FRvq+0G?vPxWZ;>ac~TZMp;ssoyqB|a10Y_v{o7b!0MuA{tT6RiRl$NuvL^k z5Y=2Jr?xVLUw<_n^~d6$svx0?>4>4OvjCV0n7owOL_axSTRp^hbA2jR^0*_8`i`o5 z?R&U|(!aJ%f<%1<8TPrw+D#DZ=J+sip+ zdB{tW+pfdZ$K8pUHG`@Wg5gy0btZVL+>hJsU1 zNnoM$2xP(m{%RL5c{D_`aP% zMnW|ZO>@*E_iWSLLaR9@lR(o#!Qau=R~w>9LRU=#zsFG@QmLm_hmTH4^aNjv<;1{b z-eaDdP)}l7qFy~6ZQm~7zW1X&6x)R*rX@wy9G-@OoBU$njBMqI3766j2Tu@gSlyfi3+t(=rDl%emED&1z49?i1RC|4}YVG%zfT2 zI-dvE`q6E>0DV&Q2jnw##NpoSvO;df$3tvxh$wq^9Gq|rKIWMZs*l39_d)-T%haj7 zSyxAUJmv*U)uTkzK5(p|*u%xZNz!LhOLQLCfB z3kIvbe3r8kWOaD5!)OHLJ`>h&^T1K2*`8W3b}00k1uHPM5}3&kbfVB$DBnDu5)`J; z=iXDqRjcR4!$F3Qe-(q9bhvQ4balh8y3$cevT-5HKdQ zHz%oi_tcNNEBn#J$AlI`#{otp$SVw(&eCIdFsoqQ^*{_G?PF#nGX@AP5K;?a@4dnG zsxIMva7?uCO2XjN+A$4o*fU*GiOZMacbr^DP%almT1R)r14%ZF|6>YRvB5L8ZIQ6g z62WX{otVPKd`&{vgw^{j>N70;dj1b|<7o76kL|?tN9XYOgcI=WzQq;lzs0x*ul^-J zsS~G@;hU`0ACpHmQz-g0G;i<}D@z^?q2VR_;&lwhc8i;L>jc@0vP5;elO|XJQ)ufP zywmujNBiPIF4zlh{z#z?jo_YmW%LxG{~%;tZ;ss_VhHu+DG{g3z)$Hj-&0Nj=Av>p z@ye{%ELQzZB;Qo=G^6OA)C7bNY-IA=3h#~*mN^|&iD2`T?Kw5sR%pDV z!wqu!-L}hDH#w<_VPvZ)J-v8pMWs?5EU3S?WT$a_O0ErxGc<4s%Ag5>*TEJKv2d`h z3z_B`{x09n&g;G(g#ENuQeS1L&-{E-yRvMnKIg>=_lK)*1wQ-3;U~+l50tte;-Ne< zFHi_CcI1kZCRkrY^sl@ckR4e052f{74eLTzA=U0xq8 zIA%*GY?35bTJgipjtn3GT<0p`W%({-VRir#-$MRrY^9FTf>Vr#e5@>$<+OEbW_=>9BhJ+saVv zJAuxGsEia1Y(-q-=3!Rngi`MoiHoT!txbY7DY%?d%7Tyw??@d!f>yyIcO43Sg1jNFdb7fJqmC9sKnupw2JJkhEOW z@}#w^Bonb*0GR|R!9a0?|Bg6dURemB56z9mz`&rnR(<(MO%4uL5P`0U7oUh2$`CTi z-z(_Egjd*Bf1WfbIDpKlx(xsTwsJjhm1|h|(*yMmp0kt_A&(z-p8O0H znU?wRkmtB@w?gIPL$_W)P&%G^C0PYJ4_LJvWR+yEVyAOEzPGd;lyLiLG#hosw0N-Qe~8%Y7K|R+MPaS zk08x~_-4y)-!eI+chBRLk8gwna>g%x3zcOhu+Wj{$|;0j_9ZJXo$q*rl(-UOh^c}k z8sIdGOlG#m;|bLB-e{f@*k5ewWU4MhYU;7rEFM>XbK=32h^^zL!vLdV8=!6Ws zl5f(?w>8vRj z`RnsKAEs*a@N`Z!^I+6&zT>(H2JJkeAD|aXfQ*A)vkaB{XNHoZ$rDKUB|Q@|S!Enb z!H|a`gxX0!ZWPUXY%WZ)na3oUPFks#vrJDb2w4?%XPbQ(d{8nWQ zUou5h)*Mar)`~1KZ+iasG&6kY=>a{>L)ouV0%x93)KwTVOZuahq0^8YSPPuVZ2nv!YAqitS^cgvb|zQR}z0=5{qf$WOtq_jH>&;$g~Y$im}N5AKSi)8a(rd z%)C0!H3jLUbA*(cw~6E05-eqeoaBX}&w;)3Eic@~avHM=elEmOzoLYwx$B6SAnwO57O0_rW8>%n1pky3~40K3!Vf#xv=%clkyNXfNQvF!~VQPH(QIq03pO+coR(;j9<>;?s4LUPDS5}-9X239+6^G_UH8P*w1_PH+j%X#GFOd8@>ubI7v^yr^E!{5YFMoXOp?@* za(Ngogl>X!>pl}tUGa2@up}a%_&EWKA%VbqG_*!~0IiCIiBVxBZ+(0X&H_R&aId(y z5i(zYU4L^;c5Agvo&)vLLb&q*e)M|hD>eh*2mNy{cLV^piw%O8VsYl+UuQ`YYry~Q zLlS2jt30~lo2w3Dzq#6Zy+4^wjT7J2k#tw<%zL0xT}`cqxgkn}JOL{{gJJdkW1g!3y#zla+3+}=ko8o+dM8IVZ zmPMPpyS=qiwt`8zS7NtxoaeOXKOKe;b{63UpLv>}yUp6$J>cK4)WK`x2pABMr2z#i zOG|H1=ds8jW@v_|_K8xkT$wD`V5CNdg7>1aPVAgJ7_FDGfc9qjJh$0|Yo@SplB!!W z`*#>cJ{73f7P#3z`><3_l(wLp)zCfwd`oEXELd+QN{@`7H?xLjoa=Hr%-(12L;Fov zI6hYMmBakn{rA!_{~cV@c}E$Tl$Tngp3ym~#ZzWhm@c%vghM^&Kq4OdQwaj5rBJ*! zb10IH{%POou{fuq@UqF(z}u#VIb*LcmWX6X?b*JuUitQ>T(W!Z@PWj`w68s3`E&8u zO7f?r@e$ysWwf`Y2t(><0beGtH<#=RVl}{`cfTm+KoVrY?j3A&Kt5I@d!>Vvp#s*S z@|0ZIKT|hg2FGqlxoB-|SDmK4Sg_-+!Adm6K}q(VsJLgipTt8;^W&b^32ltfxO4OV zAhJ-pP9Pa1!ZBqRt-dAB(iZ*%-*zNTi@*cgo{{U?`ng<&&Fmy0=AZ04zNTELue5ju zXW}ff#Lg(ciEWm-&c*6jZS&*);6-z#Bb}2)D4T&AB$GR-b^_x(UNh`8x+4ky4@4lZ zidX;u4K%##o4f5{eUdY7Pdlx!$d(5B;5CuS$<^CrY0ePmtn@~ABOEZexWdXt%%HMn zhpFJB-0f)}5Xy&25f zJsk5zk5{YGC+$XHo$MHfNi-sx9Gu66IEKbgRz1Y0D2@_oB0iGw@0* z>G#)`vx6(tx)lf8OJPmbbZbf_U;I5h8k2H-nW3aP5ypf{n6%LwTCWpvdTj-%Vz(04 zzu~$Qx*Kvyz5ohT;a%|T281WTB748SHaEcT#}tc5C;>bUG*}wKeII9B{5mq<1NQ(e zk$V^{xPgFB0h-hawcrDoxql(KGR5hEi7$u-Yq#_E7I)M0-Dw6`kc8;J?%P6;t6gs* z-nT^}Wz5!nheD)aRcp@-ms0$NqjXySEp*3DSUjUPhLTIy&W{cJ-h&FFrl2m!fQ7Ja z?)q*WQZx=Lih0h`hpazvuKj&)_&Qr%0!WOm$xJjy>)V5eekxx(1NnaR?YNJWhBOP7 z5Q|}sZ?4`vym7x+5~uc?fS17G75I`BbfI3t3q}SPX1vOVl0>&kxHjHS|0}XYT$ zC1Dc{d5~cozpmidQhjlHwQgC{yqAwtp+ISQGD0h}OmZh~9rcOoM! z%$WXWoHse%vmlAQ#9)-?*BG3BW-NbPBc?_Bveb*(cFpFO4=X3+?e0;jr*Z!t)CJ{I zHWX8*Ec5GB)N!K*?BG;Rf4;y7qb>XWeNS<%%v1ne=#J9uhg=%N5#1w^SNkT8j-~Qv z-5s7+JW`S3T)q=Zmx>L;>f9UfFcM*4+hQ^n`8RwLx2&&})CXh$H6XnFE1~ol)K)u& z4dlJsEMQ{d80>lQ&t*bve=b)+#YmE-L0+$z_m#n@8F^OrD3s%Ue%E!0!Pt26&1N&(=gV*L>bgdgq6mrm`7>OQ>mv{PHm>7-=G2YWgl3pD|zlObuQy|VL(G>f3{Ju zpW*ug3WK)zp~>#OA2Vw=N^c*&<`)h8wCvp}ep-ZfzdOcsry9M72(E9FOU2S6_~7!y zfCnYNx#{C)xJk0W&ZH%QT43T70Hu4ch#v|bM$rI);$*TKG9I&5!q7%a<2cc5LN*IS zgOYTdM&JV&`E2h%2eY=_!Ayn1I*a6H=pMGa-y4lL~MEqMgx^KtzS=pN}SE&2H`;`{^OHpu~Y)Hr)0Gf??JRC+s10 zV>;r7!2G43an5Ffv_c}%Ehk%hV8w(J6l6;>?S#{C7Lve`BR_0+SzdM;T~*H3SOtyA zNdsmHeQE0`7-9cne{ZxBC(Bk?*$GaMjDl)qL zc9H(KE1x!|9=G};Ohw=DB9*$=P4&&VBkr;Tl*p9IqcH!fIAATrvaB-^IAOl{m3t#P z-#G5BwsIrC_^5?uA3y%w!jkd^dg8X+hG}B>cdT+Yy`jb4t=N-M0BIr_CRsvR? zsPwsF^mA8J0|uv!TLp>g3rpmo)EcT1bW1YWPIx$&Z2!v@4!Y_w*gA?;R6)3Xug?n# zaGm9Vi|nPO5uRtnXdBk^{4RMQe2eWa?(P{v#{h60a`4Oq$JOkgMSZNk7M{y;=jKfi-b#bJ8nkp{FcIL>`JN7q7xb0Hh@tY9L<;Ng+Jzy{Lf<^|60er z=Z>r%dm>hxOFn^iZcbi=-3v-2DSo1}1BQ;V(GWIv8RLOF29^g(?)(CP$JC&TP3{IjF)ak{juuMmF+90 zUjMi>^urB5{o$-j-#EQJJ#)XdK_2ltxl}-=gd-2p4?)c>O@mb0{&zotN6q!~+nen->y72KT-jz^l0k%B;ph~}UvviC z^^7qPKlH9UaF96=Ane)+=8`z03DX3Y1?KZ@u|^@Mh<9MZDGVAJBJ!9r5C@&9TlU(Dz%6l~$Oe7>+gzjJO6i8FgsR^`zKMm|%WNYvds zwwmR0Nm5`7&DaACur&FH;zR16+thD=ru@*UqKVfc)$dS~w?z4V!o92gr!WZ`u2$X+xZT{7d%)oq{z5^SsG4yyOX@FK9YqT}(` zXId*^A2HxYKwW9#lW%(d>lGgO;JFzEajvw*?+Wf< z;ZTl+r-9@54FKgdsDzrM(9m)wUzl#bnq0q=w@i~N8mLuyVM0$zKbs%M4J5JsIIvdc z$R6WkxCi?mLakzkXXb;cS0^Sy&deI|f9ntnlNfNQ9UbyX>YaY#YNMLlPp**s_$$`8 z7v=B2yLh=aBE$YXZ2gDrv4S|%gNtWs-UxJuUu`?2tt5>R0%Ye*Aqjg6f&(41Y~QEu zK!{CBY!Xb4LM1Ag%PHxnzpe`3_(6Kuy%rT+GWegk`}~e;{Fl zefgs3RgYl}#iZyH^NKa;`X0>I5UMMPv+<&iQ&)%>eDuKQ3>NC5vO^}VeT3|Ap9sr| z;C=!}KMJ)8410(>~c`y-bTT-(yrT@f4+uN&u_YntI0s$PrsGf;;h(nQpwhdYG_;WO2h zch+#2lGx16{FuFd!Q~sy$G%~ zV2*uRpOs^n6JD^Ni1b6UM$AU&k&uABaR0J0*qj6&#{jidvz-d9qiOh!)gz7F)v`%Q zhBz~gZh?O|47G5G;U-43H_B=!`%s}vtviz=Iu?HwEgg;)IC95E7kQYuA`1LfjEN{+ zZfh2GMHAGKF)zgAT+U_7UzU+D72Hlv00sc~i$u%Cxlj~B>!%h*C+NzG8R zSWRk_gNV>~Ja~=gN(rtCZp9F33O(`vzkKKrNLY`KM@$-Z4F(C1er#%Ykn(=_WBGTd zzpQguTO%P*3hb|T0i z?n>?CiuK&&7Z?Tu2?c1VUW6*OC}*3!onAzj0ePKO{#x*#R+{JE)We$XfYD!1>EGRS zfARiL{Y98Mz2kKSw7FI=j+dTSrHtO$Ni9YuMb##XHHKV?1Q!fg0@$z2l$_J36PT3?ibFZE4R&28mU1X?&=q_&D;pU1K!f5Mk9-Mh+i0B|nP z)dEkAxWE(EzH5~IpJxm;cjtnrzzv=oQ>CwG!fZsko~;|TwGMAIG!2~_qu+ibdhuM2 zFVg~)7$XT%l<|MWOnQP}St}uMab7phQ)SedXemsXVeFU(X?Ik75rPf+Sh=^yL4J#N z;n|ANcU-@0^xs;}+|D=1tj+_z(>>ya(Z;Fv^po6!vq#p9E4;uC;}5&;LzD<8+#pn& z6WUIf`It}EsCof?W}e5eG_xjY_&KG>tYcHHkXJYLt_9y5QZQU<)9$3GS8qG#RgX`ugB4zGlr-RF+Cb8xV!eBb4 z^BMtBN=Ox34D(5|!UN+Pf$_hFRq^MM_M-efFF1H&imyC0xAEX|?*I8NwGvmXlzX{X zqir;iF4rM&C@#O3LphbEzHurvsP7nLUXpCQ^QH;I**rs3-dxV`BKXjF3benlbW?;3 zELeP+S6l`q3I_vefL+xOMP#t4IyfGxQwj`=o<*BT1drhnvoYgJZJ@9qlnXU=G4@ps zo!sQ@q(wH*zInJEaE1h`gX}@pIl5(Hc6JW4w0+_nUbvs^>J$ZW)-EK4z&=2*t$i`U z!#TFFP8`?CDQ5Z98Pa= zHPV<#&NZ~2O1*y-P}lVJQt%O!cb51O7lTf-g;BVHK6}yVr1e+o`gwP+`PvLVZTF~ zPYGSQSv0MMo98-tbYtSH|oO?At6zB}GPX`xf z%gKGX>!k6cDUcIG#v$ZBbfOux42R?KtTJ>-~R+&^wjpi1rC1p z+w$`gD=RU^n*Cx6&h#`27Uqt%DlD6X;j3>ur-l*`T}R>vonwe9Da0G}J39`uG)%#& zD-S6;Y62NY#*Gbpx*(o((l8C~`q&+G>MsV-Vl+b;f@wRLg% zuhrU#%b6h&ogccida18T`f0_z;KM)6;a*9(a1$D|sbkD)$s%e)VRee*t`_945aGrOC;lK^O2SAe+QPvK4>C$ecN# zp(OB|SSnDIJrxh#Ygxc{k*9sNHiu&AQd+~TkT?SkSeTbC)3|kg(7Gd;w8|W+$UcVT z@bt)iMabB#Stla2i3cZg{x{lI`A^{W^S>D4CQ^Mw1>#lTL9*}ka?R>g%`IYo{bHT< zgnd3S_a^%GU0x1EQDi8SpfgJ@V(Gk6lM-)2$gnKDMrGna%ql@_GWXCxDo2mK=K8wK z+T`iL?1-wlXzU4l6(d~fmAhN#&wYXX&UmW&Vox-EBc@g&3Kqo%+<*d|YzeAmcKrno zjQxFDoqD)3z6~&j(HaR-%a&s3uGhWUQVhI?(+}SQ;?by%38~gVUiB;XHLXDX< z_~3PtAnMLTSTesXHV~~eV9;EH*F!BJ_4HrgM_X17;<;`lJlXI;LQ-H6TTMbbySG+U zSW}q)?Fk4;ux*A+RW~2Gw8e*-;i1gKBqTH{3@R$($vnQ)nP9OjNFxjtjJ^vIC&MrR zsq&=b%U**q6MAyi#iW?NVbVDFo|;?QW#Awsz?on$>qM;4m~FN&Sv zF|LyDiO%om7x)No{~X+5P-tyPu(Te+L%j)YyZN6{`~9X<4H=zAIh{6k1g}GW zFS{+iLpB_~q>$jiGcM-g>A*oa*v2BK2tbho3vdL#mGo|){@0!xIK^JtFc+0jGs8)_ z$v_)*yCC>mm`;N1f+V->F?YS~Wzw(P8-JrdHvb~3?=HQO5gIvS?LkkRXiZ%Hpo0s# ztc!2}rIAqq3?pd2MiRb{B2`9N91Km|YZRym9vNsl?eHEZWobLS{anRg_UQ70($`cz z;awJnI8T7&FeZyeD|s-lRd$A-mNWB4nT7wY$^nC!G1ak@P2BBzh!X-{fJ5vKNC z)Jj69E^a_X$ZO71$KVIS)0phk#d@-_0PfjV}{BvsaHnLqXs6~*19oUK4yrp2NRcBbhW3Tfx1F;#1RtG{D&V7;(? zba~5CSQ)18BqdF)Z&oe;yvjU1BTM$I2@f&LzHBBMO-4~vQeqW*M1gu|9KRpPVR|ri zZnX3)G~-E5p>NWf$g(OTrIpXkPl-)${o7Wx{XI9}CBiLOy-2|K}iF zhF3=5ucPG{Rm4BZNN5VE0J$k8TtT)J;~Qu(U=e|q*GYQfmwA@=y8dvRqV&;Pn#xBF=aAXy)n%UYe;`PNsmaP)pn}cLJy%2B;%y6dynRY=BYjV6@dL}DSdn+}*-iw=gwPF}??bn@Z zoBNGg^&EFPW**;u1B!#4%js7!$6sYR0Qe=>l>|?nD;Gnow&Ri+i6TkvC)}NjJOa82 zpUksAcvVe_`|jkCW!$yctv{Vz_84t`w_r;jKRiZE7AMP};cPHw!fn<v4y^D&e0>t~{RX=x6Scd(%x zp=o9jibV?j&wuO_D&e>kRoRm9?}pw)}AlI1k(SqBjpjNa8R#HT9* z1C63(UjHEea6=juTQbsaW41=aXT{g~x*2-8K#?Flr5Q&@+qIG}*%huHoz#cdbfkFQ z74EI>gt4Yhepnu9-(l5TpUyb?YWt|wfw#DC*d>9Lv;hFXbKp^MyjDxM*B?st9^}Bd zAy$t7Cu~V|5*QVzKJv0J>{uJ8e%DPnV!J=M6)$B^20xPt zg`v1*q7D{quXKhp$@Mf?XFmhme-Ou6sLP%c?k^Ts$Boltz<5U(Yi^MO6|^x)4ITZ0 zeYRoZw>|Y6J;qfjnVW+9UERqzpEsQqUON#qc}7 zbD_B^8(n$W+GZrvoaFT8=^m6>a11ThBKxRIX68&hYDMm^D4HZf*+;7p2<>d3|3HH8 zQ>0`jA&c+$AQnR|(ZQIsme!XvE^6|P8UAkn2?c4aZNP3#C6hem=j6_}|L)0T6tOp6 z%@no)-~dkb$k|{$&F)Hc0EPCQx?&`?`?iu?${Nvad)Mes(0k)ntHZd#pSr6cl0M;q zC|+R1;6zP>cL7%PDIh+YkQ<32k4CvUjcMxVOg{X0U3&PZrPR9T4m^3asExL@WnuBu zqzhjk5OUm~b-dfC=@&e=883>(j6AkxJrqXB3KtOU#^ECa^dI9hu^c4%U8=fRGQv1L zSs56BQB^%WC;O({bX}(G-atf#!xz48F`XkuO~2OXVW|^^15EGmo_JY zuAhD*s?;}X8$YmR-P@_i{E_SXs8;moragZ@)qJWuoUn%{AxB~m!sG#WB)Qy3`ank7d7S)B&75F=+>62G_G2p9uXSdT@p|v_+_x`q z19LfLd8b8^iwnGe6H_?GPSIG@5;NL@r(0MQD<)#1LK~4K4g?y45S?gourCBfbAO{` zE)W`z;h?k<0UsGdxCQ|}NxF@4-`-N$*N5=S6&V*=1 z7e1$Z+^sj&ufsv5P`^4ay`WzwDhjn%&vB>tY#oyveFxRIxY@EtU8|%m4j^||wafzh z8P^IdSAF?>&1K*4xA8#sVr0;0`+nnP%wgD8m?;9qN|IgXt;B1?3P}wo$H6L2wY-_4 z8pclvxN>dHz?MOVFE?1$F5`h3x9?Z9XZX>SKK`mv!{!n>&p^Cg`?qGE#ij@JHEfL@78IJ$M#hp!YJpvPBNGY;j$2*oLW;c8mN`=X4&!>ye$lXE1Bw4^Kn> zRL$gev#`=nuQ3~)@fLM-d|kKgfkK%Fpdcja6Y@NnF%}eRAQK;+TZ&J^@4+MRY@H?4 zJ&`Qov6`y53>y$Q5@a3mF+8i~2Wfsu6E<^Pzam;QBJ@G%dLrO)n%B}v;No{pN7z2U z-2GkcpGL2-XDUtQA|AbGM~llAG~1G53&alL@?3(1wkZm&c{VYYuCa-|b|jjb(Nn!d zN78A{_{bKgd7q`+dwV~U{AKWWjJ}9;NF$Avhe`Q@roAaVB;?s--BGfKI;CSsu8v|e z-@@w}=kh&~I1&gP40G!p0b(c9WV$Ww;BKTX1b!Yk9PpR0K$E0tXo20I2r2A-QCUJ7 zny0=!b>4XFTv;%jp!&12xBur2+lFhTXQT-BtZdOQ#(#=?uWqdE;lUj|y^-^SdIq-t z5CJmUccPN7EJ+lftVIuZ2zcm|t|)S_!ywyMvfmk(EWE__sHIlG(5rs@a_U?X49V5? zmXLUb<`naq7)aIMa0BPy+^SR!6cYG^G?<3#RwP82<$rNzw}}ZqqcV0f_hdJD49b1K z=MLh&^_lKnqsf*tI!P-H3*vB5zTxRc3=2}4tffeNA+M!(l zpea~gOTNA+d>@e;mDD(HyY=oMSoJe-6|UcI|!qI~N_%>&P6u zgVS3HN$7}t$^F3r;bc!zw$Plz*j9au;Su@j>G4n8vrTS`O!FoSX};~sly@GTuTh@^ z=mCfV8d9x=5gJ;o(+qxOJOx`21Mdn1!AbF^1b#3afSGX6)oPKU_hK7L&YcaXj@N;Z z&6;^L6m%ooU{YK;+Xa|Je|hbk`hf zK#eb4`Hkj=_$hVEC%zj0mj~4ADbN%)l7pw|lz*4bS=zP*u70{pmV|aQ^7}; z{icBHy}t6G8_fwJOk20NV|lPiDDW-rvrjGQtfsmxa0XC~Uf0@^{<1)ptWD|LXHzhX zyCkDN@-8M@V`m<0lS>((+ehb7KfeDq{rPM2CNub!({0W*JP;5k15aWD_>HEnQL5%? zPD)&K!DYHLxQE#R+=Lbqi{ES@DyWeYCkG0kIGZg~=cTDVk!W{OP3tie){EB;)2#Vq zSHDg1H@e#dU$(0^xN4YfJsVQUkaXq$w+#U2@m$GRvBj;#ET?;TwZYS3Ng*;x_`hW~ z<;G1dtmn;~wq^1k>!#|#{)CSeloRW@bC1DYv<>1s>vsiXoG$MPAP0Jl5*`k8+aoCR z=&9Hwy!n!T$M}Ul6b4CH7+#fENl@ zb;wuhd(Y$HSWs1FT7b58W85G|v9N&$Mjadba#AdM|9Ef}6Mhgts%#G1;+ccdH&m&X zT8th!)#SCKhfbhzAz!zGnLA@XeXVE89-L?L7*lt;-Vb{4&nm(9hf7|}ban!;Ta%zm z>{2f;Dx6E==v1O&(-X&6Stz-r!VSTAUr?tZJ%%wKWO_);_UebE6SRGdA>MUDS32sq zU(t_qDGsSyP_H*)4yhuK1_F_9_YW)UIQXjXgdO2^Q~+MgXonlNyc}v$E!>}2pe6{i zw8*+B1kgGLO(Se*qbxJkV2uJY$Dozz0>{Yc=HjofN+@^J&ujmsl__DJM`Nv68321W zGHWh8{dvz1y@OAPgvOtEa5tA) z7lSPy2Co-54MwN>{hquc1zsMaIRVJ^xV2<18jE3VWvVPF83>OPby2jn^Py%N#<+E; z$EJ9MKGijRzgSqU=6{)uZ1Yi7S}48;moNF77V{?lnX(`Bd}%$LKr0OHgMCEU!Yv)L zUHzP@YPaMJCtP7muc0gUBh~>j{Q> zeC&UEU#U!#r=`0|g)x)7tc(GO#9EN=#m~h!{NnkTRBF?o&RT3}MaRBX@}Ekt z&gV=gs5d>b)~d1@hEI;vIw%%wyw^EgLph410v@X~#ay!;FW;cXUf4z<9jH4Ga1rz< zlo^szw5KtXPCH|q^SNi9SvyNIV6s}s*pSs{hNTVTk&@ie^Y!ggPJgM)c%td&;`h6M z{1g83E(3roIr@l&f+klyaS48BA^S>!Cvv4868PLyUsU5c!?p#po1}E5 z#Tc2x@=(@>OE!AU=$nP*UG-B!m=p6@Pfl$UZ1&_;`JYd6T8JtSWFqOn3+JcI*^K%z zTe3(~xOezRy&QUAP!yX@X};KO5>j2KRG(`su{?b@ar-^8*n`uxxr%!@?*&@ua4~f} z^vA(nj?9lGQ?I7Ap|WK&k*+?s%&oS^28**Bt6#`{uz1;FHf|o@$Ntlo?(*{6<#DjX zvkDVa&x6+RKnGiJ&LN96Zo6v&c>@|j_C3O!g!cgpDVS!o9$Eu0SxM0AuQ+<;l_Rg1 zp87+}JJ@}=WVWhE=#r@bO83PJtQ>D-jlbJR4?^46jH_!B-dHEV94PVctRI6Nc+8t%j=W4>tr1CT>UOoP9!y{@JD-$)_< zzo8G7+wAHYI{a^ehe%%Q9IjhlyTfg{;$Le&l<}&U?dh?9rnGmfQ0?PU^AC<9uGgF1 zQN5huAR^VQr$jCBiL@d4VpQ^80U>(a|GuytI!;{%F_?8bzd#t~#2ux3^aTqkTuto% zXLq-3=at!mhbPwCO(>09_h(jq?AIy2M`1papg3`C34I*JUiLox4w9?8Hhzq}@GeFi z2mqlixF7Yq61iRHvHx34#PgQ=-;-PXf8*#lY)QvHBnHuEDj2vxWzSddix+O@u4_x5 z8VqI@kGIbImmqpfR0J{&jbF#!^jH_kzclWO@H>j4fXDDs-@SGh;d|j+mZ4q`2gW(* z5uEb8ZTxupUXWClsN~iRNq#`;nci?1Md#c4w2($nC^vu0d(*Y|awd`^=CzUc-}%GG zq!@bj9EiQ`HD_+&G9!{e`$?(|IH(*y;;nQD2@1K4dNUZ-EB@@9Ojx7^P#IQd+T_vdttT#|R)78lc{sdRU9n zS&~uqiC1iDb8lE~JeD^lgkzEbczCBSfRarQKHYu>5B$LC=M( z6Lv$Jyk>4e5E7VI>^U#x;kpCMYqT-pEsudYDxOT&k;gvYjn?5Cb53{}LY4>3kNi3S*7xTb zsY!m6$4O{>GVNmKiK;w34b-9S+xo~Vs%?Ap2Nn3^TYhhRrA|~RkN*hX0R;e{T?HcV zq>GBtnx`v#x+OLb(?j1u0wd!-!c$=-15*$(Km=xR>vIkNPJ&{0&wON|i)T$&G4vA;p5gz`@1nSpXhTc6l!?6QD4@lg zV%IxdFECZ@VQC_+m1TVV_c-@l>UBtWlJhg-<*LgQff;<#g}rppnLxSlU_>5fwa%Mf zkWzp3Mx@MJe{Bw0gTg3L$=S~z*o#AdzifK^!=Gj;x(Wq&Q}xUKN2U9Q$@xR%SN3K1 zo;i+N1`mGdG=eZl^h;W>dV{(&pS!KRI-e9f=o9JqAplev9Y|d`PS8uiMM3GwDR`rN zd$_&~O}5EG3G?@Hb^>`SG?5A(YqIGxaGfQ7)rNNHD8GF+uVs8y z@T8EmXMov*J`LC4z6RA%$P2LRhoi8IJeOkpHhwKF-q|`zk0W21BceO67flZh8eUem zirK(}M%1Dz9(%sakxR4cv0wa))7|*Ti{#5x3$$r?s(aVP@RsJVPU8F}27pIEAy@<^ zb--9V$!MmgcfcIp-s?m_@?+_Nh%PqDn55xcz>le6IB*)0Dl`F*O{rqC5zI-|LeO^W z;7DV`cWNjM=lue!!vV3dF174e#4Ps%4=&=pLP)o}72zwaO|6%CH8{PV!ri%0D!?6J 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 =4U{m+sJ@}sfm+aFA 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 V-}`%i@9+J+zxVh4-rv9A{u}xRWtji~ From 4d7bc3094aed9445a5830edfb850c22839d7b2e4 Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Thu, 18 Oct 2018 16:14:53 -0700 Subject: [PATCH 064/114] Fix regression --- .../hifi/commerce/marketplaceItemTester/ItemUnderTest.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml index 4852158df9..dcb67f3f12 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml @@ -52,7 +52,7 @@ Rectangle { } sendToScript({ method: "tester_deleteResourceObject", - objectId: resourceListModel.get(index).id}); + objectId: resourceListModel.get(index).resourceObjectId}); resourceListModel.remove(index); } } @@ -83,7 +83,7 @@ Rectangle { color: hifi.colors.white wrapMode: Text.WrapAnywhere } - + HifiStylesUit.RalewayRegular { id: resourceUrl anchors.top: resourceName.bottom; @@ -311,7 +311,7 @@ Rectangle { } font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) wrapMode: TextEdit.NoWrap - + background: Rectangle { anchors.fill: parent; color: hifi.colors.baseGrayShadow; From d7d49ed84e66f9517b7adeaa9a1baf0fd7b71f2b Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Thu, 18 Oct 2018 16:25:26 -0700 Subject: [PATCH 065/114] Remove cruft --- .../marketplaceItemTester/MarketplaceItemTester.qml | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index 89b1dd3915..5f2268132c 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -77,7 +77,7 @@ Rectangle { // // TITLE BAR END // - + Rectangle { id: spinner z: 999 @@ -281,15 +281,6 @@ Rectangle { } } - function addAllInstalledAppsToList() { - var i, apps = Commerce.getInstalledApps().split(","), len = apps.length; - for(i = 0; i < len - 1; ++i) { - if (i in apps) { - resourceListModel.append(buildResourceObj(apps[i])); - } - } - } - function toUrl(resource) { var httpPattern = /^http/i; return httpPattern.test(resource) ? resource : "file:///" + resource; @@ -303,6 +294,6 @@ Rectangle { itemType: entityType, itemId: resourceObjectId }); } - + signal sendToScript(var message) } From b9a2f19d302f87b74a13d75f45a0285883914d3d Mon Sep 17 00:00:00 2001 From: amantley Date: Thu, 18 Oct 2018 16:39:50 -0700 Subject: [PATCH 066/114] made all the suggested corrections except the dropdown qml. --- .../resources/qml/hifi/avatarapp/Settings.qml | 36 +++++++++--- interface/src/avatar/MyAvatar.cpp | 55 ++++++++++--------- interface/src/avatar/MyAvatar.h | 9 +-- 3 files changed, 62 insertions(+), 38 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index 8749079940..fd72d70106 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -354,14 +354,36 @@ Rectangle { // "Lock State" Checkbox HifiControlsUit.CheckBox { - id: lockSitStandStateCheckbox; - visible: activeTab == "nearbyTab"; - anchors.right: reloadNearbyContainer.left; - anchors.rightMargin: 20; - checked: settings.lockStateEnabled; - text: "lock"; - boxSize: 24; + id: lockSitStandStateCheckbox + visible: activeTab == "nearbyTab" + anchors.right: reloadNearbyContainer.left + anchors.rightMargin: 20 + checked: settings.lockStateEnabled + text: "lock" + boxSize: 24 } + + // sit stand combo box + HifiControlsUit.ComboBox { + id: boxy + //textRole: "text" + currentIndex: 2 + model: ListModel { + id: cbItems + ListElement { text: "Force Sitting"; color: "Yellow" } + ListElement { text: "Force Standing"; color: "Green" } + ListElement { text: "Auto Mode"; color: "Brown" } + ListElement { text: "Disable Recentering"; color: "Red" } + } + //displayText: "fred" + //label: cbItems.get(currentIndex).text + width: 200 + onCurrentIndexChanged: { + console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) + console.debug("line 2") + } + } + } ColumnLayout { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9fe91e44b9..2c9b83b636 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -464,20 +464,19 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { } } -void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { +void MyAvatar::updateSitStandState(float newHeightReading, float dt) { const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; - const int SITTING_COUNT_THRESHOLD = 240; - const int STANDING_COUNT_THRESHOLD = 20; - const int SQUATTY_COUNT_THRESHOLD = 600; + const float SITTING_TIMEOUT = 4.0f; // 4 seconds + const float STANDING_TIMEOUT = 0.3333f; // 1/3 second const float SITTING_UPPER_BOUND = 1.52f; if (!getIsSitStandStateLocked() && !getIsAway() && qApp->isHMDMode()) { if (getIsInSittingState()) { if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { + _sitStandStateTimer += dt; + if (_sitStandStateTimer > STANDING_TIMEOUT) { _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; setIsInSittingState(false); @@ -485,8 +484,8 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we are mis labelled as sitting but we are standing in the real world this will // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateTimer += dt; + if (_sitStandStateTimer > SITTING_TIMEOUT) { _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; // here we stay in sit state but reset the average height @@ -499,14 +498,14 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } else { // tipping point is average height when sitting. _tippingPoint = _averageUserHeightSensorSpace; - _sitStandStateCount = 0; + _sitStandStateTimer = 0.0f; } } } else { // in the standing state if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateTimer += dt; + if (_sitStandStateTimer > SITTING_TIMEOUT) { _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; setIsInSittingState(true); @@ -514,7 +513,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } else { // use the mode height for the tipping point when we are standing. _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; + _sitStandStateTimer = 0.0f; } } } else { @@ -530,6 +529,7 @@ void MyAvatar::update(float deltaTime) { const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength(); const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders const float COSINE_THIRTY_DEGREES = 0.866f; + const float SQUATTY_TIMEOUT = 30.0f; // 30 seconds float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); @@ -575,19 +575,17 @@ void MyAvatar::update(float deltaTime) { } float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _squatCount++; + _squatTimer += deltaTime; + if (_squatTimer > SQUATTY_TIMEOUT) { + _squatTimer = 0.0f; + _follow._squatDetected = true; + } } else { - _squatCount = 0; + _squatTimer = 0.0f; } - glm::vec3 headUp = newHeightReading.getRotation() * glm::vec3(0.0f, 1.0f, 0.0f); - if (glm::length(headUp) > 0.0f) { - headUp = glm::normalize(headUp); - } - float angleHeadUp = glm::dot(headUp, glm::vec3(0.0f, 1.0f, 0.0f)); - // put update sit stand state counts here - updateSitStandState(newHeightReading.getTranslation().y, angleHeadUp); + updateSitStandState(newHeightReading.getTranslation().y, deltaTime); if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); @@ -3893,8 +3891,8 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { - _sitStandStateCount = 0; - _squatCount = 0; + _sitStandStateTimer = 0.0f; + _squatTimer = 0.0f; // on reset height we need the count to be more than one in case the user sits and stands up quickly. _isInSittingState.set(isSitting); setResetMode(true); @@ -3909,7 +3907,8 @@ void MyAvatar::setIsInSittingState(bool isSitting) { void MyAvatar::setIsSitStandStateLocked(bool isLocked) { _lockSitStandState.set(isLocked); - _sitStandStateCount = 0; + _sitStandStateTimer = 0.0f; + _squatTimer = 0.0f; _averageUserHeightSensorSpace = _userHeight.get(); _tippingPoint = _userHeight.get(); if (!isLocked) { @@ -4155,7 +4154,7 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontalCG(MyAvatar& myAvatar) cons return stepDetected; } -bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { +bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const { const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; @@ -4179,8 +4178,7 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl // in the standing state returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); // finally check for squats in standing - if ((myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) && !myAvatar.getIsSitStandStateLocked()) { - myAvatar._squatCount = 0; + if (_squatDetected) { returnValue = true; } } @@ -4216,6 +4214,9 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); + if (_squatDetected) { + _squatDetected = false; + } } } else { if (!isActive(Rotation) && getForceActivateRotation()) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d1ba0fd9cf..be8b5fa1b2 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1116,7 +1116,7 @@ public: float getSprintSpeed() const; void setSitStandStateChange(bool stateChanged); float getSitStandStateChange() const; - void updateSitStandState(float newHeightReading, float angleHeadUp); + void updateSitStandState(float newHeightReading, float dt); QVector getScriptUrls(); @@ -1744,7 +1744,7 @@ private: float getMaxTimeRemaining() const; void decrementTimeRemaining(float dt); bool shouldActivateRotation(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; - bool shouldActivateVertical(MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; + bool shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const; bool shouldActivateHorizontalCG(MyAvatar& myAvatar) const; void prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat4& bodySensorMatrix, const glm::mat4& currentBodyMatrix, bool hasDriveInput); @@ -1757,6 +1757,7 @@ private: void setForceActivateHorizontal(bool val); bool getToggleHipsFollowing() const; void setToggleHipsFollowing(bool followHead); + bool _squatDetected { false }; std::atomic _forceActivateRotation { false }; std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; @@ -1843,8 +1844,8 @@ private: float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; ThreadSafeValueCache _isInSittingState { false }; - int _sitStandStateCount { 0 }; - int _squatCount { 0 }; + float _sitStandStateTimer { 0.0f }; + float _squatTimer { 0.0f }; float _tippingPoint { _userHeight.get() }; // load avatar scripts once when rig is ready From e499309c8e38265d0d76237984f8c3ad77dd99ba Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Fri, 19 Oct 2018 06:49:48 -0400 Subject: [PATCH 067/114] Upload interstitial page sound and update link --- .../assets/sounds/crystals_and_voices.mp3 | Bin 0 -> 254192 bytes scripts/system/interstitialPage.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 scripts/system/assets/sounds/crystals_and_voices.mp3 diff --git a/scripts/system/assets/sounds/crystals_and_voices.mp3 b/scripts/system/assets/sounds/crystals_and_voices.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..ee9073b0156e2a341fe75e22646f1a52b2a2adae GIT binary patch literal 254192 zcmdq|WmuHo_dNig83q`T9BL?;p-Z|uhVBkQ8cAtE5g9r}N*a`*r9njjK|l}zK{~_$ zDFG>wlA7n@^ZWjvx6k|MyqvkNd-hpp&Dv|?*g zS2fTO7m}3?gf;%Z2qjURMA`-bGJF*WRhehl|NG+qZx{Zo$rV6Q#o&`M0B{AVG{`c6+ z_{P)h^0tE7HUNM>9bb&AG)a@L>J$}qprJYs*0_KQwhq@a!?FEe5EuT$bTrgdG5`<^ zRJAVCRW#j*Q$grJo9uXCX3e;gOO{o=&`&*lb^7Y>7Qxa8i=6<)_X6j+_$NI*rkWvR zI?gsDjYx+X^$O;P_oKO%_Sox15hMOA5Vb!6MAq=$VIR5@AvOq=A;e2#ZZzWaK2c4S zD3e7n*96<;Z$1Y+9)ID5b+)z&4gW|0I2B9OCcf|$gz5a8Mn;2fUdc;YRRzwN5c~Bn zmrI}h8#nRz%g@J95umF-;OoB#Xx3}WE2PHJ*SYHw1Ilgo=xNUE;x$ZpO`jFU=8Amz zNxXR!`9H9?G-B<{vz~GDT!Og0O-cp-3PTZykMmMjhvu01%84Ng`0Za0U%dVSVWFa$WBkd68*wmel`J29@ z{#u;de$vUnE1kxLLnrM705bFDJP6+n7*^6DGkv`p>#|dBST444R2~+zV|vb}C}qqN zF6%Y7bz`X;ORQsiy6|4EcfMllabX-|mZQdecVsvkdOPOY%3F8MxLTay=1W z*=wTMy4ufP6!jyTk#I5^q|{H@NT)Pa!a5_#pNl=~#YEiaMIxNgkdK!aNed<@*PHv# zpGnbo&u*zQ>$S|MpJ|&)g#E74ZYaBZIT($#cxuDBRu^*Xascv5P(bq>4k^#RN!^VU zuvJrYs<_5!K5$ydoLaBDySeab8~wAce2?U?l%|0sIhvRDY!eG4VOkNLfb0iLnYOkn zy+rI=)L~LVhaR)-y5`T!(-|F9ZE);QJ;P zSmDncF~6cj@6ip1Q_AxS_2hRsZAlX;7>I9?`{Q0Gt+mB7vY2Z;ZUx}FuHKdm-*>PiGUS>KH}JwUO(uad7~e8Y0o*9!>)Z`8%{(;`7GBcLobIC8Q!RNhWMd z;p4OuTUv~o&9IN$MErRBw_hTHdUJb3b`U{TEv{mLuZH;TP0e$Hb=`~msHJ4=M zB>>#4Hy6z*3*xw+-qr5mm(=kv`*1$eIms@B8!529ROS@6`V#gU#uJg;u@EF zUbI8fqmp0q-Ba}(6fDT$+m0$hk6Mraotn0XPbf3xFL{~FrE)f}1 zc5l^dobm&fw-WC>ZV6bg4ny;3L?$G|^$OeM#%@umD&c^36gk@tfW`%8sAES0gP=w3 zVjo;IR;Z1875cyHO}sxjl-$u}^Qu-&)w|VuzxbIzD>*^8PM+|8`mx@Hw=cm#@Mr#* zjVJ_?arocTgFNY8#xysM7|rz{(JfI=)Dl^xVpjeLjlnvAxDe7%`BNCDzrus=;otLx=5FpEJAYevF*ckR>Z9KPLJ(bx-veO3eLrSg)5FbUV%B(^ z-h$7^!lrVv!l09!o9!uq`FOErsKFPh!e0zO0tV<3RP7%?C;7H7sI@L3P;32igai?Z zJa-HS12X`U`F3#TbiOr=EUmEph+>K*;0H9>mVi$|hBq~dDyX(Op z>joa&<6XjbK($K6Q&EHx`K*2Bcg`TRYDoF17AEKS&FW}3GAqVgWWxR4)xY5~ z3R2H9d`6<)D$~nX?6&Sg^uSGWOVNdoBxOypDsRQ&7N2YUun!aQcw%D>)Ce#-SN(YaVpERQy1sBiG5+h$V7 zmozcU$~O!|?!h!}80FdI`gJZi&2AGdnp}q_$y{+9!MATHwt2HMG)qOnn?*hXC$3_lG+H#J2B&Xk- zUHkk9s$<(lL(0z$0AOI$%5#Dy8FWN4G0WF@0w5L_OFSD#SGvGr;$%_xlt`l?*+06&5k77#yP8R(KWoSK z&z;>^n!jRf$qABej-G#1tt3G|%f>?3p#=Bv0MPT(&B>M7 zq)n?kdahDiag9mpUm9Ef@&cgF|+F8?(c4uoXJlp0r>2e6We0j!C<|edcoi;5VoVJmso~>-(Z@Pi%Dv9TazV5 zhKOz{60a|ltwrQ!9Xfsy+vPp1O}l=dbb07g}k@)Y`R4FYu@#ll3O?=8TUboncw zwH)QpGDvcLvP)|2+Lhx zr6tFVF*dwVE`5=2VExQ8Fhc5?bxyt^#L4@X-qR%?B`a$Y<8`?ew=VqZU0;n8Afn;N zLpI=OYD;z+Ur1|iS6c1qqYu-dnvuF65*RkeT)aO&%`#oRcc*6Xt2rsrss7N08*3{NQ>T@j-5WA4Dol{txT~!q*nN-q|HPE~?RA6jYhqzKF8Rf7aiPQyLPfVa z-8}ZwxDG4wzu!~qAP_0GZ^}F>E4nrG+KwCDm;TFfHV7d^*o*($|4zBzzPy-uXdapl zBp{NJ%22=zF|J4vl=U|=5X$N?d6_*Ikv!s)umd>s>NFI87{~{a`=|ViwA0pkbNr{l z)i9s>IeCCRkqj3eUj>L?3G6Hag0X}UcX^M;{^O(vv?^-*0?1UZr#i_a7OOSgYFyS0 z{SANmKNsl*D8r@TuP5{Oqnk)A5M>P zrspTA?h(1=^)G5pe_yxy>t&S_$nM*P-wD>Lj-N85-{Su^{az9W!~;$J-T)wqfHKK% zOK4m}nDCQ5-&W`dRvQ=*qbp3wU_+2@Ny6hdc|K7-CiTb7OWdD*Iqs)Wr7$F}w!%wB zrk})&?*>G!VvOwZuik44%BpO)J1baAXw23yEF86>ZRS^_ScnHt_1a7545P>$3d2X! zZY5TDOt5=GXgPVfcK1*a{S+1Y*Ft2ZDVm&RaBGCXW03y*8h7p+qLNso_gB7Qsn-Ls zG&VwRa+(Sy^N$cqHGcmHS^UUZiH;FUyI1U4i$YvyGYF?-3R5Ha^4K%xo;F#iXkCY| zCkfS>VpV=H{;)!NPfbPacuuAEK@h<`6$XUqjebH89jA~4-Za;G`Q@MQ`zu|Cgw$8! z6wVww>pfgUj^$)pAN z6B@cR9t#A8l!o2^m!pJigwWndV1$}dA&IcZL|Ml$*B68ntPtYk7m7z%7#of z!tS>-wl#Dgn|kSoRq|>?Sl-QBd;7HZ&u0-QH!R6}vc@$)68xN+(`=`R{NNQv2jj>P zO{G%T<~(mQNK{N{@4VfF(fmU>+UeYj)HlB5nT=x$|0+0iyYRMe%dFP_6Lt&$R8)|W z-&7FFYrxxm1g^-)i{K^zwr5s{$+4E3a_1wH$q)WaQue-UU;7)H!Y}*o(c8>)>&HV1 z;wSf!mhi85d>kJRh(K-5{Z0L^7buS?2YCSIN2={Anb_@+Q*6D__~R`QyarJEEUTxs*@c30Hu1l?vP$ zJCU93SkU7eWS#1IsnVm*e&sk((C{@_$)reMTxem4`$a3tMkKh;^LK@c4CMJzUxKef z$jhTdO6$<&$m>3X*H=}3`$tMNb1Zr!-w<^3G8P*(pdJ!g?ZV@m2VNuuKXaHRrRR_Q$N$da%pY?EsCU^7!UdQIbo*qVdVGq5*CmN=bNVkHQmwUAJytlJ zJkO>A+5>%<#+g$RlG}Nf{hZ?ww4&j*7Tfzbsti8W_jhXOuonzP_quj(tW}0d} zA2)t3ChQ`+tESjXbOqcg7D0<1{w>TDX5J^8=K0Hrq&!G`Tf`5|oVnInnQDGg1mucz z@#ElH1##@n!fCL=3hNXYd}R)!I)G%7{=J}c4zw@S65Q-Gc zdRx`CG(C}|j{6t>G&>z2)To5JumH(^t)e;w&Ny}A z4V|_rIDU|4unjHDXp36pX;3T>2_@SDC!o4N;v4XG#n_wht55NI& zOWnAm7c{uwDXLfVGm5%AD+kVHUDY4&)Ybv154tB#(o*_pT!BaVkS~&j)W*e6cVsqF zGV!MheQmL6mcb%W1-mcFz>gRE0Il*wW?AI#__+Czo}_S7g`VXP+>n99-TZ8**wZr- zp1*)nq3y4ea-(6(bzX}Xw)Jy8P#$x7(>w;%lLh=)1`2SZfbfM1P)cln8lSnA$e9@% zroyE0u7%k&V&B~!#sBQVnz&26fOPNZX}WAwTyk|j`x-*RIQzrj;HYOUDu6Tzu;4|2 zZ|#~kpkovBR%eGJQY-b>z;`oy{AhOdfi!U(!6?lHleclG~lP`AAb%59<_SOH|fBeisbr`ahXHZgX?` z2Oz4)iLTD{YUoGzIK=mb@kask1>% z=YY*BI*i)4UEUpk3nQNb19$Os?f1fX{6Ag*5g~v$SRx_1S}LO0dJ~GpYU6vxCDgb9 zEyGST+v)zlN)kJ=~gb<*>19A(VAp??SKZW%giAh$n*rn$sekBJ9~hIaUDIR&)8xPjI-x$|(w5wrW>bs@#mk;}xpQA{NFc0SJM4Q7_0^F`7{huW`YrtRu91i$S zR6t*bWE=E>*PWI>Dv{KYsm zZg(vu;{b;^8vZ7ojAjn5ScXJ=eAO40kF&d}?(EyMTJ*d#hqi4UjJqe#dtDd z7SCB-!2v^z%qQMFSl+`R^8~f zZbUK_Ai3@2=6FWt9uZqVY;^|Wfww9 zF?iT+R7RCrOX!IpRi{p2N^KNv=XZ~5B1G#ha+}+`>Ef{7%8|R)nXfx_x*HWAbsVMx zjI6UvC>h`s+7za|CfODXi>b)WaUpomURr@qH z9PF;w1eyi)^>=*UJ!Z#3U>1bvAKd^-L}=YaQgb352fhEDkThgx&KdblXKpg+W?k`% zB0HD&_Dg&ObYVL`o1F1%?ENLjH@{9E4}HOgVs1XF_sM!ap_1g%Q(OiOpmvnNt;1(M5-` z$=FAo39L>V!~~T`#(P8h7Id2ROOqyyq)_%zy}1Qi$4PM`HCUjE03^~>fU)~|Fq~zE zXagO?ZDc^I*HE|d#I2Xsa_XO6o7+WY=vUOgTlH%p?paY3PaI@sb=Tq_l*YmaGBih-G|x?g*+MCCiI6rn)dXvG!El_~cNa^}?X#(69pYKy?D!H~;lVrpUy;N>Y6H zMnam7=w>|5q@B|wS>VIS=JccFF#utNXGX>YawL-IR!|Rc1jO-~D$)!r_k?Yfnz`N$ z5an4(y}ooms8YMnEFAmpMpa12YdU2s=IJZOZ9)*-tOjTL3cTuN`CV=aaqz@Y$*m0+ z+$G6cXKwk*{N2^Ih3RgRlk_J60P>V;ePfaX*Kf#*R3v**@sWxC+xTK`D|wzsiezx% zWB0zu!gKbFd71II5*qLS_Dv<(GM!~}4=8a5eo*d9t+c1Z0&xrh0#61Q|DX`&9KL;u z+7_{zx05AU_#Z2FV_XK&gs2B)_CobEN|b-Zemm82P%l4>da zrDRLKG;c7Z2-RlZU;bbuo{FLF@{+ryC|(%YiGXm$$s zmZ}mTK*Got1sF>l*SmMz-Fu>jlz^bDM2SzSh+II~?-pL)scMjzSxIQ^?1jo>5*lq4gDNRe~p%pE(zkjUmwGwfcm!CX2 zRr2=RW8CWJ{0NuXgd8DO=exqJ3vQ>y6V|$g#%Udo9oBj`S0^j^DS1t+g@;MW~)C|4+{s)>;AQ z6BJ$@h)|F9rH*iz(U@Ol;%zLH`igP7t;#O<8a;VDwIzZi>wP)U)D)EwRr!KU!S`&V ziq`EDsDi!(UCVR!s>$#TVAUwa`(sC?YsvB3r~In|j13tt0_ES}52n)r1O=eG08p>^ z|FNvj$O?WymB}o^PaP#}D2YI|IKE=TJ`=~^;Ygi*Xi?ZB7e%mk)s)l}IBx$?QRUHt|75inAYLEGr?pk1C9hcA8h> zS(s={OcwAP{FMjB5XorCZ<13rv^g&MOa_h_>}yU*@1t7?Rq0b=Ff!~76zUwG7w-I) zdu_%21Hr2+(NCYrHswMe(VZZ6Nt^xdWC%djIYe{)yCL@&$cvt>K`OeV5!Dn%JvBw# z9Mlca@4TEuIh0q7I{;8}Rs(N8(K#7)#u2w@PxzLfbiE>c5ufUQSe3VhG~)K$mHw(- zSnZwgbCa9=iyz?7cV|V2;x7w~_!kMG`uTeR*qQM|hYSPMNYtQCDdrp3_3&gucgt?l zJqbL?GhM>Cl)L-Z?`hQ*`@*H{c^?ROR<3*}NuX%20gtnKzhZ$OHU%D~x;5;~%d~P% z9S39AlFJ~jot6zMPP0uQtuNZ6c}UT&U-4M{k!ZB1erc2r?eVa5@aR!Loy#!Ym;X`Y zRNfT;mF@xMrE~~`c|u|a&fS%lC-J#;O^Abo&yRPpFeFB-_*LGz>B=vCj(cu{LV)~6 z*w>d~i+WZ48uTrbFZr#o>bxk2pKfH?EMe{fNRGb5_Xq;s-x;w(&Y33v6dgH_6NuQ3 zWo@tC$6Z80)>%fv_0?t6*f%;oH)P?0p_28A0#2lw=lhO1iKz99`gJ$XF&WRY zDIrJHb4Iz1fCfK;MI#LskpjK`0s;vgne1Si0R#rRKDe7BPcU*Zdj_=Gi^f-ClH zL8#9eN4%M|Jq&x3>b)uH;3D@Vw?#&H7s=KRtIEq2q0i$#w#JQ;UkjKtuT*>Ltekh_ zo83>j>MUIfWQntWow1(yxSQGkouEZGtbin@6+nbF2&W>t3w}d}SXQV-#?j*Xj!xIKO9xrNPGTLjVSV0ocvSA6K9e4>N9x!Z!EN%0YD1@VrUS#8UtA7@oW*kB^*tp`?Y+ zmYP9vzS3%f#Hd0N!?8rtt9>kFnPud+ zwf2B)jBJ-1mm8cjM6#ZM#Ii%yLzysYpWc0>qKMSqj89_EE@ za7l}4WKvS7XnV$8q%2-mq!OBH`--lSbEXHNyjRK2OUl!f3UlSVU)D%VB@$1Th5`~% zs{SQPVer@{pXi<@lZQ$!br7deUJ{?*J!j4td+9fa1~01G$gz*EG9=~_P@k|GcZHYz=iZ#p&SJ$V$da#2{df)Ia!OlmRztfF2xrzXvEg_*V2 z_E?-taT%#FwCOOB#~sKFXbbe#Oiy*s#Zf%ogYJZqJnk<+F=is68QBXAl*ni`W%;*8 zPB)qRs71fw8MQHw5%hB;oDLE>SC9BRE8 z=sa;0=7ardB4 zn?G_}kB&GiNV;C(Bku-PMCgm>v+_#i4i~(>KWofT zAXyU=X9xhVc0jXgWu8fCyK}|kXln^-v0fH|zR$Nekst4CRHpIHCA<<^cx7D@(Qj-S z$8b7WH-10M=c#nQF@S?8I0Kf5JQ2yQ7VF|dB#5aC1*ieQN@J0v?=i3nZWT4x42W6`5*u%cv94*Vr+mj5XmY=! zmMrJ^P0M}Rq4$4kGYrU2^>X{v*G)hjErQy01Y}9e7Gxplm|K40 zyo(;)szBQdS33xjA+ZMUw&>B2T(1_5PAU$?JGs-`ng%!Si@=3H+=(Laf0w_x;WqiY zbOsP}6*P7Nuzb;x5O%VflBiFw9s5vt5!5(k~jdO1XKGNi6= z7D6cuF|#1AY0W~iSsDD!HwADEhMnMNIXp^7Cn-M4nwtVBK>?+Do2vX#EQUyJq#t>V zinY_UK^mlN6lPJ26gCjUhCeu()xZHxZc(*2IKc57pkdCY6oD)lL5nXM zIXorlFaxP1_MRQe`qh0S#Aft`)AnA0Ze|-EbS#zWagfXCG5q{W;Bbfnv88H!yI3rN zit`{`4Nhzh34t}Gq~9cc&D(7Gq4K@{Pl;Lek3UKaQ#UX7;7#ONo6eX3D6u;)b4r zX5{GtIj-l;=+tqhpPxRx9D7EdfTAwjl1M_H2O(}U zVHo=?AVY}Ro8ZvOr9#y@9Fk|PK((isOjKQ@z(=LVzTAO+Dd`VI#p=9kqE_+vQuZl9 zj}bC1HPKRo@k-^gE$!m6rs%VHbi*2X%dh+eDn2Cr=PP&dBEA!1aZZ;nHg`$f%eE2u zFQ&%;JP}K3HU>QQ`Tt{F6oLWy`OHXXNH^x*sEhtJVjnlztql&`KZ>=(D%>h#O^hn@ zeZou%(+<`-E7nToL+i$|`27Bdd_x>Huk1s0Ob624CGfBvyA_T89<`rP#BBz@|84fL zCLN%}sWoroRIV=?_Z>?}V|4pMV+2ScCa&oXFD#@sOAL0J7>UeQn*?A9V$lO)5G`^> zp1V)~lDVJ#BT)D7L5kMk@%U%5b^uCJ4XDEbNo#au;$Z$KTrc|lv^<@ozN*_QTK8w2 zs!GhQxMQ!OKTn(nrrQ@ElAdtgeVh3$<3kcB{m%cwnVuXlhCoXZ)HHpTa9c5!QJnHt z$_Xt$QT{0}2eqb&kKRq1q+6&*Rsoe$nP*=hS()$i`&oG7&O=+f2!7Z4|E*pR`k`eH zq+VY!?l=k>i5~uaUq@R`eXz@OSr(2>lCCdrMsrfFU6emwX=d!J*wi@SPUL6Ne)gO6 z<+!_?9IZ$BAo4~=j$+O7qI40TZ<>T^ z|DLrKKbjaD`Ig~EAO?sqLl})?EbMeeH-MWqqL8+Yuj7&un7*URM=}}ud>5=Al3>C0O!Rlx zHDOj?ksXb%w%^*D{%M+V9BW?IS1$z>+uown8Sy=i;x^vrN5ZW?SfBtm3d(6@!@I{t zPId*{5d@*ZVi>L?fz*m=>+($0g8N5EZ#xm<&M9t779m@(WI6PjCT(=n?5rFEMQmxM zjQdFLep+_!K>c0UW4jyGRhTy(ro&{isKbjn((B_T-LWiG^fE-%U3ffc4G!?22sm$d z12id8w{GS&MaQpL( z!&(`Kr*%*3M^yk(ERpLw0E8xXHHotF;3^*yeVPOu?^!0C1WV~Q{i1kuWIWEBrJ_uG zF+HqWFEp@B+Zgn9-{q0QG#TJg1I{!Dkm&cRv4UD+++<L~7 zLY`$b+*-#&jU#{5$t3}OT&ImbmZo5&}|&4}a;ob6pCP;rRl zdecwi8s25c=}X6|^^!Jh{*D1PuT$R8Wp7hj$=IR#SFUdK6PUw zx$`0p#WE__-4JpyLlPMTV6)Tp9t6;Rnd?= zpeFH6hl~l+|HU8C`d)Q_{;Te7Ps2Rx`z;#v;?_n!cA9f5I~6uZPv8a`iT4)>|Gs)^ zIgft)EUdx*Kf%~c2XHM3>#Eg!@oq;C_l#bcIQ*H-vk$+h6P%tLkUslrXXe4s%3=N2 ztaJOu6k3dH>P^I8yJcIb{cQu`JICys>VKL5nR}h?w*yjw*g`k;6uy`l@E_vG z+}cS_Atry+b4{9LI7E8ei3@d}#uJfSVi&~EPt6})^14);eA~jcX|$W*vG44sw`3W&>VXox$nkM;!A=hTedLc_=7&Dp?s+4+opEdp55Hcl=*hD_Pu$RCS8k5TnLzG8iD4UX z?{apQP0loX{7zN#stcmu28R~WADG!;Q$@PNYF=M!*S}pYXDo-i0`4CKa?bkM+el|X zJLX@bH;DjTKU{gs6aAAtwW_m-Gnh(MN$-(9ai5d4OQ7*gNCfvw)|awYsbzEeLh@B! zi_|TF19(7I^d7=l3#}NgE2D1J77P7wT~oxLEGXhtk$5>gm%qniYPp*73%G1JCr8{2 zy{&p9TJ!BHe)WmolR~}NwEt=pY8>syDzRzM@j&YX4$C^E&;^N6*? ztVXQUb=_!1NfO%<4{?YbH%0~jX*=^F_0$1h53HaCN2b=6B4-jlK(0u)lxzLeGaX=D zG&Fa&(_>e$f}%};qkcwezH#HVX0MhwdSy%wjDu9^0vdT2XRpu+%u*6Vp294 ziqB@5Ji#>AD5^?COYWp-*X8RY`#6cXwQqfhzp@rv01?JA`rAlnK$Vl^yBlvPTp>tx zTanQ5l7d$;p=8*;;hZXQgJRs4=FXL}S{Y?=`t!9vu%T3OE2iBR2fE&bp+?*04O{rtP>kSuO*_TcrRb+w^4L++KUn~d8z zaSzh)_zTHtN5bm{wtL^eH`OTBM1yuSYsc^JHR*=(KAU|@{VEl8@_-?y+Su_f&C zU9k5v%Ld3yh;*x%@qHJNHh6Bc_O|N-Uh`51OEzMGkT1r9FqPO;sAECUa|+(}Y7o25 z|1|wYYdyhBEo^1wBE~m%wP=K~jiiDNf0mBf#zOX3#(X_daD7gjg*qIB!Y)+yUk89> zr9SVHj8^&n*?rUO=jt0`WBZ$vj2*m_UiY~A$71~nD-^jRu`pXsLc|M_2ir}m@avlC zL6DU{k|`edZzyV89?GrHgoj>FYEL5V_SemMFgI`TZDxDhCR2!d?eM=6?y4`U20+kg zO!Y1B4~^AKk9W?yJ!G+B({e`yR)#iKKmL?c!6&>tzT8-??5?#YezGxUv`86W%+QkxS1JOGjLj_aI-6X5b{ z&ilYWmP;n^`pH~UrqAGOOh(~;!UogHNhZ;Rs+aq>Q{B-B3unJ*i??nFz>7*u&R&G5 zx7r`W`qV^p;c+#`hn_DU%vfthz+ck|Y&|R(;?TTtFkmrZd(C0>%sO4n=FGNG?aAN& zy3{Yyu)r)9ruJ+XN;7oD>{BdMie=Q#6ARaNX{X%kfRK;{DA#pzIf+wLUF2q+Cp`6M z5_+mOZ=^*Q);v?w^n#R_K<2l2FL^W8^FyW8!ksnx$ya)I+q~TGq`$bfPbv^9IVIyj zu|{kJBudaaKt(Mh>$%FSM6n(Vi_1B4Ic4h5pZ#JrnZs)>G>4GeDcY?*g4XR}COcuQ z5+i+E*4E~b`_Hb%ln(r_ckcvCsS zv+UM^zZT05FOh3_zm+px0M!}Mnt;&!ToOQ2yGkZKSc0gdP#?@!2qn!n7#B32dWuQ}Snjp;s@S#VQu>YH>*K<%+HtjHb0vITzzEb>b2Lx{q>LEP@U#Nhu!I9=qV`La z2>dr|>YLwE?aGxOZYJ>*z3P}S__Y3N{Gjw$08&)o1cPoLmdQRBt<(rDk~Fhk(zU(4 z2q537hUoVD>EXj82L!1iT$omgFi#{?RAhhb_($wi&mWmWa^XA4kI&xB*E?{zh)v=3 zC-~1U7>yi$-I?y{GX~WB`LrBk#FV7#XcceIm{)Ykyp{>>{nL$nxF(Wop(?+Psbq+u zXoS4G5r#F3)8xN|5{2Nq{@GiH1*zmxL++Ls0!IZXZZ#P%{!6X8sH=0u-4>X-Ag%wo zSDK9d;l_4l9#8hGd`h~3Zniu3Y&Rs^x|7R%cp)9Z*Lv23g`=D-JVG|Iw)me&ZZQ?c zs7^=n@^0K-EH+czVoO!A0^EVC-D&1jR9`jg*xzT}XF>5$en zC4B&~a#jzxB;|V+n+-N#1J*40>ICk)RC_dQy#0BvtL^XYEc)+5?(2mOUA!KHqcAbP zuoqW$WFrbP!Dt*VtcTPfsK&d+$G}Hf%Wxw7gYUC7()kzD@Nh8@ zz%1Y+qz+`jcNnYrx3>R?I{@8j06dJC?xM4FgA+c8h$x3G{mb~HvUh4K`>n9bH1KJn zYDlJgF1aD{+ezWKUJm-0E;Da&G!hRLh}Wcj(v*+rO5g2ypgj!3yW4I z)xjlZDhlgb#foaF2hF#IWVz$d5iFJSORoTwTg{#68$hX;a1O(scgSm7I%~g-e_g)a z;AUgHo?i~qhlY+5`_`@U#W#K4qx8%<^28FTGN+tRyHYh|4*vb;HSzchbKv0>y~^^v zAsL&&UCHDqfVpFE^kBr}X5P4`hemC=jY8o7`fZ~&&m1|5No4Ze5AmAYt0qA{-i41`J26Rli_?UUG4)qOJY!b*50I3R!6<{j!5gbfT{MzNp4)y_(TK*R<&VS<4+21Z5RnC_b|J;&Gsjp>kPluQhaP#miLd>UH z2QvfoolRY5^lxY(QOOo2W~YD9ODBEDe-8Bz98#`%nv)U?E)3EfwMN(L#P!3MVR~`) zZr1w}{~HpyfC<9LnP}5Lo&e}Sl9parOGp;R#@M!Xx?GW4k!H$);fuvkjQ8DYT)siA z+(jJ=Q35mFbdLd%-9r_mg7z~gAd&fzg#%iu8nSoxmRw#C)Pg(l&Px|fZ=D4BLdYSdJ zw~Y3@F3e`v)7g_)J3w_yaCq@|Dz9P@$`y!NXnJ$56G0HEYs{c2;W`3QvmPPhPD0Fq z)9{>0h5&+G1`fI`W-~Eu3%LYb+h@LE-_Z}*F%G{CDT#{?{X||d<1Sp%A@uBV;&h9o z4Be8{A1L(GC&|4Az*Ey!B0s>3pQx&^`#B{tMz0;IG(d`0BQms$3n+iN8DAS=|pT7=@ z2{oE3xX>wGVj?Gk=~-3kHieIc=erI?N%RA6&CaKeG$>*`aWF_K(~m_6i%B3+JatB5 zllypC%82UX6D0I#pOsed<8koDL4+I8w1m}3RI>X@TzV6~lCS#}a7R%HFAk$KL3LjB z-a)(*S(0}5W96+*E+@8(+ZQ=>+cw_AJ%X9-xi`Q3<&J8q$L0}&cCPdV)L>rh`C z_H}AG{&bk>Q(7w+W*NU6^kI?{C!XT46X1&31Hi)(^R)v&v2p4Y)Z&!-t~7#+_o%QO zw}bdBIi%`c1CnIAf-JP3E0s@8f9P%cS0l$=z#lhSwW6dKqhQhGAtFeD zUK>$Jqd)KQe3^REoZ*9xzE_g|~$PqA?~? zU6Q4TKOC2Cy;3Kjt@jgAGk>-t_SPWdlb@TRO0b7UM_}XoPq6nXN}iiMrZpAGQA>=H zxSh2-^^x*+SO_D!OiLJ$IgFEh!0P9yI)e<#eU*LzclbT&7Rs>kSjh$F*9>Z~+T`Nv zDLrtc#UU|6!;Q+BV-FgV34Ogc_;S}8qN{m3e+(WV1UQV(g!#j?U~Rjei7q57`O4dh zBtHS=x?&~c{|%I1yqGWsz*Rf3pcp_;(SlLSFVsuHsP3w>qSr~CTgYI`<2`lhqW8qK zL}cB3#K0pd1-eyOOqWF+sKTh`Rua+uUfsDdF2uVDh!Q~c3l{-$fGUHx`P$3t>5TsQ zPa1ldiAYGKPRwLG`2PNGZFG-crupc8ag>ahwC>9EioCN{#mVk-wtH^^;#^FqSTJl#hCPIs3t}cLNlMxe6YflYhny@qy0YNGn!^P zlAPYUj~l!lT`}&N4$1M}|J0kwz6-rODDUidG2i_!Xwh+?E5+sDz6hAc;F%_R2Xw7) zkIBD~XHIdBecXFuo}*5w%V%O+I*diQi=u`EkR4hg@~Gt9D&K{K=BpZ|+#SI%08^uN z4ZJ18#AIk{9-qb6jJ(bBDL_yp4&dw8&2hh z7ue|zq8o_V08(5qc!C^X!T0@c8XkYyh~H%ffHRRh|I-N&6hmkm5bL`=a|z=LW`@*A ze;{!Tw9Eaq0jcf00&WLD1=x+kjri{ylKy0aXlY00~Dmm@t(1s476S8=I#YUW8!5v~;f9ge( z+0K+m%5q5J{a+_uepvgp|CEV~YOnswgez^wcN-BQG(h@O1L3;@XzELIXNj@)T!qKR zb6RKocyy5c6nmduMc8F8M4sAlPREYLDa>#n0Z~_B)A9VH!ZYSWudc~|T9EF@l#28p za4-Ug(}1U|OH3Oc`spn%gBr9NNwC-d&V}`!7q`)56b#ze4=soFtrswk+p2i#(Xx9T zL#yPZ3{kiZ^nd)Y37M0!<=WnTyz1fq6p)f6@XGuAgn4xmlZDtG}f3+kjm6qS z*jFNcL&9V`kxm~|8%S)la}__Zv~DIQV0L?VsX$KL1>jfE6t=hlgcoU>A(4orRxr+( ziR@zU%O4z0zgnb@*X2?6P%K3;u4__`Rn2as!=r)CnLl=ts7t#WusxLg*Yg`V06@mb zzP?fnmV-&cBBUdba>F#zuy46?+)?JmoCk}f{V%_CKuNc+T#cB*ON+PLiagt_#}4XU z3c|sF*r##Exn-h#G>C#Tr?pIXJ{ziikJ2lE>@k~Gz(X|&71j!jBfB@Aeyq%1Cw>8G zqJvCamJBcbh(Vk_I;)_aqtH-+C4aQ3=Gr`PM?U4Be*I&Xpj;bKHR-6Rp4~dR!)8Se zT7F+bzgr(>LwF(=8yZjqLqy)M00i8qD#7du)gST{skXF!liszxbiNy(WM^ZaG93cx8fr0DzlthwNsA+SoqV=Lx$2#PkLL*>#UPMsGg6=YSU05@^9Jo0mZb=6kY(tMOsk$n*wM;%VDwQ+cyMb z3)mMCfW5w7FHUE(NNQLOIL{JI99_kwQ@(Izzh3FaAuqeZGh^ z=M2Vi>Sf#y?0jzcJgE_em+&LOd%c6DtP)JI-ukFy8-5)xWDRa+@)MUS#N||Rk zcUmAB|#1r__Q37zt;}pCpwdHYfoI0l@vqWBjG1bzH zPotx0{hjl^IKP(XE*h^fLi}bna~-eNuKQkZz3!Fu2C%fnb&ZWelrXIWfHn?5o9oBM zrqf*>tgw#9D^$M_`ap~&1Q)u*$Ph6GBZ|hsiIU6i07T0Dh`~!W5{ef#DX7n6ls-gs zK2CH$zU}pWqr-iq(mHDmjU90WU@=Vwp%ufvFstW*Y z;z#LczsU^M-k(%MBmGX48>*OVO3cY85KZBjl2A(f0F7o*wjs~ff!e?Zli*qG`1l!@ zsZo>a97G?!^R-{7q?_Ld?hH+)!8U$vENA+3qvFsx!V|A6@ljJTnwd3)qq*@2o8K+{ z6U8@^P$~1h8hk6E^Mwk{hez(uQqy{Wv`0RCVTj@|edfHSC-#r{^)5aVw51!8i3aSH zdPrl$Uy>xJ62qPF(Un_;GmAWkhM4_;QnWtBDa@1|H!avi-Px3j3J;>8UK7ieF!~ch zE~M_x_IOzLg%gfuJMMZ1mMH#G!Vv&dfztqbcMcXE}wyZ+Ur`b)V#=n&IX3jLd~Y)}h800;;D4M1i~JpyP1 ztY^+ouX#Bv&Kze-}38{##9KkyLw zp0MuKG1hw-6oc8u80EEz05L0r!yf{>f{_Sp2b6u=|@^DvIuRB5}U%2`_F8^U@)ii01YX=T=NkC9flrr%gIXE z;X0^)V@xK@^yjGD-T(R{Xd6DEOT_XDLdwhIdse`y^G!ip>p||X#qaG^bxe_5XN>(5--kMW`8rhfIZp%wv;ALRN=D)u=0g@s0ciy zk#0al$aqqUPsYn%qVb^pVeU&y^z#=F{5{`fW>>v#?t#&zbf2&6yVC4^zhnkPY$e)A z$N27FybLpF41lR~-gIXtJ?97hw4`i>@^;*w-z#{*)z z<{XnxUj}(bN0=V)p&ywvo+EaT%?)Y+VQq-Y+Z6ySp6muyWThwC3QYP_C>=j(cO0&x z6M3xq6(v?JXG@(|uW+i6n^DKpa_3QBeDd656AxQG{P4rAeV(;{Hcl5n7?m{Riw2am z+rkwzR6(U!&o~8?5k2p7wUD+dO553lN#5=Ar$07!2e#^dg2eBR|Go8Qt6Dn1mBjv@ zaNE}Zll6N(n3RlM(R?4S%v)~E#oK2tuusPPFOKI!y8Lek7oC|B;kY zSr8;lNK%UWeZcFp7p`0r*&lZ?)poT~;)tkPhysg}!Os;GNIoP60f0;v^5cX8$ikB& zB?${;lAnF`3QSJz@z-H-$1%>{QWL-9frJzjMrE;lGBDv|qD@vgs|qeo<$=@Qk0_r^ zVtwF@sZu)vK%h|img=Ucd1!DjIGYVh>i>P{jT+oSp`fs;=WES> zt$-a6*<;p;04d{PB}IRXZIro6-+kh8SY;x$@60SQFs67g#LAwz*-`Zy&g%Zn5>325 zS&>`$3%S<2$?xs=In!?c^b>&aQc!TQ0I2JgbzDgENXvG~l#@&!KEoEP-EAB-cG1JJ z{pm4?vGn{W(+&-7;K_^)K6MXNN@ItYum72-W9j{$@`J%R|Ct1{Q;>_5tpJ2bavaHe zYPSJyQkxK*di^|F;!W1Sxt6aNn@^wxH6euqvD*^otx4R?xy>VkX-&tLv6LzWv5_;M z%W7=E*;_||9H2@ta? zuLx5Gp4b?^em$s>|J9!@UX^)-ap5!BY+-4i&-T6U-Snv=UUv4xTLp+tN-6er6CfZo z`&OYWgu{TukB-z&4A(P0p`ulg6u0{JTDLlyRNyloZ{V!$KyAs~7S-C@t*Y2h{vP;x zEq2F=T9g*C*& zg6HQvDHjLz!MtvH8n14BNMG7>T=~TWdOT7&6~|yOmrQrA0Nh(*=>~u#+oo`Gu2@WC z7ud{PiSddNMUVd?H5ptNYdIU$)};KjGFzX;57wCf)nfJ{5GL^W0cC}dW5;e@$Tb{L zf!gVQj7=e;PEwEnoCm0}7CP~yqX`w|;jW*%%tn(0d?VCazjkikp33~Uy#l~$EECsH z0tTNbN|9Lp;lZCtl-+Z*X68&Rm&vT%U^1%{b8=m6X0CTEZrOq*M=AXboKr6B9Ue3H z1zcC-E3PZQ3{vsyoC@G*UoGJIWUEZ$9zAa$3L#JHwrr`>R?74hk+Mva02#f1zO@p< z8o}SkI`3$Ss#JUu<7to&h~VmrQmueurBSp70zIvVt&?$Y?e}~1g`o%Jb4hQyxzT*= z7uKD)DNiPPkUsRR&pA_TG4EdT7F_H@f_9Iu=JYcEzeJp;34rQ^DjLM8fp0iZxsmq6 zFEZ@Z*vl*NiaF?1!6C~0L$pfe*WtPuz4)}wip|rBLmg%>et#ip&#XNuc{XO{q`;T+ z&LF6iAP#fQFc%F_BlK*X4{{@j*#(f?oYvD0F0|~r_HKy3_kr6ECbMJH3Q$#$kVmKy z*$jrNQb)_|b@Eu^k~oNF7SNySk)>54$_^DN<=NW2DPp)g*4tLz;o}xv`D2cJ_Iy%^ zb{;kFR?-OTzV{*d(YFFXi&zLe-8cz?0o%|B7p_LecSxH-J9*-=uUz~Q_7ub6-BQXw zA9GH6*Gug&+;GcH_`T?;LXR(tBu&ei?^D-`JkYk9dxN=+L1XEQDyjTj0SJ1)V0v0u zXm;9acx1;{q}lxerR{zPG%V}75I zKG5?)f+z>0iUL5bE}ZIY+Owm_U0A9}!`*HYGE?ftos36ajGL?!1V4WI{=--@h{lC? z$<5O(988Q)WEc5HEkt=;h_T=gO73DXr`%s|F@N#_dExtdeG3HkMob1glrPuVsKD5( z^5BW2%I>eSIdYMd-Iir-h$%7b#G!BuT8*Zi69q%Rg?!RQD)CokZ5IKk$wwwWKYrnS zw@g?65-olmeZ1FMB35`#Ucq(q^0}$~*aAt~`-qVi4mhCPr;^k;E9ju2MkB-?ei;%% zPvoeY@lrd9Y&hY`^2k3za+%$Dg4g&tjJt^v`FfEzUmvy3w6FDAEw&Y%s6Bc!Kv?_} zjM4aa&- zp7ofeZ%VXfZtvtdRhe1Wua?lzby8Rv08GYl#1SRT5amEMu@zYuSj;0qx<&i`3YUi$ zDyG(=h()b2d_%S82r`X73yyG?6oa-G@RPH^&rVjcBN~@zfZTci$8EFiz2O2FGTtxm z264{!^ymc-sFiBtQh@RDLBZP5fCSh=2VNHjV!8L}DET65Qq<>^%itTd=xbO-oSzPmDS zE9~CrUI+cL2%$In3w3a(h346kmi*U%G6n$fa20_tujp0(eZc}2QrH9#U`RAEA${~v z9=6oFE`RWo9*+VEUMkCV95o?&O=^)X_HH*YY}+hB&_gY>DidEAo~ZFY`X_Vuj4te` zGcA>;fM-;dLQ6BMjG4#NL`HL?q%aaOEOxBZh0Wh=@{pc5M-jd}T^Y5+BrMen^rE|5 z16343mL=W>Y$Z%sj>D%1`ulW!46ltw&uGSjmoEGFUo19jr-yDebWYS6Nw0^|I z|F;X@xtc)}e0i4r3jjBYsKL0f;mm3O6#)QPf<@ce5rwae@c&uW2-0*55N{g=K#hs^ zvSLS|s1_xUj(smjZ|syA?vOEEHy4shwVywVOb!A9e@*<&dZin>PAL80LtIyZPMNph$ngrZkSjMlnYcMMyWCSv!Ujk0cW@?+T>@%KwRyWe9I+)XvG|QMf5%Rn@gmP`RscY6IK@^kHOqwu4j_~MVP*P z?h1;%4+K?xYZz%<5PpLY;PB^fXn%$rkDG#=YL;dCY%c!7Z9S7|_}nLGMgRdM)pSye*vzXkFVZtT*= zTk?E3sDOxa+EQ3wuPawRo5}E-6~>PcX={4^5O?#?aJGI62@0m6_beLT3Cq3Hl{$8j|Q^4?>m>r!Qe8+Nms`esCu!3)|$ zLq7mc?Y?~J_BPr&xT<(jsds5#xSt50))v#RQz+BGmGJ|3sP6A^PK~2$B8cx81tx3;-OBkuVsmYV>CQ12c<1pr002?8Hj%!OnC|-}0l0;ovV2w3EcJ5hxMN0ZPIkA3 zWgg{7NmzsXiA8Kf?7;f?bOc~%PvC=+83ugq%t4P>Nfx%yF({GXQH_CE4J}dqDb&v3 zsk~wzbujcAIwLV0#C86-*3>pBqS-3mY6c1O>pe`UtB?y(V9>LxzjbwLFDHwZM z9=(5ss~`v`C5;IYs{KFy)nu8tR+d&#u~Ef1?ifI86J?r;0WQa6d!Obbh_;7J=@fDa zi$?Q-4(Pz*YikDS+9E4>4WasNlW6sVOG|ao8COhuL!$M7wE+@Z_Fdf}Vw3sk#Jb}c z@dnd&KPY-tIeUo2g&R89`9}C)`nv!(0O$pTxd*|kMG2y*#Y=x!U3=pVi3w+7!pCai z_-N#)&r7AJP+W4kV037`NiRHEiHp#Z_7lVV6J=a_j?#ajqys52IGXP4W1U2l1Uzap zls^JY13WU+76Q}~9!;#D%$t3>H0m|~FtPP{907fUxti6crhVJcFw)S_atjBj0RSwZ zT2L1jrNb>C!0+;uxwNNpV;TmKNB!#2foTt}{$nJFV|Ulcf_o%v2GSra?2Z zV0b5q@VPtEdmmufLiLcBzAMTI|#nJ;hGTis|`Yc4;^`upZ@z&h}&}TDgh4 z*I+PL?CF^6e8polmL;R+o%0IdwLWw>)&amo(nT*v0nlBd-51Gx006MlRU*Rm*w4kf z?x6yMOEXir6~FWx;_UiKBKV=Qnn&${qF0Xb5#A041#CsxW)K*mcDv!(N$EOP($_QJjb#adPbltB$$F1HAUTn|cDDn>S10EC{ zfb8lz9mRY(o4Tkv~G87ov1ps+ZrpXf>pjj*obU zYI}zW{{26vLW>&!7%JRuJlaYE000fe?-wV*e@{%miJwRG#7gKQ9IqhbctwJ{28P29 zVO>GGFA*z;QGSb{*CZTAb!pYWep}4Ol(ap_pfQOXx=tQ40R^#LPKz$_K7Gr;le;}g zHB-@;mE7{iW5b-7PP^rvm@t@I6aYXKKk$*&T%S$eM_7b>O94NM)-}s4F2Z4`w}}0- zm^KV&+{LmlF3PWmo>NjqZsmFR=8qMdU{A{F*4EU5-g09q3hEo`OQWi9`8$LO=@!3U zRZBDoI)q7TfTS8V`yiP1DTY=L9DO*#GCLy5Cn{PE2C_;0N6}{{#PuI90_AX&1yOOfp%KB5vk9Dkax+T%%<@Qb}7}A zsD7>;r9rIX5*wv07|H9{Z_8yn;h@>QVN5G|_q`p1xjRonw>L?5NcV}jt|RXQgOVTW zf%UPhhiH?>&2OM7s?l^+UUqT|**}!wG$bO}*!?_M*|XXXFv-}iU`cf@a8UTqN9bYL zhjZ^|1gtdJL=Rt`u`pH__J0TOza(n9_(VjQWLv`~>`a}plg9Vz&@AThre61h_IKfw z=2`#%uu-L&MEEW@|A+geFjQn6FgYbqN1fH9P^1b8mcvp2$;o5E0o_`-O8(kYav*r* zA4yzD$&-s=UTMa>w6$g%DD_NjFZ46*808d0pwMJUoRR8h?R)&c`SR2embJmEm#`sJ5# z2Y?tIAbvTD1{IUpw}_)biK9{`Cd$uAi?fT6>vGm$^dwA?0F9OG^y_m)ba1W|sZ}(j z(|n`C$;ar&%fr?JxxDRH78CAyQDw8zmBFF?Z)4x!7!6ga@qVG?ETM5_!qlXcVBhNi zZQF*5`2Z9Y6+$cW=wr4rumS*B1$t&}av<_Vh!T!6RcJPae0+o|q=hAN!6R9l0*e!X z(|_h>Z}rgsNF$#=C$UhZN=_nr>VsY_K=RQ7S=MTKoR#sqYPkb=W#i4qW_dXu-$hQ9 zjjF&c-e7JUo+4Z^YqbCbEgx-j13(n1bD9hNmw*SW)wzD(a256h6HSL9OM{^GiR{pyns(~upymW5`1|+2`GD{PL5Zam z0EYiSWGEb$FyF(b#+L9x0%7}P_QRv-Ll$G?{SO)iu)Z>nxp=|>k3PvS<0t^?7cY04 z25^xjl>0VLVw3TH&tO%;Zo${;Q4H=$?S1>a?D;F(Ln+V9Tenz=O{evNK>(Ibn&^rG z2#{EUBlytowF0f!F_OH|*5;^}!$yqejh^_spR4MM111I@=9$2~G!V?Zp_i^|wp6Uk zk28X?v#!{Z=i!7uwZ}18sEFde*z2FDSZp}JMo2N5kwi=$@=gHjS7*&!qE;7De{Zko zYKvg?;0&tVkKPwiALWz0dmFf$pqS-ERjpk2ee~`KD_QkZ02;@f>jVj>Bizyxa#l@f zTwl@VR6)tI6vl8rRA~t}6T4_}-3&4&%|ef1W!x+;_MC4~=L`K` zsePy5oD7iaVm&wS0%-9m2AHVJycp^tkHHkjitb$abru(LJN&H-Ra34ld$n}|OmOcg>AuxTub z*#x6V`rzM_Vx2_UbgC~?E_`3UFM!{h2asY_7h_KEt ze3;r3btp~IXDVvmZb*Ef-(!c9#UPC)`lMQp@rtn<_3s>C;)m9wAMTdjjaC1vPHg5j zQZ)ttY?n372gF&y;tVS&P(d8n;{%cyiyx+g#Qz{p0EY5TkyS9cXOkCFg2g5pcmj+z z{wB!kA92DU$6a=M|FXUu~w^^S%TY0k<5bMlwUrN&?e4`;hQo&e_ASpV~+{@8{eJ!Sop&ZU*~nu zpBbU{0ejiIw+H~%*B39@4nPv&D2HtVDPg&9_&qUMh(23%bEaRN`#jDB&uLocw-*=r zLD=uw^Y%zUSV5CA>YlS@MF_Vcxczjwur8YwtB!q>0XP<=TpJ|(*HXzn856KcmBTw_80 z7ysQ*ixH~#u^|p>#qQrBr|UWq&7L;E8qHdj_;(Qfgp!!1oexf%6jMJy4|jipzH@RS zO>daQ+hkxh0~$>4$9!$hgUNE(G_TbaRMa8ahmJcu(9v|6eOp#b?qvJUQd))~?JuvW zq(fxHN{*dgO9f0pK#fz>I+Z`0pB7=%w_nDDr3I(U!Zd9)kf^%eg~7qZ*b=WUUH(6zixmB zg8+ONOIUF>RnX;Ydo4MO4Raus1QMXPKfF>&X*=BV#C8?==>J7)gjS4>Lg~zwE}gGg z{34YIM@gdeaP@l~R|ft@Wj>IB1$kt#0>Gzwu=O`sqtv2mAdH6V>PgaArZ8AgduecK zBasP=8fKy4=2uJu{4y<1~Y&IvF*^)1u?x zA9pDhjM|wk8+TnamWOc&#BJNeegF8!moFJ-Y)KZw$ZBmfdt{goP^cik8Mb1D%x6^+ z8e#!A`OENE*k_6=_B8dP`?^j_!^$5eYu1WArUk8f`0biOeet=A?fk95qKJ1N&+k^z zPPp1r_j3~mw9t`y61olvg#ZsZu|FRdhna-G8&f2ot-=#qt z;uxJfv88CXMuxt^^vUUlDn&wylUG4o)mAHZ_H`@_nUHmBD zsa1owTeolDwA26KXi5KU%lCH~ga~NFrA-YAtkGr4AM-4XT8%o#Sl}%dAE{seZ{Bz( z2|&t0#7kC)bQF6agW|})e#_F?Pt2Ks5cgv(bs@&dK%(J|q9+)+>!;U&@?Aq@AYMLW zb0_DA_b9y$2K%vUU26$#KPgtlINAlMie$>}BgP!1N$oo`i0Qdw#+X$WGj*0vh4UCP z8vi%-`vG$Qeunn@f09llZh- zbKz}bl=sICkyGj^SEPr2iVQ!z`i8x177ZxMvr1)L0EqIV&!gc;`Uq<(OEiySJ*qI% z(i+lamLaq)V^YEt;V|=RLF#Wkg&g>&xBl^B$!mf<_`FZta$lZWo4dhBFEltSh1dQe z0Nen`I9l;AO;ea#8O{0g-f>%szc2pAT@jSEgo+rvp54M;by%56VkU4{8o4yV7Guw= zSsTzH*}4A1^qFg%rc=PshE=I05JYH=PKXz|2`#1B!L`Lh6E?K2SZ$RI@U$8`yUxws z^WqUe#=$xfU@T~?f$+a|WRJwx&y?A-Wo0HLwZAQ;^ger6MtrW;yZ6@*3q4l+dA)Jk zr_JC`X=z-_hvpeq6_*uI_NWH!6F01|N>WN*DJ*HxL>$}TlF+cwqAcyTU(9gN(PWVh z+4Q&Zr0>X@+ayjSj?D?W2w!QmDJL{m#)dy7qh4z${!X9gdnWk5&XA+h3dF;OK^y?k z`2~Wh{Ruh?rnb67(h3b$54T=)^ZZQcbCn??=6ba$y77{nVW@Zu)pu56bnADqN9jRL z@;kSo?RnVEC)J!G1`9xKVW!LvD_rdX)T0R`D(ljpCk_K>V9a9YHM{w8548A`)AB~P@9W$; zuq@{G*)$CtP?V2p9=f>U)4hb@WNVwGk!N>kqt>!H-6n0S9XN1WPtNe~QF;m@(_q(n zp{^+LB+Qh^*1;Cqmngg6;kW}&wm z)r_)EXV`f9D9X1nWR2V8BWA~FSv3#iSPppNtY`RPo8X#-w!{|;DeLJYDJTd#geaVm zBP4_kjd&mIGYpLmxc1N!t)8eflZEbbRqqvPiaADFivA1yzc9~y2$**CHvnW7l48L$ zkqy$uBQ1n1dC?Xz-u&H}+fj|IJ>q>1(|ut-#Po=b4%f*IHx+1?D%iJM>39+hC>)WH zR~TGEMUs7q7ykB8S$xrJSAW=puV z6<=4DbyxTGJ2!GAcB4Nt-~P%F2{;R3x`wEy;AsJx7|g{%HUJZ5)r}tqKq|5175S}} zL*-Z=%q99`Ioij(0co|A?L<9Khs<6@a4_p+=EFu6CP5Q5LKk#Yr!r9)14d7^-{uCV zNl9>c0We^UoU1K~#yurT2~Rdb<^h2@LHhJrP=jFk>EgYPc>;j-*(P3S(fa9zeIl_| zWxxxJmEGr^T;)kDYbwh|gv@?^6G$5?uk$@l%DIXKg4t@+AYmZ)p>k)HX6@rmG*5dD zKn88>EIusCg)*|3`GzEk3B(Z?*U5vz2deP|WLc{?*u%=D>t_jgq#A#mDNUE5QUteM z<5gMue@?}{m7wWuSeQSfa*c$LZzlm@9I*283P7!c%GQ}m`9xT03E^6RbE$=Ibd%bh z;SW$*z>7V3Qg@Uzryd_8&tt5aqU3^#LV6$|OQ*0%CAed(RaIgk01TpugfbHVmqK_L zTbFV;UbX`>)f|ZJM@Li;9_~@>5lu1e-}*ll2t2!4tepU&*adRlSxG+ zT5fL@tAI1vzOyV{rWFZi)3r_}ys>7RkIxBcG?ZQ?!ZUinu2#*(qKAjs+`{D`D zCt$eya-V0BG$kxC#?DQxoYS_ z-)cXeZd5b9ro#MCrXJIB;fmsyFYgW5ne&`$?Iz|dg0>|T(r2%`u;~~y4gipGbXe2~ zTibW24OJRZh#Ff|p_|^aqNB|%gUM*t8;;jvfpz;5Av?sT5{Qy%-SVdURM>vDTk|*TeIe9p$U3&m zU#&bFB&#Xj!fo{Q}Rjb>1;%9Do z)b3R23obS5mZ)^L@TTiap^BA3i^VQzn1BB{08o?8zZq>qv*qV237nHM+r&E?8SN=Z z>`-NPviY1zbEMjdsJoh&nzVf7`S@IA{_LX4f$!N^%W2?~9D%V&39PYxpRq2i@UAQY zKHjMjk??M9)q;{%0WMN52>~$c(56F1H)U-o=3$59>)~HmZ+s|z!@=)ovdk|JbR273 zYb-VB9d^}1^93!j?yoJnuaVz{y4M&3`L9)%Pg}O`g=TOFKJoM(S)Bdm;INA)Get3T zDGZ83E68lHL{DF*$ledfhxy^)a|SBL+#~KZn2d>e@`Z`YuDrtKt>dEYeNHO5ve1-S-95+T=g& z6s3yOs`KUk&lDv8|E_}hd;pHcEJqo}A^T77UJ(R9p0aW=#a*O|UHQEw@8hC~<%@&> zic2L*%b5-eC?ghYS1p%2v*dr^^~atc*J1xadq% z6GxoApVeu86q@V_FfVNxi_-%tm6s%^OhzgJh32p+5H73NS96K-Lo12cUw|apuQpi# zgtW741){dK9|i|HLWOf)yG^kfj zK7|@WL;n7tVMJR6y8ZIG;Kqyk3WJw}#qOBWa@Wz6XL%oA-8|d;gb`r1!mfMw0uwvC z*S+#`HQ(gn>j3pGfDSKKTJH`ZAbgfm8A|W9o^Ysqa3UCF{?R((d@YQ-iLv~;^C zUtm|etcmLu(kRo>Qy8PP2_nRy7$5~RWVMmkdiZXc`N-6I*2`>Wu`t?`OnHorLI5>V#G1F* zg&WMD{t$5c76D4>;}l{3TdlZcG>T(p6s^tG&%k;6#QqhbgdC;?v&Z=67;Be}=xKo3(T_jsW>% z3jt6_@npW@W-)qE$%Z|RV$yFkn|&wjMLdXAxW4oK;xnT*@gZ!&_{64QlLvoA-Oq4r zKvC~>2g4F)iiH!O$)1WUp`l;J0(=1w3jshO;;2W7Zo67-S~?eNJ`OZ;t1Sf13*DE z#;b(tLY}nPv0qK;GV(`~OU1;mOmHY$FJ66RJkPv%a56{4(p5Zg==nQ(GJ`5c!fN(72{85Uw`Fc~c+z(SgD#R=D` zvak}PJLNG~9hD{|-Y@4B`<|WBxIXv^XKHxRKu!GTpnbxOq5i*~tQY&leMS8G6zbn@#7|hNd27@`9YZ4af0QfUS{vJt? z-P6c105)Zs*mqpPH-wnnR!f73%mTzOJJ6tCBpmnsDs;J`yueB%d(Im3aIRMh>VYx7 zlXB7F`-kXCp(5pfHSBYRn{7q@9Uf#}5^ar-!zOYMrK-;Q?W5mxytaP6rty{l%bnxi zm{?v5z!Vh?a#yqoa&g#b@I=}a^qqu!8)Fr=H0&u)ic21%Yt5jM0{M@Et)9}UHMOeg z&$*4=s8dG7RR5v7q|n>c6P?&)@2JAi-BCq9B;hW(Klt+l0KnpA#(lHoN|n5dm3X%w z1D`Cg%QXeM5OK&jV?44KoVrkJ#%Dj~HSKkIHFjh_R=i@{F`_co6_o6wFKw)sc+AE1 zH~NIrQ88)X-8&zMd1&$w0In*7@yWT7q)P+lR0#%rYH=Q$yryTB5p`+ZhX+AIC6RSA zXH~e#rbE%FX`#F$yDy@59*rDYL7wu40Jsma>(v2(x1q!;BD3@2AsS@K z9A876c4=O!Qj~K)^Vo0EMe9g=yZp&1yL8!oH6|)S0?3aAJZsW^8en{;vx+*tFE;kk zWL0bv7)KOTH_YUAUmAqpn)ztIV{%n2+5UA|fy|(Z@@j{*8l_kC1*8N!d2BTepO+2_ zcB`h|md{UbQ{hmoNad+KRotNJ3Odbb3~}s#&MV`viq|OorB!DJKF~Lx@RE0#lr$0~ zwWp5;F(>g<_yVZ({8fbzb=7G%ct{dnPa`gl;~^b^@yQHdYKQgwo3W6IGJ?{gyXJgj zhP;@dA<2Q<2Ky-145o{%XyrEzxeEUQcxDAh7ytVk0BC=ji!_@h;Ic8jrk)(@ z8wUV{z49P|D#>J6wuH7))S!n9&j{hyG^Z*n`31_DR6}CkfEp^1Y^*mdNyK;-SLttL zHAgFjB#j=rT8}I`V|4f58DV@?J^~WSKZmZ+;oZbo;^47Uv{h0V{|5M;v-dz?J$B7M z>cYmF8zzU2QRyn`v9i^IgsYNd+cL$46!|H$RrKUcKn@8Ox33M3u>!;X;dPY3_q$5t zHT>442w`Co?IvDrg?QLB3Wz|cj6Ch4rvha|!k7nmvIQel@Z!mHdvFG*bCP=szg`x4 zikbDy{FNX{EebF7hI0~+<@O000as%R;O~4h0WO z%Qc%C-;;y3T7GOmAunsBfm*Ezx?#NV?Sn(n+Yj!&lVNLmo|KK8 zIzPu#Jv)2=hCPueBz8B*PWp+_VNuR>>pTV)EUHmsYRT!rDsa!)*TLY&Y!iR9jSIl0Z3Q<*E_RmPoSSx1~fI_qSNzQ*ziqb?ic z^SW68fQc%oM)~<*TK}`MDJlvN-k@4N*}1rmMv96^A=(ZqeW;{@R5_b`$Tfd*u-q0l zE*8=e-dqtG``Fl&CnflUSnT!}KKEtkMf^P#+JxDPNcI~O-JiLU7N2TGqhu~#mHv&VB(nfSS`${g&-n{Cx)D+~)l*sPl~`l$=>^ewddQSD=eCoBcUJ z9;X6@J$PxS1r82bS$$Ac6?+VVf+jSfv?1z7O1SFxeYct!s7pL8Xm~TgNCz zmBGw=YY#IsY1!w-T5NT>Mk5kBl8VPC1>S*gi(tPQ{nbT=ID#}1NS`Hd+g?@T!MUe( ziT^Ll+%o3_0G52Dy?2<_H3|T*1h92*7RA$b`-Mv>DI%(fX*wwKN|9AkpW&OB;5**cMc{6{^X4ANbVEP zZD1opq4oG!amnyNVH8>A%yH1dF~KPOIq^q?uR~c0GIYpSig>O@^pfkPcdYP8U(`1< zEr&37di2TSDDo{t=9c59e5mylgM;<%%^5prtdA_?L7o8MS2T3r@g=_S|F0!qn)qL` z<6aP>2Yv>_L87!Yk$sNmqu#}PD}K4|_t z<$V5*NkdC;NYHvRofLDXBmuOBPHA+}!`YZDK==*fuz@vN)AJ8JA$7Wx>RCcpp)1Cs zly|kia+}rq4Y-B~+_J2S@IwE*QTJ>9ka1hb4j*utvwdCtZJ}v%4dpj;KdXJ0b5~W3 zCLkbV5f@K@VyD~E9IZtwa`y;v*OJPi7p1CrgJlu(a&9*qhVQ7p1ylVNRyXdd{x~wO z*Zw?DP~toF!j{9U^V25}a*zN6VDKlel+%o5P$0G|U0pqerRwx`%a%k$$~Ir@7p}4| zp{stgWlE#J-h6KoREuSH_dRC6^<}s_P^FPERQ|D!2nkAiGgb?*h#5SkTp{N8il(#$ ztLBg^=c~dz79W^(xuj-P4Qr;op|e)Mw(ob-<{ z=8+;x2SaSFst?nndpP{KN<{*QQiryY0jx3s?Pz?3SA?Srs`YRiw5prgQV{lA_dU6- z2)^A`9mZ~be_LPXZ@Y=sk{JS7vd>&|Bcb)D?+2G=o*j4`vwF4n1uJM_?u73*JU_p% z+1gtg7z1c#mMYC7PRkJL`z3S|OeV#ob?AtK8rk^YZ_c5`>9YH%ua59!j@zmf#AQIt#Q#FIE?F)4o6PUq%YsN*>SoP%aAU&KW z_3Ty>F{|F_6w|W-5NfEBEd&H=!))Xl=p9R-gQ-j!kQC!niDU*Z&X>uc2pXUFu9F#> z6d$q;ajl1S7jSQb{=9JGI=%ZWwM>?r!i@$5m=R9zR{-iMJhGBdWd{a_98;2nXgvsW z_f#{Ebt{Pd1D(4)MM|5_+tUaMotl3~*yUI6ww$fg>L|3Qe?FhKHn`xAKLkiMH4sb0 z;8G-a3%&n*uX%Y3w7HMxTuXMbB(M+uI@V9vj* zT>xP6gQuHuycvK>gIC{I8WQ5?gEG=)D)moQb>5~E#71wl|Kv?k`cTd>#+Q1MYA<>D zMRWAqEX_{*M72UBp1#pHA~>MP$vr!^O6adRPTSpqHVBa;{aLBRxiB2~0+DKiZ{MVv z;7~KhW~H{Hh#=g=c<*h~+WF)l^K;d6R>)cV$-0OFN0OQ^!9 z#+5}jH}#6-$2i}=HmJw>FceJ^eXE6XZ!E# zT2%6^$b!djkC|{jzc26%SLWgNI+5;QW<>!l5axjD>iCST=Ih2_N``E5_c<3%g?2tP zpajE?*za;<5J1|J;3|s+#PuXw>+x-)N>*Lje=KSZyMMk!=Q7EJ^YxXUd}GG)VEFrR zqKSR>y<)h%*7IfieS>@bcw%T80OVP?Jx00!fuwwWLYtLRQ+-t_-UE5aa`8JJTANq% zp5Zne4t!$f`T2hS*~?!87rYCx=afHmH2kCH4nF}9ZLpHY0SJayS!%OH z+p((JjYq2%t>Eqx)A?^(*9kl7pI0>27PWQ0;O!Cp8=vRa2Tar$=^t#d2Pst_$!4KV z#E!TCh2T9U+@Z<5SpFYPU%?h-_kDe47+{7RhVJfe5Rf6I8v&K>5)cs(lp&=hrIBu= z1yp26r9nbO>26F=V&04A_kX{@9p~C-$J%SJZMd(iE~i#jz3AyiuRWQid}z;YkEC!@ zN@w9V)_DAe0krn+B_B4<5GrzS(G{nbJF9zIFcXviIDGs2p0h={-)vH@9FxDI+rRR| zz57kli{E~Z&SzS_*B}aLYy{3IJagw200rSmvXlg86Y5g#10^E~P?~zH?N>+6CG<08pr!KY9uv5LNbvAd!G(Dys@w zO)y?EK2ofmPup3Pw6iqwycs($apdsMz8ukP@#u5GlKJ6b3h_6FA~CHkt{q#P5a>5D zrw9(c@mmk$C4MZUU~JYNobg+;CifBl>X`mpG0}$!@LIY3Coi%02{#?QQ9mW<8mrC$ z${>uu-s`B8JQsk;QDdRJZv5+m`xA~bylxY#%4w7ZeT8^UhWJ^tATb`>U7q^uxBXgY^N%H&SCS!t2U^VpiuFAA z;aB~%89f*Xr397vCKk|tw<9WG$az-Vq-nhAZaMuSydJXzTc;{dkD;_(E!+#pFRp%f z|D{FarFnhz*B^m}`T~T0(A!#aRpr!LqlqryPjdv|vX{D5erCs|1DBBMfxz&jnxQnJ zscc#cBcIq*X%IyTOOd+mOdIvXDQ7idJz?K49GXzCBX}wo=Zr!Z1v&TIHrzWs?wU(p zdbd}{xPw}A3F=0HSgz7_%_=cetP#UV}IA48_BGu<9_H=4^*>m`R`4xWt^vjl!S*e!#q|lm+f> zw@>+TnOqfDEHoa}eS@1mIkf)zb>QZZpUeM2Wz%^+6Cmd?WX>e}H@YtlR^Vppy8qW1x`H-z~*8sKMRhG+CbNp0+z(-hL zGC+4i%V&lhj_6*YT2 zxkBO-ct=U5rC#uD_{NaiQZ3Qqz&9+Ox?YwK9>^|#O@$QK@Q+dypY}EKkQmm1P*KOU zJv}V*zBDnHw+li)+59JZ!~!9yU8}PT!OvHJLy20r|4jj%FHyuN6`_o~N(6Q7Tt9inpz-goL5W%&QAwYaLc2 z@YS@IV~XY6Nw+(r8sxez_;O!cE_!NWb+b2$hxAOA+IafyE$8t6E9#Op8Qh(T-A z8+*;e@n}B#0Tk8z(0rtMz+I}k)+4uMiMM%K&sUR01hqNw)}Nc7 z(J7Oa)wrfWOieYkw$A`{w%INor_`?>oOmb+Jbq)No(Nai4yD%u`Fu5d?f~<9Xn<6^ zR%YMBtM;I9LBG3?U8gs-Z@YTwh0rg}9oK7)ZSS>|SiRZBLYom;qQJLW_d?7nsUz;w zD@T()k;%#A=!Z;wB7y~$c#l1dR*QvF)qYMtC&xQ_$p4@uQM!XMO)jsaW{tCWPXM2Q z;d+AqY7RFGfQOUI*x1O0T{Us<1PczLvbMwW+Dy?{9%(6O&Qefs;oHq9>88OEz-%%> z{CJJe=Gsbsg`>onrb0w@7IdRJ554i?;MXFdjXwNL6s}zr)B)xr%lr3_)L`53OLuIa z^nVrW%3BSowu8ZnVjgsVp^xEvx#ba5QmW79Ztuz5+F52cLUWhl#o>-=oHdNUm4frw zHv7c^O_Z`o!H2oz!sJHTvm#KznV{Vdk>apR9yw_Q;{H-`JS%|YO{9M4!xg&J%qyA= z;mu9mhtwZ2bbO^9%it|CLjAUVKKqFj1%Z2^Z64Z$z=~ztXKB!%nUX^Bg7BeC?e_h7 zXABgX!>JnvKm>=?2r*&nBNK-Q6+-GH6i+<_S1GJ~#DAEo_v^l~o1=XEBJ0oWcn|AK zhOXnv6&8)`qS4a%k4l}P5Nm*EB4(z21Xi+l<7~{uyf+z+2Vb!v1VY$$#lz@f1714Q zc~;jb%#UzXERSJ`p-zzAM)0BY&MgGUQaW&F-{niI?5ZGRhKiK?G2}`o88Zb{NQK&Z zEgyOloj-(ByzqWiX?Mf}rmq1<9PV`jz(a~jsoocZu&O~awV16cNQz3zJha!grI}`s zLF6(yo%8+;p3*e%mgE4W^hu)7avqXB%t(%nkh;IA4UAwJBouHV#-{=+Fv8?CT#@fO zr&cxRAFsP|Cut6z%%Ti~xhAW#Gg+~%Wu%^e6^685nHQ#1Di>1WpUSj{N=qsqs%tPr z$Bqta%>+KhZyAqFzJ_+MURDAS_0gOv1Osfsp>t@c@pB%i0Cem9YFpRfUKT5U(n@HV z@V0SNW{$2Wng$xr^LPB4vm|cu0#X~~UWJ9?6(V0=i2e!Z^9{EZ#*bj?~#}9hX0{(>WO5KvFxp(FM{n|=# z0BX)WajtjwhWh$2x%0ZAHa0=&kZZh{Bh9s|G@0pFyBUC_(U)+B(E)2@Dx69hJ84p5 zEK7;h=lOIq&x@u{nQcWFf-*7-iqxWkhZfiQf!-nhQn64VMC=o)(6SG>>3)a_ z`}4jCN+~U+A+iGahI zYhY?#7r9{@jn`Ts}f2gG3P zruxbl zQ&G<)cjt9QP+eQ8{Vrds>t#}rQ~PPH8t9_gs+9LC?6{|=QWKwhQ5e2qbWIn$+6pVd z0{BO**1Q)pJ!nG8BnH?3N_AuvqQ)s%mHGq*@N&rxiM5o+JX6PiHE+P*_ zY0zJAOl$?E`qJ`Qbl+C^o|3NM;Ry?hGLgP+)RCKS;5c(DrG&G3(e(tc7oRr4uE zJnC*JestT_pU3xv?aB7< zSto#`oFKk!V3uXetAk^uJj*HGN|w($tTu{fteCNot9VzILE}Up1@mrg-kF?U*XR;o{}t_XN|kJiRL;@w&C{qrZfP z6On#_dPn6ibd-L97bR`HGk~h>p;$GU6ZckH6%`+ivhLg?McR8tBvLO+Fq!6gC7&BI z1$He~`_5*3>Wuqyk8%fE-W*iCeIZ8P<|?PiwAjNi4dn{R1Uf1z- z%<7rCLav;_;Ol!=cI4(=lb4|Z7$D`u<#M_L7@@pHL%G8AjXQVX1QCgikzd@{A;jir z<;9JFS3iS9MNcfPH^a$yB~&W?zJ_Thn`v~V#~3KTw3*GW8#vAfkm{6XC0XE`--Gtc zV2k(doac#k8;a&>Zj@*>7WO{vogbq@OAeIW(m1<~3Q=8$_|} zeER%7HX*ySk04g-+VWd||2l!WeW1+45L~B9-@{Qg+=iZvmOJ-gRya?%AUx<=sE^Q{ z2esW*nIr86?AF*c-(aNKyJ_euZa!-jF!m9;`$_N>!a=ZgW}wuaD*6d3+~5!<_dVP=1?CHxTSnbe^p6iF9=6*{0jg+}EYB_%l#3!F zmu@vhi!K9v5BD=78}?TvV0Yhr*bWo*$e&=2@jL!>$YWj9ALx3VpK$(EUs*3z>@-K? z;`3(BRM~bTb0ZWj9(C(@1<<=;*e3@*NybrX)58f(HaK`71F0NYUebj(;fC$Pt~ZRH z^x5Y;Wj=Y(>uUv#d#@@x*H_K-wmVjlh+K)zEdxa z>7@~rR88$q&nBYKzF!|kIPFQ1(cNobi6s%Rtn|#+7hC_-af9e`EvxLxbjHw`XVoKY ztry;4K(_)*l3?V$Z-+_l;K=!s0VmP~Xz_DA7R6?i$o*=wpH2xj)3#r#(wh|N34SM$ zhlL~ABn%(K9DR^Lwah<5oPVArN??@kBr}p;fdaPoM*zG@#XfvDn%Fz<;s;!?@Q0QO zuruXhpo9JOns$acwK#2_5SP9xU$YAKi*EqwIV**3{d9h#9T7Bxr_CfW-!;= zv!s>rz+V9lME0BmZH_0zSnI57UbG>Dd$59apK9o*>CY~{FgdJ_7w=^u2}1rnw4y@v z=pSc|>Fniu^B0G<+A$yFlyQF>4ln=%$bMr$lTnb+eeYgZh?CDw&z`9KW4^n?Mv@;s zowqoxTYYoOwH^Jh?1Z51Fi)H-Xzl54{5^K(dxl_ou2lcdca;~l9Z<)1SkL%3;rovV z2 zEz;wqo^|h{4gS;SOUF)5&L5Kw$tQsC1I0@$Fi8U?#y{vxZ)vk@fP&B^lLOPth<&f- zi;UiR|I{>XBKif5eHHgCYE8$DFyr3OfmdnVTv3Y9itrxNj;m)73sC6sSANkT_t&-3b#=+9xpOA(HCcUmBb5As_<69g)$&w)L)_qqt<=6w zJ@)?=%N#!u5v*B(0)qi%Ea*%bB$l%8OGk=Z0waH72Q{?+eq%PzAFVel?Bj|_5vts) z1=2>6dNt4${P^mZ70cScg(sruo{TIx27kg`NicM%03Rms2Gwdnel4g zyt?+Krx2(y_q8Sygxg zDHnJt*RNGpY}3eU+-gp zvf>-x_fnHnTdyH^J`hCo2P*%r#IUocy8dZBfvG#{it;yO#)o!9zAYWz?(}%uc)9S@ zwHt7CU*!S-n5S~tH|=E(+3;7$(dL zv$8M8HdoAz6a;+6op-kB;&5Nv&oKZE*I?h`VNm}4--I;<1xtDd*UIn;W$3^Mg3=5z zGwmfjIvFUNt8Xl#GaXN-zv(H~G@_lc?)A=~k)k=vr?E5fK1&{=G=XBC(yZE?k4Pt4 z7U}yh1*yJ;Ro6T7#yhJJnEKXHj!;(_17EexK?^`tWZ zo_IsuV;g`R1pmh&s(Y3w&v;i@j_EUWb6Pml6=aD>b_LG z`U?TuEFP*%{tq;To`)}MG|BB!&To~KSQl%^8P5wp+f-JA9y1kcY2JQ%8UKgO!|@vj z4u>0C#NpZ+005?Zmd?)7=Uf;l27n%wzB+w`$zYIEHc6}dBm0&J6*QtPCUJvwRSZos z%ErcqhTWjRL}4_5zxVbp84D_)tL%7~%V-)G!evnxe$!IR_xr9{w7;>RT?%Ew(g}Yk zY}KX(FJyqNOI#OU%c)p__$}^ouOC9GsT5WULFpJ3q0y#gn8_vlE;0)IioX8Fn&i(d z3(awnp6vg0Ux&@H?DnD2Kma}Y)o1TMXTFToLY(vy{qG;0gr{~QNG*qWm2tRAb2$Lv z8t_@eFi%#gsuODSAHRzKP-GPgTj0XS^LLqRCw2BUa?d0GJaRNqH23(27L}ECRmI$s zZvzFLFFJoLpIzoo-^&^Le6#aK6biSH0sxPOw#zyOsR!rL`Pg?)rWry@Y9w{;%-_eB z{_O3HqbgFBAWHRtty*4XzfTtN`MZc@hS}(9*CkPw$HovCo>lR>X0nGZu6x=J@WA8W z=wksCkD$(6Xcu-qI+5>z@03&=8at*J&nf_qkZQes%_h49c(Kg?X=(=H4K<8A0V1Jv zrLHmzyA0)adn*=(`Ey_4h+?K^qJgq!zsoaw&i1*{=Gvag5l2!xrN(dypy1)u+{BVm zOhOYMus^GFK_!L~osg>?-WcSAXcMB_{23vAcf9L=JfD_lo6O&{%O$B>%&V!eZMj%E z$@9i*+Znn}UE>!ve2Rbx52cmuL4H4!`G$vj{x*SC)%ToVa8Ru;8>k$5Pa+08#ND+e zYB4Ty7U<1*K~1(zy_F^0rIWso-YrQRhetMBb} zO{3skXr=*pSARgu%&H5kJB-=CC{w=5Vk|sFMJW3>J@QBTlNzX^OCm}(Ow3I5=(0j2 z0L+2SmGTTgV#4tl5;T! z>OW|WD2ig!_JV$2Ii3ip5=XR%ahc-!xBxypcFYrJ5l%dP3w);|ixPz*m7~;ibYPZE zHZkWK4nOlN)UtN7=yPCa$_b#!YC`GzCIo9{vmpHs%5AD0} z!OC~Vl>eZ~zrL~)0TS6wLuYs~CITQr&RWc&k<+g_$&HHJWReJD`s9|0pg;TXe>8-r zDZW-rZ(8pC$u`YPU;f%jd70#!$|AGq<jA!FbxuF{>e+cXu&%B;RUtC+ zYeOx8vGp!i=i+2D7#TbRB96BW+cuUqg zP+%K;KJMj&PTBMrJbU!qF3!U+Z#lMDiPZT=qAZ(P$~DpC-;=Or42jr_-|v6`=0%Xu z!&85Rh@&A?B?Y4L8|lnvqoLA6>>p$LcKrP8&OIjE)Ax72T^J2fY%+e`A`t4MXv#qF z1eyQCLMj@`i6eTuuj}Y7fKp2yh~81cgD9DPIdiVnIrwbIv7_a zi}fg*d-@bA{)NqmvnLcHN?#Pu$gMlmU=`6?O#L|Z9^313feWRyU$@m9Zy@&G<3&B( z`?`ic{!8ktv|azadb_A_;!CSGh8^kBdi~6)W-LJH!{MZ~+eR+CF8N$Dte#IZK82Bi^SaGlYF$Va{ zaH&2h7sM-i-d@F&ri#{={xBE1x#n@l6x8 zFmQ=HrG3<2BSU`9{AARt?eOwp6#M^v_tK_9I0*VnU$=e*(9pdvk6`CR%b)Q{{d1DA z<@l#zXN>((i{GX#J>YOl`ro(PO0Rp!RUcWCtF+wz%pu;aS0U~_l+Ci;e-&Xb!fJK_ zy~F;2clG+Pe?m|(+!LN&jPvGPor~`4)zf-X_q}WB9j$Zxtix5Eo)@Fk3;MFia47%o_KT z_Gi4u3I!Pvk+w%p!@a(E#gVV(SO}f4f-C?LM%CfTTOQ$SF3eFnZ~cq{19m7#qNcP& zc=M56N0%0~ry}q50~yPxVFr2&4V$NAK645bolhi0SLqxb6s+Tm04Efmr*s8Ci=woK z6G@(}{|mw{2S{m{0|Q%!|2;h^e}75H+d>+om;P?J5Pj1|H?n3 zK9Kre371ut+hy9quM@b%@lwQj3JsK+Osn5_hRLZV|JhBfEA5-!nj36iEB|;q&+&YY ztzKO5|0PUH`nToo*ay>>ZMj=SYgRY6BmS-{w5e%D*`sDZZVw7^wLwKXU!Z{QH#?PwYyG^V$%n@J%mSP>265fA*t=QehizVPs~qK zQwv69>qg3b^a!`jc~ud>gWZi@RmJgcm~S%j zwOaBRs3(1~q)(W|g0wil&>^Ebv<|@+$v^9Cl{B;lTRPF-nkW^eS=%GfFUq|=O2@t` zj1`28nSbo;3HSOCSGH^Y-j0*}dH6=vRgC3ndUbQSP7$C+!JHb_0W!m$AfDkz`x z0T~DHWekuiQ;IXEK;gy(Su6`1*WR0V2CN1hD?)f0`F z{uobkEBfJ_q5i!Dst>yj01O6SeJSWGMz`D9XSohH{`CmjPTG9rNgq5YEBB5-|fXpKbE^1-zAbY`0A$Ij9lSnKK`5I zq0p&#r$5e}ACJ?Oc;8bzp_NZgqZN`y~`3u81pQfaZw5)^y``2#hhZf>|tL;m*>~VKfYW!93(OV zC_5#r{VAX^vz|Yp3ohm07t&6=5jVEcb|aE5?~7=7U^$JsdcEL9CHjMbr4mHw;UP1& zuW;0y?*mOFmG#odky7pd1(2(A009v5`xk_eRSGIgImR!w^qsy6CL02clO5$cGn*d+ z&1c5b17dHbzVo29+x}$%$Ep@~Nzm+$bxa(B_)#ZzlON&Zj?zDtGNeo{f&8n#&nVpCwIBmbIUY%zV$tF(&}69CW-)gxdF zMmpn^z(`Q7 zJBrrgr@|tn?x$};dcxVoRDvTgUh3KHK8n715;@-*-}55;bPOyN@vJ+)8ySV&+lc09 zztLlt-}y;Xa~6ktg#jQcw)!hZF?f`Y|4Dof1AS`bDmh(sOJm1_XpA?u}3umQfn4fR7P+lL;w^%Wq-!EZeCvhv&h4gtV+Qq zDoY3%6{V>>t?5pL0e$z8?*OP!Wuurag~v;sN%BxIjHs$+DK|}V;5F&qlmG7O_U?#T zwla>dBXy`nMr}0wW<&NX9)^)iwbrOlgm-q_AD<2^8~`9d5!W781j5S^{m?}G(sxq* z^qe<2@bP(}nYq`VO~4nOyV~Nb6j#VTSX9@kR9g>GP;@q{ z1>|J&`WIv{u}mitlEwA1#;H7f2|d?hE^4`Zbl>x)?dY$s_xJE?$wtpxOjTwZoy%Sy zqv7ZTrFwgOcUk0hj_Gv@!%U?}J@9o6sJYUjT=+%Dsf_!1((n0{W;jNlRF3SWN&qq; z4EHba-x;8eN0T9;P%bt(k_w+2c#_QOdOY7{cwTUFWk2V&G1~WrkBn1TX%KIPzQXUl zRcP!ta`LlFyw7>tvudNWxJHcl#`QYU1Key8Am)&G3P4J+5xXW3&3QSKlPq5k!^is) zFEuz^{87;4W|M?#vZV2OUXx=3^~kB$=DQMeCJZ9?k}vNcG|`HWzrh1m^i*NkXMBte zIC#a>A7cUciKP&M+XIw?q^ge8GdJHmGz<>2GpI448(>qr-Q|W2{1v%Rw1@ikpUWh@ z)xTB#Ud0n6k$fI8)-`qjf^ZW>XGl_DRI>0?|4QRUqMP7{M1(x|l*y1PH+MVK<9dxb zNJYv8>fY==e^aTy@qGsKl>16>VlXnRGlXdA;Mz*BFdX{qWBWl?!&+RO$L@Rqh?GF3 zda=<}fwaoDI<~s+C9zgL;(T6{zZ1f6Kkn?>yl+^W1OQ$ZRe$+QLjuCH0qOW7$k!Hu ztmlT_o@lAyWOTGcBVdhtQQ3S%W$^=M;!ui2r zqFD@}gsO7+U;%Nf3`HhKtJ)ZexC=x8YLq#id$3C~6mh)!_3LCO&6M-99iZul^7(1ke+m<3x?J}n#$?nd>*!I1 zy}i@G84k}fJL}4KQc6n*+wbprXx!C3BJqiTZZULiIFHh;MNu(f^+ioAn<`Zr!FSc_gww;FX<*m|SXR-T7nb*6GsAI$c|!n#GDp12R|ufur`-UYkVLbMI#x1S#gfQD)a|H(u|cdHt3QO_*tk?I-EUN~ zy^!@Vi+E*Lv{v7~pHvvgOC8XN2=cObQrPHfP=1IodJ8QR4;bT2ioqc zpm!#vlkdke2!AJ58H%5VK8r$6I;=k&u1UmO|MU4Tfbl+38~4r*F1?v?!x1j&c>fXe zGus6jOMr-@NJ(E?rr=_BfNXfbVUP;1BFQbY810q|NgIVDKn z_z?hsRUhpcTS8(tZB3$2=CcJZf0Qp8e=mp0haFpbA1~fxO0J>$S;r!Ckn7Cws{h|k z5nwas-Ix#iH&iZbalkq?C0ItI^RwuP^% zzovReA|$u=$<&6hv47oXKxukyrDqV7-nDFm#A7{J+@d>Q<9*=^!g7@Biw`kqSXQ()~h@Va*B?USr9`r&Ehx&e%Ib`S0-Qf_Z9=$}042Q1H zUs|OF1w)+@$j2u`7C79K7jMl|0E9#B*6})^@k@l__v+WPjd9Ya_`aF(I6T}?RL`U3 zJ-NSwAH7tjWI3vjs*SzXXrNS~0WTFOP7`lKJIdI*W0oXBDsD zaz94P&%2N4ESr0K+ERD11n9W#_jK@s;_v)_i?bNZ6}UP4bvN)5V7vYTH}@u3Q5-xC z3a@FWT)axV5if%mbvdv7;&C{XjAbH(LCZr$-RjcqL!8#bETzNj6L%pB*WZ;z2T*5I zri02T6FsLwN^gP;`Rt0|(Ts!D%Gk+3oT8T%{C~m#J6JeIl2zHVN@yw9NxqUNo2bfv z5(}MSA=60Xu)33c(MBN_$}^x-vx~p^PR#V*FO{<5Fe#T^38`FjYxJ$`48;j!d*_O{ zKKvRiG)cl$8Gy(N7+cAY+Lp^IXI1(ez6>e@)9h)1{dP8i_z5Pb6-hQk;<@Ph46VuA zRvpu6^_yyO$EM%n6>26{e*kEds#f6zz_Sr`w=;fS;;@L|Cs9|0P|!BB$phEIvZ;!# zGM%}pdDoVPZN_(LLZn}4qYkw0z&3i#o~f=&O|iP#``;Hg*aSca2KNXX#gm>ldN{;4 z%1_m&F_=yt`5$2bpkkRPLcFBpv|;YY&g+K6=s1P?cay7JsoMeVnM$vto^4=gD9>Fp z{05)tU*x&dWrqp4b{CK{j4fxTO7&JBzi2HbEmRIxR`$Xj0VY(E?mt_61hYNL;EsBL zNMmPBI1x3vdC$BsF;i7kw{KUR6JqrB6rwkzz;Uu!NOHsGPN z0>YEJl>vxKsX}7;O9CUa^bk>0cY1UFAvRbXt_n!MWE*H3P)%FwG=G1)-sYW5gK`Cb{-1YjgE)ilFT ze0>n##6iKWuD948C=Hn z?U_Zd>+Ag|97V}#xUVTBpdICY?7pL`)#0yv;LW~Ep3d9$f;}@TsWp7h20#$CsLx^7 z1jsnO=BLrNP!G)JifzfE61St0JBEUbU#`=hb*>&oO;A* z=@whArvOAN)lSYC2941plWz z_y+>@bBvAr<`?`2kjR0Ip%mk6!()G5UJtzoHyCuVMT5hTUYkGKRBenA6j|!zcXZs}5ekBWXbRq(xoKr6{!Nb|T|aBG4k^V9%ozm3bd1a5n+^V}Xz8Frusqf@ z^-Bp|qlCkK;Iw#L1pu}Bgu)qcDZ29mre~Pg`AoyTI%9(6KHn!ZE7y;Doif*caR-93 zVK+Dz)sfS1>O6FgcGW^BDAaR}@zbPi2bAVA;fc@N;9rP7Eh=?e)1@trJ-`9-O&>8ta1^JjCLS?Jx((lCZ%*W$b&j3$ROtvs)z&|8 zdDT{?P(!@^*^(Hu=NY*)#{6S8GLkarR$-Z%Pr|zh40MBxU%3bZM_UQ@x2pV%nN~8N z5zoJYh-Ft8?@cXSY)t$rq{9-D`M~3HJ_c5Ps)i=Oh>7R?zEi6iZF4ICEN2JgWVs;NNSKG;Bg#W8K|vbG~2l!mhes zvFNfgj{APaTW86htGjAHA1mFQ%m7d^Rob{{S99F_bte+fewjG?KhOf8n3%^yEVUMl z`a35);qr)&e#!^s_g6{MD%;AFnbszurJL|ARXG?+EWD433qnJSbHzaA)x&+_wToNm>Td0-a8mPIF-Nv zNDb?Gi}L7y9cU!d0EvjAi(~sqKZ$l)S=oWXq5%ju`2g=>W5c@9!Ny2LSTvlijpfSK zZVNC8IcE&NKm=>dO1P5CUkFv4i@IK(Qqk!NXf5s}l2~Y=dz7-hc zW_}v~-;2~=c!%{xRs2;YWmU+t`w?D}9uFlX2p?2Y=a}8W=s8_5%&SVJ7s=7jFcgw~ zCr|iJnhtLy!3J3bhw9uWb$T-?**mg+H(f}YyFL1Rf~09_`>mlivNMZR3jm-(ncXj- zcDerFo0jNug*eC=uma|c_;*z%&{|*~ZT4L1`mj$iPyud3Z+igO>+c+^SA^&_1}pr1 z2OwGGE~oMsFli^pS`sVb}ib1LT zx9j=gMB2*6+{@H=xsv}@a5URZh|1Xrdnak8+QhsIIVq~FOrYGqa1`Ub>)W1h^6NQC z)bj~x+)|(&NY#1ag9QdORnf-H9NvF1nFXp92;#?$!@B{znRO-S6{5FlQI2$z=Qfz< z@pt1+>}pu{MhEvv6@J=0%epHW&~WjGfF1EfeGdyDL~~cbH@hfBMcrSZNVdA-P7T{6 zEUB`{o!`o3@=2|Zz-E5QmB`%%R(-y}4l&f&x2AlyrlW@WcQ4j9mFn$geOI{=KmSjJ+7Og8aJ3N|6T{lt;QMMD9c>v436@7~cH<5gFjq*B%_ zIJK-fUGZZZCF1JeO-M!6sft~t)*KAkMhQ&g$x%oo;BYuYU{Ur$>0E~nYVJ!d@?;_L zLE|RP}a%o#V#FPX+&v4Yll#NRTz=UM^zPoI@YiZwE^F-{_-G z^fHCo|Bz!0L;rQvCxWki#Fa7LV*aJe2Gn5$20mE8xi>B(C*`9ylS3JE62T$W&Z1-M zOmPA9H8@O9%UbW{cHa2=Yodk_bk$miFF#dYfB0xIV4_`l%7W+7$(a48RDBEyn)1QX zUykf>^h%1pG#rz{j$oZ$g+IQ&4JR0sHLJnC*Ig~Mvg&2`b!$XooKn3KFS{U$x2-a# zetPQPV=QYPlqW|_!gYW+7T=>xc#;lGRN&LS)yFhL;j0y7zcx8k|Pa%@w=<+ zR#8iQJRw+&Q}b3>L)XKa6~IGuotWKQu}@+O+IsVCiY-y8sBIR0(Zz@V?!$_fAw^EvZG z3K6#4Q=PnT4Evyp(WD|UqvA87h=4x31&Ik?^ed4KJ)>qIoJxbq+{rqTv~>8Da(AI| zv)PVJI6I$ZoS(Ddjc$Kl*(0mb7Qa$kjcVd_-YgR!k?!8L@cF$R0Dug@;AemO@wddk zkx<rCXLe?m!i6E4M+AV64$np7w z>E3?bVo%a+@#H#}{Ru(Yb6;y04Qr`)E_xEn!ut~x%v&-1H`2CcTCwY%83 zVl-P)?1ZGqY$u91b(V<$xUKvI3>_KbttfqS`)cy$Vo0t8O?!d^t3S33`TKz&iF2Us znL70?3p!R?!6SJC4gOI}ztJXE9Bv;#?4J_9&hjV%?l0C>^f4WrjJs^ z_M%wm(3dQxf~ z)C~r9csa;q$2*0U*Cnr*?Hk}s4u_llt$@Q_dNcw&fT!Mo1xOS~c{FWKc{4{m>z9Y7^PVC--K{N8hxhdF z1qwqDdA>LyD19u1CcbE%7k4x;#tLg6XC?c>{%T>Z4}>dY=xy_b7YF zev2pkc?2B-A!acqfggw0ZZUA7R#m#}M-WS{CdxqZAZz~5--0Ec{h9&9D09t&KA?Yj znzjNU5Kx-+6L!xeT;R8ji!1{VH)O{8uDPOAc~q}#fam&0R7k^rt=LNp)Pvao=e=00l%omH%af$5{g&~YoYQ!!CucIw*x>dX zE&$ZA`eT1FS_IHqSKBQXv7%IV4z|WrN2`i`=dSiY{WP%Uo%nXa6K5;o!3cn2ePtIX89HquNey)Jt)9jaD z_JIp(mH8_jij(p)Q1W&auz3r9bH*=G8|<|+lB- zQJw;LkQ`QlYithO{lfZ=#=BT#&-NOkKW{szfpWpY+c$!RMT(d9%`?0Z+lk+w7_|8* z!k??2OgNO07$xLH-JE5G4ao~eo;MG)udY!a{5%t4Q5mLf&{L} zwvcz0!%j_;l2VyE|0zY?DJ10vVV>U;Ul2xz1ft}!-m^F(qMC(NIa2_oI7)*T3#h!n z4IyXym*2On=2>>xANpv$uFAyNuq#T1R*{R8TP4|w3Tp`7wLqic9KOVa_wvp-ATN$8 zG<9UiMJ=X4&f)n@Bqlb}fW7Errb^_xmdX(3MZWT2FAqo9O#ITto9ODPqaQk~`>PmO zUgpcueQ^bNfTDc6=%(j-aNEI+*+18Nm!deAJ6G7_t{weFIEs#YBE*v4L%X#4*n3kK zKANO-u!~nsmAri|I>KVr!cWBy*Ms{;YsUF|E~=iJ=NbrCxU37bYoK060Ro8J0t!?;=p zH(toNxu1z4-=7Ns&fAuYoS`{kL9YOygCk3?Q;UCbC`*nBPcJ4p%?<5k_y0%JS9mr3 zzVAO912%FSAUnx>1l(inM{Kpn$Z9Ac7#Z-{JlF z{$78;cFujSb3J!l_jN~E;cg_T*7Z1Vuw}T0m8V|p#b;iS)(*5QW3$kdWp<>&N1ZY)u$VaRIbi}A1K2sBUp9Mgx zrdoZO4!d+{G*$``#+etAI%N9jM0cu6$ClZYn3iXgs}DXmUve`PFDYZQI!<5y^TeRT zJGlLq)r0ko9)yn=fQIKqKLMa3IbJtHZneb)!;ZEKct!X1b4I*972!2ZkLDtNo6cjm zV#sQ7Gw$-fI-D%$DvmE;@7=S1GkSAtqmC`ZqCbwVn&oQ(sDcP=c{*fU{Z{Nb;tn8a z8BT-a+bTjjeEHkwwusnJ)h$V?Y9^FxSUXR4HI8TPXzRx;h&p_Xz|zzf zk9v|r;g8H@^Gia@Qg6TaSDzT3?c=#VDn!IdKdr4gO%*O*Kw}e+#+!F%*`A{s2|h~B z>K64sibzkdKmS$ng*m$z2FPDL0AM0(T4c-~JNk1BKZqMB@kk{1D$Ud$a(&S%x?~#` zm!ETK_-S9oq7hogMP|9_@mu$tn9k0%2NokJ#@kr4tv&)&!%i`r3>0IgfZf{}>jDCc zHKS4|n(71dZP+`eU#Impsa4crDOu~Mv&32L;?b_7t?B@K#W_NIAFcp6FgKu@x*lX0#_$ws{`0`?6QIUC=ci{v zbfde*eW(@jaObOA_RjV?sg+^vbR7MsAAjT7Cv}6pzKGIL&UTZ064egG(;i4l?&n*4 z6pyL~WW3V6x#2gBgwhifb_$6`>VpvSer!!q!uZqQRyWXbdVHVvZAD%@u8Ek)%=~P5 z$a5#_BI{Sd3&A!o+k{w48ubLz-j~)8DA44(;UHu{3rj&YVXXJTWHefHq$OjK3ljr# zkAGQi6nOoMh2+m6sT*;2VoF*3V&$uNzh%XQkHJrBTC-X5|^_ zHDd8>Vdb~ms6#s_Q+#u;sL5{$(-93`BN3(yq1N+~Yb^qe<(=3JQnNO8 zO!(^M76a#xQ?BcNEzFi$+0#*OPPs^XzY_xX^uNMGys6A|l=87{-9A>)L$t=RA0!?w zF^*rgX4Yk}|@!*S}($0?+-; z3m6c2B?ZKI7QFZzc1oWThMd2Um6K#G>=K_MmmyJvIkWMt&mjN+fmw(X0VfeB6yL~P ztWQ(wIMASCFBd@I&+O+z}$>8$k&73};i_a=i;x+k5G`3&ORlP@v z;*-fy_(F5;6re*Z#gI~N`p&+F-Tv-~vD0kU?aC^$DK0m&-7e#uWj;Jy8;NcWqiEh7h76JfB`eO%@hqFZOs}`vNCNfeuwczp_ePP`n z{Fk#|@ntI&9VpL2-@F#|WB&7)nu?2UYA^3emN8L^M74a*i^mXj9p{9nmjjDNRKi!U zcxSxIBgMKNT6b!cYg>CsiqOxvAC8s+G&x28mpvXWfPN$P?L0qkH3`E0Q!_~}4rXUg z8rQ^sb7JiBm2+aV-|Lqxb?Z}oBj@5Ll`|+auEc!)U0?7|*Sc}l}e0V!S{hMU|b@! zG-xVL7b+7?E8XVu*dp4WRI<$ZmlJ+3;38|%0T!TbzMOPLL$o~DRVZ;g6cXtafix(p zm&7m3oD7F$wQZvQL&hgRTdilsG$nEAf3v>t{r8~k63{x_6URR6);LYY4ljXF9hMZu zx<=nc=G3*owgL_&iZ&&u(GX-q*M)cRaUeqD|MfT!1*6WtB7$Y?r$;iEF0Vu0I~RRs`s zu?3mnKj{HCScnc|pLJ9(no~`iecWtQu^Zy0W0&QuoheLW71fjH<}i_2(4d{Ck1^|m z3JrgwQGcvL$NR8g$#!5I1Av#!6Ce|o8E}uMr`Dw^f2V}jm`fnaVg zmjz@;VDtIetLTRw(X!AZ@@E?K;R}Ou>;!~=^IG^vvrEz}FXGR!(e>b;4{6&m0|PM7 zvF7b(F$ClzDaq7b-`4)94WYU>&)Qsg&k?r)LBn__JuR_ct~ueqdbtGSEOV9XB)r@? zQEP2w1&ol87cJogONZy>p4Kh|2l=+zyX9OPG7iOlw;Dse+NmGc;ASR5{MfQiv>V6peiw<@P`ns0d~F zsg)SVJZ^n3Z3lq5gN|X+f&)+4`E>9{1ls=M_@*u=i^X8qxVuXnLLyLgOT~AC>)~2Y zNAf;-sSMfk7%2f`9s!ma(=~TFBDaD)?#sH6eWLD8${(q%t5-ZaNI&~mtX-u}^P9#u zA0#U_bpOz+kCsQI7@_zX#d;$M0Y>Xmx7@1*afvRa=|<^N_l2&EeGlaplM_NPFf4B+#!817N_&Ey78} zz->ALf}n`73zVf{F*S%oo zE2Zy@qe3@VyKBntrG>yZWTjW7X7#l$XKYRZG@SR@@$PWJi9+G1t|GIUBAj`YOv?tZ z_rmvC8fMzUeJ;VBhu@gjwd7vf`RlzG0k!9xIL6y_UK=<+uce3(ic;L_p4yN>y9Rco zsF*<@qdAvNod3p5dG|Qsq}$_PXES`dS_nWC8{4&TKt*7byG@asN6e^q7&SRmpf>x_ zhoDVwt!V1X!uh+~U*dL!V2 z5|B^?4JVZ+Tim%=Uvnb@D#tzH=_B>yypHx-zlm$SbM@SLMK`rFtgN0h{>i zT{te1?q2cRyDx8k?Dep-bXS;c&u*nfJnTJS`*Y!e!_vl!&>w~NC3Y+#I@^D2Os@m6 zA}`%TplMDHrKVG|8P9~EcE@u>vC&vFN{EQ=oRKa%+R0qE@n3}fMM|bV*S!zO#H?H) zFJ#D*h#_ElJkwIjbL`E9xLFq zz`8S^qx2sEs=+-OdRuzfkRMNSUNS^DC8%zxQY{+)w@zI9nJb5R?h|w?#7lM2Kk=%K z_qz2^MVR1p3&mA0V2Z>3C_A*^tqF-c3GdLGWAMl0vr`o#b$+834u zh;a~|+CG2msswqJ5iwKzVS>|z3$vlqi0+zEC79u4E5pxwIeH>|b5*w_{Df`jDrGD4RR-l9^rTQJJiL^Yo%Y1KTt6}oy%znx zr$0tsj27;$9F+*1&Y|Edx1Jpd-DJ{kkY$*4#k{($Y;$V8O`pnomQxxLcT@~u?=5VJ zM2UCDRI~-r!jHwo{{+Aosde3k_UmQHOla*amX?{it=&uGOqG3I$$k>un5?<&Ryb>; zH-GUApd|S(0LWNuj&m}J^z+^k(*gx-#QX|?&=&)9e%V* z*V_jf;RgUHv3!0Bd^?hT1-wOTzke26zsEF9QL43kc1bY&*$2|d5On0667~T!j8}g% z2(O?uP`%|Y6oWs>RIHN}D^a1VY-^`ou2H@0`#Id}H|}5Zidp<|68*q*_yTrUJSx2` z^~s15pLpnb@zK@c(a=>09w(|dY}a@pVK71r6(o|P5uG=lk87X+9jia33d{A{weHB5 zTG5Bu9Bhux%L&25?y+Hde(bS?&rP)2>%@2MPr7%@&lWrP+D)VQqi<&fhyO}mQqg6+74inV?qAG+^0`SXRomU z4v$2MF95ny%6LY4HS8DdF%wIyF|L;S`Z!x&&uz-uC`xvE`G1>9uLtMp6$zj(a7=nC;VpFs zs^@*Em30&nl+WE-XdYJXx1^?k;dopUDH*WAz50`)oIxcSyEZvYwjwpfC-Hu@=qmq5 zA@eX&Cnm2j(O*!%9EwF*{O-`{j8z&-dP*@_V<_irVL_z=xp#VLznY2wU?ym^&nG$> zEXRljBr#6G+nG=y5~;WT#E|!*6kiSzXWwvibv8aN;h@Cn!O-!C`L=RR)8m5^LFb@v ztHXO%blUJF=Gc%^o2w+!=@IW=0B;x2);a+YzhooGysM#_E^r*ud=d*_TD6KPpOiO( zBW#+Y9GgEhXueOsfo0d}`L{rrB#~{ea{4l=BI8v;FwR(#M zWg=j$EDRUOFqOPz5uuz^xO=jjC!T_Mtwy;)XQb6pYaT!Fs&G^Wr>uW#dM+pFM&}Qy z-xOuQ9zOSHZ%%?xtf^LxVh=(pvht_9&uZIvoO9_f0y>G);5Z21sTXZE?Wf`VGVe{;U0i-W zYJJz5JpRFjkoF4(<)z)cx^2m*81wC({9^)?p^tby>7D>{{uX5l3J{cysR5;}8E!DNa2A1sv0JI`eCRi~s-`yphf! zl;a}nz6>Ld9T)4Ao*zn6&nm=COB2yoOysj+1`@lNQp8NT^9wOIvEz}|_PZ6e()HF~ z-H?{=>pttnW{9Qm{#L)(KL6wI#S8zv_z`FY-ic#&OAlOh*OsRcCt@y1wXF*X^U$re zw-U*h8E)3qetX_}*Q>~tt zIlX=1hWhr4*2$}2>&Zaw_wDn&@*M&hf%8A(cK4@m#?Mc6ALc6GECa&AsjeOEJ1|5# zF?wX?u9oIt{m^+l;=cwH)cqWWiAAcWy1BeNVm;aaq& zTKR*lUm*=T=EZyV#9Z2dYXH{XfOCRhelP*yZgN+KHZmmVRizmmf?2*^cMloXFs^=&sV@t z_2p(Z1+Vm#BsfD`Cs*KAD7n^7n<4JIp}KtOl$g4 z0PMR0_l%(bs1W4e46-pNV*Ex_%N6cG)W4s+L8x#5+D~Ja`jJ6|UvoO4#1d0jaliVJ zKASO9d;fI&rIVO*{{07_NH#-HHk_rdlhwS}k|EC5Pql8*q2zMfT41ecZQ;0p~1`UkR)e`(x9*SJIXuA@Ht zlg?~VG%qp=`JP?eo%`fr=79)+V!h>ii+$e`i(R;tT=*+a9C#3(WW~>@(tM8$D`V0K z|72ttUc~9NC}8!T?_}D}AYhjmUzZ=m?+x{wZCNG5@&b$3qm{TEm3m2}(+B2uP*|KQ z0Pm;?VA)ABRaHiL3{%3w4-lF+k^^u9T{O}O2PafQPC9bUeUC1aP#gyyScUON+u>i% zn3mJh{&cdnoFNYFtow2giUFWdqtlt#X21KN8i56oLoX2je%0|-daGWL2|2Y|F#{qZ zY1P4(?L2V%Aks^~VADr!{Tg5XxVvLE-Y7!3ZiBCcI@Pthwm2Z3md4n!*!OKBOqSYG z2GGYyn@AmWq$(R&B_o5H1TI`^twi6;&ls(C;seiHe?=#?iFoJI&QH%Wmv^)i01{w$ z%XIi2{O1h2<{#)J(Epz_Wh9iY6WFLjG3&W3Y;mGgO0|ptIUI> zFgf^@A{&e9BF;Mk!eKK63=8!Rptv77&`e(>opu|Yu3A$@K_+&h^eT^>Ij8O}T6UA- zoDzNkXcEVym)8PZm#pjgxzg=0Sn=N&0g{m>cy2n9&O@A&e%v`We_`G6iYMvpr=k6; zuhMyj%a4?5|9-T0z{2mz6JSs(oue<6NQn=7abv^D{Wmm_oS;fw&{ths*87EjTL2vW zMO2DsDEX+BYwZH_7XyLgxGgH|jh{qP z_}}lU?RU3xWPH{#*%bs z3i;y^fx@WRY>##IN@xDr%+th=wf<(|3FNMb%IIP^>)$WGKY2TM$0ci zom9wo?vpUz4gd_B!14sBm@N1~SpSF%_30xW;Ls6Fx(miU);{mrjiNr__V!Kpr_kU= zQN^gZeTHCBnQc;8Zs2?GyTz_IZSPCD2ZemMC6P#LXAM52nd+Ki02uhS4;BD(9}lb1 zN))}(WGf{lRYYu5)*vPPW|v%zphQ$Dcgub9^&d_dhWu0Md~n^5JA)EU|2q7AWe;Fe=gNWC$LqP1cvuZTa2QecIerSKGs|IJQ+X zTHCxJ&AuN}5S#k^JFkxa>+cvH%NY`BV^#|Q0*ZC*o<;3k77O`*sx<&D;ML!}&2EVw zRQ&2gdl`Qird)Tie$gPKGOSj#%3(_ zbB}E6@wEqsBtio7azN)Kz4#HWMw`@Ub0VP0^gnwO6B)0^W?A7a)x=}!5NqOTuF{@an@lyQv{iPiCJ)!ciGxXCnJ_h5ZpoO0TCf>1rsBsBhdU^w zfxs6j>``j)e9>6E{*%+wdmh!>r~Kki8H^Hqes+HZNdMGJKk|}em`wE|ZxHFRZ705C!L1j73=?3^^mHfV;c zh*U(w&9^UI@B3J0=iI0Ji}0);_+d!8aDC12x@pn#)|(|6TlXNbPbcM4Mc45R56EkZ z0Zg*>48Vyx#Y5)OE>EP<8Ymkw31;V{3~u9c%f@R015uBp;bya4xIG1NrpmWhzv^V5 zqnj8a-MH&a6!7_@-^k!@c6c_;xg!>@|LMUiCoK8h_8)-8s*`}1?-mrZ2(`*ST6B9o`h>XyfvNG$} zj1VYFmD5VINc*vOWhM1$mr_}PI_L3``4koZoe_CoZ|SN7i-Jt4_it|0oNxM*!8(W# z)8fIw{@2$qJFW?@FxD!TUt&>mk-Fr6|7ColkbaVc825TjuH0J~x@wAreHwav`bjf6 zv_b`GGVrl1JLM0q% zDUXc1nHiHQg?Qm9cbYK$+t1@zJ3ii_CUU_r*h+B`kHDt z|8l9daADA!_!-xLrAYRx6XEW6@-{Ow*N1vQRy^cgZ2C>gmIKG8)jIi?%)XMXJohe2nuZ+i7$H85{nto&BqI#z0c=Pn&;Nyonn}V0_ z&n}tnHq_Wb78nh-zw(}=RC68j@Dazvv5)Z~exQ2NYh4!)Pg1T^@vKJDy9Rdi*YT^; z97$LC_QR-RwD0DnB`^BZ7g<$Ouw1qlr;z&f#vH@da5Q4owZLa z%8#zyq?>#-?hDj9WP3+*ahqz?&ES=K-XH#MUZO?3!N}GEZSd}O^O}4s_5ErLAAzdaxBRN847?PZ3QqXZ2sy48J0thM2r>e&ZhS^^vq}WzYUw z66xsukvNHT`eC|@Q zXT&e`Xz2s1OX^CjGZ!54d$xpobBY#zWy)Z31GcvU0167J-)fS;uyFjd*GIZJ6)Fm) zE2$Ta6`P?buiF&5B?|u6y^270Va82;WE8adtG8UWIdOCOs&y*5i^vSuw#vMd@Wf8Z z9PV7skoTmAdm@~JJ$q->d}4y)#|)eYf4@vp>+o?-Kj8;(K!Y#ZZLBipAJE`HbF5Dm zYr(cJXGc?ostcv(X8e3P)%RC=BrI7)oA%!C1weVNxSGQ(iC*N1wTYUxLQd{!4G}Qj zTPLGDfy3+rDoNH(Q36g`n)Q!|>bP$=itJXo)`;j2@Vn-%RGt3d>=Q{PiH#o|e=HS% z5fsG25Gtvwqhj2*jb52vVTbkc+685w1N8Wt>+vB>0P1Z>1aj4{gzXwIar*AMmW6~C z?j5WK#c^xGaZc&rA7ZiY95yw-Co}Z&{+E%3VV}#~qziSSJ-vs!efaoa2l2^>hbxh2+VH{mU?7rPGUX~Uchs*{aH$7CU>D(^oX1pC1E@=8SXLZ)q zp$q^N0iJu+WNM*F3(zPIN=7xY)1l0yBI>fJY^rVh#oqw8-r~1Z-?ja(ep-r&HL;%2 zDD`@_sbBuCvw2kZrc3g&z8wU>t6u`prKJ|lwEB|*ut_k=73(l#(Zq40Xttld)R;Cw zsA7SCw_>NigSET&*T7zVfsK#S#*-pR|6yEkk^LFXcVCmGklyYEawJ~)4A9c@yNfz1 zixyfkSz8y_p)ewx1{(Vp;v@9h`7aD(~( z?V$bnVFt*Iio=e!#2R@5uE55%#xPk5-y@79x94xZ8Alg5@3VbTcpLutM-JZ0&-2dV z)o^XvRvlYpg=Q>Q7ff z(r+kR6nxNHsXXalKRHczQ{L4H&n|`lxO8|i=)*-s0=2VZZ-fqeVRyWN?n=ZRIBnu-PXq1n5Qn4<`WPnvB%b z4)XKTmcwG`xFR+7zNxueD|L(^y6LVgIM-h>n7#kToV7G|ae;@<%4&X?`U@-5;1<2f z`@qH(vGB_%W&$9i$q0|<$>Xv78$mzCX5_Bbe;u1Cl%=X$y)70hTB0bd+)uc#DnL9B z+*SnI4l}XoqZ5LEnt$p^EePK^Z;p^}z|$&a%SyifWhi5RxjuJ~^twN(Yi3a5zW>WQ zDLGY((l8k#fPIL1*~l*tk4uZ$2{-D*Hb)Yv(k~9&yyrZ6xd7YF)nq(t8B@kmVyf51 zW*(eE^Wfml=R4ch3~x$E_hz}wN5f-8iZKL`eg;6k`qL86rFI2rjGxgvV#0`}%wO{7 z7#Y5670*sh-kW=TeR4?kS8j$kevR#KO<$vl>#x&G2EEU*wP$Y%mg2ioq=lq{&U+e2 zk23&a(AK0-8(w%_ucxwqiJVZao#d;pK(4(^OTUi2T_jS#Z~Ei&(Nzwo1^UloCp+N8 zbhKu(8OAY7s$N)t#fbFEJS;}munsq;Fq1oJFYt;e=W;Rku(z;g zvW47q=&YPPW>zQi^=GG{^TsfrTxBsG+Y|ro|S6Inh=vl*t>7rf32qH z-3*t`M%;_%vaN6ayMsCPBs@|A0J|vHKEj3g1wt*N^fiH2&mSg*?MYKmNOY&UE@IlO z-BZK(=i8b^aPq?~irojUeU0}E%VPIGnb0{(Nf7i6{_)LV zs}MY_Yu?Kx7~h&8U$^4C!A$2G*ey}$nr9TmmQX>VXVj(1V03ze@0NVcayx%pAUa__ z7F;vOKI4B!DO&}BQVw3G8GNgmKJh)Rjr>99g6Qi}y~#me$ELN`VReh|hyRK=dS&(n z+cR2OzwOi2x}N3ybx#K{a%aZv4}ix7nIgLDw$1-KUFKQ$Bckf1Zd<)2;T@GJq`60^ODmsUSevW06kAi3b2=Yxex?=NAwo}S{VyCI z%Y3$b=#V==B^34EBmd?{uQxHNJUTsQ$=aADY-Wz#M`59Jg+IysrmXxgt(yUW4Cx&LP?bUiCj0SWf84`DhTTv)P>J;OAuGSq z^CecHK;N3h8z1$MQ%RqUiajoYs_L!N#QwsA8WW&j%$QFr3+d1tc>n*kCt8}N9T3|g^DqnBu`zvImu3QeK6TIHK@$;Xf1HoPBdrixUu;_fY zp=V3WH?Jp6#{__c08mK;G)TrlZ5W_LhPWj0I7!?qa4&|vur_HczNJ-I*%z&3yY*@_ zaGdsFla1jH%g#V;ZEsJ9A){>6XJvDeoFUKUo`my>2+%$QkV$g5rL-N5O7KH<)L5$s zozazBadK3{EXQJpM;pbbp8|Yh1Ff(4IYBdjKgFq+B}NvHg=LFbFy*{w4I2hXXhvkq z-%=J1W7N-EwDHbWpcff&%R{oDy$1b%0<;R2iBL;?5dP_TC4@)t-&3v=eOGlxSGixv zA82gYhq9l-!~{56yU0^&y45G%DHMBZ`F$_%!}keC&PxUzQ7_FOJ+GP^umn&nh^;&k z1ES0bx#+kQ0v{wF%_2hWe|Qat^_0oshIviy*e5|w*|5&nJ}}IgXOsDSbhOPXvo0A9 zX&+?UPcmZRU6Pq5K*{_rh69Mi%hwoAau?P3kB$D6(}5i=?mc;o>>(BJr~>={`3t=@ z+t;HYKD;BXdeZ1*sEiLii_lR~E=>*F743`OH3Pr_=TdkGpv4e&Lyf%RsZ_c`ibmTq znm|^hQ6krp8KJJF@2Nts!S6=v(-eu$uS`?pH*SzCE7xcXt;c@20AprzVMYshUN8dD zWa_ZBiSz{oRZ~17ugX{;-tQV?Yr->8(V97k?3(cnHboz2Mf`V3{LOBQ?#Xre1Ce3D zm~nl&2GL(%NoLg(j1!4;=ag_9fi~lv2=&oW(kipsb{mSp!_O5eUhdpLyjjt{j#Rm1O{8W9XXz zp-rlAb>|rd4i#{}S+7f#D^S_PYrxjTc|R?d+j{NCHE%2cFgU|J0bH}U!igy)vV!lp z76;5wC%qMQI+OmIwk@8qfyC+}SWeIt!<{IWeW#q?uk~M4)|k8PY~HYzY(Dzi8qffU z=?_2!gF#@i9C)Iz-()RWJWi9K{w;XA>Fz_}hVFUhftTN(36#;49KN*vEGhouamsqX zpsQz?sb_^0{Xp5(d+%{$6lix)RI&}*laMNZx|2v#wLx29{a z1X5iHP?!YMnL^2O0ogUO5Z_O#QdMx`t*oln*>)BC+24CjiQ)Ol2GZYAjM>zGD2n4I z630vbs48Am`*)yxPpQZ7zNu?EAO~cyN+R6_B&*$xe_Le^WO;NLKOq=(a(3I)qBqfs zym-_u$f~}X5jXjXE6%AS8BP88bBXE_aV;wAmxQk2YqBbdHR1I0!(OC2W>Syi0g!-U zp!YG*K;$)JTG=dhQ4MAaiRh?W>?c`~&!$c8!sSU`6_?l1RQi-x!fnlpEl3WZvna`= z0uqu+)A)9d$ts`~YUy^CjaWJ7`8_c?EMNgJs(C3?1k{W{OWUCO+S2{4E;QP zcG#3uP~W*Ee&5VX93jl6mq-0;=G_Bdz=(3&9sCqs> zU{&qc_uH|B4=_eN7S31)fi;5b1TtEdVgKQ%W9;A$9-gL?KsvL8=m=-qvu8?71OTwD zr&(aaltl~HpCV5%Q04jl2F6Rv*RD>R6iHzgOzb9mWcGuK|HOdpW69d|P>gSbv$!Js z@%+CWXZvE8n^bq}NF5u+06>t;4O4)9kw4}48xap}w!g3W*$}Z16iXhzU6RGrzKybO zTQ^kJ5Y@SpvM3Vz*R@hYyM1q^P7hk=zg-4zOW2!}>1DZQCNIw6TMU@^-$t)Ke<{y!x#DL9 zj#90=Sug2&N69Y@njh!QH~<8R09_VfX-6|&iqA_i3Mxg+a-hu6gKfMxidqZ$v|6j} zW{Y<#u$_K^a5m)xb8!uqj3Xz5ZwI;!W$Mf+Lp&iI3jn~0gQGiuf!V$@8t(eksni3TNvqj`PSJJH$Vx|!9z!He&H8#_vk z*oQoeOgK`(nJT~ZPe{r6^GW-KgwIGe0RSi(xTaIF6RL3is4O{zasCMo(Mi}LM?_yh zSuG|)BspVxAN4`HpJ!ibDQXD}Hj)3B{>Pdwf2H8|nH?8q{7DmA-Zz(4);n54X*pZx z#%~WQ0pOGKIsqc(V!i_|O`{Z!tM`}*sP{yT7cgSuGp1;UN093(2Ah{74}YXiG0Mv- zJ4=UtRk^QtJtyq2J*E0^JK@*z)%{$Wk1O4B-2b~`c%Ehv&UN=X+!LWeRwKHOUGtvQ z;&_mxx}{39$eX&l-<`ET5=fIiPvDS)u%KS`i)ek5nHZidNhiRwgIHavjtm9K+#S9* zn)v@f-tNG-kefLx?Q?jDx7GX{D|@j_sff9zgmSY->f0pDxA7}n5Kv$e<7S3;fP`m6FuZIO8UBP%@(ZsW z0B`_(vC~;xviC)rEuG)yM~!u4z}F#Nqn8fIWmofSKD+fCBCFS=or>NYM&F_4=&p@g zP6+65Ng%9+B^-}9er_=}$MUALAF@yqSl|%LfpoZl9T{I@&85~rS9d}80c~o9cC0Z4 zy97u5$r427+lQ*B(z+=%p~IYXUoU)V+5OdJ{}HcHWB7oy`>pf5ct={_2jB}oK=}}v z=^z7)Foh5;fxO=vN`jZ&cqO^Z34{fVwYGTxIe74Na{QsPC_F7hBkUO ziLCh#H`3T8d_(XfM z)n5_EPT|!>j_7jxTQCE=f8Czc5K|^{I9{>L{A}OgnpD^259A($5*Jk(NTly00H8R` zTyn$zBV~vMpH&>Rh}%OH>Vn^=(PZY*BA$_aUOzKlUbh+z41Nlb_r0(y?)YFwu9#Vs zN4{2+omOkBXq}?p*4d!adbLWzqV24@SLuhfMQEGf{qfU3HmgmNMV5y>#bmo zY)IMq?UXAvr6%*N--@mva<1PXV5qK~OCHX@adRR7C%j>K#<6cd+QPa`;L((hapa0x{u+~EiS7>L5yAN6&i?L(pyoC!7VgZ;DHTl;hTxN z?6Y5*40EnO2iai|!9*I4i0Jht_6 z0MOMTS&nm|w?eDCW}x`qa>j+jR8*^gkMu%uo9; z8wfOJVbsbfm^j8dLLz6X?+E=d*6h|wo-8xwN$3>kawHnf`c?NFH#rUj?s4U|uKelQ z4sELk4ytMxbJU73N*tme$oItX2$9zk6^6%*HcQ(Lbgz$Jna5Y0QEG19^mz3B zosr;Lwfa`X?HrQ&Tr4$pFbf2 zpf4Q`AS_xk8!D7`Qd8e?O-M@|QcqlCJub2^wrrJHCa2G8(AfQ*$VeXR&T`{76`7IM z!wNyi^~b*iS-7@tT)q=_s#g@>35?(CZe>ZBmCkj)g0&nfmXQ;9lQm%!7oE3EPtBb9%HgS{d11Zp zw6XmtQ;A1z&BwO+=4*p3XI_2I&xkX$`AespUrvi5Q5eCiP{PX?4Nb~xOpMMD3L$=e z8YPJcDCRyxCJ`fh>3UX{=3(8IY(jH}q76fun@kwRx8|5ygXx-_D=(8S-Tr;m2m8+3 zMg$I7QIp1s3C00clSb^yer z?*>0(@^plEg{+;Ogv9PdnowucFij%TWq2`t+M}trhkayAvmd4BD6)UOtoC>k1}^rE z{?Pbc=1!Yp>%(}L+71F9Lg$6kB@}AO42?eJ%As|X7?Ehc7i|zD^tsT21fcO86UUYg zN;;b7J6Tt$SX|}nR+cyP&})GmwR@}%m-;uG=?iOkMZ*Tw8Yfx;_w738_2yD1qR7Wq zEZ#p}OsubW^<2sH^SNK+^6$Lc#80)IiPQYF9T)$a1=zWiL-9X^*oxcU@^t3>@|KVK zRaxEmk>JsZh_2lWHcFIp@Iz=)*|RmC2CeWr3R>Ot=!-Oy+K+@#Kr~^bLxAeUYC8L^ z*!@42uEMVg?`z+U0V5rw(*dJHx{=W#-Ju8w(k+65GPyytMzR%DBJX#@q zrvEWs5M(`iEZAFIM;F$*K34C6*$iPywsToPVhngBxtk=+We0%fBz32CQ@w=jNIGmetKR>>5 z8b$kNmckGzqU9v}^8=4s@03Kr=Z>fhs+Jab9Uta2H32q0q39%Yo3jocaNWt-LyAP5 zTn+n^u+wYtaAU%rO%y#x-i9zLR2UMJ?N!3z&O>pyuXp|J00aX-(jkBovauICI8IWE zBGo?ZASGIzKABF`S6mZM<$o6U>PL(GLzV0oT2Cw61g~#|p1JO*{TWk?){({=`!|3- z!8c&oTk7`BExN`=k(xe|-rKrY>5OYYd(6FM8yrkk+7i^Xl( zc$KL03?$gTX_>Z4Qg;ne!eg2UEFA*bu7Wr(L6^m3vCpK}3yMsWxE~5dx6ovfZp#+d zD_P1s(_V{xTx)gWlft(UzLgWar`v`Z89(YO4YI}u&1GZwF$z&O_3sQS{jH|cbZqMybw;hNa}PcT!z zqtNOPBLJ9RFMv?fXwaCFiELpplST`)Sy~#S)NwXnIXCT!YFJ;Gc+!t@HjL*|@*|QUHKZ5#E>uw7j@71J{@Xi+j@WInOn>lR-G(i-u9$^xYA?(vj3*j z^$Xq&zskTHejS4OZ~vPF$Nm8eA|t2>P=uoBUKv$UVB~{Bg~uo#W!a7ETG7iRs@k(_ zpO|Qt-F;?*T`~`QkQ!q`8ZE!wLC{;G@F>jUCK>**I{_-?9Ai5{_Ww+aQ>uSsqk9NvNO;NE5{ZQX20-=H4#bsk z5*qnq1dvFg*=)G41cQIs=P6iEDv9pC(&**wjp}!IwC{d(VyGJnwQjKg^VZ_X*xK{G zi2k)#KUZ_w4lhY>g>5e5ceW@3yUAP6crEe9{)IIzy*_?!AR%W0tDNwL-_l`tA-|_k zYtNa%BiYU_xM78em$KIW76wwtT4s7MdZ*gdM_$0_S%eiOT(nKiXaJbDULi*dh001ns_5{G7Q5s~>^~jg*`UP5_ zC7>4ZPO?TiHaQX~7m`*Z5mA#*i7u=YA2iWwOiJs7(J{a&-En_42O<}X^mF*lS-G6I zjzNs*+HjlH0f+>GsCgMOKlhBLVXQA*z_3S(d`N^$LZ}YI3X81} zoU5a&;5&M6vyQ-VMm3DGqNy!8jD?rqXb3^h@&DW7|H-}Mz9Uco5TeG=KgR&V9!aiK zPE^XM;E0JDlXsCCc?hSw8~ITHH6rSz-fsKr%OlXl+l(MjBRNk?EVynEvcA2Im>S?{ zE`=F|X7Ardm&I33RZRkRh$!CJrvR$XYT$0bzp3Y#JK@cJgAAT7S!?fHsFT6-H- z^k99_=)!@Mh>SGwURZiqUuBzC9C1t}1lq;89Pd_yxJi%HRHy!;-;l$Z8Cdiv0a55- z>72xX==l=(9_NpfXf))P<>Djh1`vRR9;}mxCC1C8>^F!QrlZ9^YdQZ^`-(L-e`b{P zbemVJFjUNGU#gZVhG@;DT^+`Fgu(qFu`L=`slkD;s60f?Uy#E4-hjIzYwXh#dSO@t{11d;N21nH?*2u8HV$wXnKH;03%^Nsj zJxA6-E`NgC8a#6L7y(ap(Wz1;9P`v_=xDp~iUB{!1)wyaKnrIxNwVu4V#Muy;d!P^ z+CrwDhv)}zjSPGk_YZ=sV>LL}6=*ReBsp;9%qA%)RK%;q*Pl6elotvi*$+OI#tU~_ z-|D_^SB{3MEuO50g~96+_J}it`Y*ku6)k6We^~+mAb}qFgR8SH> z96nld;1HDxub2;h=zY6b*Se=)!9zHz_-mA#Ol+Nv;^~*;Z;u1l`=0Ld|0=tfNSX^f zI>B?G0DABfki*G)HDRjGFnvxlIx#v{pSheA!5%*KVD>?Jm-##2WYeTS3Y+}ykFywmf$EXqDKpeZ9lB!Zuh#M4)c*4MM&HX zqRnTGV2Z1n=E=)-eifRrexW1UHt;qq@_LDzCI9r(1$CiL1G~O(3Wd zOd2`ic?!-x_gmhT%K*TLZvs%%Q&faj9iovIorD4hzX3b`J1#Df#uPOF#NHwsz5HSy z%zM)J`zN+dG00GHrpP`UIaBK#nVx82zoj~;D9wx4qVIMAzSu~SRTI?*9@?*hC^_hK ztRGVAf2Ah3)6GFxrsxQ3TgARRBp75C^M;OCxHB1HwnxwnMq94Du^5P;?KSXUaq=mE z=J6T?doWvCuT~zoM#YedWXspC5UxC+;tps>w}U>XzmRPkB&5dOi+y)PFsDPq5`7|E@3gF3(P8`P^L2abA)j3Q zneF19gkB}Qf7S(5mX?871{Jxq_?_Vd!lgJ5A>C8K5= z-}u|_-`YVR({|!;Cn(sLtKasq8Fvw}ULrt9p@r7A=FF3qLeIyQKfkiPoT^#6^$3smG-#&^6` zM%1Gi7hS`h$;dP1YZb}ZC27h7Y6ROwK>5f5ikPaFN%m-*f&mqYjXE-RmsgL;nzW?Q z#zobjKIJML6KXS7JGegh_$cYcO#NT^e%5=q59XooTB_T>fBIeXns2mKl^F#9%#m=S zfQ8-?qs~PcmOfvg!FvGoSIH^lFH%OQSxtW%xqCK-e-e#XCVO}H8>y3EmLs3;CpD}Nx^}0UtLvTKAM{N@a-Re9pHe7KyFL}gsxLU{By!$3sg@7weEndBS_1^{fVPXF?ZXOr|?uRY>Zu_fX!D`7D?d(7l) z)s(Hv+WLB}=iIMlpAcd(Cg_7VEJlP^77NgYD0xu>(R{bq7T&s6JjD*ULouNHnaJ4S zEru6FNxsi+lNta*0#36SGi6Qak6unMXq4XGjNi~` zz}GxJ4QKxzb8Z&r)BpYn;9LW!RsrvWNBz%S1{uD9Dj`D?=YUq_Yr-r3h3~|Tfly>j z=1T^C>8PmEr+bdF{dKpg&|L=$Vv~J&hpfq7sGnc1yK1*ZSlycH0#FR;C4fjo6O|ox zS9r&Vxj+-7m%B#4(LSh1`IYLVe!W{%osLv@^90ilm*o7(FiEI(xrF6W1~G~i=2#^-U_-aMinsQR4Pozm3MeL6T~R{52tfOkt9S*Y3uW}^-}TW z-+B?ws!-N6AN8uDKDA30E8;@0{~sx zP(-sVZq(tP1i42Jmh`IuiCb@BkoAp)`=9mhHnF~5NNH=ocqlwvz7xs0O@f$re0v`E zccb^5w02}oGsOR+;G7TU^$oXh`7NptCFF$j>ad zd~o1F?z(N(6gp^)4M3%&bcKb~Jhe&=SZIl%(yQINmuc%QwG7~0n4!*p8EHr^2d9hN z=MFRw;5fcv*3K(#%{SI&<5y zd)(Iy3&p_FI{^e%hS@bCBpvlS!Si?)(vZiC2|mlbvNl~=rLEVJ?X%0o|Dnp?qgdsyCLV@L z%%YCUPLnMpZl+&Nt4dVM{_AnrhKTv1^>-}AtaZ?MHQEZkkgc>QO1{FFwqaC*>Ja`; z(4+tit7qtArkD@KW#07dtMWwM3O;x^2AFE-?-3Ha^OI;Nz^SOF_4qwz@!u#t-k>Y- zJNv=f8xfVbl-$Y^IE`aP8Oru7xYmJpjNj{oY>{kFeM6RHbS_Fn87hf8wG0tHY>1o? z8phG_`5VP)YY>EY0Tm2!DDe4J>Jz)VR6&7i8PFpfp*y1dOZBRXXCPd)gt7!$bU|X1rS;gl#ytD53;@lLK-v$7N z3J_fZ(5d_#{_&>D4MQ6CEz)R=-IlTPS9r>bQGUaXT)(NJ+Beb&CF|W2+vP&gJmfJz zkhniXbz_dE+<}&$=kMQ#SW*a<{2vxtDtKt9wthWP(uJ1+!Sqm0`J&cl6iG|AbZwodD;Kgnpa#`Jq}Ju%`Z(Jz2KVi1 z#(!nU|I^X1&Tp>Q_Bm@gK$Y9(13tG_1D&sn>>_x_Jn#7hi9jo(x=SngF32-IUi5ko z5E)Ufx(LMXEI2$~I-zd~YksRm5kpa~u%9?orM1p3Vx4pS+ke}8z?)^j6ebcB3rEAc zO-AievQLejiC*@KhCogBC?l7{-?CUFX6zTBJqq8)-Cf0+F6F*t@VL1@x;`F+yD)C{ z`r1Z{KW!A2`T~&pNWkm*J~c@utE4{TMb1{#hml;zaB?f7ZMhd$yKRh>EsdY?DGHinV7)V(Mm9Wcq?#o7&c=mb(6q1J^Xzn>V<}Dj}g?AC0{U zUK-J$R~*<*inRG3o#WQV-vvaW9MH~Xz|!{_ts4-m2CTZx`5uPyI^ z-Db2#VjObBVoxLf_542mZnZ+)&-*80I~1puZ8&y0r7qVmn}EoaP+B8osP z13*}u)xo*lrs7`7q`gsE`P(wad?z+xrS^84Q|Uz&2tzeuykB3dR)5}U@W@oGmc9!> z>>xM2&=9y!&d0LbR*6+)6>4q_*X?E2MK{&Dcz!n=wR|bEvTzaq`^~Sg^*iIg;tW_~ z&YPvO*$-QTV_APZ9R`yQP9!#rmht0GIsnMwotCY;5EZ2?X5^rBGxp-w)5xIsu4aB# zu>A2;QJ@)vPhSBg4b=~wf2m9Xn(fcgW`Zy8&nJF&Ye<=RDEuR`1%N`r&@Ld2gpjek z(0JiytuJM$BEmlm71pBG*Wj#EyN0@zDdC&X&nUa!$t^>1`tg!xaNUBwublPEh2FPw z-@fm31w;Tw8)!eo#rRNaCEYufN-A4h+4xAcx{(OZPGqWi=YLt65SL-Fh8lx5I`_ae zHb84LQ?a(5f}JOgC!nULV}WqVSbcxuQi|#w&ff1qHPsW?=$TVgZG*t5?IY&HQ7g^| zly-fSEI(aH|@ni5xf)e!v+2l6QqoG z=VVY#5H35aH_VhNIUH*pc#r(DO)H;a=u{fW_C*z9;etQM2XC{ZzY1 z_g>UKGPmOUcKuy~9TY%Spyx5lgbXQJqV`eKc*C7QjJ3HY+;y4$>P1%K@a3hLZ24Lz zPCmx8jkoPAClsBWBl$2(we#l=A!wo#cWj0a_o0^nY$ifU8**b;`n93n zL`CG}ykp&u^(jfj#@1X6O2y$u8y{t>kAmDuR-c4#@JEP-TSoF^*t8Z#nT#$R36_%A zzNwiq(y^HkE5)B&mvZpm0^+U|J^|42+e5*LBLFqxLn<} zWoA4Y8)w*>ZKkX<(i26&h->~=0A#m;G?#98(*2BZk8fpuZeB>a9EANZVIma8qY3U$j{QtF* zxXZT9|6YcPLjs~mwI&Up$s;sFY+tuUk3anfQX})G7oTDuPV1$N?u*SaekgGSF5lX2 zd>qp8+-4D3`Z*B5t9%$g>L_B#blUVNxikm6%%UbCne8r%W|;{XNKPk z)@XM4If#@0+NHi+WL=t^Q z@k#vBC*uep)9xO3WB!Ll1vMV0+F1BZd?_^*bkJy_p=+X%|D0j%Lg>Bgb1y}}p1d`x z3jpm+ES!&i7)h>Q6O4krBb77}!K6xX9@6u#i0SmwXAMue=KX3aHep;c`b%0C^CDJ; zAWZz@H4POj@)Ya4NOXev@5Zk>L?wcy#hGc@owzmxw}pmXqaNV#Lv%_&X|LMI&VD)lx% zK~?fj7VyU2icEWlHVD=gm(f|BJ8+72)~?HyuN9>%I7{7FjEVDvLpd1&Eb@M-sjJ7O zMFb_hfBsBf=uSnNJq?^-J>xLshNklDc?0F(0un0JaP=}hbs|<{H7>AoG5D9k4HHUI zmlOb~pT6K!C1nZFCngEXfbDnw931E)R7jeVq8li}SeEmqG-e|pWb90TzPhlt^`>}P z#hXY4hJ+-)3dMArF)^s>3ofG)0ev$7@dI#%MD}40&%xMaWTa&ciP;TdQg~2-%2s4! zciB4!L}aB}FY$1#!0r!?(azSr_`n;STe^QP42D*?EJsD7FCTB9uI_L8b$A&EqA0-ZS!5m}??UXI)U?|+dh91}ab;#K-+ z?LF5uMR-oO(jFJWUYnXHpp3n#E;e5_bb2~hJcNT1M-F(I7}UtHIrI0zIp6q1nA$v< zz3VDhb?*In)OSL6xA*$Tp%a>0+$}a(I0n4Dpd|2PA(E5%_erLg2$PhIprcu#w7=$r z`hJ6ZNiA8n;HUROvuZ}4-)8A!8L@L?&octzdp|ut&(re}8*`yx+b#t}e>ihbOBVC!s-BK%J zuPo<*H%A{H)xZC7x>keMf%rV9h{NyS`^>v`i~#_|f?yv2|3}J1MxW1)ZNaYfmeA3D zP;)P$V*jdZPLQ0i33F2$Ms&)UHJ-oSI)dcRziaFlb)?_9`aXD>-S(VD@S~@AhhQCm zVv!&AM?SH*aXxnrhfilih-?p66x1aLFf1}vEW8}rjChoug+Zfu$9EoC&T2b8+H;L? z)|$nm)YD!*4d0G`{FT(@mST#pGTn<#t#R0$Qu+mjK~6^gwWH&pu0UbYFKNqw22g$Q z=!VP`Ug)|^UV|`g*5>}aUt}b?D`NDzfvi^Xw${E?YHGGxntkmOV{hNmY;(87rGZ4v zT!*LgH2OJX6#p{70LT+8SX6_+D%WL6@3Y$x`p_+-Aa^33t(^Gil8-XF5#4u^doQBX z$YsEI^gw{`U%IS1E3W3Eu;u+kAh~*J*+E&EDhXe*^p!Ng0BrOHfXUnzh2E=?n7_`5 zZtdo<;z)mI``~@h^s?w$0jZLNXRnj&AWu|9OypxNQ=31bz6zZe)ZUUp))gsC31($1 zOdAGv07Zl%4DMEmETe2@N^{mv0z4z8fDZFNlooR02^Gs*YPkpAe9T%I=}NUCuU9A# zpN!aFLf{aB+8-UY+)1MVY=b9DOzv*a}N}o zxf=q*+Mx0P*b#9M;-UZsiquk&RU-7Tk-RMekF*=D&47N)%v^=XV=JJdTGS}2&HOIw zteX#m(;*>zkinKdnxyEKK4GM15yRe_U)fx^34x+60D(}^G%o|P2Sj3K`c7qxQemzG zlS~bT%g#Ky4ZP6(;5+*^5rX>(U*!j%y1E*F6s&u4PnV7C+%y>}U$}m!vEQPyonMkt zZh5dr3UH$wQCSxNk|*I&lGx5bmyInXY$t>FET8H?#2gdFbepy^lj4-Wh$eUX?Q-8s zQZZ|^ng}D5@LD<@DE__j@A1afWtK7g=0T3f_zolKc{B&Q0}l6(eGgUb~+K*e}rUZaV@v0FaIrf(VvkV}g2?7oqe8MkH3_{|6xj2%4cowzJ~DLK{b)kOG77C(4s z_LM&b->iy0U4|sujh+&*%TQkf!pe#tSsVid?sKoTlblM3j`pIrTi}a1`!wzjl+})3 zdlS=K{_6aG#s6{s>!!vP?%gYh#+U9@HlLXPchOg`C1n7BascxS3{(+9n35uS7%|FY z>5%nq(ujXvu4etKa6tc4T{^*q1(hG$qg9#JCQ@!_@j8~L@S*Ate-zP*P0qs+<9;Qk zY#6L4?jP#Ew+fHaJrbxpmqDl34LEPIl5RbDr4F*ZBRf~2dc{lA5Gj7s zRClfyzWG9&g_h08T8h_~JFLf)PZli8zOol~u6U-X!@2eMIUBDV*(|hU3ievIl#~3&-OB`*+ZC*~?^J1#%I-4{E=~o%V z6A$5M{?$El3G~TyjH#3R!&a{gzhB2(-myV){vpEmKLOamGGKHWf-19b>CPY7sZD2# z|Bzt5$7wty3>BpKbW;tJZH2K3ihA&{-igb;oBvEH4^_mj6at_8O(^vMCb6u1X_Eq! z0rbx@;1o7ohQw}&XjN)-6}Y8J3RbVKI8=Ql;UHA!~wr8byN zB|xEgl%9nl8_^TNH^eOURv#U>t~--N#z^lel5cUPZFFRD&>nTQy$fqWr;2mlEX~vp zJ2nw(DxvOoxneuIJ*?*?AsH370ye2|)dALqY9m`el9m|W zRVRDC`z>iY&*#pVvY+up_B48Bli^p;?zmB{Dfc6K(}3R}Z@f)3fBQ}BE$kGpMdJk_ zEt98U@n|j%b6|NEnekm;HplYLj zxWSX$_ROC`20vG_-y#W}Cfo8ff4HE4JMZ3DuJtu&4 z3y48hBG8P5{Pp{`<1R@f^p(505#8T1?JRu7^69?*d=iH_a^TYt7#Tca4Utw{5vrU_ zk%A%&0SHGgVMS7SWx|e@*-}<{&Cjj1H*b!_ig9-~9L@0}3~nqw<*4J2pS_tj5I2oV zl3zUvbaD^8ru_F`)_}5wZs z$M4dy%t5vCi89K6Dj<(&Y*H#?3O#GQAZ#7;Y$fc|ef{zeMiG(h-)*~vx*&;wq7#7H z9tbB7r8_pNh^n8$g;xjBD$peWBLk^+qeG1W)f3*aPG6Ew$_{nxG_9Rz_fAGfsc!Du z7+A5w`CiSd;WwB1<8}cy{XsQmpi`{QB7DlQe?>4?w{Yd1M#NFpz<2;;iSy<+8O!_E_&B0=hhuf)H!{Rmt6>f_?~>s|6Kh4W9QcN|mL z!{2Kg4J`u#4A(mX?1XX{Im?Q9Kdriv?+~H$4>dD7{h*X8ryJ4fD;1q5sGhKvqka{F zTKM&6MsE@7f%R7Z6a#tMGTd&qytJ&Z$uxu<-NjvngxoSy`+K%h+(^}tzx!BE z%vi156eb~wpH+GFWfG7eVBgv~L6lMcqZL0DGz@RJ0|-)-(_lxJY1^pJ>e8L$I=m}M zaj)(pADW7%qrC9N6uAG-c&?+qh=88Bdi-sQI z_Z1#fg|wC7YG3y(pDxpZXJfpviy~6u*IVtmNly7GwUyVgkKanShbO(@7H>H_`^unx zQ{?vQbtOOqAu(tHFj1;BbeWq-L_T>W8}|!#pUMwWF@LLWY^mriqH`XMwp!Hde~?M( z7j(YsH?>LG9^1)4F*d}`A9JVrUvk^bwds$j>~;M0UWXtHIVRj6S#BD^a`#-LQ%Nwn zinStRu8gS_idl>`C3trQptxm7>T$P-uZfkNz>ngvSzSx4%JhyEazG^mS>a}V7kc~p zN5+8eFmD$J6PDW_y+u7}EJf_uVN$oxzKp~DU@_r0{x@u+diROSBLG1FcK47j4RwU1 zOuXu=s0i+Q-ZefX7sEUDc;ebCc{%TQBPOcfO@w_EwB|~_5WBs1`Tf>6j&r!6m*vh# z%f?&UE(ib+TBW~$AUZ~ef!m)DVnj=VCgp2|5c8P4wdHMM7k<`bT=^)3tTknCklp^v zy$sa8ddzu>g9LebG9ya>xj!>`0@c8J3BCduDE0{@nk6Uy9V@m^ib*9(8^}f%zmvzbh!m)af;M*vU%sS zqR$;$fVxNes1`efa^8vISBITsWO18_-xMrE#S27S zLqv>j()DXv=*>O-eEW4pvLZ9LIEf^wTB2(XZ-DdVG|73A6KcjH@uA52==;!zkF(}m z|3^fOY^MM!4nX{HElUh$o?=zUJe3%7jk4XMi}Cm-J+Gl5l#NU@-@vcdnKZ4?LA&5J z3w@~Gzc4ycab6o>#EA=5HcP(?O4IJGL?37DYxj-oG-I;+8yNLS`|Kr z{t@^5y%Ssw%QGMT`}S7~Kq3KwaF-8R4S8Zl0Tu5lC&o=9vW8m=*+}Ws!!OV>*pS1S z#85Ul++KPsJ+gS1r6gjR*3gok@#pQn_br80NhcPcEd9SY=ZKl!#o^uukh_jlbpZ&B z@Bj`onP=3UwC`jYfRiWZyTI1v83X^qK z@;5pQ;U49RCMl-h^st)uaOp~$_fm{4wSVDt5HR28_SdO;2LK=itJG#!YQ$T% zqZu9{kc>y^83byJo(Ps>+_X?QC0Wi?+*25HHA6Z-$u7))^5l=@?F>bRK8JqI zZAM56*J`&|)sA2K?(x%&e8Mxr$(#)1$6lNHWBDl^+Vx5|p93fg`s&m#zc(UE93}!` z@mhOWO8WSR=i5B8%RtkNH~fkdRB_}EU6=rCN3pP;!k(yTqHC#^Ow>*tV>E(BZS?)1$L83LsEJN$fT4A&hL5K9lS%5Q7yw2tQfu-#Uh^K zy7%P-9V?5A&pO+RVq?NcE`CGtY1!4uAJ2FeU8B`P)r2+v39(p;?;mYh{TLC+RO8cwGNY#J09Lv4q z|DRAndhqD)SYiHZ_vIeAZdz%%Bq{IK?QT)0ZJcC0qgZVyQFk5KN&!F=fIrI+JHJWp zvz~CKTFTZ>8TTp@3mYNg_&vtvlno?$Yai{=;8J-F?fQ$0yngVPW96(7bT z7`AooMTR(t|L29Ta^K?TmqG#fung!#4vi}s54COTc z_0yfS_cDrT=8+`#WrddmZ~Y?n`z<7X>=V1R7qNkGcu}s9;xvGSVF4cwkjE9IrA|X~ zevs866R}dR!H1ZQM@ zZtnQ=Z;0bb*p1?R2$Mamc~_D=pFmj+?qLt1qF(@r4w`V_E%#28OnL^zeUaAp$@Pf` zGa7}AMz{9ISHO5d^Sn$!9X z5|22gTKkAC%9M?hGTH@W=7GA&O5Ol3f?*4yC}Bh~Wmo{j%1D2psbQvvkyft>L%Q}U zeTpFax1!=3u|JP^-hDKl=Rv&w@jt)4c+n3hDTpOu#fic`JCK!bl1Ck~x?f0e@YoIJ z&-`e#%qw*<>1^tHpMzzg`bJ+AJi{K^ilORIAu+Q1~ z<~g%J=+;G7=K0sl**AMLVuP2KOk7;zo7dTCvvhdMP0xwPCisCsP$KWHzk=qlVl02T z%X|Q*v15(Mk@RvXy{MNm2elKsP#KEW3xB=;0His`gu9@i&MkE7f$Qci9hq$9-FosB zDk>Mn#F7WzySIfo1Eu;;2UIhi#~yF!cK-M^IxM~OM3bZB6TdokBn^kVD%$aF8u{~7 z3j5zEqVGVH0nS-Uc^R>AEKFt8$kXq#{OT9VCEj5x-L{i8wEJfqj)J}_ zw6fh#Ph|YQ#+Ot*)vM=puf5deT9Y+eSCf<)1;j;^;DgNEDGa-)=0x~iLo5EVpc zTJZxKi5v=6`p-wM9!#_tUUN+;ez_&X^R(=BQgKcXnd5bJEF1z5%s4=v*HfYiC2A+& zag0Zn!XT-R@qw&SOI@Uf#(Haf}+^TSd~ z&ZtvIB#RjRSxe-F`Y^AF{sq8tWUcj21jjr_9_pRE-CJ#C!D>d!uM0=MQx*G=#QTd_ zT|-*+>2-2|fwLYm5Fse|IYI&%C}D6l-LMojl8++sdv~V1zXe4;u`CxaO=>f?apN7M zZ^Y!3Puz?!+dI?ULLBLY^qVw%fr~=FQYLZdb>c2vbLQWENdYJXfr7TVkk=XTSxGr>N85p3rGzyKToEr)9ot#oJuEelh^dG3{3c( zgW#dBgDUS0dhffRE>0XTOkBRVLF@WhMZ`7YPWwY~SME4mwM(B^7XV#=^nF;rIjyah z2qZ#`SOh3j#mBV$xAXNl49dlA7_3cgX%ab%bKSfJ_eoXSYp-fDmYFhyD zBM~((iW(6T$PD&pb-=wCcpa3yk!g@dxaKb*dyZ+P%!@-xsZXycf+DQ88e@jM~zqNKl zQN8S@6kC??nkv(1ZQ>#ZVu%3ZBC_dm-6?XIr2Jd>+R1c+&FeG6?v8T%O>Y`dfO z2p^Z3JM%>V0wV`*xC#-ORAaD1@*0Cl+l^x#R4=_gi{y5yGv0ELJX-dqN>Exd$EkwlpKFDY6s1>9$HPH`o# zjY!%>j$5Q@^p_~NzWB;L`g}v8VuM%~@nxrx8(C24a(?_`T~xF+MbGpQU;uOpi{JL} zZsVbyr8YclfA~5(6L}O|yH1e&$5Cw|L*@ZZR^P|fGt63M<^b>Awa|VIzIKi6`rDnt zlX62fPAnW9%K(Cnr4Bv*N9mK-N0fMN1zKLumaD_n+21A?;n8oC*s5wJ*42UcrP~ms z6X%4xwpxWI+I7#BH&CkpUuaQTNtNdEB#Yf~PrX}Fn5-(}7Bbu?%3e1)o}L-KSkdz( zP4IpAI1RB`NuIJq1^@s9)Gt$Fi6}E=_!FT;P?gbq3s(X@4OQmiM`6NS)_xa!_sZ{{ z>2gxtf6ZfG!FW(Cr)Xq@? z!tiP5Eo~RPFD2unNGrcA&vfKT87jlFVPs;XYml*A^}lYd`KKb`mjf#m46ToMp6JXx z&T|gXpLtUEFv;zU=be4((5s^6;Hx|UP*8Tx+hD~Dl(W?Jxr|C6+387V-=!E1GpNq^ zO|M1pH6@PFl+CxjA?-)r5*8Qj4NXS0GI-r>xLr<9K~Eo%g=bk$IaRPQDgYo#%K%_8 z<NI64 z?umM`^QM+}WM>Mtdzz{Djc4!3cP$sJgwqqP{ckwS5 z%Z#vjvm5etiSc2YgR>jY)oY5Eykv%KEH?!lpG&Z}l^OUxXhqo{TFl(g7Jy+Y`|e@v zc4w{@t@)Rs07ZZU;FA`Fjv}Hj=U;r?(?$}R8rp~m19Bz3y+BW!MLiAPmhYoEx0z;n z-VGo^JC*d9DJq{&BR$LDa;flGX|hQ1KeGpB=}26B#Vg_p8k{kFSp+Ek3lz-_TF@wFlWo<#HpTjrr7uyW9OW$Ea3kUeWCW-C0cGsifz(exE=O}O9N&&GfO14l|T8U{!=d?ZG9BZ{ph{>cDjKy3$j;wwB|081y#Jw7aF2l~MV>@(M1Jp}Je{ z&2CSK3t> zzrl;cVudpyKmCUh zJcWgi?eG(SbGuVs(@BokilM?CjENhhctZc@Kj_YWxy&&N%1t0y%m+}C_!T~i7 z0j$*!*Nap(!%Bt*c#n1QSJ;j}uvE5O)9$)Da_W(tm#)#y+ORCe-EzGWc>0!Pc`~`` zDh&~?G9g!DHt|0?o)zEGpi|k7o-th&6_B}B5*q0koY86Gz7skd5W{0M#&I8amG21P z$}n}dvzApMKtU zPA9psWK{LSXzr?p{cbasC<;VRTRAxM^+ zc?v0i#CV9pvMval*-nAW!ctVx!3TF{w?nR8Tiq~<4W+I@O}ZQGMR06; zc>KKWeqU!(gXCL#=F_MDaC|J)E$*pv192JM^3FwXxG)L6E)_+rP*7DXR>fZao7U0Z ztjiT7jDph9YZFAg>kW|WPa(>;+d4St;U8Gf(|A|%j91goCNWU)paJf3Vl5d5dhesXDO%d6Iveo!W5Rlvk zlPmb_NIg$p|89x1hmqAJ!}Y(tU;U5A2~T5(Qm}vu079u{3I^l5W8u?8uBGrJ!(!9v zMB~Z?Cf|KBow8y?=rHjQpAzkrRfHWw`s6om3nNBPSxBkxNa_{8O>Tm#`V@3^r_ataV0|{YR6-sZS2* zLf=!TB7CXzD~?K#+i>Ta%7}Jk=cGH4JX|S9&ZBW+n+~7xlL{>?3Wa{Z;`i<}W!7~4 zio=~rw;f{`yu#lBoNR zLCFiKG63xt0J=d#f{sL}TVz@%DO0#@tOV^K$=ja991LBTu$iZ^-d6I&s6K9DgHE(x$QhhN)PXsO5?L^hFuy?cX@`sNs37d3R{&EQj z{Ul>zP$pU&3}`#OlCQ~gHDUhHz{B!S+vi=4f;kq-4dFc{ABcQbR-DAFY&dyvM6Xaw z3tu_*h%tGem91^(o;A@zG<#D0bY|m*hynaiwZ-PgyUBc5inhnohZ8A9yq<@y_e6>5 zaJa*e9vn@|&f`V`2#S*X{xX0rL%6vO`xM4`U{nQNE@R~$Lh5g0-K)C7Em@|%XDV7X z*b?yEdvTlYT?Ms>P{Tt8FB={I&PNXY#J1pozIz7XAw;?k<^Byyh^2V*vbX~!kL`@H z=>xL}V}*f~0sV~GF9zNBOjN=@F=}Xh6>m<4&8u&r&1fbnlCIiKMit{J8ev5^jV0Wr zrbeJCz@w=}m#;Paj0gmz3FC7RC>e~l895bMrIm}!d+URtU`PD(J_As5p6PQuF>hoS zxm~ogc4~%v{hmXKLHg$JN=9bpg3s;7*EL6!N#dvYJ*h2J+9Ps0sJGAz{YCRX5@38N zpGezbO?w#xc(M#33nxTr*6$3-#|%0VC}Gtk=eh03Q^Kvp2du9Hx&t=4afTmX`NKcc z(jC={5e|G@wth1d+b+Ex6Zd?_BuGJ#5-P_X>n9)x{h#734mVPZMgH&3rc*w5db#C{J;( z(UadMqe`->#BofA^8tW?Hy3~-J}MfH>CfB%UUxHPIkl;y^D3N5of3QNX}=Cy=2G8& zmZR==Pr2iT^;yq4)6?$-cRHWG;CxK$q;oNb8G7=>x9#|DhRSwjK*!1d(*Biu830Of zz_?Tu=RQ`>>{kTo!B`2de<`{T?bXgE^}R)oCPT&!NsK=P2XiEOh5iS-8|_cN1vZdA zN?6)vOoHC9U4N%Gl~7WQmn|liTn3D(d~5CU3V-4al%`05CcTKHakX#BL7RI3oemGz zPo!;okA?1K9Dh%6o@R?8{h#M^zHKvF_V*n_HgV?x)JR*8se6=o55^Mip8}_7_1UkI zssHtbeg>nka6WFd%G+5jZ-BO=uS|aHbW9{GC8eOFAADrAtVrO_cKd^uuj%goQ~9fp z$5m?L7U3$b6te$U<9z(La=s6v^5fQbf1vzOyS#JXDf*U zkU{~~<8eVJ*2@TOXgZ&-0h&1is>u;fPiE|h$!eT14qnO?xwUXf#!d7?hsC9reN?c= zfgGJ08<1R;e>OB!acxi}?#ctep^-L!EBE<<+!S z%xAewQ7+Gih1F8L#kcI(K0Z+%^yl8%^L}#YkHe6~z@;B;-)>J?2& zw>Rrl(S`uUf9erA#ehZxdHv=xV2*%UC^d%7SI0`PbJ5EUUL%5K>@kP6Ok} z9P`aLby;c&j@G- z_^mJmQiLCB_Wj!g23xl*-2{gM_^7QRs*&#VJSvWKK6*Fn77Sz1WOT>6=t$w&V?@uC zQst}9_lIq8|K+<06f7!uXAq2k0`zbaV6hA+e3dZSEMgBZw9ptq%p3(K@+Sgcq za{HX}Wd$QDc8~Jbwj?#|B}uqaOyDT7!wW`EomDQ+OKIHR=*!n*mHF%HHl^9WPfSs*@hs?#^L_l06-UxB|pOgLyp;zNtS*u zFCgp2qHg)15gT*M%%6mtU07(w2o9QwTypz|T|L?>17jy1{F&yY74Uzy@9+fYet(Gc z_SgID=>RC90NW{Kpwf7T4M|+|T*7 z7=>QH70X4y=lG9G+WW~zTO#~&g-tY@m??+B2dSAP`STVy}${+54S9;d2DSEjT;O?2(aoUykz?srJa*@r8kk276( z{$UirEd!K@t=(6HL^ZeyuEv4k^IQ9WoJ3xZ`(+fl^RcGDM8B&eyg_%Ajo;P(jA}&)io(atB z@$=p*U(<^I?edld{QSY^yf!s#6Es+%$NepdlZwr{csJ|n@V_=O23P`gVS;oDO}c2^m$%!7)FLGxGoYz{jul zE*jHn$`9ii zSSXSJ310Ss>wJl}>n*XTACpYl8?B5JJzufZQl|SBwJB&_dc1zKn)hs)Dt*XpcrN-y zbl0w1J)1ZEkB!>>{H|xK1%HoB@zaO%0-FMSaJ~W$MRoa;x_V8x*Pxh=ifv zgId{Z8E3Z^4 zNPgID>A+9RZZ?QatdP+-Z)daLA$L(7ihFDAaBb_07Z$)2kFQ77O9&oDe{Oq~o}_jt zs)}{MPACn++7xH&$}t_rY`Z&u!p)^Se92&PVeB!~MTz&^hL(M1k~ebIuJge9e==F% z&blOD;XV$dQz3u=z;FYAT4W+Yng2L|gI zK<=>ti*Wz7euBcp$cJSrg#K=`rb74YvTJYrO2)k!(o+ITSn97cGHr6(Ihu=UTh`E2 zUU`WMquQCRJo^6}z);}H?-{$1s1(Zjn?y62YOPhVX;LMRMzE%M!|jEs$a7Dh8z^rnax+}o zML3gG7s>Cf5N<1`RXxs064W`W5Os4to3d~^Zuk4KTQWU(K_V3Pc9J?UiHzGa&Fe02 zbWcsZ;Og!~o_?0zKQtGdbT^jSJxm!hOB3#`2E@kVIIj+BR~|>Cxe5ca)i|@xQ$EOg6t50sz5ldT>A*MPJ|`oEM`~ zJW@mzW+=rGdE9H5%0cprBoAd*dy>wwJ+aEDXtf@}oiu21ru+F2a{7IIVq1UWQBAlG zq2Zx<;}Xs)6pswS0l~LMU?1%wGBT>JOV{sAivWDH{$o5l*Nvv>HWM-)7zO*Fq&m3> z5p=r6&mkX3f|yTiT7Q4}buPgF_4NSrV}!?(e{cwd%9rOKk(a&`|DMx^Gl^lDVuKyw ziX64GVg^NG=gq<~FDOLu7nF>ICBW_Enflfbs4)ef42It@wW5T$!hs6TaGK>OSLGWz z#RmpAdpjG04;t@}qXTAU?1rj{vS>qF6Q`Y8)g`uMwQaFffD-!j0w8=wDGVXZ#~4%O zcIIOxU7Xko7zsAW8{9uvlo%X`T;ri+{j7 zHPzTm^Ieg~Kixy6dj8c8p2>J)A4EYz*{9s`!;vBWCA_gEisT#Y2y0juhlaGD`S&G5W)QmJnz{g5vX5Rny3W6+SCI2enAuj%G|^^0Z?k`Ozo-FYveaNu8UAmNNA)6A}Bw9W0a(%X$?y z$e2%19iAY&<+T1QoHe@;k@H;6&?6~#x?_YQ>31)|fV(8h$^1dXd49L+&C$mJ)!}4x zHuL0usxT8uwg|GJ!Y?k2^*dMJ9NKM5WP1>l1Z0lDWQnN;jGAOiva`> z(7ilGu%pH1Ep0{Yg7zGE5 zZigT?=t?kZHpM=jhR^xTt^Z+-M{yLFQFR&39l4!~=eeYLeqc)$X&d>Xh1+l; zi-rqH_`OIQ9%z_>K$aM^Xt;_69zsy9Hl>EuHy!gW@&c*)6AQezE(MwVdM=MqDHw|0 zh~mUMLv}W}GcT(S03yh28llg>v#`KNU5Kqni04^oZDVVGpi7|5t-KszBi268G{2H1 zxe4r|FM`Y$8guh(tJA3M_nId2n+&4*f3KxBsq@j3GLdsfJX8DsH=V5U_)w05zBmSy zaND{;`>X4izA(DfUb;`I0kPUqgj!LBRW%s{XL%hL+J9YFTOtP-NKL7Ri0rqf%1s^) zc@N0;q7uKO2lD!+Q(Z3c%n4Y??F)c#QHlR7S*s+%)g~!)4na(r%Fw?iLe&YUjJv!T z+|d~g*yGckXRuKyzdy}wiuqP|bH_dE)2FhRH-jrhc<4%L#t?%6d-&wf zGt~$CPHWDjnmO`&3ZCpvl+JCL$%%{woSFa|mrKxdVo6I>R#}<$#!^!^kDiZFuIg#t zyk`Fv)yTuoL@*U&DN4<*lVeqfBonjv=EF#0aS#b=M+Fju%&3afPQzzBB&Z5cl44B z{G=7VHO++7Iw0p!&v=)H@E?29VnFBNVD?V3{di&WSJ%8oenhnhLj&hKI3>(1(0uXz zmxN}gMxX>6gcw{AL`Dn#xZiAB78c8BJ5CJx`7(jm?ZZP`tlYXe&6sOd!G036P2fc2 z)Ya047p;ch+|!5BnGD~$=Bsn?Wy8{QECdO#BsjZXK#2G3qcEr|zd?v4!$V_2*CnSl zYi&XNn&jxVC>6d+s3$As)^@&n3Q#lAjSy3$DMJ*I2Qj5S#VX&>!{ZoIMouT)I^NPw zsj-cIW>GlPD<4#N?j{v-w|@2(Boe~^^>-QVLP>QP4(IHZU_dql;1D>(<_sWUjiTrh zvxz;GMjCsx<_ZKpgXSCi>b72M{7+h}}QpFUfVw2NMR7wc3>hc(Km71O%EFi>EyulK%3&M36B0D0~ z1trGpxjABo-v#R5RU4G_`OZxLg1M~UX0|@g>P;K{isX^SIkoG|cLUs2fZ%y@luSn} zLmLvmC<^FKun^BgC762XbsCBHskTVGu}`tkd;x=VVf3k1q}4UMaBDKb2E{!EEj#&t z7k!0-YX4EcQ>zZ=E`|gx z*f%TON(|x7_Ei9I7=iF4S0q%U-%0W>Gk2Sw9|Q`|gitt*qlu_}HJ|++CF$KUS_Ff~ ze}8@A@8u6KyPq4^RM;{`UBvzCLUVa9jiEq2{+|>V!F@dEI}#K1Icty;rV{%B;u1)8 zPsB>JSOp5tq-a$@5V#do2|8nfZt{Fs=;s%Ln0Mexi)ouv6;d6=(Bt~O%Ddu~Gi&XtXK{_Q87O{ux!vc1Wg zH$)kPpmYjWMa$|ZzaHtR39y~1zfT}z_4r*Ee)8m~W+uwAWFl*B$rkVd6sh<84jWoS zViy6oEn7it*zaO@RbffAPwaWs`a3dTwT*pL2<50k!zX?Eb`1^Ws*% zf=rxZ42m#;X+G!KL2@BJGBRBZe%vMg_>;qYp@W`?7L#YGSsa4#(mDQe zhYWfpSEe&(tV~+oxZfX--UANc2rO`ra7PC5c-tqaKolDK(QZVBLOV~+%I!-AuSY1y zD94Fg0*xw+Kuje(2=ApoA<$ejelB2T@x5lrl{1DER;IWo;hEGd-c=XM7n`?*4>CLdx&;E^p*?mH%eS^v`R!mntZe34sg||C zjZP#TqQk;0H@8u&b3ljc5J9GMMsv*SF!zjV_O{yBdUFxK=fD0aCQ~lW-1UCKiZ;1r zr33&RYqm54%mAtHNYs!l;k{|dgE=EZWBAkqHHzEueWBP+{cnbAsNjWh0;sAuS2wRT zN1$Eo)B5u3`I|p~csAr?>{0C+rU$seN%TL&7VQ55bZ{f7x9AbWRvXR-?8f|+gJwg^ zeB1qL0VNXe>1vgk%WtP&(}WF zCTQS|y%h#+5ikhRVwN$jxV7&%5J&PUOMXw3qDD5Ex4XVP5Q16}2n)Wwym(EFXLV#m zmGw0H-5t7I4cxK+Hg2g)3Fsn}2ylkLO9hxbS~R<{lJ+Z($aJ)?|95j^pVwP%!|125 zh4S!v%vep)D;&{v~3?Pqyw(ufghJ>9cqMfuNxNxL$}`SQJ83 z+BlJnhl*=ktHfP8-+ChN$G!fyX@p9 z4M%@FUaMr#D+WCHYnxd>`;MBEr=To%)A*Y1vytL)D<34Gy)bQ^J6%wRwTYxR6@n%NfKr+I5MxwM^x^VM(!LJ@0g)5n>gL>4QXX1l~=PJi36-2z`( zY+<2~xb@G4#bqoovfbWrMUvnw`Q6L_JHEs%#Y*l1041`xnh~hK8d|7%H`6sAv_GAM4~*$9xY0bnMVzE+wPfz7?(hFn zwg>%(ykkD4wtuor&hin=_{kYSd`AN#*Zx^Mtx7FQ)4@zmg0$=;92oky2@?r5;h7E* zWRlT}bj7)@>5=s2Deg8QN;oNKQ!B0tG^T=TpmkHundUn)`SF{kxKQ~4#(0WOH4y}!Vl6GtN zH4JouVQ#MTa~Y zOkN4c7SEL|{SQmJntBdA0Ho+r2?1B)+l`UuL3@zUo5Q=vAF>*3`S_|&nE7n+X&7F6 z%HMdM*yuT@2KKNmt>~_H;dn|qkx*gN@HBE-{<2$=cys-^JbeUwdVYen- zH=MN^Gw^Nn3U?ZBO(ku?M)T7nhBKkXf;WFJBtm#F1DeG~v?T~U8g>{L)~P@M>V5+f zs(Xa}Y?hl3#A*>)OQs~gcG4v+`r7br&Yvy9*tWpZ3G;4=?mJ_jU=`Y35!A_&IW@W5 z+V{iBYZo`GsV$Av{p((xW$(vb&f(iq!Z*cW0b0tzt4fq3Q9(DM5h;_UUFbg<*$sw! ze^F1A_>6T@z8LZQXv+RB@6+8k&G(KqAEuOO>QepfQVUvo?Rq!$Ns&teqvLKj;XoYz z8)@HQ!Fd>zaJo>csynurBZB{{-knQ!bUhnEaODh{rT4O2hPcd#hedGC;8m|mg%k7r z^~&fAz4r z+uzVpKHKWYZDuxU7OLpKiXCTqKcn-A&H8w_=Q^u3Pk|u$0hCycB2svjSj09F%BY0y z<>qJb=Gw627=UEHLa108ILpnqPcOY^FD8BjglA@xpN%2 z;f4R#es3>RD#J!`y`Zvpg@b1JZd^A^gpT;GK_3$BSIkq~@Zy1uijrZ1${He8+f7&c zc;MBpkfJbQHqR|zd*r~|{Dxni{$}5}L{2plzE}V_63|^?37TUD;d+M=&4zGzoc--K z&9?}&dKSMZ!n1*dac}T+xY$ad9~}F_|5k)>5{Y&@Ie6V<*Wz`HK30q$*^^OM3{IjGJ?_Y zg9$V8P8`y1z{}0`;0i95vlujyI$Lra$lz1i(3(Z0Xx4DH&AUX_9rS2S#~=M+yr8oC zb&=$f2F?H=;3(@WK%_u~AWM%+W5{zsd3sTh4h(_kY3by3tI96y^%jAYwHkFaB3z5f z=vMAZtI#2pyG)84NF$pWB+B)E<5#oaicVq#9(y@g*E58EvS1;|o|D%|RHjx0!gfBF zAChIleZMU6o!eJmhF}w2d`P$eVt2WxcXS0bHSr`jeD_IxQY7(A?`+h(omF{)JH;Pd z(~ZV?BHX=VH{@hZ|-GcYS%zfHFp#(&)%O9BAP85a653xS+d;D$sp zbkXHL3SULar&P{T(L}^?ePC#vT!@WO%Vp3rr;0Ijz+v z)NSpf+wP4U;w+upMP|SEV=f~yPxGF36h0*JGyJy!&2kC|pk$;f;Q<9I5swHcbfIch zdIDs|E742E7lz@O>M$<8-=ywM9{sMD#KT5MXUp*!#sEN; z5}F;b{H~LIasTSyC};(@{<(pUj47;U(UYT0b1+8{4?;?(S4mdo9z(1WF1c+>E{x-| z;^C$V;yF*Do5h{dfJX8*iJjl7{3~>eN~QLXvJD0KuWy`A+83sv|y1Zdo%ANeooekXv@>OUZyEw z3N*`&7JmG%-vy*)%6=~44kA#cD7uUU)iO>NmU1F8TP3Ir#|^>5fIh{bBBJZ}zGZ%s zvA`}43^VC> zGKQsYNwrv}+5Gm*y%IhuTc?e;Q1qTqtAfyvJQrz~3LnjDe6p8{9s))@=wf5dJCR_{Rd#cxd zJuz+F*fa4Ir&yE=h>E#@^96!yBoixhL+K8Q5YTpmWvy%jB%A!n^=NHP5N zmec@!9?ss!yvdre#l1&+((w{f@Nq`% z54@J{+g|(}V-25kDCFzn?f-sk)c$$Y{9(KB??u_z{c&QQ7y05^UT0#TVtWYzins@W z_r|%krh_JA9`q8-NJH7X4Bj!WN5qC|>`loZDp~p7exG(a+%c6Ly&e4?xUR8^|7tg5 z@OJ7B{k#A2*Brx3trNTk2mri~h@fnQfU-`ZLl=guMUEuoiz!5p#iWsG<74R&A=MP` zwB4a!}sA5QiO|QB}3u*^Z#C(LaWYFtI4x4nU!|T&Yw#Xl%s@j z=@g>K*lG;ghNHlx!RQAn+gA#Q`y=f@cXj|!0OI{A-8?Zmclp6kWdt#CiaBLX{TXdy zgHj*Y8G;T$AhcIi5r{QKXPSMf?3b72yZFUrm3{)~j}>LG$LxJf)-qff5IzQA zjT%r+N{A&otg+5MSINU_wK9$@bICZ;NHU20Hzplo&Xr7etAq)zdqY?(2!c$G59UzP zmKX^y6#8c6uwvxZ^9uqvyq5urmYH43^Ym#t5!hr+>3%ZV9lXX!x1s%oqqyiT z&v&j4m20u)3ZecXl=RMF_xG%h=ZdW-dEdGaL7^T3NNGV@08|iHSZE~`R30(BdcDa8b)?bbT@BQ)8V7m~Am7D9hTVkK>pxW6j|VY+F01y-FYUZ6_p}z+_#sye z2p|yH%Vmh+Y;P=Avz-fD#BzKXiFP;(<+8thZ#E5MmUS2vNtp6~0kM=c0rukR5nJuO zP}w}c$)$t#b&P6@$>!6g&CF)PxBODSU%&YG+HrqVlmHY4gbrxPXO$X%87##zG6uZj zhQv7VdnC>E++OAh3l1QXxG^68UmujJPPoO8e(TZurOa(t@eOx`!N7wTpMOXRKP-7) zguB|Q4+Ve{2pv_BVd>x7$FV#FtiZn^z=y8Y1unYIN{=7H97a;1sJy)aL!V;MMc0 z>)_>RW@B&)2l-jPoF#C3$!xZcjnsr0&@l&7__brF z*2J!}&U&&*?>=Cc!Q-CUGg@(ByS6Nb*Q|%IgN9{*B!$q3GPBHF=^>M;Jl>Cg`oymu zArr0Zs1Wj2Ax@ktRz-ka@k<@VHi~LwKVk2YR==Yhq&Q*x*Ka_v=slu+L8Oc z0QsF=U5U@)a14W{AORgTGqZ*gu0Cm>Uv0BKHtrJsCZ#3uibQqrb5R`T`L+LKUHYxO z85KKRkGW}Y{a76IDtZnRI(n2uisV<+NfwNf;=m`NT?o|>-_*I5xTY?wbI~cnc4VvXTl3SaUQ5V_IetUP!v!8lyCWsbs?Hg^@G<=8J;jZKB62|dO zqTJ!EQ5P1u#idtzPc}!L_Nwvx`w*&2CCF<+A`zo1W$X|641^p*swEABpKD9wijn8z z;4BIDY+Ly}jt*JyP}$^2*S^uv0HUf-IrFGnuCPIwS5Oi(s4 zb(-gDnVY6}{lgpYoB{xWcw>S1N@^KaKcGzJSY41^CRWrpUTU0D%W3SJ--D4@Dghh# z$!*)x-k(D9u8!MllXQEne?Kd8mXcdujgm#yuQorZ?TYvp$!vyzbhSCk)VVg=Tac3D z+r;PG#*e=#CI?OHCK4WUzk6}$7xh*E@1-YkP)m-fa|2a5ZO*)DyhJr3M`llCszxcT zN-?LTAjv%M+W^xc>5TPSi}bAz{!HFmg1BEFg61mpr&mNv=AU%&t3)FqHUq4$qHvM< zx{OcZ>+o1KhfYMAH;p6GD{C{t^}V#ESZ}fG1BMzI7jeUd_Xh)A=UE}z^=S6CzWaU` zFQWzD-r%wyQZrw=%E93-L!K|BoaZflzyfLrCA4Q1%Sht>mIBVIA1nl0-n)xNXdf-x z78a|OO*0cSL}5f43(9MVgM&#e8B>D}zvEb_QZdOY$2 z5T^i=%jjw%PEF{zC{Cl|L&#OVY&f#-LtiJr4qM`INdKVw>-iWLw*iy=>UMVGl8_NE zL8P;IqKlI^DvBk|L&Em0jx8Q4$NT`{+B{P`-b~s$__i~`UF#xGzCmGP#e%BJH78Fn z$xjJPAh6U$Si&a>;o1k|m;e1t4RB2o#H2D+lC@{JN)?b>f3!ni^#~ryCRlyrmb^WXY%SrYvXSqtqAr3-_q0GH7}H zU7XnsE{phgX^Dh$@c0+`DWrdchDfgQv{1?r8OliUH)v};BHao z>v#3RH7owK8o~OTaW$5o^^;{B85h)87cb2+JZ~ntHg>S#w<8{#Mgy)K-h-pYC~X3Q zq`PpR84TTfys;0l#_l`@A;Ap6`i`B`u4}H^j=qX}c7%4c>CS=W`Q%pO7J0N}o|*7m zNXfRp_~g%AbhL*$Cw14D)6<~6ZYRK}g;0-cuJfQpN3woD^ob5%5{A#8bw?pqYnoq% z)I!9{28FF&F7267vlVs`m0^kCNYgVoft(hyi(%v)Vwo!TBqB~reB(q4qAvd5#lY;m0Yp&N*Cdhlg|4PE+|NNHW z+AN-bzxCi+Q_7ABHD!*a?soGYMl>FW`zLk+AU%0X67Pw~%Yk2RWih}Ky`l23oxVj$ z_WH~9JC%c?4sWeF`2{&_IW+_5dyupjJq>TV`Fk+BvA_IRMId&dbUibla`+%t;9$f9zhts9(Y`hKLSMp?`6PHYnFv@lo?L=l6m8(HZn@lBwqbc_MKE~bVbmRRb&`sW!a7cYEZ0{6Io%%4k`3R=kS|`RM<+59QplbwdD)zdtt+L zrkVEP>kw~k?oHi5h}c`ZSb&iqq#=%Cf#21QtN-EzQGw~zmzZM0@y0&EQdM(Iod;`a zs&jSj+m@ASOGHRFG)}DW)7<-Ak9yr?D{xsP`c9g7ZvBbM`}pqFDC|>@wr(%s%;=+r z`O2GCo++0(MKw0-Ot`Da82|uj(JSpQa$r7>bt5OjjzpDXJByf6l?RJv-*s%ORFU#F zO-(;jf>k??pS0?b?P=H?%-?x(vg6+Ob!YLlet^Ck11+9Eia4|w-jpE`RZzPw)a+>IK)~Q<4=$eBl<%^pA2DlL-gARG8Y|FMMP&;vVNXBjHYvHM9Ha zxEF9GW<@5PX7IBS{cG0bc}!^4eP@lB5cYY%Rm=mjFSpG7R6mILiH`8J77C^kH;XlL zaa=(Cc_<8E;~3|&6Tk59AD(8o2FrFwFK)^WwQS!a{?7p41mGg6qEM3`JjAPYzcVzr zZaBkRW8@neCrTL7s{$(-=EShj_`qF!=>guf`hXHLlWz*MZz=5wwa^gN+|KOcM7YN! zT}@G1w8-`1xqz$20$Mw2Mx)*KiIIw*Z=NIycFLW-twwS;KlPIpGjee-!-rAu+7>LP zEeJjqFE^a6`f#0*=oLGk5}&(UeM!S%9wWgw^w@u;UPD{0|IKh5%|#L_+qS3@{oWpb zQ>uDacUfi876Q+k`0EZ+HWwNft^xoC%q{@zF-b&2-&6`I2z^g^LZlohHpO~fI5#DGQv~o z4QI!Qu8BwtO~F!U^j{Dp)btnEy7avBi2jV?*X_a^?l*+$3A6r=hj_JSWGBwCze3Z} z{pMabFF#*WweCwujuPf!sYw5sDDakxsn zJ`m*PiC;K}b{`EtkKVtaNw z_#?`GI@!TQynHjbEkT;-8zUaWh4JdFB7>Du8n){(0|4QYE7%cJj1bv?Dtg-HC*?MiOKjUQetrX7b`U zVG=T{jh!s+83x(D<%tJMP(u2+F8e>%Q5k#>?0(1(3`{%o#*M#Hld4|6*d=2ayisZP zsEmujZ=_{mYp~7av)*)Ue9RFR5HcJYG9b&K6KN5ch2BWEWV8}SMl6yvYyB_1$_8R0 zftWv#LBx@@c!mT~zNOhV7+`@!=9R%AtvEkRM4Z-*mEZ_s2@9toXj)|Bb$wIj^y7MpHzjjn zW_KSIRAs+ty|D89RVcP^(~)*;pjy8hl5(Pi7q25IQUdy=iOI+O#eNBL%&~UHLK=RT@GPT>$id`hh#ui`R*i%L zjV)0e*p3g*J5 z`)2zzWQ_B$snxC+G|GQzjJd}*-@%Z_YWuuzXDd+gm{vi>!(NOI-=UyN7aIvj(~00R z_AMy*11MXaif)L3T`~A^A|&$Trrh_zd)H}R8b!=y8%qbsq*K<3dyEpa}Pb zX4Ds{n)*3`Z?0-Ej+?f}c}a~6zxa;lBnG25i$OdJH6li2>4~y6B;lniAY&y9 zdrYl-MzC#4+2!-Lf}cIStR8XATdJizh{<7_KM@ZiI$Wf$kz41V$euKyRF z@yI8)Pbb+(R|T!WwXh2JDY?-asUkJ0Gw;hBE6mgSX zOJgUdRKyhJR3!bExvlm2{)$uR$LcS6p8JuVOs`HJJ}oAIPy+nYAzDCS&{v6oOu+VC z-+QEHQywXQWo_r9;Vc#R`tOvKQ||D`BNs6 z@eIJmBBA$>j#6{EDSS4HYGna($h@%D`-ajGsp0+Zv#gdtIG2>f_b16C&9O)Mx9BIN zZFqhe$=6+)F+RGT65M=msUIDNpW5S9fNhMB2Z{A_ySfLdFdq8n2{rSD#zsn*h?zYZ zRBBqn>o<=bH!}lU#76?IzPLzaM!fVgujpvQ_iPFREu(YL`{#xv36+_xQD_y|R40I-#nT_0}*YvG@&dT#EmWtaDA< z8r@2g@wZa>KfNSah{>bvFc@haX%mx_W<9YjD^cUnLxxSwUdFM)!U`TV$b|sq^cHDv({s zG%}D5z`#8~{Z|%4B2p~KGwwi<^lAD|u6x~bK9}R_la*^9xh^T; z$q5z@7M40T_i>-O$+#aa1tQrd??2yux(ver!v6qB=^umz>T#`XzhxXDD~>djK^@Ba z#iS50h$On14$f4g=;rdnNm&lC$p$4|-}zzb_sVcBrhGBDP$9(9+!s=j3DB{P=f{UB z)m;K2s0@!1@qm&O*Z-sGtN)^WpRcc77T6`1rBk}QBt({OX(XjP1Q9_ISsJ9fk!~av z5fB7KNyqfwsYN~>!!OlGC;XWiN}#QwI(b#UxW~_{EE1j^iCl< z-LW>*iMv`X?0_>cj61J(V6JRKbI?12X`#D(IMT91m)^Wv|5qzKCk+?_2;lpf*V%YR zwz?KCu1old1e!|sqF-$js;yM0_wu(OpO3v5wMyC8$2WhAUwbDve+qx*6dc@9`t!+R zS6i}~uMmir$}?TSYf!sNU8qDh>OXm^an#z`4}ML+oR zAV{M`f0AA~n6sJY#gnI7Wmx;vJ!cxf%&OZ-Wxp3cpC4}hO#@JNG%){%fre6WS^`Fi z#Ij|mLw!5~Xaf<@Q@JzGnp#2)i z#M%%Gdj8TA!b&2M`Hq1#MtHq}f94nfK|`JZhcP3M0GgeW3G!&3Sm??ZKt(&Sn#yt{ zwqW>rO!oIZwHGtq(W1~8p{a)we^PGa!UfV?Q?LfibWvARqiT%WFzKu_m4U{d>wLD_9SqX`L;O&b;&@UiM#oCPyRbXSy5*i{UBgV{9>o~ z6>&S0fLPGdXe~Q-C+{i4*@~84rUM*60ipf(RkSMj-2#&_Hsi+B-XXk8Ine^j@qs&n zK)qRSd0R<5(j`bZbl2g7mj)>B?L=|#Qo5h!=5zBROGH22j%CX35&yp1u>7jqDBDpj zKntA|a2fasek;)6)yy?UYKgx&`6g7=*`)vpk>I#?uxrFB7;-0H6aw_`j`DR5I3=T{P9_Eg@d#fP2;~+0D%!a zp@Bzoq_?7@USY&Px^Y5%3V3uT#D2waTS5_U+=I&IXZXhaWD7DbZr9Q8P1($k^FgMr zIKIj*v<>Qy#TncDuKYF};5w*M#!M{n>}QJ2-NXNWwDmD?1~`CS0Wdb<2x0mCdtyBQ z!G}FJ4<{B`7)!2rM6|u9^^=7wOTz=>oZ7iI0U3u_Z|ZjB1gFGn#u?njgaE$0w<1tU zoRi)Uwa@gN1#qrW?g*EJ|M*qh6nJgFV%T>KEF;*QQ5HZEkba^#B)`(fWKJpuNQ;PL zZLF&N@JuA9r|CZwnq0xN?s3ppndCq5Mw5?=LVUvfZl1ddZ}+uSG@bv6DP(z#KdXoa z;}@d-=P*Lehh z=c^;8mHVDe3ojJM>+O`SC|ajh;!%R2wnn25(;bJ&w4r|a%?(%j#hyK(Enr~g}B#-lxo z;s^b9h<*Tpa>@pOM4+N(jdrsI9O@hEv;`+nkj7e0OwEu0BSt!a5Ype4SUi_r2>k-itpx zdn@w&y5KngfEp?01J?3U)Pf%+3=QVPN2B8&Fpb{tuRwo(Zy7x=DE}t7>WIK#5QSz5 znEaLI8$mUBJlgV!j@EtEQTOIkhC*L_0$t$km-ud%U`%DBl2xefZ6mN z%J?ex!&9nSAKh*ZU0*6cgkgS595#pP-nC~q;Uz5-43RjL9dCMq;%0(J#3#*sm3A;D zfHJUilEGf*CdNDHFFV$ctCmF<#DJMfaq<$U%FT7=bn6AVV6}S<(hEO33kuEO>D}Gb zOMALTM{x*9$bb+Q5GJv}G>x{hBnaRD!6Wk4cjju_l1q>F=2g+*C-tRYkH&^RT%vk& zXN77k6Ib>YwzEQC`xbffYKZ>6dh^EpGHs4jFb{~cLx2eu4FRR7SdnXhPrAcytO`nH zxq!O=Rqh$vxr=(w5gGTrg;EOYm!imaS{7LhzL)-ufXd>P(N!&V*Xurb!>?(JrzrBD_UCI0u51mzuAP+~ z8X{eLgPl%V(jA|rHUBQJC<9@Kz&uJdrL;caZ;hO0}&o1n{D(d!LPXHh)1b$cI z5OP&ir~yVjMdM>(o~~{iB5MslLLOtFVLVfzmR7oY>s|YJ6Pb}h#l2o34$E|RrJDRA z3Q&fADZ;`cn_Z6l^tc-GvF~=b-kncuGYcy2pX~lTTjN+d$EC~?dUJjb$D#n#fgR0) z12CG*Ds&1u$tHc8hJ}O!R?1MDmI|loeo@EBAZxIG{}$6%I(-hqkNcg@T*p5(N3_kZ zA?3^p&<4?+bo&@Uhy>u}DqxEDXDD@y=ZNgrEp_NMMOB9Kj}$e`g`@2B$J3>%vJy6??$z>z298OwHto%= z9x)|v`O}7_^<9Tl@x%!AzW^%9Idx$uIijX+g>&Wd)L}_h-fJ0mq)TzfW+l(zJ|)|9 z7rLG-0Z0TK+WiNR>u?a0$!eCc!oE3ke-2pw@n|%c`ofR5uPN-F;uEiWJ@pUc)|$MI z3t_Q01k~f3JQymCq;El|U*NBbIAL3>fJ{6P>QL*EllSuWkV1o%alpErdTa?hlRg>Z zMn@5jjpV~fX#I!9*RPLSQOJ6usIJ4Y?)%~FVGJ>B|v@YC6u1hCNp5Gd*3E%JOdF1`AhH9(gKx#PGvtYiP z9R{Fi!d?uE)HL8glv>k#R!u@8S6_ne*h93pBz;WLZA* z;J0bzGlq*!hzIz;-M6s!g6slKJ#PILqAli z0^>bGd<|mnpN-(*c7S^FHcgfiB1X?!UOB1*%6}TH@YL9}%>=ldbq)5Y^+wXiH`d*7 z^ZM}s-XPy9_b3({Dp z4~H&9k+#D#%$}x`q7dg0-01kiiQedH|my~JQLKNP)YxZZsBmad3HcV#EF>dFC)80WfrShR`crhaAy_% zK{)~_6_%+BeP&(NAssv>q}vfJzrXr!jV#5zx2B4l0}gRd&R1FCyy%&F;l^Lm_U-c; zRHJb@VDtyK_^<)ZSJYbaq5SZtq*9y>c-wbrdfKG**kF=oV)<))ZY!R z?YMdU9>6*M$xSZMcJh2b@xDo!xi9FL&XpVQ#;Y#yiXhfRmE$%Qo2nDxAkz{VW0>(( zo~nQ&=|w})hv-?+gU8Z+N28fl+=0#QEoGVa2ClytS39wSc}U-Zn0Zw-Ce91(TcoTU&i2zpVA zYj!&@9PC5`2qYdN6@Z~2QKS`;$bqP%1;jPpd2G;!)*J ziH^hS(dU`3E-dd|_V^c!|LDMMF%|g~xZT#>et-akVgM|do<-Nq42btb8b85Y>il{{ z%YLJ2n6i9Heng|FezvUTRhQc%kSSrW;W{cTFwvgt+CMvv-WR<~VRs%VK?aHg0CNI% zmlOo#Xk&u492T`6ZnX-j?UuPj_$Ulo|M$;$$aL*r3$5D~+_!mxM~DhypS4Bbq>d!f zd2hxj%28zU8HZcQ$;aRMaX|kbFs2Vy8&Dugr&U^RBAm3!$liuB){olk{Zk(Fu|>0IoD<m+EtpbLJm8Bo5A8*|lEF&taRDtvR z+m$)EMQcOnn61yF30qleBwQZUZp&V?srY?0lJ1vh-`tt~rDQLwaAENWmLIJEsIo=? z1OkTy`U3spt`0P#2@51O+KoAf6gYh3vcQM~dbTQd`%c-PlTX{-JOVUwcJ+2Yk z%xoDuT$L-4+}XC*o-TFU#^N?okf$=G$4mEl5gkoBg)8lW$I0{m{bQokxF>h@nd`MG z5^yeqQSinvps2^NmY_f-|pc6(B4g zzp)CE(urltOl8?D?(KLq|FZ>x1Q6)+RludHLTpzoK3s{6DHmq+m}V*?{25R4EB#}+ zwpwo4r+VKZPVvTGgG1fNWbP9qL2Y_>7Vnjm)!ZpPTPGinx~T*J;@663Nc_rdTT=I# zW}XL$Z5aU{{A7z^n+ia=NxQdS-LW-|FM#ke=qNaS9)35)?Hlh>c+ixMHGI8pWaBOO~(69Z4#g_G+z}qc1=+3X}7M=O$9?%3# zKBV(Vj+FKRssKW^7ZR;*X25G?bR(qazw?>>7-$HmVW_^1wsytxq34d6?nJ&=(?-k= zb*lSmBSX;lpDxiOwc!%OnoM{0kXm7jiyx?+TC#p5d`tAPKM`FONb~x|5VX6D!<~jP z0PR4U!xO-Q>gRkn%WV`>&O$VihIFzDf}Ct@Jf9VlBX2)_RUV>em)D>n&J-hBOHo9e6QY`VW9gT(g55hKI!d~zZ>d4`>rKNh0KoO% zDqa8>G!He1nl$6`GuC)l!;uz?yrrI0)gfS`j)}Qu;mo5|^r+v6{8pw$mCOEL*>ILW zpP#LJGlYaNt$&VX@t(R82V|Ip@=pKj6eOl}BGMc{yn`s!ue_8Ca#w>e06N}(kS%S^ z*xa08Q~BYQ6p_i+_~hLcxky(In)h7zU!^k)^g3QJK}cI&jS=g)tEj^tsIu28?8t); zws4rbRY(>tFTguV>(4z?#?3w)4tuxLkn!RS0Cmy3M?iW`lZsVgA}QjwhD45yzD9~_ ztdP*iD_hpsBziI@X~KQFhYOUu4O~mtj;skU99fTW{>?K%{Xk8a=OzG? zCbf?6f7FHK$heL#)H*rSU89`rS>yt<6rNOmpBhGls8_N?5mj%_{$&k z(%r!Y^P_fBz+sl@ZO?C{&4T*XJ*cDOaknz=Dght?8cF?x5K;jj=p)u~*dI1&dOA^I zl9auBOPnjjQ?AI>7fX{a^&bj(0-*P}4MWAGbhUph<2*MNb)$2Y_bScGXem8pYVt*l zHvV2sulHSN`n5HE{H62d6J?fd)n|b`@*29N;W*sqZ(0x{b@tI7KrPgv98GzqDVz4>6`9>9OXD2*IkwJs@7wOG-DSQq0vIIp@YklS zwm!MGEWC;q#r#ZjDDZARXy8DZoeBoE! z<|O{bk(|`rY4_bTV-XDwCC7^i@|Iik(V_gaTt=`ODaEN>ZgC~2Le`Y%1lep3YgG83uh zD1Z%-KH$Ir2%!Y*-~=!tOHJrwhZwAx;6{qF)0So)mZ6i+nKk5trc2o~yBURR}QTo3bZ2F#9c+IMSBV7N(rfCb{1Q=k3 z#Xun%s>DX*1|5gdNjKDWlOGH7yb}PB4Em9Lil{&2PMD?r*vGq9!(eW9=0ld^F0-{v zmvlh(;cJC;f{)q%m3IV6oYinwN1937#R}`XsibY2tlZQ}wsVbg>$IlygsV90mkOhe zcnP-y`U?Xg@-1QKG2JDGF@fxUBHcqL5m*Tcq?&;E5wRnhCGsXIjQ%UxM}zM#nq-8B zF7x`TueQWiLU_W=izQ7g+d^CC3%J7P-8g-&d_+ER6 zB8zlyUpV_y5yMGP{C9BjZ*0R_VL4KGOPGxKelv7#Wnx`_~USW`JEz znFQ($0!>l;>-`6V^5QeR(2?d>=gP<8opdn8^80H%Wn5HSr#1PmaeX&?8_IYoi+qNs z#7GLS5|B4C*7d%$3$|L;h@kKPeule>ET&@zPEhtHY%zUl3?UImM|Oq~Gc@%&zewrJ zeaaD2>WIqQJP=+-scxyIEry#lDOyacfL7 z8?N0-wD-`DC>bXD*6lh6J6@;~s@MN=m{u09QeZuAb$kt>b_jTeQPSfi)j!e(VRePT2z5Rf;?ezjL7Y;(S$ zc&pIDm)o&>y*fJQbZh&^?*3xZgpim_MVoW~xN$lA`H3N`z6^eB#o_)6;iU!vhM=#D z{~kBPChWXO-SRV4yzjO9tz}&7dK}S4)D%})wd8f8k$Z@{mqw$+l#eZ%O&yGzm`04+ zt7^gty8o7JTePi0iQrnwrC=Qfjn{x`o{uOqvwu=S*4=fJBvq?iI0cd}k{iJCV8a5xeKUonv0XJH9oXT}5# z6W!uu|7cFg_@_7i^ey3Qu7pi5|UN9`Oti z`%*oS7Ued%=p256JGF!WfQbk^D&^3K*W;S_vJ~sgaKFP!M}h;6=tP!UNI1nztOy1c8>bqQA9=bmD;9~pF9>)BCz$X>m-!T>3Q>hXV?5?8~5v{nzRaYp|79`%Ui)xPI+B}7~+@%--Rm^VPE55|OBSvv`@}oSQrsb4i-iz`<*^r*C1g|rxj8cbS_+Kv$sVq!qBKOlv1a;hQ^(k0VIp|K=>@nbm_ za};fi5~|cL;_k%8P9L^ml@grw-$H9NPtPYhvdP!Jri}#OeRmM{Z)*01KY#)#NX90^ z2hxZcY-v&?S7_2}+hhn{M$)j`jH)m}H3}y95$`LFbhX@M@mcy0M22upUMNUB(ykoE zx^C-{43#PF?Gu*KQPc`lGZwJ~a2JPB+g9svT=pvH2jI#ve$-^oKc125>$Kn{?FPm48mdNtOwBmjV<4=R z^~cTAa<=#|163O8I~R5__8Y0+ekzIyb!%(h(J%WHcSkW$_PmY=H6I<0!{TA!e^@*V zF!Il83zvsBRiQ%1E%;H{iIw)kfjaAbgLe*t7WJYkMEAc{)8@@duGiaHrrdF0Th31| z6DS{QX<&6Hu=*)zid5MC%T9$z(ZXG(;xsS-q`~o7`ZEG*C5VS9thLm;aGtU5I>HUg z``i<2GN`TI@{}aT@P2Se1y%KIM!bwiwz;uI`*x9PO&TC*OXQHEC`} zQP1m|@^3Y#mhk#2wM=w*0y8&+Sz!kiZ(B-=PYXDj`VWB06LTX6nWGIZ`MJNtFiZgw zTS>h}KMOkehXOD{BeL_<1cBa%w=V7yeNm~W(EV}`82{1=hw zB*Uj{^k9DVbf0=O-%`-2tn_W}@5z-=9Id`dL+O8xxt&-v5g9kqb*HPySB-x94!bz? ziGnSKKsvj2dn$UNOlf~!vDy7mlEwxbQH!uswm_0iThd``#HkK_a+2hu+Wx^9UTxE# zxM2q?p-|{xp<2O=&h_@|5ST^9@a(6V-wv@`M zvxGHNyy!K`s-4|Z55%)Gl3tbk3iFQC`1yu$_9u_jkj3qje~B0EPF){kQ>NJ4{qhf< zFjXK7|1JT5z+l49&=l}8)rR)#awIgykb0;ff|ltL88K0O@U+kLmW^lgyS2Ew-nX|1 zqk?yjezpFPGGMVTH2UbE?Q``tq?j!5`7OPRzTFo5o*q?w1Q`91PL;f~v7-(oMDek9 z*;<~w9kx7gY2IMFgHLx1C7v-e8Jc@TDLm%@TfpIG$}QVOh4Ao7rS0eb!1^eFX{HkjXK`e?d8qO;a==WI1YymU%3Lb0G<0U4zA!Z z2rr1NCLqYw_K{@ECgMZGO53IMoFt4s8IC=?qN%lLttKR;NVO*x3#@RGDORq0m|iJr z-539GfUf>gU1kJn!|j@@Io!YcRVV?RKHS0ooPI)`YNNGjCJZW5W={8kUpsi)CFWH@ zh)4RPiGVEXjo&Y#d z$=yREP*5^qSkIu)4m1jY$Bd zb@-_^fPe%@a4-fj?K~cz$>6wU0=IGyut{sI+SQ2kB*@>VqcEtWy)$^*dBP-RNv8Pc(VlL^? z2IG)f=Puql0jA%T6INH5<36uV1Jg^a1rK9P!9aocnq|cy8?D z7?Auukd#3-`pbM*WE|Z@ZzF>dHEY=3P;s|?wTi`E-6)TDNhGg7 z6qHnt)Hef0n71aMIHqExU}>%^0EUc|7@MzCP6nwNc;r-uxBX*8W(xybZtsJ23x(fxfIL6HrN>tS~AKP|Ikj zBDk9Kk<7%mghLD}iQCXyOiJ!nrTo6t(P!5Y1az#}CJpb4wUF(U)U$NpZg)=~8@58eKuaKMi@qb2R zAGb}z0EClX^b%6i&Vr7i${!}v5~N(PVt7ihMbnlhC+vGu(cI$P*Cz+7+cBH^+W4aX zw-U*5QDELjfe7F@r*In8e%Iz>vtI2B{Nfge!+ou?gph!If>3|3PovI6$|C8l(ah0u z`2F~{X2{DT7~w@m@h2tu4UM+G<%p*QA!enHoXg6$p9OO8zO2!_)9@5dR4Li;e>Mh7 z?~P+B0UC`4yS;$;@emQCxQkP9&bY9CsDd@YXqD@dL5yU!Zgu(FpJ$Fu0j`7J5B{?z zz64M=VMA{nmRhw+`TzJx=wzk+9#2ORDn4v(zOYVSx!-G|YGvj>6S}evMp9~wzb6@| z)C4qf=@5i5bHg8R3r*^X_1%%WD(5)j#;`)stm)3w}tckgc+q{07s+lsU z%KOGfT4%e)pwuqxTG|4WCl%MTJQF>&e1SiEHPoF-9AMS^>9bWD#G-fCqU2k$b{y_M zGIs;Tqjf+Cdk3+31z;ZqOU&SJjrM7?%1l#Xv8biAHQDJkLyasB!l}=1ot+tHjwakD zg_4P2xmEzi`vIqKV>=^UU0|B`WW{Z`%XDZgNUTs+_~pxor=4rE5vMX35Xny; z>;OUe@E8x%t=_3k9?9iZqS0YA84xY&*X7*Pv6do!x=S}M=Bh4!id}M}bD}bR|KgZ2 zuq^l?Euml0{NUP`lkSux^V-FJ2#B}v1CV0QhMa(Ljti1F4T9^E9F(J>s3C_1=L~pS z$79(tqrVU2#&0e^6NV9PiYY$6{q0kw^-7Ikr$*q!CIIXlg(nfs*-$1rEj5*>pDfF3 zf!5ira0}g3?T$Jd(u`)2jWMmszjHQ{%ob1AbqWlc&Kbg|6K4M7$zw670lukFL)8(@ zbsd~5&qJM|Y~_6=gdaYqeafMiTF+n)GT~9#RvxKN|=AM-4ayDkcb1dV=o~Rf^Cuo)rxjttW z^2)4iMo3Aop;^5qm316@=k^QTQUDAXuLF|R@?WG&So@mYEZf!gy4Mv6xW4(7sVNn*BdS509XT4)4FT+#IFl5bnR0UmG@k^qv z%9YmxWQ#iYjXqh2{MZzkrlGS7-JN`AtEFf{q>Q_~iwg!YfNsD_!vzG!k|VcA-@pYT zhUjUhm~0-RzeY^cjOTG@UdtOpD-rQ(=xKEK(JPm!*L**vmDYOfA~5idGPP!P{!MrB zkM5W&L;HVy;T2uA7=VOO(|4{#jNha62ngJjqBT=t`*mjUi_43TbN+`ZV#o*?JQFRj zr!!Lg{FsFI?E>@QO^G$@2k!ydqpB~DV_sN2+cwa};kNKI!$o-DA{xL*v`OrbfcPq! z`#EEKQ5igj*`Y$upz(uX#p@`4MQR_43d6b{&y1frr)kK9?Ubbg z=ZC>=!k=G$i$iy999@KPxG`-2$3#%)KE{yvAkEAm%}{>>`Xk9ixG(e5=}u)exnZ%a z6c?@IHWJ>80r9v(egDX>barX?+%MPD?oaB`p3DXBh3^JTemdIh`_qhr_nn8pggL*5 z`eQ!ur!kuUqG0zzM3kmL`2IKELQ{FCF9g)&ZV_5jx@(JQpXI9U->7pmrmYF<%sa9B zq%v@GsMdV$gxn2u{;4cFK$-XHsF_#RYWZdz9rXTtC;EKY8e{LCYxA1zn~l|PwICdB z{Xf~CCXWLQKqAGVTbGa=aWw6uzZ%1dYa~qF+VT+jiDUqib)Dt6ZAwQ7`O>>1d)h#c z@E}@qTXiSv2Tz;RrVAw$-w0K@?Vg`V%J(HjgG%UcjrJSF zVN23>bKy9B{7x>O_o@^^h#?@UQ>;y9j(|IsHc2QA7B)mrB*laZK35E(SyCQymtU(S zZCe;h^iY7}vvd;!jo_Iw)ePe|cJ;*J?TpiMRq)aornFnwn$nYz1BHra*PDy6l+zW) zhOac*ws)J}R9|r`wApWCpily+?75 ztzOSY&x2$)5T7p0*EMa1E3E5Qs+E3mmK2jOj~}?L2F3HWzpGM*ZIz$kaQXm1q7|=z zm7ba4C!U#-3FDf|4mobKPscvcsMm)?_q2P(7BMU%_hi%{gU7ya9vqYud0W{(ZjMq{ zqTo*Rjp_5Tywz~IFa`O)j(XNs3RJk|pG<&{+EB7tc^`cbx|O_3JKJhn!Llf?cN?=U zgQ^XUvvqg9+`UIH@Nxn#Kn0GQMu$U@y&*zIo=ZtEtM#Gk! zEmGeqW9^BQ_p1B3pvXGhG+0f+u*a%Te@yjraG-c<*xezbb6-qAE^BG^X7>#xNJWA+ z3lFwqZOaaOCh2>mcr~W$zEk<|!hYH1A~s!-g6!_^zJKAki{vMOj58zf5uijRcJsw* zg(Q|Xl~J)PC5Vm!F|~+gQ8#P5hEv2nlZEso>H2UrIuFs^U@hcjN`8j0yZe9VKmdAI zaB5dySXlmp>C)CJWheB=R5|@x@qa3{(2&TlahWcS0RSE^AT|O@ zt6@e7JKr4~7x-%3i6K69irNNu1bMd#?qQ4%UIz;;Qd#x9TT*5cHr``XR6b%#X&NFI z;ZA~23`E_hr{~hBCqEDW_aB1|`mdjAn-(fAK7L0kb=Z{7>=neATeaHcOIL*rpDeE( z+~v&nMTOY5D~E`U$$6XrYklvYfHfNz(bms|AKg-+OMbX}GTeP#&D9*?yz@Ab|8jc9 zI{o=7&@d|Otc5^%LgEn%kDbT(#fzj{)eEZi+}}E|Yy~adH{TDl%4*#Xm3*5(TYL^P zgbI@|^__})e3RW}Ir#EB%X*V{@u=m-wOJhY0UnnDIXDc|tL$DaDv7f+tAB50)9o33 zu1i3#m$S4gbn)Zn?H&50?da-YrsBJMo^szKf-FRN^JWS^Ui{}by$hhxiqpILLLvG* zp8KxbN{H=3<$duc$H45()0(EDiZxSQ0FE=FvI3(<$Zq!x5LghCl2Rz@B@d~X_p85W z1pbU;p$&6)Z6DOJjzfss)ytcYEZ<7w^>j|Jp?0hI;gl#qxei{~$6as;p@g53ui`7Uu# zL4jz~+X;uorfpYh3saFBq7uo%92h;8+}rbf8?@$lg z-&SLMFiiDYiv!^hyd(CSgm6g9k6*edgK(doC;pEgZR!`)<;bN&Z?ZN+vOizL5x+Rd z^;@T4dUFZLBvo%;0n%)uEdL<^@mNTW&X>}o)swq!B>biKWhZV|&i#J>)sVl$w5o|2 zB~bf&()YU%`=cf{L8S`ybvr@253xlmg4Kun)?Mhw0=--KHnIz#-n`S^R^n$mu1_gl z`Q1rCu~L)6J4b~azTTQL;YI-7A|oz(0W3^Yk~BqVA|VdRBv8`f#9zEV`y@yD_asgY z;WqbB$jp?{!mN4^(p<2LdwG>|H{dU36gKNQ8$#lEvXr>G^{8((mZwN@huz>7w6%SG~A@J$&;nQut%J z9dyh>`oq5=df&**gOR6^y-NUyVE#5O)9a>_;g2&g>L(cJQ>u zb8TI_W463@=?JSg{`V_YEewFv9fPaW^@Esu|ngI-ZQhD%juevcqAUXQIn__RZKd z$~V3(G4*r9k-gt=V@m+U*F_dy0m22sojl z^p>O8In8j-M;YOCWxPKq*`AFP;t}6-2-J^vI+R!Vl|kk5p(jx`;zql2ld!QPUwW-f zQssT9{EF^}&c}1Y-&Qj1XBcQwf=(w^yAQl@56@mZ>52?H00@FP;N(kv_FExV}8oeCIVuG_R1 zR+`3aW^$o-qL=9}i(KmbJPXjW_YRP3KSa;(KULDg;amY64o_ZUKT0#Ugf_HM)N_#}Ns^FUI4<-0fw#q)wT~BSgTBY1<7XT6I zd{PQd;xS~oGWYcBPfLxL4fOU5RPP%R$WRsEHR$jYjrAJIdU?rsW5$~AdCvGZjy^HT zlu*e!T?`QGHP8DX$JS6>J7+tStIqZs0xMkzy}}>qGg`D3SbDnUc7)tx=3MpH&`v4S z{;~HV{ibcjWpP#V*Rw67`lHj`&u?6)zKl&@-OG2=`xfcwB)uNPwfIr4Syz|IRrzrL zY|)RP?BMk(Ab?8AD`Au11p##?!*tiA+ef$f!-r=T$|Wq5uaa0q z650PCzWgm9WPP3~SG$gsNeBH?MLkwYY3Uy~5BI)5-@^T(#2u^xQtR$c3`nl1A<3FB zGxc(llx8rKlCXPh=XbW+Wg|56`q{k+juE+e|7QY2VWjR~6dvWGl2jwiQ;K4ELhTZ2 z6n{&J8EdQ)7R2S^zT$&@ih-Kr`>*Aah3i8c9;GOwB~yi=cyN2+ z^Dsw>w2DJLg94E(CQMby=#`-6)peX91|)DWDBWEF&OaVzxDX^wiu=dTC7*3yU$>auXRjm~w! zegH)g$sT+GkV=p-Ru3kVXQ(18^ed{+br657y@Ms`oy=+!8YO z@X}|HaS8}X4V?rg=Rch4_~UDN_nrm6ClxJ}%)rf;0yvbv&AtV2CggI9)BI%NU-(EA z)u=1J2AiwD%bHFf;&6j2JSg!5y&{_Q(mA}U-dd=2WNFa+^$-6%4Tp>(4hDY5gJTxJ z4#^Zb2h{lAxIX||Dl~mTCbV>`QU~j~>8Xo(tG3tDv34`XL+OLCbRNI3tMR=0J!9^3 zRRvBHL2nliA$uNTrBCix*R~Fn=_a3fhbsQ1AE<*)smyz4nEAQhOm3Z=VUh$>vtkexgWoTq)H#Kv;D0E81L55KPs-7 zcaGEj{uH^nyhKJhTH^*y?4Kj1gO2TLTa_eWIlSXyXYDIA zo7ftDQ{jXC7eH&or$Y@DJhY*6M2I%t8SY1KP21g}8Ia6o3M7c74Ui^C*%T<4Z2w>roWL#d zGA)aAt0cRy$5)5f8+tQvU*=8UKYNvQ%61+8AJ%t1wFy1=x6qt4wZ9(MccqLyy>?ah z>}MK~B9Me`?Dh}(I1l#oE47r>{DfhF|QnJIWlf=n$ zC;vBVUS!5V^v^*ozSVrU8K4E z#h|_^OkMaWhB)we;_f2!$S`kZ4jk9lZlL(EMeIQV?^$%JFZlS+#?Jc(p4eSa=UB}R zD((0*HmzlCu26jIlm64)c_C#SZq5&naQ!p>>S->|0)TF|>_5Py19)CKeJPd@uvGdZ zX@-jFh)xzOv> zuTKUSPs4wf5~;G+-F=5yEnBMVVe(L%6(O(-&opA8%a_YnHSGT|;3r6)zn!XqLloxh zh!N|(_@>kP!doy@Mjh9pdyx`4*YqyII-%ekJF4L^f!o8`wEzfAn&;{gP|u0Prs$+) zW&5x$Mz`E={*W=ty_aIo5^9yzes)Y_93TH|F0gczS_2+kne;09hPXk}^v{3QN(D&H z-QD5nRvo|r2-r;y`ys^o2*_x40CHxoL~Aj|goiErtr9oIw0Qt`<3BGS+4c)Au@9}P zW~B>T)&}wDH^m>BrumRv3!Krh9?zq7$+eZ|n>{0Nk5;bXIsu@8!^js`0lv>)VW3Sy zMxolmmiF(hDLp>qB2F4qnk2~9RCD-VR3)DXLA{?!O2N`D>#0PIWM1mhc+UC=8(>4s zE`KNIo#a}l$Gbj>)|5I6@BR*mzMVdw+YJ}6Vc7WZ z<{n0tI}AkQ5#p894y9v}&+bGbH_+sv+=h-R_AGX~RvQMJgwSLD77I4=jB1VQvgu*h z73QFZOSmTIm110t?-TOKCbvGEA+B$OW)*_up~J0GG!3vzmb!5cTHMetVGqoY9*WK! z@V~9)r7)4l*6Lo6*!mnR=4Sa@fGCx)@L9zPd77JslA!Pd8I>8|>v9WoudGHny8lb> z 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 Date: Fri, 19 Oct 2018 08:16:14 -0400 Subject: [PATCH 068/114] Made MP3 constistant 128kbps and fixed path resolving --- .../assets/sounds/crystals_and_voices.mp3 | Bin 254192 -> 334366 bytes scripts/system/interstitialPage.js | 64 +++++++++--------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/scripts/system/assets/sounds/crystals_and_voices.mp3 b/scripts/system/assets/sounds/crystals_and_voices.mp3 index ee9073b0156e2a341fe75e22646f1a52b2a2adae..1dd2037e6bfce5d4db21e733dd8a31b4d5dae84b 100644 GIT binary patch literal 334366 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�iSZj~m>CA?pj#|5FpF1oHQ;W_1Mcxm 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 z ze|BW&>vmE&NGc}8ESCE-2Ugi+IdWAdF0PZQU{lK4Z3E2L?;v*T{)Sk++Ko%VJX^*r z8z~vIKyDfH%N_~AecQz2b7Np%dHup@f>}%1_Oyr%XPV}c0!fG*UQ+}$?(cEi$iB|7 z(a#7LZ~`P!_R1-8%>?^)XThJke)ct(6PBG6ZFmI&u7zKeA`gHeB|sNC++0 zIXVW(R6cA(r*PVx|B0q8RD}U#Nq==uSPGh%CPE6A#z)b1w2QV?3PMFF+jQer@e7D) zZsmY^7f$onpTNxTlVXnJ#gr30#r=M0Qr|;}icSoOySzIN~ zO;;D62Yt^?dbL>mq7K4-i8&SA42n$b>#?;&RIhw;45+W!V|w+kf;GTc9xfxsHxi?` z2NH3HNjTdWhzTU!DWM3(FHsTm8Uphv@;@*m+fl4o$Z{oXkp3Jyxx{SNr?s?D0$Nf2CJK%zFd=LT+>i0E?^Xas1dQW`;0=_&sP5PEm{G zX8L!ruQ3Tp(teZq28*c%8o#mN4rci~rLoJ8&>eo1*d_EQU= z@B0?}o&Z3tA-@vnJpGiekr2sK3fg;XBhCE0mr50aq0XoJ8P13C2k}NAinf)@0@)@1 zXGeuww8>{V+B}R2c4^p~S%pR#Ixg<~GkuPqOlQ7vWy-Myn-z@Wtd9GCpZxmz&c*G% zo{9FoisV-B{2D1U{8EeFlJ3LsRu(N0FU&f8`zR&PZ!kidrfR=-P@n4`ho0aTLY!rI ze)C^Ba(tAuU`|k~r6Db8lc~Eg&c&i$4uYBHa{Pg|F+V6Dljjq|_Q+_sH z^4jrnO|jYJ;frgIQ&c%8jK$Bu*gm%A*YZ1w>P@2F)cr#LiuT^y@?J)Xlit3q-(_BL zwp;PR{85eU9}iSWek0NINqodbvG^5>TFxSOIFI%%9ql@EtTOLgnZC3s-`4JCEs36nFOQB4I zX6T!c_Oz`=+D6qJ4@j0D3(^@<#Zwc9ouW5_c}Ufhl;V zqodt(pAua=y%+8~Mcmd3l{a7}^^ms;CU2M_CQ%W3GR5BxlfG70VOtTtKSq$mb5IDW zVrU>I)pn?LbdRif?dfe&=gx~^rLV3ja$B8jl0QafPS(l&$XH`~+J2z}p>M$0I@;o$ zHh&}N$wRM{4j*tn8Zxd?C!H^2at8J=siQj z`$E%K%SpLw$S>Fwi%Qy;ke6?MERv< zJ>MDNF<1+j6e-t_UO7HK&q0@R7syMxJHb_B2aBM7MYtLX`HDu}LmO_5%vErq%4@DOVqF|m{bY06K{Yte?UA+Jguk(qX%0gENijP8vMebbg? zNcycRozg;v9T*mHKIKtZ-9aSb;{5tu!%#F5uffn@e^7@ep0t)sv8 zUUyc)UNX@s>{W z^G_V!)<1M0JDmTRqunrdGI++hWGd40&`uR$dX_tQhL+oyy*douIyv(<&M9oo_g@*g zlrT1XQRBVz)nRd7Qsz6Vhct9$lqIgQWp@A?Kq8R7MrCJb%CAg#J|5k~p^ECUor03Y z`O!u+S!f*vj;OjCG)}BwKM=+Ib_m7an-0C;u&tGEvvr;g6}B(;u1og9c-pBmR5@Sg zB=unuP1@T=YzdVghlMi|S=7h$NnE`S)u7Vwg;%1@c4my?u5eHQQ+qa5V*M;SCD-eB zwxPU&MUWx>RODNJ((%sZ76`AzZHH%@Um);wtfb%i#@{#2CcS41d{nCPUn+-zaP2q{ zUCe)_c_!4!M_Zug*9xkP$LjYIprxNpfVqFnM{7k}lSBQi*RxH+N?d#u3yneeQA`+@ zs2bauQ|?;BlHc1drxUZLSp}IwSS9ry&aN`=Z60gd7pMq5z#H9BO|rAb*2(%UAh$pM z8f@beHB;EL)NBB(={uM?QEC`%Ea3F!W#NYX(nh$+BWgTjy>}x0#F%rmf7_=qh~Q$IAaC@prxJBpo{G zGt=Ef+@4p1?>|bE{+*V4iVzO$kdEfS$`LNWg^>NuzUB=^ec$5k%9FwVfiRa?-s=)j zh_afcN@THTsme>ozHL>2lvm1vMT9AGe;2^Xv8 zePP@8w^#ff9~;m`Iq-SW6kRTO984F#yIYC3bJd7FcRi%F_nKy;O#g6?m6m2qb|8FW z{BQ*x1Gu=3%nO0Lfd}Aqb8^aS!kfq*#DfZw?Jr5Pqz=IiAtZoLQHIz2htMS^;wPs8 zbUJkla~G(VB;%w?Q0qSm^{ci1Vt|YJYa|P%-ov-(!&XL3Wy#9eGy&W5V=w|vf?!=O zRYt!35?(GT?j(7OuTGL_ikAY;^?oc!xsdY>dF@eI)(Jf7EFYUBiK&g(sRZESeirE6 zC4vwh)L?`Ns<_}e+~}fPjuYkgD67OY1{P-IT4#m)h}D*2oeF`Qnw)xAqe0&xi)h$4 z<{agL!t`YHYh3GguN48ziF}@Ww4-6h zYNU!^6eD5HwcnIdggbd^J5s-e7+>A2;K8Offx`QSN1*cj_VaV@<_}BEzZtkCXt*hp z9Y|R9ys@mCwxCc=&?l48{drgo-8K}34Ob7kOj$ECcP&W)O- ze5+lsjjY3&f|}MoP}p~#_-T5#gtvI4Cj!0Xl-iPyxkFK?B$NjHUjy$?{2+p}bo36H zh0PgMN|CWw71jtsji~$A1do`_`70OxI|5PuOOK=?q2w`AiD_L7>yrxUI5?Yzh=4DKjAm^|CVypQ#n z+P6&^T^nG55izw9S~Ekc4b}WKM^Ga?ZN#4(F;`t6?isP}cOH3zN8dA5#y3HAw)I}7 zS`Fn|%r#>)q5Nr0;xOs}=l)RkEhC*>e- zhf3C+HwkhHBk$H}KT)ueNOmVHd9<>Ie)VQ=uvR~IGGF_k`yL;74{xDl!){soZ8)IMOySn*Uodh z$9@$i#Sr|QC-pZI-X{(M)9Gt@Ej^;3jzt34s%nguvj=^)ssaV!O;f4;S>Sy^Q0v*9 z0`Nk1QJhyT&9jF#n81T2jDU&aBP3IULyzlEG>@?vv5$)y&N+_{@^S>}DM3Im9rfXs$*qbM1h85(ab?V_}*&~K6> z?ofQ(B|Tld8cwumcCK>&Nkk>9wp%^Zc5{w9weCcuyug9kz3evNT&%k|-;R}by+1oS8)^EN>%UU|XWPDk3rBO7QQ9GpwwTI- z@X__64>uD0Yq5q26wCgp`0MPNp6J%CxVR=d)7(%ZL{TbkS+j(l@D#*U>dkg<%SNF! zQSCBYvk^01`#qy}Pjw)BvvRt;smB4>I(k`pbI%W&*3P-g_ik!cf1v6t6ii$%*<1!I`&&F&`bj??%-ih+3{7F&JP(RXAO`O z(*4;b&HVE6WjAmedqKHAQd6{%s9nJCOwIAMikI@_`0!19RRg1q4xdknkB*W_42he9 zox}O>>(}+~2ibe(5(P9-wno(uA6oxcg4pF0H``i`FgnNNb z_Q$PqSVOnL){~p)_YrS4C47#_Txa>|4|1QU9?nP}HV%C3Cn+ay@z8lbi#p7ff!hWd z|Db#|du%8KjtT4Kg(^2(9ZO_J&ln0icS%ah_1;y}l+-8x z%>ck@)oS%+LAS+ukBO<;@dW#Mv(N~o zEZTC|0yB2(o`F$_|U_N(^N%-8XdeJyeoOku0A0WrSN!OBW$qN0jjQE|5onK~birk>>p?as= z-!AdM)29Qkvhv{9b;9-X~o z#x>wtCKMQc#bG5ZDBnP;;VTMVYyB!RPl}Hi-*V$ATwvt3YvdOUY>r<8I028@?3J(+ z+x=PrHWj>YC%d*hmO>%it89$ROz<#6oRUk^Z*x`z_MS(WVDn=ymi`v(dK+BRMzOLJ@IRp=Tw zFGaF?0zt(4nDMQHPrx)0#4CqJ=bDK>Kr00|g<5J>M9c~dO1y&ROGPmo z?GB@3k1Gr&;fY3|KX5~jk9#JHUE{13sj2F zp;x)M5qB8LcT9)hauqJ&p%X->zN9Er?&nyV|Ra5naP^Qz%o*=c_J>DaCrYRYU+Yv&m%O58dg%#=?Bgapnw{Un>5y)(t;{A$G`0kW}~h~j$VkjbJ!@ej-XYQql<5% zsj#NmoPJ%YtEkqzxO-{``e5d#o@T@-(pllGEJ->@2zrFYnzX1WJxD0O^=Ujdq8xafywS{G7kHvt`^05Rdv(tZw!i?8(GG@Cjyj6#$XQh%B({(9)j zmB}<(GHv4^pA^e>wT#&4OEek7#ovYafb{GZWp{ z#5mv_cF^~ralOy?vuDD;!#d7$v7|Vs4o!H>WM@$2zjL`4Az{Cq2gh~@EX=SBeZ&}C zRc;&5%OiZp>f4HuE*bx7GLFXTff2!(cb6LP3eLA_Rvpw>9|eC>xL)}4l6$ZC>ayVN zIdM51PN~0Ki4xqE^Qobw=RU=g2o z=K|<|c7Z1>hRFM~kGQLLMa00dW*_d}`Z z4}64`oIbG={gSBxpaLnleD#LU|06Y&4PDHRlr3YdMC^aT&e547YJ)@H&cyXAr z44wx#_i=&8h9|+n)dU!8Glk)l%-e6&jG7_gH%IT$xJLvPl@{FND% zRP_Ge#6N^e60a`o%jOtKQy`dpAH*1YCE?)9;Nak>;o$f};NXz{-@NSq$N$9t0v;9w Am;e9( literal 254192 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 z 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 milliseconds){ + if ((new Date().getTime() - start) > milliseconds) { break; } } @@ -503,7 +503,7 @@ if (errorConnectingToDomain) { updateOverlays(errorConnectingToDomain); // setting hover id to invisible - Overlays.editOverlay(loadingToTheSpotHoverID, {visible: false}); + Overlays.editOverlay(loadingToTheSpotHoverID, { visible: false }); endAudio(); currentDomain = "no domain"; timer = null; @@ -519,7 +519,7 @@ } else if ((physicsEnabled && (currentProgress >= (TOTAL_LOADING_PROGRESS - EPSILON)))) { updateOverlays((physicsEnabled || connectionToDomainFailed)); // setting hover id to invisible - Overlays.editOverlay(loadingToTheSpotHoverID, {visible: false}); + Overlays.editOverlay(loadingToTheSpotHoverID, { visible: false }); endAudio(); currentDomain = "no domain"; timer = null; @@ -527,23 +527,23 @@ } timer = Script.setTimeout(update, BASIC_TIMER_INTERVAL_MS); } - var whiteColor = {red: 255, green: 255, blue: 255}; - var greyColor = {red: 125, green: 125, blue: 125}; + var whiteColor = { red: 255, green: 255, blue: 255 }; + var greyColor = { red: 125, green: 125, blue: 125 }; Overlays.mouseReleaseOnOverlay.connect(clickedOnOverlay); Overlays.hoverEnterOverlay.connect(onEnterOverlay); Overlays.hoverLeaveOverlay.connect(onLeaveOverlay); location.hostChanged.connect(domainChanged); - location.lookupResultsFinished.connect(function() { - Script.setTimeout(function() { + location.lookupResultsFinished.connect(function () { + Script.setTimeout(function () { connectionToDomainFailed = !location.isConnected; }, 1200); }); Window.redirectErrorStateChanged.connect(toggleInterstitialPage); MyAvatar.sensorToWorldScaleChanged.connect(scaleInterstitialPage); - MyAvatar.sessionUUIDChanged.connect(function() { + MyAvatar.sessionUUIDChanged.connect(function () { var avatarSessionUUID = MyAvatar.sessionUUID; Overlays.editOverlay(loadingSphereID, { parentID: avatarSessionUUID }); }); @@ -553,7 +553,7 @@ tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton(BUTTON_PROPERTIES); - button.clicked.connect(function() { + button.clicked.connect(function () { toggle = !toggle; updateOverlays(toggle); }); From fcde53fc65091309d14932193d6423b3149dfac9 Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Fri, 19 Oct 2018 08:22:43 -0400 Subject: [PATCH 069/114] Include black-sphere.fbx and update linked url --- scripts/system/assets/models/black-sphere.fbx | Bin 0 -> 56208 bytes scripts/system/interstitialPage.js | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 scripts/system/assets/models/black-sphere.fbx diff --git a/scripts/system/assets/models/black-sphere.fbx b/scripts/system/assets/models/black-sphere.fbx new file mode 100644 index 0000000000000000000000000000000000000000..2e6dea233f762a19946e328df85727020e49d9ec GIT binary patch literal 56208 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 I4%tHgf0O8X)Bpeg literal 0 HcmV?d00001 diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index 6655e1ef9d..d54a8415a0 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -64,7 +64,7 @@ name: "Loading-Sphere", position: Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0.0, y: -1.0, z: 0.0 }), Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.95, z: 0 })), orientation: Quat.multiply(Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }), MyAvatar.orientation), - url: "http://hifi-content.s3.amazonaws.com/alexia/LoadingScreens/black-sphere.fbx", + url: Script.resolvePath("/~/system/assets/models/black-sphere.fbx"), dimensions: DEFAULT_DIMENSIONS, alpha: 1, visible: isVisible, From ba459eda9edc2f653acf95d84f68f57abcd3b6ad Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Fri, 19 Oct 2018 08:41:04 -0400 Subject: [PATCH 070/114] Removed duplicate backgroundAlpha --- scripts/system/interstitialPage.js | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index d54a8415a0..7ee4abb7d1 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -112,7 +112,6 @@ backgroundAlpha: 1, lineHeight: 0.13, visible: isVisible, - backgroundAlpha: 0, ignoreRayIntersection: true, drawInFront: true, grabbable: false, From 5db7c7821e81537935a88912858c4b62107d4444 Mon Sep 17 00:00:00 2001 From: Flame Soulis Date: Fri, 19 Oct 2018 08:51:13 -0400 Subject: [PATCH 071/114] Proper formatting (aka no spaces after anonymous funcs) --- scripts/system/interstitialPage.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index 7ee4abb7d1..a5a952444d 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -12,7 +12,7 @@ /* global Script, Controller, Overlays, Quat, MyAvatar, Entities, print, Vec3, AddressManager, Render, Window, Toolbars, Camera, HMD, location, Account, Xform*/ -(function () { +(function() { Script.include("/~/system/libraries/Xform.js"); var DEBUG = false; var MIN_LOADING_PROGRESS = 3.6; @@ -310,7 +310,7 @@ var url = Account.metaverseServerURL + '/api/v1/places/' + domain; request({ uri: url - }, function (error, data) { + }, function(error, data) { if (data.status === "success") { var domainInfo = data.data; var domainDescriptionText = domainInfo.place.description; @@ -534,15 +534,15 @@ Overlays.hoverLeaveOverlay.connect(onLeaveOverlay); location.hostChanged.connect(domainChanged); - location.lookupResultsFinished.connect(function () { - Script.setTimeout(function () { + location.lookupResultsFinished.connect(function() { + Script.setTimeout(function() { connectionToDomainFailed = !location.isConnected; }, 1200); }); Window.redirectErrorStateChanged.connect(toggleInterstitialPage); MyAvatar.sensorToWorldScaleChanged.connect(scaleInterstitialPage); - MyAvatar.sessionUUIDChanged.connect(function () { + MyAvatar.sessionUUIDChanged.connect(function() { var avatarSessionUUID = MyAvatar.sessionUUID; Overlays.editOverlay(loadingSphereID, { parentID: avatarSessionUUID }); }); @@ -552,7 +552,7 @@ tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); button = tablet.addButton(BUTTON_PROPERTIES); - button.clicked.connect(function () { + button.clicked.connect(function() { toggle = !toggle; updateOverlays(toggle); }); From 0837f790ebd748add984b1ac2cd21a34909fa512 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 19 Oct 2018 07:46:16 -0700 Subject: [PATCH 072/114] combo box changes --- .../resources/qml/hifi/avatarapp/Settings.qml | 23 +++++++++++++++++-- interface/src/avatar/MyAvatar.cpp | 1 + 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index fd72d70106..64ae03237c 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -366,7 +366,7 @@ Rectangle { // sit stand combo box HifiControlsUit.ComboBox { id: boxy - //textRole: "text" + comboBox.textRole: "text" currentIndex: 2 model: ListModel { id: cbItems @@ -378,7 +378,26 @@ Rectangle { //displayText: "fred" //label: cbItems.get(currentIndex).text width: 200 - onCurrentIndexChanged: { + onCurrentIndexChanged: { + if (cbItems.get(currentIndex).text === "Force Sitting") { + sitRadiobutton.checked = true + lockSitStandStateCheckbox.checked = true + settings.lockStateEnabled = true + settings.sittingEnabled = true + } else if (cbItems.get(currentIndex).text === "Force Standing") { + sitRadiobutton.checked = false + lockSitStandStateCheckbox.checked = true + settings.lockStateEnabled = true + settings.sittingEnabled = false + } else if (cbItems.get(currentIndex).text === "auto") { + sitRadiobutton.checked = false + lockSitStandStateCheckbox.checked = false + settings.lockStateEnabled = false + settings.sittingEnabled = false + } else if (cbItems.get(currentIndex).text === "Disable Recentering") { + settings.lockStateEnabled = false + settings.sittingEnabled = false + } console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) console.debug("line 2") } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2c9b83b636..95141d614f 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -533,6 +533,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); + qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter From 71ec5f3612713cfae43c20dabc3c9986f60a4309 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Sat, 20 Oct 2018 11:57:46 +1300 Subject: [PATCH 073/114] Fix tablet highlighting when using the Create and Shapes apps --- .../controllers/controllerModules/inEditMode.js | 11 ++++++----- .../controllers/controllerModules/inVREditMode.js | 13 ++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 1917505bd8..2b17f447a0 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -158,11 +158,12 @@ Script.include("/~/system/libraries/utils.js"); } } - var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND - ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"); - if (nearOverlay) { - var nearOverlayReady = nearOverlay.isReady(controllerData); - if (nearOverlayReady.active && HMD.tabletID && nearOverlay.grabbedThingID === HMD.tabletID) { + // Tablet highlight and grabbing. + var tabletHighlight = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); + if (tabletHighlight) { + var tabletHighlightReady = tabletHighlight.isReady(controllerData); + if (tabletHighlightReady.active) { return this.exitModule(); } } diff --git a/scripts/system/controllers/controllerModules/inVREditMode.js b/scripts/system/controllers/controllerModules/inVREditMode.js index 65b6744646..0c04918ab1 100644 --- a/scripts/system/controllers/controllerModules/inVREditMode.js +++ b/scripts/system/controllers/controllerModules/inVREditMode.js @@ -101,13 +101,12 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } } - // Tablet grabbing. - var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND ? - "RightNearParentingGrabOverlay" : - "LeftNearParentingGrabOverlay"); - if (nearOverlay) { - var nearOverlayReady = nearOverlay.isReady(controllerData); - if (nearOverlayReady.active && HMD.tabletID && nearOverlay.grabbedThingID === HMD.tabletID) { + // Tablet highlight and grabbing. + var tabletHighlight = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightNearTabletHighlight" : "LeftNearTabletHighlight"); + if (tabletHighlight) { + var tabletHighlightReady = tabletHighlight.isReady(controllerData); + if (tabletHighlightReady.active) { return this.exitModule(); } } From a43985ef64088a88b02ab2bf11a1788fe611a6cd Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 19 Oct 2018 16:03:53 -0700 Subject: [PATCH 074/114] combo box for recenter model is added --- interface/resources/qml/hifi/AvatarApp.qml | 3 +- .../resources/qml/hifi/avatarapp/Settings.qml | 85 +------------------ interface/src/avatar/MyAvatar.cpp | 35 +++++++- interface/src/avatar/MyAvatar.h | 24 +++++- scripts/system/avatarapp.js | 32 ++----- 5 files changed, 71 insertions(+), 108 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index bf647b65bb..2d714c0d33 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -252,8 +252,7 @@ Rectangle { var avatarSettings = { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, - sittingEnabled : settings.avatarSittingOn, - lockStateEnabled : settings.avatarLockSitStandStateOn, + recenterModel : settings.avatarRecenterModelOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index 64ae03237c..cd71442bca 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -20,8 +20,7 @@ Rectangle { property real scaleValue: scaleSlider.value / 10 property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked - property alias avatarSittingOn: sitRadiobutton.checked - property alias avatarLockSitStandStateOn: lockSitStandStateCheckbox.checked + property alias avatarRecenterModelOn: boxy.currentIndex property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -47,21 +46,11 @@ Rectangle { collisionsDisabledRadioButton.checked = true; } - if (settings.sittingEnabled) { - sitRadiobutton.checked = true; - } else { - standRadioButton.checked = true; - } - - if (settings.lockStateEnabled) { - lockSitStandStateCheckbox.checked = true; - } else { - lockSitStandStateCheckbox.checked = false; - } - avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; + print("values " + avatarRecenterModelOn + " " + settings.recenterModel); + avatarRecenterModelOn = settings.recenterModel; visible = true; } @@ -305,7 +294,7 @@ Rectangle { } // TextStyle9 - + RalewaySemiBold { size: 17; Layout.row: 2 @@ -318,51 +307,6 @@ Rectangle { id: sitStand } - HifiControlsUit.RadioButton { - id: sitRadiobutton - - Layout.row: 2 - Layout.column: 1 - Layout.leftMargin: -40 - - ButtonGroup.group: sitStand - checked: true - - colorScheme: hifi.colorSchemes.light - fontSize: 17 - letterSpacing: 1.4 - text: "Sit" - boxSize: 20 - } - - HifiControlsUit.RadioButton { - id: standRadioButton - - Layout.row: 2 - Layout.column: 2 - Layout.rightMargin: 20 - - ButtonGroup.group: sitStand - - colorScheme: hifi.colorSchemes.light - fontSize: 17 - letterSpacing: 1.4 - text: "Stand" - boxSize: 20 - } - - // "Lock State" Checkbox - - HifiControlsUit.CheckBox { - id: lockSitStandStateCheckbox - visible: activeTab == "nearbyTab" - anchors.right: reloadNearbyContainer.left - anchors.rightMargin: 20 - checked: settings.lockStateEnabled - text: "lock" - boxSize: 24 - } - // sit stand combo box HifiControlsUit.ComboBox { id: boxy @@ -375,29 +319,8 @@ Rectangle { ListElement { text: "Auto Mode"; color: "Brown" } ListElement { text: "Disable Recentering"; color: "Red" } } - //displayText: "fred" - //label: cbItems.get(currentIndex).text width: 200 onCurrentIndexChanged: { - if (cbItems.get(currentIndex).text === "Force Sitting") { - sitRadiobutton.checked = true - lockSitStandStateCheckbox.checked = true - settings.lockStateEnabled = true - settings.sittingEnabled = true - } else if (cbItems.get(currentIndex).text === "Force Standing") { - sitRadiobutton.checked = false - lockSitStandStateCheckbox.checked = true - settings.lockStateEnabled = true - settings.sittingEnabled = false - } else if (cbItems.get(currentIndex).text === "auto") { - sitRadiobutton.checked = false - lockSitStandStateCheckbox.checked = false - settings.lockStateEnabled = false - settings.sittingEnabled = false - } else if (cbItems.get(currentIndex).text === "Disable Recentering") { - settings.lockStateEnabled = false - settings.sittingEnabled = false - } console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) console.debug("line 2") } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 95141d614f..14829a7b2e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -533,7 +533,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); + //qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter @@ -3867,6 +3867,10 @@ bool MyAvatar::getIsInSittingState() const { return _isInSittingState.get(); } +MyAvatar::SitStandModelType MyAvatar::getRecenterModel() const { + return _recenterModel.get(); +} + bool MyAvatar::getIsSitStandStateLocked() const { return _lockSitStandState.get(); } @@ -3903,9 +3907,38 @@ void MyAvatar::setIsInSittingState(bool isSitting) { setCenterOfGravityModelEnabled(true); } setSitStandStateChange(true); + emit sittingEnabledChanged(isSitting); } +void MyAvatar::setRecenterModel(MyAvatar::SitStandModelType modelName) { + + _recenterModel.set(modelName); + //int temp = 0; + qCDebug(interfaceapp) << "recenter property changed " << modelName; + switch (modelName) { + case SitStandModelType::ForceSit: + setIsInSittingState(true); + setIsSitStandStateLocked(true); + break; + case SitStandModelType::ForceStand: + setIsInSittingState(false); + setIsSitStandStateLocked(true); + break; + case SitStandModelType::Auto: + setIsInSittingState(false); + setIsSitStandStateLocked(false); + break; + case SitStandModelType::DisableHMDLean: + setHMDLeanRecenterEnabled(false); + setIsInSittingState(false); + setIsSitStandStateLocked(false); + break; + } + qCDebug(interfaceapp) << "recenter property changed " << modelName << " sit " << _isInSittingState.get() << " lock " << _lockSitStandState.get(); + emit recenterModelChanged((int)modelName); +} + void MyAvatar::setIsSitStandStateLocked(bool isLocked) { _lockSitStandState.set(isLocked); _sitStandStateTimer = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index be8b5fa1b2..c59bdcd66d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -143,6 +143,7 @@ class MyAvatar : public Avatar { * @property {number} walkBackwardSpeed * @property {number} sprintSpeed * @property {number} isInSittingState + * @property {number} recenterModel * * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the * registration point of the 3D model. @@ -244,6 +245,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed); Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed); Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState); + Q_PROPERTY(MyAvatar::SitStandModelType recenterModel READ getRecenterModel WRITE setRecenterModel); Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked); const QString DOMINANT_LEFT_HAND = "left"; @@ -265,6 +267,15 @@ public: }; Q_ENUM(DriveKeys) + enum SitStandModelType { + ForceSit = 0, + ForceStand, + Auto, + DisableHMDLean, + NumSitStandTypes + }; + Q_ENUM(SitStandModelType) + explicit MyAvatar(QThread* thread); virtual ~MyAvatar(); @@ -1106,6 +1117,8 @@ public: bool getIsInWalkingState() const; void setIsInSittingState(bool isSitting); bool getIsInSittingState() const; + void setRecenterModel(MyAvatar::SitStandModelType modelName); + MyAvatar::SitStandModelType getRecenterModel() const; void setIsSitStandStateLocked(bool isLocked); bool getIsSitStandStateLocked() const; void setWalkSpeed(float value); @@ -1530,6 +1543,14 @@ signals: */ void sittingEnabledChanged(bool enabled); + /**jsdoc + * Triggered when the recenter model is changed + * @function MyAvatar.recenterModelChanged + * @param {int} modeltype + * @ + */ + void recenterModelChanged(int modelName); + /**jsdoc * Triggered when the sit state is enabled or disabled * @function MyAvatar.sitStandStateLockEnabledChanged @@ -1829,7 +1850,7 @@ private: void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); - const float DEFAULT_FLOOR_HEIGHT = 0.0f; + // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; @@ -1844,6 +1865,7 @@ private: float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; ThreadSafeValueCache _isInSittingState { false }; + ThreadSafeValueCache _recenterModel { MyAvatar::SitStandModelType::Auto }; float _sitStandStateTimer { 0.0f }; float _squatTimer { 0.0f }; float _tippingPoint { _userHeight.get() }; diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 4a25ab9551..d64454c534 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -64,8 +64,7 @@ function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), collisionsEnabled : MyAvatar.getCollisionsEnabled(), - sittingEnabled: MyAvatar.isInSittingState, - lockStateEnabled: MyAvatar.isSitStandStateLocked, + recenterModel: MyAvatar.recenterModel, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -138,19 +137,11 @@ function onCollisionsEnabledChanged(enabled) { } } -function onSittingEnabledChanged(isSitting) { - if (currentAvatarSettings.sittingEnabled !== isSitting) { - currentAvatarSettings.sittingEnabled = isSitting; - print("emit sitting changed"); - sendToQml({ 'method': 'settingChanged', 'name': 'sittingEnabled', 'value': isSitting }) - } -} - -function onSitStandStateLockedEnabledChanged(isLocked) { - if (currentAvatarSettings.lockStateEnabled !== isLocked) { - currentAvatarSettings.lockStateEnabled = isLocked; - print("emit lock sit stand state changed"); - sendToQml({ 'method': 'settingChanged', 'name': 'lockStateEnabled', 'value': isLocked }) +function onRecenterModelChanged(modelName) { + if (currentAvatarSettings.recenterModel !== modelName) { + currentAvatarSettings.recenterModel = modelName; + print("emit recenter model changed"); + sendToQml({ 'method': 'settingChanged', 'name': 'recenterModel', 'value': modelName }) } } @@ -329,14 +320,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See case 'saveSettings': MyAvatar.setAvatarScale(message.avatarScale); currentAvatar.avatarScale = message.avatarScale; - MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); - MyAvatar.isInSittingState = message.settings.sittingEnabled; - MyAvatar.isSitStandStateLocked = message.settings.lockStateEnabled; + MyAvatar.recenterModel = message.settings.recenterModel; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); - settings = getMyAvatarSettings(); break; default: @@ -527,8 +515,7 @@ function off() { MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); - MyAvatar.sittingEnabledChanged.disconnect(onSittingEnabledChanged); - MyAvatar.sitStandStateLockEnabledChanged.disconnect(onSitStandStateLockedEnabledChanged); + MyAvatar.recenterModelChanged.disconnect(onRecenterModelChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -543,8 +530,7 @@ function on() { MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); - MyAvatar.sittingEnabledChanged.connect(onSittingEnabledChanged); - MyAvatar.sitStandStateLockEnabledChanged.connect(onSitStandStateLockedEnabledChanged); + MyAvatar.recenterModelChanged.connect(onRecenterModelChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 070a517423af7e6304f3ddc50564b0e65dd01bd0 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 19 Oct 2018 18:07:03 -0700 Subject: [PATCH 075/114] changed the recenterModel variables to userRecenterModel --- interface/resources/qml/hifi/AvatarApp.qml | 2 +- .../resources/qml/hifi/avatarapp/Settings.qml | 17 ++- interface/src/avatar/MyAvatar.cpp | 108 +++++++++--------- interface/src/avatar/MyAvatar.h | 20 ++-- scripts/system/avatarapp.js | 18 +-- 5 files changed, 80 insertions(+), 85 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index 2d714c0d33..549db20ab1 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -252,7 +252,7 @@ Rectangle { var avatarSettings = { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, - recenterModel : settings.avatarRecenterModelOn, + userRecenterModel : settings.avatarRecenterModelOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index cd71442bca..eb994b86de 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -20,7 +20,7 @@ Rectangle { property real scaleValue: scaleSlider.value / 10 property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked - property alias avatarRecenterModelOn: boxy.currentIndex + property alias avatarRecenterModelOn: userModelComboBox.currentIndex property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -49,8 +49,7 @@ Rectangle { avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; - print("values " + avatarRecenterModelOn + " " + settings.recenterModel); - avatarRecenterModelOn = settings.recenterModel; + avatarRecenterModelOn = settings.userRecenterModel; visible = true; } @@ -294,22 +293,21 @@ Rectangle { } // TextStyle9 - + RalewaySemiBold { size: 17; Layout.row: 2 Layout.column: 0 - text: "Sitting State" + text: "User Model:" } - ButtonGroup { - id: sitStand - } // sit stand combo box HifiControlsUit.ComboBox { - id: boxy + Layout.row: 2 + Layout.column: 1 + id: userModelComboBox comboBox.textRole: "text" currentIndex: 2 model: ListModel { @@ -325,7 +323,6 @@ Rectangle { console.debug("line 2") } } - } ColumnLayout { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 14829a7b2e..0b58c2c158 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -470,57 +470,58 @@ void MyAvatar::updateSitStandState(float newHeightReading, float dt) { const float SITTING_TIMEOUT = 4.0f; // 4 seconds const float STANDING_TIMEOUT = 0.3333f; // 1/3 second const float SITTING_UPPER_BOUND = 1.52f; - - if (!getIsSitStandStateLocked() && !getIsAway() && qApp->isHMDMode()) { - if (getIsInSittingState()) { - if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateTimer += dt; - if (_sitStandStateTimer > STANDING_TIMEOUT) { - _averageUserHeightSensorSpace = newHeightReading; - _tippingPoint = newHeightReading; - setIsInSittingState(false); - } - } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we are mis labelled as sitting but we are standing in the real world this will - // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state - _sitStandStateTimer += dt; - if (_sitStandStateTimer > SITTING_TIMEOUT) { - _averageUserHeightSensorSpace = newHeightReading; - _tippingPoint = newHeightReading; - // here we stay in sit state but reset the average height - setIsInSittingState(true); + if (!getIsSitStandStateLocked()) { + if (!getIsAway() && qApp->isHMDMode()) { + if (getIsInSittingState()) { + if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateTimer += dt; + if (_sitStandStateTimer > STANDING_TIMEOUT) { + _averageUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + setIsInSittingState(false); + } + } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we are mis labelled as sitting but we are standing in the real world this will + // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state + _sitStandStateTimer += dt; + if (_sitStandStateTimer > SITTING_TIMEOUT) { + _averageUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + // here we stay in sit state but reset the average height + setIsInSittingState(true); + } + } else { + // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) + if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) { + setIsInSittingState(false); + } else { + // tipping point is average height when sitting. + _tippingPoint = _averageUserHeightSensorSpace; + _sitStandStateTimer = 0.0f; + } } } else { - // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) - if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) { - setIsInSittingState(false); + // in the standing state + if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { + _sitStandStateTimer += dt; + if (_sitStandStateTimer > SITTING_TIMEOUT) { + _averageUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + setIsInSittingState(true); + } } else { - // tipping point is average height when sitting. - _tippingPoint = _averageUserHeightSensorSpace; + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); _sitStandStateTimer = 0.0f; } } } else { - // in the standing state - if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { - _sitStandStateTimer += dt; - if (_sitStandStateTimer > SITTING_TIMEOUT) { - _averageUserHeightSensorSpace = newHeightReading; - _tippingPoint = newHeightReading; - setIsInSittingState(true); - } - } else { - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateTimer = 0.0f; - } + //if you are away then reset the average and set state to standing. + _averageUserHeightSensorSpace = _userHeight.get(); + _tippingPoint = _userHeight.get(); + setIsInSittingState(false); } - } else { - // if you are away then reset the average and set state to standing. - _averageUserHeightSensorSpace = _userHeight.get(); - _tippingPoint = _userHeight.get(); - setIsInSittingState(false); } } @@ -533,7 +534,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - //qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); + qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter @@ -3867,8 +3868,8 @@ bool MyAvatar::getIsInSittingState() const { return _isInSittingState.get(); } -MyAvatar::SitStandModelType MyAvatar::getRecenterModel() const { - return _recenterModel.get(); +MyAvatar::SitStandModelType MyAvatar::getUserRecenterModel() const { + return _userRecenterModel.get(); } bool MyAvatar::getIsSitStandStateLocked() const { @@ -3907,25 +3908,25 @@ void MyAvatar::setIsInSittingState(bool isSitting) { setCenterOfGravityModelEnabled(true); } setSitStandStateChange(true); - - emit sittingEnabledChanged(isSitting); } -void MyAvatar::setRecenterModel(MyAvatar::SitStandModelType modelName) { +void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { + + _userRecenterModel.set(modelName); - _recenterModel.set(modelName); - //int temp = 0; - qCDebug(interfaceapp) << "recenter property changed " << modelName; switch (modelName) { case SitStandModelType::ForceSit: + setHMDLeanRecenterEnabled(true); setIsInSittingState(true); setIsSitStandStateLocked(true); break; case SitStandModelType::ForceStand: + setHMDLeanRecenterEnabled(true); setIsInSittingState(false); setIsSitStandStateLocked(true); break; case SitStandModelType::Auto: + setHMDLeanRecenterEnabled(true); setIsInSittingState(false); setIsSitStandStateLocked(false); break; @@ -3936,7 +3937,7 @@ void MyAvatar::setRecenterModel(MyAvatar::SitStandModelType modelName) { break; } qCDebug(interfaceapp) << "recenter property changed " << modelName << " sit " << _isInSittingState.get() << " lock " << _lockSitStandState.get(); - emit recenterModelChanged((int)modelName); + emit userRecenterModelChanged((int)modelName); } void MyAvatar::setIsSitStandStateLocked(bool isLocked) { @@ -3949,7 +3950,6 @@ void MyAvatar::setIsSitStandStateLocked(bool isLocked) { // always start the auto transition mode in standing state. setIsInSittingState(false); } - emit sitStandStateLockEnabledChanged(isLocked); } void MyAvatar::setWalkSpeed(float value) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index c59bdcd66d..691ab80530 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -143,7 +143,7 @@ class MyAvatar : public Avatar { * @property {number} walkBackwardSpeed * @property {number} sprintSpeed * @property {number} isInSittingState - * @property {number} recenterModel + * @property {number} userRecenterModel * * @property {Vec3} skeletonOffset - Can be used to apply a translation offset between the avatar's position and the * registration point of the 3D model. @@ -245,7 +245,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(float walkBackwardSpeed READ getWalkBackwardSpeed WRITE setWalkBackwardSpeed); Q_PROPERTY(float sprintSpeed READ getSprintSpeed WRITE setSprintSpeed); Q_PROPERTY(bool isInSittingState READ getIsInSittingState WRITE setIsInSittingState); - Q_PROPERTY(MyAvatar::SitStandModelType recenterModel READ getRecenterModel WRITE setRecenterModel); + Q_PROPERTY(MyAvatar::SitStandModelType userRecenterModel READ getUserRecenterModel WRITE setUserRecenterModel); Q_PROPERTY(bool isSitStandStateLocked READ getIsSitStandStateLocked WRITE setIsSitStandStateLocked); const QString DOMINANT_LEFT_HAND = "left"; @@ -1117,8 +1117,8 @@ public: bool getIsInWalkingState() const; void setIsInSittingState(bool isSitting); bool getIsInSittingState() const; - void setRecenterModel(MyAvatar::SitStandModelType modelName); - MyAvatar::SitStandModelType getRecenterModel() const; + void setUserRecenterModel(MyAvatar::SitStandModelType modelName); + MyAvatar::SitStandModelType getUserRecenterModel() const; void setIsSitStandStateLocked(bool isLocked); bool getIsSitStandStateLocked() const; void setWalkSpeed(float value); @@ -1545,11 +1545,11 @@ signals: /**jsdoc * Triggered when the recenter model is changed - * @function MyAvatar.recenterModelChanged - * @param {int} modeltype - * @ + * @function MyAvatar.userRecenterModelChanged + * @param {int} userRecenteringModeltype + * @returns {Signal} */ - void recenterModelChanged(int modelName); + void userRecenterModelChanged(int modelName); /**jsdoc * Triggered when the sit state is enabled or disabled @@ -1850,8 +1850,6 @@ private: void updateChildCauterization(SpatiallyNestablePointer object, bool cauterize); - - // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; float _averageUserHeightSensorSpace { _userHeight.get() }; @@ -1865,7 +1863,7 @@ private: float _walkSpeedScalar { AVATAR_WALK_SPEED_SCALAR }; bool _isInWalkingState { false }; ThreadSafeValueCache _isInSittingState { false }; - ThreadSafeValueCache _recenterModel { MyAvatar::SitStandModelType::Auto }; + ThreadSafeValueCache _userRecenterModel { MyAvatar::SitStandModelType::Auto }; float _sitStandStateTimer { 0.0f }; float _squatTimer { 0.0f }; float _tippingPoint { _userHeight.get() }; diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index d64454c534..b30f87c944 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -64,7 +64,7 @@ function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), collisionsEnabled : MyAvatar.getCollisionsEnabled(), - recenterModel: MyAvatar.recenterModel, + userRecenterModel: MyAvatar.userRecenterModel, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -137,11 +137,11 @@ function onCollisionsEnabledChanged(enabled) { } } -function onRecenterModelChanged(modelName) { - if (currentAvatarSettings.recenterModel !== modelName) { - currentAvatarSettings.recenterModel = modelName; - print("emit recenter model changed"); - sendToQml({ 'method': 'settingChanged', 'name': 'recenterModel', 'value': modelName }) +function onUserRecenterModelChanged(modelName) { + if (currentAvatarSettings.userRecenterModel !== modelName) { + currentAvatarSettings.userRecenterModel = modelName; + print("emit user recenter model changed"); + sendToQml({ 'method': 'settingChanged', 'name': 'userRecenterModel', 'value': modelName }) } } @@ -322,7 +322,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See currentAvatar.avatarScale = message.avatarScale; MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); - MyAvatar.recenterModel = message.settings.recenterModel; + MyAvatar.userRecenterModel = message.settings.userRecenterModel; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); settings = getMyAvatarSettings(); @@ -515,7 +515,7 @@ function off() { MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); - MyAvatar.recenterModelChanged.disconnect(onRecenterModelChanged); + MyAvatar.userRecenterModelChanged.disconnect(onUserRecenterModelChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -530,7 +530,7 @@ function on() { MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); - MyAvatar.recenterModelChanged.connect(onRecenterModelChanged); + MyAvatar.userRecenterModelChanged.connect(onUserRecenterModelChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 55daeb11cdcdb007ec7cfcabbc8eac18d46a4270 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 19 Oct 2018 18:43:02 -0700 Subject: [PATCH 076/114] moved the radio buttons on the avatar settings to even them out better. will be corrected I'm sure --- interface/resources/qml/hifi/avatarapp/Settings.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index eb994b86de..dbf38eb5fc 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -32,7 +32,7 @@ Rectangle { scaleSlider.notify = false; scaleSlider.value = Math.round(avatarScale * 10); - scaleSlider.notify = true;; + scaleSlider.notify = true; if (settings.dominantHand === 'left') { leftHandRadioButton.checked = true; @@ -191,7 +191,7 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right - rows: 2 + rows: 3 rowSpacing: 25 columns: 3 @@ -214,7 +214,7 @@ Rectangle { Layout.row: 0 Layout.column: 1 - Layout.leftMargin: -40 + Layout.leftMargin: 20 ButtonGroup.group: leftRight checked: true @@ -231,7 +231,7 @@ Rectangle { Layout.row: 0 Layout.column: 2 - Layout.rightMargin: 20 + Layout.rightMargin: -20 ButtonGroup.group: leftRight @@ -260,7 +260,7 @@ Rectangle { Layout.row: 1 Layout.column: 1 - Layout.leftMargin: -40 + Layout.leftMargin: 20 ButtonGroup.group: onOff colorScheme: hifi.colorSchemes.light @@ -281,7 +281,7 @@ Rectangle { Layout.row: 1 Layout.column: 2 - Layout.rightMargin: 20 + Layout.rightMargin: -20 ButtonGroup.group: onOff colorScheme: hifi.colorSchemes.light From a427ddb23543dac8e9cf1a111b24c9c6267ac797 Mon Sep 17 00:00:00 2001 From: amantley Date: Sat, 20 Oct 2018 09:16:05 -0700 Subject: [PATCH 077/114] removed extraneous print statements --- interface/resources/qml/hifi/avatarapp/Settings.qml | 4 ---- interface/src/avatar/MyAvatar.cpp | 2 -- 2 files changed, 6 deletions(-) diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index dbf38eb5fc..b7083bda13 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -318,10 +318,6 @@ Rectangle { ListElement { text: "Disable Recentering"; color: "Red" } } width: 200 - onCurrentIndexChanged: { - console.debug(cbItems.get(currentIndex).text + ", " + cbItems.get(currentIndex).color) - console.debug("line 2") - } } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 0b58c2c158..c8d33a770e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -534,7 +534,6 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - qCDebug(interfaceapp) << " the sit state is " << _isInSittingState.get() << " the lock is " << _lockSitStandState.get(); // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter @@ -3936,7 +3935,6 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { setIsSitStandStateLocked(false); break; } - qCDebug(interfaceapp) << "recenter property changed " << modelName << " sit " << _isInSittingState.get() << " lock " << _lockSitStandState.get(); emit userRecenterModelChanged((int)modelName); } From 5efb889de53ea3fd5d4375a05db885ce4bf02787 Mon Sep 17 00:00:00 2001 From: amantley Date: Sat, 20 Oct 2018 13:42:17 -0700 Subject: [PATCH 078/114] removed unused variables --- interface/src/avatar/MyAvatar.cpp | 44 ++++++++++++++----------------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c8d33a770e..94a6c6f514 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3606,12 +3606,9 @@ glm::vec3 MyAvatar::computeCounterBalance() { glm::vec3 counterBalancedCg = (1.0f / DEFAULT_AVATAR_HIPS_MASS) * counterBalancedForHead; // find the height of the hips - const float UPPER_LEG_FRACTION = 0.3333f; glm::vec3 xzDiff((cgHeadMass.position.x - counterBalancedCg.x), 0.0f, (cgHeadMass.position.z - counterBalancedCg.z)); float headMinusHipXz = glm::length(xzDiff); float headHipDefault = glm::length(tposeHead - tposeHips); - float hipFootDefault = tposeHips.y - tposeRightFoot.y; - float sitSquatThreshold = tposeHips.y - (UPPER_LEG_FRACTION * hipFootDefault); float hipHeight = 0.0f; if (headHipDefault > headMinusHipXz) { hipHeight = sqrtf((headHipDefault * headHipDefault) - (headMinusHipXz * headMinusHipXz)); @@ -3914,26 +3911,26 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { _userRecenterModel.set(modelName); switch (modelName) { - case SitStandModelType::ForceSit: - setHMDLeanRecenterEnabled(true); - setIsInSittingState(true); - setIsSitStandStateLocked(true); - break; - case SitStandModelType::ForceStand: - setHMDLeanRecenterEnabled(true); - setIsInSittingState(false); - setIsSitStandStateLocked(true); - break; - case SitStandModelType::Auto: - setHMDLeanRecenterEnabled(true); - setIsInSittingState(false); - setIsSitStandStateLocked(false); - break; - case SitStandModelType::DisableHMDLean: - setHMDLeanRecenterEnabled(false); - setIsInSittingState(false); - setIsSitStandStateLocked(false); - break; + case MyAvatar::SitStandModelType::ForceSit: + setHMDLeanRecenterEnabled(true); + setIsInSittingState(true); + setIsSitStandStateLocked(true); + break; + case MyAvatar::SitStandModelType::ForceStand: + setHMDLeanRecenterEnabled(true); + setIsInSittingState(false); + setIsSitStandStateLocked(true); + break; + case MyAvatar::SitStandModelType::Auto: + setHMDLeanRecenterEnabled(true); + setIsInSittingState(false); + setIsSitStandStateLocked(false); + break; + case MyAvatar::SitStandModelType::DisableHMDLean: + setHMDLeanRecenterEnabled(false); + setIsInSittingState(false); + setIsSitStandStateLocked(false); + break; } emit userRecenterModelChanged((int)modelName); } @@ -4190,7 +4187,6 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; - const int SQUATTY_COUNT_THRESHOLD = 1800; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); bool returnValue = false; From eb3db9a5715ad53c0344bee64647e67aa0de8eac Mon Sep 17 00:00:00 2001 From: amantley Date: Sat, 20 Oct 2018 16:13:41 -0700 Subject: [PATCH 079/114] added default to case statement --- interface/src/avatar/MyAvatar.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b2146fb14d..dd40a748af 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3970,6 +3970,8 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { setIsInSittingState(false); setIsSitStandStateLocked(false); break; + default: + break; } emit userRecenterModelChanged((int)modelName); } From d008bfa523e6f61879290b09fd1d7a8cc61b8037 Mon Sep 17 00:00:00 2001 From: Wayne Chen Date: Mon, 22 Oct 2018 11:29:36 -0700 Subject: [PATCH 080/114] partial requested code changes --- .../controllers/controllerModules/webSurfaceLaserInput.js | 2 -- scripts/system/interstitialPage.js | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 9f4133674a..c2949bebe4 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -90,7 +90,6 @@ Script.include("/~/system/libraries/controllers.js"); action: 'add', id: objectID }; - print("ignoreing entity " + entityIndex); Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); this.ignoredObjects.push(objectID); } @@ -99,7 +98,6 @@ Script.include("/~/system/libraries/controllers.js"); this.restoreIgnoredObjects = function() { for (var index = 0; index < this.ignoredObjects.length; index++) { - print("removing"); var data = { action: 'remove', id: this.ignoredObjects[index] diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index a611f386ff..b29347872a 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -241,7 +241,7 @@ } function lerp(a, b, t) { - return (((1 - t) * a) + (t * b)); + return ((1 - t) * a + t * b); } function resetValues() { From 1ce1902fa8f9d2dd0571d651e0094abe425a5445 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 22 Oct 2018 12:49:24 -0700 Subject: [PATCH 081/114] remove magic numbers --- scripts/system/interstitialPage.js | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index b29347872a..670d21c7a7 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -459,13 +459,14 @@ } } + var MAX_TEXTURE_STABILITY_COUNT = 30; + var INTERVAL_PROGRESS = 0.04; function update() { var renderStats = Render.getConfig("Stats"); var physicsEnabled = Window.isPhysicsEnabled(); var thisInterval = Date.now(); var deltaTime = (thisInterval - lastInterval); lastInterval = thisInterval; - var deltaTimeMS = deltaTime / 1000; var domainLoadingProgressPercentage = Window.domainLoadingProgress(); var progress = ((TOTAL_LOADING_PROGRESS * 0.4) * domainLoadingProgressPercentage); @@ -485,7 +486,7 @@ textureMemSizeAtLastCheck = textureResourceGPUMemSize; - if (textureMemSizeStabilityCount >= 30) { + if (textureMemSizeStabilityCount >= MAX_TEXTURE_STABILITY_COUNT) { if (textureResourceGPUMemSize > 0) { var gpuPercantage = (TOTAL_LOADING_PROGRESS * 0.6) * (texturePopulatedGPUMemSize / textureResourceGPUMemSize); @@ -501,11 +502,7 @@ target = TOTAL_LOADING_PROGRESS; } - if (deltaTime > 1.0) { - deltaTimeMS = 0.02; - } - - currentProgress = lerp(currentProgress, target, (deltaTimeMS * 2.0)); + currentProgress = lerp(currentProgress, target, INTERVAL_PROGRESS); var properties = { localPosition: { x: (1.85 - (currentProgress / 2) - (-0.029 * (currentProgress / TOTAL_LOADING_PROGRESS))), y: -0.935, z: 0.0 }, dimensions: { From 35c1241c9886909cad86dce0b8079245806b5bee Mon Sep 17 00:00:00 2001 From: David Rowe Date: Tue, 23 Oct 2018 09:08:38 +1300 Subject: [PATCH 082/114] Fix tablet highlighting not working if start up in HMD --- .../system/controllers/controllerModules/nearTabletHighlight.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/controllers/controllerModules/nearTabletHighlight.js b/scripts/system/controllers/controllerModules/nearTabletHighlight.js index 2b02bf3aed..c24464ab38 100644 --- a/scripts/system/controllers/controllerModules/nearTabletHighlight.js +++ b/scripts/system/controllers/controllerModules/nearTabletHighlight.js @@ -109,6 +109,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } HMD.displayModeChanged.connect(onDisplayModeChanged); HMD.mountedChanged.connect(onDisplayModeChanged); + onDisplayModeChanged(); function cleanUp() { disableDispatcherModule("LeftNearTabletHighlight"); From 9cc2add4a045396bd8ff2bce175040ea2f93c6f3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 18 Oct 2018 12:35:39 -0700 Subject: [PATCH 083/114] Add copy/paste functionality to edit.js --- .../resources/controllers/keyboardMouse.json | 2 +- scripts/system/edit.js | 239 +++++++++++++++++- 2 files changed, 232 insertions(+), 9 deletions(-) diff --git a/interface/resources/controllers/keyboardMouse.json b/interface/resources/controllers/keyboardMouse.json index 80933a2489..2ad07911c6 100644 --- a/interface/resources/controllers/keyboardMouse.json +++ b/interface/resources/controllers/keyboardMouse.json @@ -133,7 +133,7 @@ { "from": "Keyboard.W", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_FORWARD" }, { "from": "Keyboard.S", "when": "!Keyboard.Control", "to": "Actions.LONGITUDINAL_BACKWARD" }, { "from": "Keyboard.Shift", "when": ["!Keyboard.Left", "!Keyboard.Right"], "to": "Actions.SPRINT" }, - { "from": "Keyboard.C", "to": "Actions.VERTICAL_DOWN" }, + { "from": "Keyboard.C", "when": "!Keyboard.Control", "to": "Actions.VERTICAL_DOWN" }, { "from": "Keyboard.Left", "when": "Keyboard.Shift", "to": "Actions.LATERAL_LEFT" }, { "from": "Keyboard.Right", "when": "Keyboard.Shift", "to": "Actions.LATERAL_RIGHT" }, { "from": "Keyboard.Up", "when": "Application.CameraFirstPerson", "to": "Actions.LONGITUDINAL_FORWARD" }, diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 1720cb8278..f172df7bae 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1933,14 +1933,6 @@ function gridKey(value) { } } } -var mapping = Controller.newMapping(CONTROLLER_MAPPING_NAME); -mapping.from([Controller.Hardware.Keyboard.Delete]).when([!Controller.Hardware.Application.PlatformMac]).to(deleteKey); -mapping.from([Controller.Hardware.Keyboard.Backspace]).when([Controller.Hardware.Application.PlatformMac]).to(deleteKey); -mapping.from([Controller.Hardware.Keyboard.D]).when([Controller.Hardware.Keyboard.Control]).to(deselectKey); -mapping.from([Controller.Hardware.Keyboard.T]).to(toggleKey); -mapping.from([Controller.Hardware.Keyboard.F]).to(focusKey); -mapping.from([Controller.Hardware.Keyboard.G]).to(gridKey); - function recursiveAdd(newParentID, parentData) { if (parentData.children !== undefined) { var children = parentData.children; @@ -2398,6 +2390,213 @@ var PropertiesTool = function (opts) { return that; }; +function addChildrenEntities(parentEntityID, entityList) { + var children = Entities.getChildrenIDs(parentEntityID); + for (var i = 0; i < children.length; i++) { + var childID = children[i]; + if (entityList.indexOf(childID) < 0) { + entityList.push(childID); + } + addChildrenEntities(childID, entityList); + } +} + +// Return true if the given entity with `properties` is being grabbed by an avatar. +// This is mostly a heuristic - there is no perfect way to know if an entity is being +// grabbed. +function nonDynamicEntityIsBeingGrabbedByAvatar(properties) { + if (properties.dynamic || Uuid.isNull(properties.parentID)) { + return false; + } + + var avatar = AvatarList.getAvatar(properties.parentID); + if (Uuid.isNull(avatar.sessionUUID)) { + return false; + } + + var grabJointNames = [ + 'RightHand', 'LeftHand', + '_CONTROLLER_RIGHTHAND', '_CONTROLLER_LEFTHAND', + '_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND', '_CAMERA_RELATIVE_CONTROLLER_LEFTHAND']; + + for (var i = 0; i < grabJointNames.length; ++i) { + if (avatar.getJointIndex(grabJointNames[i]) === properties.parentJointIndex) { + return true; + } + } + + return false; +} + + +// entityProperites - array of entity property objects +function createEntities(entityProperties) { + var entitiesToCreate = []; + var createdEntityIDs = []; + var createdChildrenWithOldParents = []; + var originalEntityToNewEntityID = []; + + SelectionManager.saveProperties(); + + for (var i = 0, len = entityProperties.length; i < len; ++i) { + var properties = entityProperties[i]; + if (properties.parentID in originalEntityToNewEntityID) { + properties.parentID = originalEntityToNewEntityID[properties.parentID]; + } else { + delete properties.parentID; + } + + delete properties.actionData; + var newEntityID = Entities.addEntity(properties); + + if (newEntityID) { + createdEntityIDs.push({ + entityID: newEntityID, + properties: properties + }); + if (properties.parentID !== Uuid.NULL) { + createdChildrenWithOldParents[newEntityID] = properties.parentID; + } + originalEntityToNewEntityID[properties.id] = newEntityID; + properties.id = newEntityID; + } + } + + return createdEntityIDs; +} + +function copySelectedEntities() { + copyEntities(selectionManager.selections); +} + +var entityClipboard = { + entities: {}, // Map of id -> properties for copied entities + position: { x: 0, y: 0, z: 0 }, + dimensions: { x: 0, y: 0, z: 0 }, +}; + +function copyEntities(entityIDs) { + var entityProperties = Entities.getMultipleEntityProperties(entityIDs); + var entities = {}; + entityProperties.forEach(function(props) { + entities[props.id] = props; + }); + + function appendChildren(entityID, entities) { + var childrenIDs = Entities.getChildrenIDs(entityID); + for (var i = 0; i < childrenIDs.length; ++i) { + var id = childrenIDs[i]; + if (!(id in entities)) { + entities[id] = Entities.getEntityProperties(id); + appendChildren(id, entities); + } + } + } + + var len = entityProperties.length; + for (var i = 0; i < len; ++i) { + appendChildren(entityProperties[i].id, entities); + } + + for (var id in entities) { + var parentID = entities[id].parentID; + entities[id].root = !(parentID in entities); + } + + entityClipboard.entities = []; + + var ids = Object.keys(entities); + while (ids.length > 0) { + // Go through all remaining entities. + // If an entity does not have a parent left, move it into the list + for (var i = 0; i < ids.length; ++i) { + var id = ids[i]; + var parentID = entities[id].parentID; + if (parentID in entities) { + continue; + } + entityClipboard.entities.push(entities[id]); + delete entities[id]; + } + ids = Object.keys(entities); + } + + // Calculate size + if (entityClipboard.entities.length === 0) { + entityClipboard.dimensions = { x: 0, y: 0, z: 0 }; + entityClipboard.position = { x: 0, y: 0, z: 0 }; + } else { + var properties = entityClipboard.entities; + var brn = properties[0].boundingBox.brn; + var tfl = properties[0].boundingBox.tfl; + for (var i = 1; i < properties.length; i++) { + var bb = properties[i].boundingBox; + brn.x = Math.min(bb.brn.x, brn.x); + brn.y = Math.min(bb.brn.y, brn.y); + brn.z = Math.min(bb.brn.z, brn.z); + tfl.x = Math.max(bb.tfl.x, tfl.x); + tfl.y = Math.max(bb.tfl.y, tfl.y); + tfl.z = Math.max(bb.tfl.z, tfl.z); + } + entityClipboard.dimensions = { + x: tfl.x - brn.x, + y: tfl.y - brn.y, + z: tfl.z - brn.z + }; + entityClipboard.position = { + x: brn.x + entityClipboard.dimensions.x / 2, + y: brn.y + entityClipboard.dimensions.y / 2, + z: brn.z + entityClipboard.dimensions.z / 2 + }; + } +} + +function deepCopy(v) { + return JSON.parse(JSON.stringify(v)); +} + +function pasteEntities() { + var dims = entityClipboard.dimensions; + var maxDim = Math.max(dims.x, dims.y, dims.z); + var pastePosition = getPositionToCreateEntity(maxDim); + var deltaPosition = Vec3.subtract(pastePosition, entityClipboard.position); + + var copiedProperties = [] + var ids = []; + entityClipboard.entities.forEach(function(origproperties) { + var properties = deepCopy(origproperties); + if (properties.root) { + properties.position = Vec3.sum(properties.position, deltaPosition); + delete properties.localPosition; + } else { + delete properties.position; + } + //entityProperties[properties.id] = properties; + copiedProperties.push(properties); + }); + + var currentSelections = deepCopy(SelectionManager.selections); + + function redo(copiedProperties) { + var created = createEntities(copiedProperties); + var ids = []; + for (var i = 0; i < created.length; ++i) { + ids.push(created[i].entityID); + } + SelectionManager.setSelections(ids); + } + + function undo(copiedProperties) { + for (var i = 0; i < copiedProperties.length; ++i) { + Entities.deleteEntity(copiedProperties[i].id); + } + SelectionManager.setSelections(currentSelections); + } + + redo(copiedProperties); + undoHistory.pushCommand(undo, copiedProperties, redo, copiedProperties); +} + var PopupMenu = function () { var self = this; @@ -2567,6 +2766,30 @@ var PopupMenu = function () { return this; }; +var mapping = Controller.newMapping(CONTROLLER_MAPPING_NAME); +mapping.from([Controller.Hardware.Keyboard.Delete]).when([!Controller.Hardware.Application.PlatformMac]).to(deleteKey); +mapping.from([Controller.Hardware.Keyboard.Backspace]).when([Controller.Hardware.Application.PlatformMac]).to(deleteKey); +mapping.from([Controller.Hardware.Keyboard.D]).when([Controller.Hardware.Keyboard.Control]).to(deselectKey); +mapping.from([Controller.Hardware.Keyboard.T]).to(toggleKey); +mapping.from([Controller.Hardware.Keyboard.F]).to(focusKey); +mapping.from([Controller.Hardware.Keyboard.G]).to(gridKey); +mapping.from([Controller.Hardware.Keyboard.C]).when([Controller.Hardware.Keyboard.Control]).to(copyKey); +mapping.from([Controller.Hardware.Keyboard.V]).when([Controller.Hardware.Keyboard.Control]).to(pasteKey); + +function copyKey(value) { + console.log("Copy", value); + if (value > 0) { + copySelectedEntities(); + } +} + +function pasteKey(value) { + if (value > 0) { + pasteEntities(); + } +} + + var propertyMenu = new PopupMenu(); From 65fdd16d90798ab1a0efd26e3c423ef04ed5c6ba Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 19 Oct 2018 08:42:44 -0700 Subject: [PATCH 084/114] Cleanup copy/paste changes --- scripts/system/edit.js | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index f172df7bae..24315857c4 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -2401,9 +2401,11 @@ function addChildrenEntities(parentEntityID, entityList) { } } -// Return true if the given entity with `properties` is being grabbed by an avatar. +// Determine if an entity is being grabbed. // This is mostly a heuristic - there is no perfect way to know if an entity is being // grabbed. +// +// @return {boolean} true if the given entity with `properties` is being grabbed by an avatar function nonDynamicEntityIsBeingGrabbedByAvatar(properties) { if (properties.dynamic || Uuid.isNull(properties.parentID)) { return false; @@ -2429,7 +2431,8 @@ function nonDynamicEntityIsBeingGrabbedByAvatar(properties) { } -// entityProperites - array of entity property objects +// Create the entities in entityProperties, maintaining parent-child relationships. +// @param entityPropertites {array} - Array of entity property objects function createEntities(entityProperties) { var entitiesToCreate = []; var createdEntityIDs = []; @@ -2438,7 +2441,7 @@ function createEntities(entityProperties) { SelectionManager.saveProperties(); - for (var i = 0, len = entityProperties.length; i < len; ++i) { + for (var i = 0; i < entityProperties.length; ++i) { var properties = entityProperties[i]; if (properties.parentID in originalEntityToNewEntityID) { properties.parentID = originalEntityToNewEntityID[properties.parentID]; @@ -2556,22 +2559,21 @@ function deepCopy(v) { } function pasteEntities() { - var dims = entityClipboard.dimensions; - var maxDim = Math.max(dims.x, dims.y, dims.z); - var pastePosition = getPositionToCreateEntity(maxDim); + var dimensions = entityClipboard.dimensions; + var maxDimension = Math.max(dimensions.x, dimensions.y, dimensions.z); + var pastePosition = getPositionToCreateEntity(maxDimension); var deltaPosition = Vec3.subtract(pastePosition, entityClipboard.position); var copiedProperties = [] var ids = []; - entityClipboard.entities.forEach(function(origproperties) { - var properties = deepCopy(origproperties); + entityClipboard.entities.forEach(function(originalProperties) { + var properties = deepCopy(originalProperties); if (properties.root) { properties.position = Vec3.sum(properties.position, deltaPosition); delete properties.localPosition; } else { delete properties.position; } - //entityProperties[properties.id] = properties; copiedProperties.push(properties); }); @@ -2777,7 +2779,6 @@ mapping.from([Controller.Hardware.Keyboard.C]).when([Controller.Hardware.Keyboar mapping.from([Controller.Hardware.Keyboard.V]).when([Controller.Hardware.Keyboard.Control]).to(pasteKey); function copyKey(value) { - console.log("Copy", value); if (value > 0) { copySelectedEntities(); } From e0851c480775eae2195631be05df63ad59a44e9d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 19 Oct 2018 09:51:53 -0700 Subject: [PATCH 085/114] Add cut to Create, and update shortcuts --- scripts/system/edit.js | 48 +++++++++++++------- scripts/system/libraries/entityCameraTool.js | 18 ++++---- 2 files changed, 42 insertions(+), 24 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index 24315857c4..e2c4d78d96 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -1254,7 +1254,7 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "Edit", menuItemName: "Redo", - shortcutKey: 'Ctrl+Shift+Z', + shortcutKey: 'Ctrl+Y', position: 1, }); @@ -2468,6 +2468,11 @@ function createEntities(entityProperties) { return createdEntityIDs; } +function cutSelectedEntities() { + copySelectedEntities(); + deleteSelectedEntities(); +} + function copySelectedEntities() { copyEntities(selectionManager.selections); } @@ -2768,28 +2773,39 @@ var PopupMenu = function () { return this; }; +function whenPressed(fn) { + return function(value) { + if (value > 0) { + fn(); + } + }; +} + +function whenReleased(fn) { + return function(value) { + if (value === 0) { + fn(); + } + }; +} + var mapping = Controller.newMapping(CONTROLLER_MAPPING_NAME); mapping.from([Controller.Hardware.Keyboard.Delete]).when([!Controller.Hardware.Application.PlatformMac]).to(deleteKey); mapping.from([Controller.Hardware.Keyboard.Backspace]).when([Controller.Hardware.Application.PlatformMac]).to(deleteKey); -mapping.from([Controller.Hardware.Keyboard.D]).when([Controller.Hardware.Keyboard.Control]).to(deselectKey); mapping.from([Controller.Hardware.Keyboard.T]).to(toggleKey); mapping.from([Controller.Hardware.Keyboard.F]).to(focusKey); mapping.from([Controller.Hardware.Keyboard.G]).to(gridKey); -mapping.from([Controller.Hardware.Keyboard.C]).when([Controller.Hardware.Keyboard.Control]).to(copyKey); -mapping.from([Controller.Hardware.Keyboard.V]).when([Controller.Hardware.Keyboard.Control]).to(pasteKey); - -function copyKey(value) { - if (value > 0) { - copySelectedEntities(); - } -} - -function pasteKey(value) { - if (value > 0) { - pasteEntities(); - } -} +mapping.from([Controller.Hardware.Keyboard.X]).when([Controller.Hardware.Keyboard.Control]).to(whenReleased(cutSelectedEntities)); +mapping.from([Controller.Hardware.Keyboard.C]).when([Controller.Hardware.Keyboard.Control]).to(whenReleased(copySelectedEntities)); +mapping.from([Controller.Hardware.Keyboard.V]).when([Controller.Hardware.Keyboard.Control]).to(whenReleased(pasteEntities)); +mapping.from([Controller.Hardware.Keyboard.D]) + .when([Controller.Hardware.Keyboard.Control]) + .to(whenReleased(function() { SelectionManager.duplicateSelection() })); +// Bind undo to ctrl-shift-z to maintain backwards-compatibility +mapping.from([Controller.Hardware.Keyboard.Z]) + .when([Controller.Hardware.Keyboard.Control, Controller.Hardware.Keyboard.Shift]) + .to(whenPressed(function() { undoHistory.redo() })); var propertyMenu = new PopupMenu(); diff --git a/scripts/system/libraries/entityCameraTool.js b/scripts/system/libraries/entityCameraTool.js index 73e73d67a6..4410f19a5e 100644 --- a/scripts/system/libraries/entityCameraTool.js +++ b/scripts/system/libraries/entityCameraTool.js @@ -98,16 +98,18 @@ CameraManager = function() { } function getActionForKeyEvent(event) { - var action = keyToActionMapping[event.key]; - if (action !== undefined) { - if (event.isShifted) { - if (action === "orbitForward") { - action = "orbitUp"; - } else if (action === "orbitBackward") { - action = "orbitDown"; + if (!event.isControl) { + var action = keyToActionMapping[event.key]; + if (action !== undefined) { + if (event.isShifted) { + if (action === "orbitForward") { + action = "orbitUp"; + } else if (action === "orbitBackward") { + action = "orbitDown"; + } } + return action; } - return action; } return null; } From 573df2d922ab975109a411fbe7db652fdc5b1e92 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Mon, 22 Oct 2018 08:41:52 -0700 Subject: [PATCH 086/114] Move copy/paste/cut to SelectionManager --- scripts/system/edit.js | 227 +----------------- .../system/libraries/entitySelectionTool.js | 174 +++++++++++++- 2 files changed, 183 insertions(+), 218 deletions(-) diff --git a/scripts/system/edit.js b/scripts/system/edit.js index e2c4d78d96..b911541f79 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -2390,219 +2390,6 @@ var PropertiesTool = function (opts) { return that; }; -function addChildrenEntities(parentEntityID, entityList) { - var children = Entities.getChildrenIDs(parentEntityID); - for (var i = 0; i < children.length; i++) { - var childID = children[i]; - if (entityList.indexOf(childID) < 0) { - entityList.push(childID); - } - addChildrenEntities(childID, entityList); - } -} - -// Determine if an entity is being grabbed. -// This is mostly a heuristic - there is no perfect way to know if an entity is being -// grabbed. -// -// @return {boolean} true if the given entity with `properties` is being grabbed by an avatar -function nonDynamicEntityIsBeingGrabbedByAvatar(properties) { - if (properties.dynamic || Uuid.isNull(properties.parentID)) { - return false; - } - - var avatar = AvatarList.getAvatar(properties.parentID); - if (Uuid.isNull(avatar.sessionUUID)) { - return false; - } - - var grabJointNames = [ - 'RightHand', 'LeftHand', - '_CONTROLLER_RIGHTHAND', '_CONTROLLER_LEFTHAND', - '_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND', '_CAMERA_RELATIVE_CONTROLLER_LEFTHAND']; - - for (var i = 0; i < grabJointNames.length; ++i) { - if (avatar.getJointIndex(grabJointNames[i]) === properties.parentJointIndex) { - return true; - } - } - - return false; -} - - -// Create the entities in entityProperties, maintaining parent-child relationships. -// @param entityPropertites {array} - Array of entity property objects -function createEntities(entityProperties) { - var entitiesToCreate = []; - var createdEntityIDs = []; - var createdChildrenWithOldParents = []; - var originalEntityToNewEntityID = []; - - SelectionManager.saveProperties(); - - for (var i = 0; i < entityProperties.length; ++i) { - var properties = entityProperties[i]; - if (properties.parentID in originalEntityToNewEntityID) { - properties.parentID = originalEntityToNewEntityID[properties.parentID]; - } else { - delete properties.parentID; - } - - delete properties.actionData; - var newEntityID = Entities.addEntity(properties); - - if (newEntityID) { - createdEntityIDs.push({ - entityID: newEntityID, - properties: properties - }); - if (properties.parentID !== Uuid.NULL) { - createdChildrenWithOldParents[newEntityID] = properties.parentID; - } - originalEntityToNewEntityID[properties.id] = newEntityID; - properties.id = newEntityID; - } - } - - return createdEntityIDs; -} - -function cutSelectedEntities() { - copySelectedEntities(); - deleteSelectedEntities(); -} - -function copySelectedEntities() { - copyEntities(selectionManager.selections); -} - -var entityClipboard = { - entities: {}, // Map of id -> properties for copied entities - position: { x: 0, y: 0, z: 0 }, - dimensions: { x: 0, y: 0, z: 0 }, -}; - -function copyEntities(entityIDs) { - var entityProperties = Entities.getMultipleEntityProperties(entityIDs); - var entities = {}; - entityProperties.forEach(function(props) { - entities[props.id] = props; - }); - - function appendChildren(entityID, entities) { - var childrenIDs = Entities.getChildrenIDs(entityID); - for (var i = 0; i < childrenIDs.length; ++i) { - var id = childrenIDs[i]; - if (!(id in entities)) { - entities[id] = Entities.getEntityProperties(id); - appendChildren(id, entities); - } - } - } - - var len = entityProperties.length; - for (var i = 0; i < len; ++i) { - appendChildren(entityProperties[i].id, entities); - } - - for (var id in entities) { - var parentID = entities[id].parentID; - entities[id].root = !(parentID in entities); - } - - entityClipboard.entities = []; - - var ids = Object.keys(entities); - while (ids.length > 0) { - // Go through all remaining entities. - // If an entity does not have a parent left, move it into the list - for (var i = 0; i < ids.length; ++i) { - var id = ids[i]; - var parentID = entities[id].parentID; - if (parentID in entities) { - continue; - } - entityClipboard.entities.push(entities[id]); - delete entities[id]; - } - ids = Object.keys(entities); - } - - // Calculate size - if (entityClipboard.entities.length === 0) { - entityClipboard.dimensions = { x: 0, y: 0, z: 0 }; - entityClipboard.position = { x: 0, y: 0, z: 0 }; - } else { - var properties = entityClipboard.entities; - var brn = properties[0].boundingBox.brn; - var tfl = properties[0].boundingBox.tfl; - for (var i = 1; i < properties.length; i++) { - var bb = properties[i].boundingBox; - brn.x = Math.min(bb.brn.x, brn.x); - brn.y = Math.min(bb.brn.y, brn.y); - brn.z = Math.min(bb.brn.z, brn.z); - tfl.x = Math.max(bb.tfl.x, tfl.x); - tfl.y = Math.max(bb.tfl.y, tfl.y); - tfl.z = Math.max(bb.tfl.z, tfl.z); - } - entityClipboard.dimensions = { - x: tfl.x - brn.x, - y: tfl.y - brn.y, - z: tfl.z - brn.z - }; - entityClipboard.position = { - x: brn.x + entityClipboard.dimensions.x / 2, - y: brn.y + entityClipboard.dimensions.y / 2, - z: brn.z + entityClipboard.dimensions.z / 2 - }; - } -} - -function deepCopy(v) { - return JSON.parse(JSON.stringify(v)); -} - -function pasteEntities() { - var dimensions = entityClipboard.dimensions; - var maxDimension = Math.max(dimensions.x, dimensions.y, dimensions.z); - var pastePosition = getPositionToCreateEntity(maxDimension); - var deltaPosition = Vec3.subtract(pastePosition, entityClipboard.position); - - var copiedProperties = [] - var ids = []; - entityClipboard.entities.forEach(function(originalProperties) { - var properties = deepCopy(originalProperties); - if (properties.root) { - properties.position = Vec3.sum(properties.position, deltaPosition); - delete properties.localPosition; - } else { - delete properties.position; - } - copiedProperties.push(properties); - }); - - var currentSelections = deepCopy(SelectionManager.selections); - - function redo(copiedProperties) { - var created = createEntities(copiedProperties); - var ids = []; - for (var i = 0; i < created.length; ++i) { - ids.push(created[i].entityID); - } - SelectionManager.setSelections(ids); - } - - function undo(copiedProperties) { - for (var i = 0; i < copiedProperties.length; ++i) { - Entities.deleteEntity(copiedProperties[i].id); - } - SelectionManager.setSelections(currentSelections); - } - - redo(copiedProperties); - undoHistory.pushCommand(undo, copiedProperties, redo, copiedProperties); -} var PopupMenu = function () { var self = this; @@ -2795,12 +2582,18 @@ mapping.from([Controller.Hardware.Keyboard.Backspace]).when([Controller.Hardware mapping.from([Controller.Hardware.Keyboard.T]).to(toggleKey); mapping.from([Controller.Hardware.Keyboard.F]).to(focusKey); mapping.from([Controller.Hardware.Keyboard.G]).to(gridKey); -mapping.from([Controller.Hardware.Keyboard.X]).when([Controller.Hardware.Keyboard.Control]).to(whenReleased(cutSelectedEntities)); -mapping.from([Controller.Hardware.Keyboard.C]).when([Controller.Hardware.Keyboard.Control]).to(whenReleased(copySelectedEntities)); -mapping.from([Controller.Hardware.Keyboard.V]).when([Controller.Hardware.Keyboard.Control]).to(whenReleased(pasteEntities)); +mapping.from([Controller.Hardware.Keyboard.X]) + .when([Controller.Hardware.Keyboard.Control]) + .to(whenReleased(function() { selectionManager.cutSelectedEntities() })); +mapping.from([Controller.Hardware.Keyboard.C]) + .when([Controller.Hardware.Keyboard.Control]) + .to(whenReleased(function() { selectionManager.copySelectedEntities() })); +mapping.from([Controller.Hardware.Keyboard.V]) + .when([Controller.Hardware.Keyboard.Control]) + .to(whenReleased(function() { selectionManager.pasteEntities() })); mapping.from([Controller.Hardware.Keyboard.D]) .when([Controller.Hardware.Keyboard.Control]) - .to(whenReleased(function() { SelectionManager.duplicateSelection() })); + .to(whenReleased(function() { selectionManager.duplicateSelection() })); // Bind undo to ctrl-shift-z to maintain backwards-compatibility mapping.from([Controller.Hardware.Keyboard.Z]) diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index 5f5225418f..843d3e986f 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -26,6 +26,11 @@ Script.include([ "./utils.js" ]); + +function deepCopy(v) { + return JSON.parse(JSON.stringify(v)); +} + SelectionManager = (function() { var that = {}; @@ -199,9 +204,11 @@ SelectionManager = (function() { } }; - // Return true if the given entity with `properties` is being grabbed by an avatar. + // Determine if an entity is being grabbed. // This is mostly a heuristic - there is no perfect way to know if an entity is being // grabbed. + // + // @return {boolean} true if the given entity with `properties` is being grabbed by an avatar function nonDynamicEntityIsBeingGrabbedByAvatar(properties) { if (properties.dynamic || Uuid.isNull(properties.parentID)) { return false; @@ -228,6 +235,12 @@ SelectionManager = (function() { return false; } + var entityClipboard = { + entities: {}, // Map of id -> properties for copied entities + position: { x: 0, y: 0, z: 0 }, + dimensions: { x: 0, y: 0, z: 0 }, + }; + that.duplicateSelection = function() { var entitiesToDuplicate = []; var duplicatedEntityIDs = []; @@ -305,6 +318,165 @@ SelectionManager = (function() { return duplicatedEntityIDs; }; + // Create the entities in entityProperties, maintaining parent-child relationships. + // @param entityPropertites {array} - Array of entity property objects + that.createEntities = function(entityProperties) { + var entitiesToCreate = []; + var createdEntityIDs = []; + var createdChildrenWithOldParents = []; + var originalEntityToNewEntityID = []; + + that.saveProperties(); + + for (var i = 0; i < entityProperties.length; ++i) { + var properties = entityProperties[i]; + if (properties.parentID in originalEntityToNewEntityID) { + properties.parentID = originalEntityToNewEntityID[properties.parentID]; + } else { + delete properties.parentID; + } + + delete properties.actionData; + var newEntityID = Entities.addEntity(properties); + + if (newEntityID) { + createdEntityIDs.push({ + entityID: newEntityID, + properties: properties + }); + if (properties.parentID !== Uuid.NULL) { + createdChildrenWithOldParents[newEntityID] = properties.parentID; + } + originalEntityToNewEntityID[properties.id] = newEntityID; + properties.id = newEntityID; + } + } + + return createdEntityIDs; + } + + that.cutSelectedEntities = function() { + copySelectedEntities(); + deleteSelectedEntities(); + } + + that.copySelectedEntities = function() { + var entityProperties = Entities.getMultipleEntityProperties(that.selections); + var entities = {}; + entityProperties.forEach(function(props) { + entities[props.id] = props; + }); + + function appendChildren(entityID, entities) { + var childrenIDs = Entities.getChildrenIDs(entityID); + for (var i = 0; i < childrenIDs.length; ++i) { + var id = childrenIDs[i]; + if (!(id in entities)) { + entities[id] = Entities.getEntityProperties(id); + appendChildren(id, entities); + } + } + } + + var len = entityProperties.length; + for (var i = 0; i < len; ++i) { + appendChildren(entityProperties[i].id, entities); + } + + for (var id in entities) { + var parentID = entities[id].parentID; + entities[id].root = !(parentID in entities); + } + + entityClipboard.entities = []; + + var ids = Object.keys(entities); + while (ids.length > 0) { + // Go through all remaining entities. + // If an entity does not have a parent left, move it into the list + for (var i = 0; i < ids.length; ++i) { + var id = ids[i]; + var parentID = entities[id].parentID; + if (parentID in entities) { + continue; + } + entityClipboard.entities.push(entities[id]); + delete entities[id]; + } + ids = Object.keys(entities); + } + + // Calculate size + if (entityClipboard.entities.length === 0) { + entityClipboard.dimensions = { x: 0, y: 0, z: 0 }; + entityClipboard.position = { x: 0, y: 0, z: 0 }; + } else { + var properties = entityClipboard.entities; + var brn = properties[0].boundingBox.brn; + var tfl = properties[0].boundingBox.tfl; + for (var i = 1; i < properties.length; i++) { + var bb = properties[i].boundingBox; + brn.x = Math.min(bb.brn.x, brn.x); + brn.y = Math.min(bb.brn.y, brn.y); + brn.z = Math.min(bb.brn.z, brn.z); + tfl.x = Math.max(bb.tfl.x, tfl.x); + tfl.y = Math.max(bb.tfl.y, tfl.y); + tfl.z = Math.max(bb.tfl.z, tfl.z); + } + entityClipboard.dimensions = { + x: tfl.x - brn.x, + y: tfl.y - brn.y, + z: tfl.z - brn.z + }; + entityClipboard.position = { + x: brn.x + entityClipboard.dimensions.x / 2, + y: brn.y + entityClipboard.dimensions.y / 2, + z: brn.z + entityClipboard.dimensions.z / 2 + }; + } + } + + that.pasteEntities = function() { + var dimensions = entityClipboard.dimensions; + var maxDimension = Math.max(dimensions.x, dimensions.y, dimensions.z); + var pastePosition = getPositionToCreateEntity(maxDimension); + var deltaPosition = Vec3.subtract(pastePosition, entityClipboard.position); + + var copiedProperties = [] + var ids = []; + entityClipboard.entities.forEach(function(originalProperties) { + var properties = deepCopy(originalProperties); + if (properties.root) { + properties.position = Vec3.sum(properties.position, deltaPosition); + delete properties.localPosition; + } else { + delete properties.position; + } + copiedProperties.push(properties); + }); + + var currentSelections = deepCopy(SelectionManager.selections); + + function redo(copiedProperties) { + var created = that.createEntities(copiedProperties); + var ids = []; + for (var i = 0; i < created.length; ++i) { + ids.push(created[i].entityID); + } + SelectionManager.setSelections(ids); + } + + function undo(copiedProperties) { + for (var i = 0; i < copiedProperties.length; ++i) { + Entities.deleteEntity(copiedProperties[i].id); + } + SelectionManager.setSelections(currentSelections); + } + + redo(copiedProperties); + undoHistory.pushCommand(undo, copiedProperties, redo, copiedProperties); + } + that._update = function(selectionUpdated) { var properties = null; if (that.selections.length === 0) { From 3aac294a92d9b3331fe2765032266f2844902e07 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 20 Sep 2018 16:57:22 -0700 Subject: [PATCH 087/114] optimize sockAddrBelongsToNode and reduce connection filter usage --- libraries/networking/src/LimitedNodeList.cpp | 12 +++++++++++- libraries/networking/src/LimitedNodeList.h | 2 +- libraries/networking/src/udt/Socket.cpp | 10 +++++----- libraries/networking/src/udt/Socket.h | 2 +- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index db6ed15792..7cae5d8a71 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -1187,12 +1187,22 @@ void LimitedNodeList::sendPeerQueryToIceServer(const HifiSockAddr& iceServerSock SharedNodePointer LimitedNodeList::findNodeWithAddr(const HifiSockAddr& addr) { QReadLocker locker(&_nodeMutex); - auto it = std::find_if(std::begin(_nodeHash), std::end(_nodeHash), [&](const UUIDNodePair& pair) { + auto it = std::find_if(std::begin(_nodeHash), std::end(_nodeHash), [&addr](const UUIDNodePair& pair) { return pair.second->getActiveSocket() ? (*pair.second->getActiveSocket() == addr) : false; }); return (it != std::end(_nodeHash)) ? it->second : SharedNodePointer(); } +bool LimitedNodeList::sockAddrBelongsToNode(const HifiSockAddr& sockAddr) { + QReadLocker locker(&_nodeMutex); + auto it = std::find_if(std::begin(_nodeHash), std::end(_nodeHash), [&sockAddr](const UUIDNodePair& pair) { + return pair.second->getPublicSocket() == sockAddr + || pair.second->getLocalSocket() == sockAddr + || pair.second->getSymmetricSocket() == sockAddr; + }); + return it != std::end(_nodeHash); +} + void LimitedNodeList::sendPacketToIceServer(PacketType packetType, const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerID) { auto icePacket = NLPacket::create(packetType); diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index cffc49521a..dacefa8e40 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -386,7 +386,7 @@ protected: void sendPacketToIceServer(PacketType packetType, const HifiSockAddr& iceServerSockAddr, const QUuid& clientID, const QUuid& peerRequestID = QUuid()); - bool sockAddrBelongsToNode(const HifiSockAddr& sockAddr) { return findNodeWithAddr(sockAddr) != SharedNodePointer(); } + bool sockAddrBelongsToNode(const HifiSockAddr& sockAddr); NodeHash _nodeHash; mutable QReadWriteLock _nodeMutex { QReadWriteLock::Recursive }; diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 6de43219e5..25e6fae023 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -228,13 +228,13 @@ qint64 Socket::writeDatagram(const QByteArray& datagram, const HifiSockAddr& soc return bytesWritten; } -Connection* Socket::findOrCreateConnection(const HifiSockAddr& sockAddr) { +Connection* Socket::findOrCreateConnection(const HifiSockAddr& sockAddr, bool filterCreate) { auto it = _connectionsHash.find(sockAddr); if (it == _connectionsHash.end()) { // we did not have a matching connection, time to see if we should make one - if (_connectionCreationFilterOperator && !_connectionCreationFilterOperator(sockAddr)) { + if (filterCreate && _connectionCreationFilterOperator && !_connectionCreationFilterOperator(sockAddr)) { // the connection creation filter did not allow us to create a new connection #ifdef UDT_CONNECTION_DEBUG qCDebug(networking) << "Socket::findOrCreateConnection refusing to create connection for" << sockAddr @@ -376,7 +376,7 @@ void Socket::readPendingDatagrams() { controlPacket->setReceiveTime(receiveTime); // move this control packet to the matching connection, if there is one - auto connection = findOrCreateConnection(senderSockAddr); + auto connection = findOrCreateConnection(senderSockAddr, true); if (connection) { connection->processControl(move(controlPacket)); @@ -394,7 +394,7 @@ void Socket::readPendingDatagrams() { if (!_packetFilterOperator || _packetFilterOperator(*packet)) { if (packet->isReliable()) { // if this was a reliable packet then signal the matching connection with the sequence number - auto connection = findOrCreateConnection(senderSockAddr); + auto connection = findOrCreateConnection(senderSockAddr, true); if (!connection || !connection->processReceivedSequenceNumber(packet->getSequenceNumber(), packet->getDataSize(), @@ -409,7 +409,7 @@ void Socket::readPendingDatagrams() { } if (packet->isPartOfMessage()) { - auto connection = findOrCreateConnection(senderSockAddr); + auto connection = findOrCreateConnection(senderSockAddr, true); if (connection) { connection->queueReceivedMessagePacket(std::move(packet)); } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index 30058e1d23..99266e105e 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -109,7 +109,7 @@ private slots: private: void setSystemBufferSizes(); - Connection* findOrCreateConnection(const HifiSockAddr& sockAddr); + Connection* findOrCreateConnection(const HifiSockAddr& sockAddr, bool filterCreation = false); bool socketMatchesNodeOrDomain(const HifiSockAddr& sockAddr); // privatized methods used by UDTTest - they are private since they must be called on the Socket thread From 493262052cde39fd38090960d9332d05f6602504 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Oct 2018 11:32:31 -0700 Subject: [PATCH 088/114] Remove extraneous code changes; remove QUrlAncestry code; remove extra logging --- assignment-client/src/Agent.cpp | 2 +- assignment-client/src/AssignmentClient.cpp | 11 +- interface/src/Application.cpp | 7 +- interface/src/assets/ATPAssetMigrator.cpp | 14 +- .../scripting/ClipboardScriptingInterface.h | 2 +- interface/src/ui/overlays/Web3DOverlay.cpp | 5 +- libraries/avatars/src/AvatarData.cpp | 18 +- libraries/entities/src/EntityEditFilters.cpp | 34 ++-- libraries/entities/src/EntityTree.cpp | 16 +- libraries/entities/src/EntityTree.h | 10 +- libraries/fbx/src/GLTFReader.cpp | 190 +++++++++--------- libraries/fbx/src/OBJReader.cpp | 26 +-- .../networking/src/AssetResourceRequest.cpp | 4 +- .../networking/src/FileResourceRequest.h | 8 +- .../networking/src/HTTPResourceRequest.h | 7 +- .../networking/src/NetworkAccessManager.cpp | 2 +- libraries/networking/src/ResourceCache.cpp | 19 +- libraries/networking/src/ResourceManager.cpp | 3 - libraries/networking/src/ResourceRequest.cpp | 3 +- libraries/networking/src/ResourceRequest.h | 11 +- libraries/octree/src/Octree.cpp | 21 +- libraries/octree/src/Octree.h | 11 +- libraries/qml/src/qml/OffscreenSurface.cpp | 5 - .../src/FileScriptingInterface.cpp | 4 +- .../script-engine/src/XMLHttpRequestClass.cpp | 4 +- .../EntityItemWeakPointerWithUrlAncestry.h | 31 --- libraries/shared/src/QUrlAncestry.cpp | 35 ---- libraries/shared/src/QUrlAncestry.h | 32 --- .../shared/src/ResourceRequestObserver.cpp | 16 +- .../shared/src/ResourceRequestObserver.h | 4 +- 30 files changed, 210 insertions(+), 345 deletions(-) delete mode 100644 libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h delete mode 100644 libraries/shared/src/QUrlAncestry.cpp delete mode 100644 libraries/shared/src/QUrlAncestry.h diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 1561af4d25..4490474599 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -895,7 +895,7 @@ void Agent::aboutToFinish() { { DependencyManager::get()->shutdownScripting(); } - + DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 06b3f4da86..76ff5ab2ed 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -37,7 +37,6 @@ #include "AssignmentFactory.h" #include "ResourceRequestObserver.h" - const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client"; const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000; @@ -162,7 +161,7 @@ void AssignmentClient::setUpStatusToMonitor() { void AssignmentClient::sendStatusPacketToACM() { // tell the assignment client monitor what this assignment client is doing (if anything) auto nodeList = DependencyManager::get(); - + quint8 assignmentType = Assignment::Type::AllTypes; if (_currentAssignment) { @@ -173,7 +172,7 @@ void AssignmentClient::sendStatusPacketToACM() { statusPacket->write(_childAssignmentUUID.toRfc4122()); statusPacket->writePrimitive(assignmentType); - + nodeList->sendPacket(std::move(statusPacket), _assignmentClientMonitorSocket); } @@ -259,10 +258,10 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer message) { const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); - + if (senderSockAddr.getAddress() == QHostAddress::LocalHost || senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { - + qCDebug(assignment_client) << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketType::StopNode."; QCoreApplication::quit(); } else { @@ -315,6 +314,6 @@ void AssignmentClient::assignmentCompleted() { nodeList->setOwnerType(NodeType::Unassigned); nodeList->reset(); nodeList->resetNodeInterestSet(); - + _isAssigned = false; } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 242445b0fe..e515a22403 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -170,7 +170,6 @@ #include "ModelPackager.h" #include "scripting/Audio.h" #include "networking/CloseEventSender.h" -#include "QUrlAncestry.h" #include "scripting/TestScriptingInterface.h" #include "scripting/AssetMappingsScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" @@ -947,6 +946,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); @@ -1783,7 +1783,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo updateHeartbeat(); QTimer* settingsTimer = new QTimer(); moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{ - // This needs to run on the settings thread, so we need to pass the `settingsTimer` as the + // This needs to run on the settings thread, so we need to pass the `settingsTimer` as the // receiver object, otherwise it will run on the application thread and trigger a warning // about trying to kill the timer on the main thread. connect(qApp, &Application::beforeAboutToQuit, settingsTimer, [this, settingsTimer]{ @@ -5029,7 +5029,8 @@ bool Application::importEntities(const QString& urlOrFilename, const bool isObse bool success = false; _entityClipboard->withWriteLock([&] { _entityClipboard->eraseAllOctreeElements(); - success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId, QUrlAncestry()); + + success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId); if (success) { _entityClipboard->reaverageOctreeElements(); } diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index 6912c69db8..be7f2014cc 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -203,7 +203,7 @@ void ATPAssetMigrator::loadEntityServerFile() { void ATPAssetMigrator::migrateResource(ResourceRequest* request) { // use an asset client to upload the asset auto assetClient = DependencyManager::get(); - + auto upload = assetClient->createUpload(request->getData()); // add this URL to our hash of AssetUpload to original URL @@ -243,7 +243,7 @@ void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& h } checkIfFinished(); - + upload->deleteLater(); } @@ -299,24 +299,24 @@ void ATPAssetMigrator::checkIfFinished() { bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) { static bool hasAskedForCompleteMigration { false }; static bool wantsCompleteMigration { false }; - + if (!hasAskedForCompleteMigration) { // this is the first resource migration - ask the user if they just want to migrate everything static const QString COMPLETE_MIGRATION_TEXT { "Do you want to migrate all assets found in this entity-server file?\n"\ "Select \"Yes\" to upload all discovered assets to the current asset-server immediately.\n"\ "Select \"No\" to be prompted for each discovered asset." }; - + auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE, COMPLETE_MIGRATION_TEXT, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - + if (button == QMessageBox::Yes) { wantsCompleteMigration = true; } - + hasAskedForCompleteMigration = true; } - + if (wantsCompleteMigration) { return true; } else { diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 535ccfd5ab..60b6ca2e03 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -64,7 +64,7 @@ public: * @returns {boolean} true if the export was successful, otherwise false. */ Q_INVOKABLE bool exportEntities(const QString& filename, const QVector& entityIDs); - + /**jsdoc * Export the entities with centers within a cube to a JSON file. * @function Clipboard.exportEntities diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 53505c2013..084615cae2 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -61,7 +61,6 @@ #include "AboutUtil.h" #include "ResourceRequestObserver.h" - static int MAX_WINDOW_SIZE = 4096; static const float METERS_TO_INCHES = 39.3701f; static const float OPAQUE_ALPHA_THRESHOLD = 0.99f; @@ -539,7 +538,7 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) { * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. * * @property {string} name="" - A friendly name for the overlay. - * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and + * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and * start. * @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a * parentID set, otherwise the same value as position. @@ -564,7 +563,7 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) { * @property {string} url - The URL of the Web page to display. * @property {string} scriptURL="" - The URL of a JavaScript file to inject into the Web page. * @property {number} dpi=30 - The dots per inch to display the Web page at, on the overlay. - * @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms: + * @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms: * scale, size. * @property {number} maxFPS=10 - The maximum update rate for the Web overlay content, in frames/second. * @property {boolean} showKeyboardFocusHighlight=true - If true, the Web overlay is highlighted when it has diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 753707f0fe..032ffe25f7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -380,7 +380,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent } else { AVATAR_MEMCPY(_globalPosition); } - + int numBytes = destinationBuffer - startSection; @@ -648,7 +648,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent if (!data.translationIsDefaultPose) { if (sendAll || last.translationIsDefaultPose || (!cullSmallChanges && last.translation != data.translation) || (cullSmallChanges && glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation)) { - + validity |= (1 << validityBit); #ifdef WANT_DEBUG translationSentCount++; @@ -1055,7 +1055,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { auto newHasProceduralEyeFaceMovement = oneAtBit16(bitItems, PROCEDURAL_EYE_FACE_MOVEMENT); auto newHasProceduralBlinkFaceMovement = oneAtBit16(bitItems, PROCEDURAL_BLINK_FACE_MOVEMENT); - + bool keyStateChanged = (_keyState != newKeyState); bool handStateChanged = (_handState != newHandState); bool faceStateChanged = (_headData->_isFaceTrackerConnected != newFaceTrackerConnected); @@ -1527,7 +1527,7 @@ glm::vec3 AvatarData::getJointTranslation(int index) const { } glm::vec3 AvatarData::getJointTranslation(const QString& name) const { - // Can't do this, because the lock needs to cover the entire set of logic. In theory, the joints could change + // Can't do this, because the lock needs to cover the entire set of logic. In theory, the joints could change // on another thread in between the call to getJointIndex and getJointTranslation // return getJointTranslation(getJointIndex(name)); return readLockWithNamedJointIndex(name, [this](int index) { @@ -1608,7 +1608,7 @@ bool AvatarData::isJointDataValid(const QString& name) const { // return isJointDataValid(getJointIndex(name)); return readLockWithNamedJointIndex(name, false, [&](int index) { - // This is technically superfluous.... the lambda is only called if index is a valid + // This is technically superfluous.... the lambda is only called if index is a valid // offset for _jointData. Nevertheless, it would be confusing to leave the lamdba as // `return true` return index < _jointData.size(); @@ -1827,7 +1827,7 @@ qint64 AvatarData::packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice if (traitVersion > AvatarTraits::DEFAULT_TRAIT_VERSION) { bytesWritten += destination.writePrimitive(traitVersion); } - + AvatarTraits::TraitWireSize encodedURLSize = encodedSkeletonURL.size(); bytesWritten += destination.writePrimitive(encodedURLSize); @@ -1936,7 +1936,7 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { if (expanded == _skeletonModelURL) { return; } - + _skeletonModelURL = expanded; qCDebug(avatars) << "Changing skeleton model for avatar" << getSessionUUID() << "to" << _skeletonModelURL.toString(); @@ -2163,7 +2163,7 @@ void AvatarData::updateJointMappings() { if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { //// - // TODO: Should we rely upon HTTPResourceRequest instead? + // TODO: Should we rely upon HTTPResourceRequest for ResourceRequestObserver instead? // HTTPResourceRequest::doSend() covers all of the following and // then some. It doesn't cover the connect() call, so we may // want to add a HTTPResourceRequest::doSend() method that does @@ -2402,7 +2402,7 @@ QJsonObject AvatarData::toJson() const { for (auto entityID : _avatarEntityData.keys()) { QVariantMap entityData; QUuid newId = _avatarEntityForRecording.size() == _avatarEntityData.size() ? _avatarEntityForRecording.values()[entityCount++] : entityID; - entityData.insert("id", newId); + entityData.insert("id", newId); entityData.insert("properties", _avatarEntityData.value(entityID).toBase64()); avatarEntityJson.push_back(QVariant(entityData).toJsonObject()); } diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index c88ae138bf..4865c0ba1e 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -24,7 +24,7 @@ QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { for (auto id : zoneIDs) { if (!id.isInvalidID()) { // for now, look it up in the tree (soon we need to cache or similar?) - EntityItemPointer itemPtr = _tree->findEntityByEntityItemID(id); + EntityItemPointer itemPtr = _tree->findEntityByEntityItemID(id); auto zone = std::dynamic_pointer_cast(itemPtr); if (!zone) { // TODO: maybe remove later? @@ -33,7 +33,7 @@ QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { zones.append(id); } } else { - // the null id is the global filter we put in the domain server's + // the null id is the global filter we put in the domain server's // advanced entity server settings zones.append(id); } @@ -43,7 +43,7 @@ QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) { - + // get the ids of all the zones (plus the global entity edit filter) that the position // lies within auto zoneIDs = getZonesByPosition(position); @@ -51,12 +51,12 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper if (!itemID.isInvalidID() && id == itemID) { continue; } - - // get the filter pair, etc... + + // get the filter pair, etc... _lock.lockForRead(); FilterData filterData = _filterDataMap.value(id); _lock.unlock(); - + if (filterData.valid()) { if (filterData.rejectAll) { return false; @@ -153,13 +153,13 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper // otherwise, assume it wants to pass all properties propertiesOut = propertiesIn; wasChanged = false; - + } else { return false; } } } - // if we made it here, + // if we made it here, return true; } @@ -175,23 +175,23 @@ void EntityEditFilters::removeFilter(EntityItemID entityID) { void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) { QUrl scriptURL(filterURL); - - // setting it to an empty string is same as removing + + // setting it to an empty string is same as removing if (filterURL.size() == 0) { removeFilter(entityID); return; } - + // The following should be abstracted out for use in Agent.cpp (and maybe later AvatarMixer.cpp) if (scriptURL.scheme().isEmpty() || (scriptURL.scheme() == URL_SCHEME_FILE)) { qWarning() << "Cannot load script from local filesystem, because assignment may be on a different computer."; scriptRequestFinished(entityID); return; } - + // first remove any existing info for this entity removeFilter(entityID); - + // reject all edits until we load the script FilterData filterData; filterData.rejectAll = true; @@ -199,7 +199,7 @@ void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) { _lock.lockForWrite(); _filterDataMap.insert(entityID, filterData); _lock.unlock(); - + auto scriptRequest = DependencyManager::get()->createResourceRequest( this, scriptURL, true, -1, "EntityEditFilters::addFilter"); if (!scriptRequest) { @@ -265,7 +265,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { FilterData filterData; filterData.engine = engine; filterData.rejectAll = false; - + // define the uncaughtException function QScriptEngine& engineRef = *engine; filterData.uncaughtExceptions = [&engineRef, urlString]() { return hadUncaughtExceptions(engineRef, urlString); }; @@ -369,11 +369,11 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { _lock.unlock(); qDebug() << "script request filter processed for entity id " << entityID; - + emit filterAdded(entityID, true); return; } - } + } } else if (scriptRequest) { const QString urlString = scriptRequest->getUrl().toString(); qCritical() << "Failed to download script at" << urlString; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 8992157681..0b3b8abba2 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -38,8 +38,6 @@ #include "LogHandler.h" #include "EntityEditFilters.h" #include "EntityDynamicFactoryInterface.h" -#include "QUrlAncestry.h" - static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50; const float EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME = 60 * 60; // 1 hour @@ -100,7 +98,7 @@ EntityTree::~EntityTree() { eraseAllOctreeElements(false); } -void EntityTree::setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist) { +void EntityTree::setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist) { _entityScriptSourceWhitelist = entityScriptSourceWhitelist.split(',', QString::SkipEmptyParts); } @@ -862,7 +860,7 @@ float findRayIntersectionSortingOp(const OctreeElementPointer& element, void* ex EntityItemID EntityTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, QVector entityIdsToInclude, QVector entityIdsToDiscard, - bool visibleOnly, bool collidableOnly, bool precisionPicking, + bool visibleOnly, bool collidableOnly, bool precisionPicking, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, Octree::lockType lockType, bool* accurateResult) { @@ -1353,7 +1351,7 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity key = sent.second; } - QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; + QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256); bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8())); @@ -1797,7 +1795,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c if (newEntity) { newEntity->markAsChangedOnServer(); notifyNewlyCreatedEntity(*newEntity, senderNode); - + startLogging = usecTimestampNow(); if (wantEditLogging()) { qCDebug(entities) << "User [" << senderNode->getUUID() << "] added entity. ID:" @@ -1822,7 +1820,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } } else { HIFI_FCDEBUG(entities(), "Edit failed. [" << message.getType() <<"] " << - "entity id:" << entityItemID << + "entity id:" << entityItemID << "existingEntity pointer:" << existingEntity.get()); } } @@ -2043,7 +2041,7 @@ bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) { if (hasSomethingNewer) { int elapsed = usecTimestampNow() - considerEntitiesSince; int difference = considerEntitiesSince - sinceTime; - qCDebug(entities) << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime + qCDebug(entities) << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime << "considerEntitiesSince:" << considerEntitiesSince << "elapsed:" << elapsed << "difference:" << difference; } #endif @@ -2495,7 +2493,7 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer return true; } -bool EntityTree::readFromMap(QVariantMap& map, const QUrlAncestry& ancestry) { +bool EntityTree::readFromMap(QVariantMap& map) { // These are needed to deal with older content (before adding inheritance modes) int contentVersion = map["Version"].toInt(); bool needsConversion = (contentVersion < (int)EntityVersion::ZoneLightInheritModes); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8c787f8eb8..2f971b8566 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -22,8 +22,6 @@ #include "EntityTreeElement.h" #include "DeleteEntityOperator.h" #include "MovingEntitiesOperator.h" -#include "QUrlAncestry.h" - class EntityTree; using EntityTreePointer = std::shared_ptr; @@ -96,7 +94,7 @@ public: virtual EntityItemID findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, QVector entityIdsToInclude, QVector entityIdsToDiscard, - bool visibleOnly, bool collidableOnly, bool precisionPicking, + bool visibleOnly, bool collidableOnly, bool precisionPicking, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); @@ -172,7 +170,7 @@ public: void addNewlyCreatedHook(NewlyCreatedEntityHook* hook); void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook); - bool hasAnyDeletedEntities() const { + bool hasAnyDeletedEntities() const { QReadLocker locker(&_recentlyDeletedEntitiesLock); return _recentlyDeletedEntityItemIDs.size() > 0; } @@ -180,7 +178,7 @@ public: bool hasEntitiesDeletedSince(quint64 sinceTime); static quint64 getAdjustedConsiderSince(quint64 sinceTime); - QMultiMap getRecentlyDeletedEntityIDs() const { + QMultiMap getRecentlyDeletedEntityIDs() const { QReadLocker locker(&_recentlyDeletedEntitiesLock); return _recentlyDeletedEntityItemIDs; } @@ -225,7 +223,7 @@ public: virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, bool skipThoseWithBadParents) override; - virtual bool readFromMap(QVariantMap& entityDescription, const QUrlAncestry& ancestry = {}) override; + virtual bool readFromMap(QVariantMap& entityDescription) override; glm::vec3 getContentsDimensions(); float getContentsLargestDimension(); diff --git a/libraries/fbx/src/GLTFReader.cpp b/libraries/fbx/src/GLTFReader.cpp index 89592c399c..b93dc3541b 100644 --- a/libraries/fbx/src/GLTFReader.cpp +++ b/libraries/fbx/src/GLTFReader.cpp @@ -40,7 +40,7 @@ GLTFReader::GLTFReader() { } -bool GLTFReader::getStringVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getStringVal(const QJsonObject& object, const QString& fieldname, QString& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isString()); if (_defined) { @@ -60,7 +60,7 @@ bool GLTFReader::getBoolVal(const QJsonObject& object, const QString& fieldname, return _defined; } -bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname, int& value, QMap& defined) { bool _defined = (object.contains(fieldname) && !object[fieldname].isNull()); if (_defined) { @@ -70,7 +70,7 @@ bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname, return _defined; } -bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldname, double& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isDouble()); if (_defined) { @@ -79,7 +79,7 @@ bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldnam defined.insert(fieldname, _defined); return _defined; } -bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldname, QJsonObject& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isObject()); if (_defined) { @@ -89,7 +89,7 @@ bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldnam return _defined; } -bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldname, QVector& values, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -104,7 +104,7 @@ bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldn return _defined; } -bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fieldname, QVector& values, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -119,7 +119,7 @@ bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fie return _defined; } -bool GLTFReader::getObjectArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getObjectArrayVal(const QJsonObject& object, const QString& fieldname, QJsonArray& objects, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -229,7 +229,7 @@ bool GLTFReader::setAsset(const QJsonObject& object) { QJsonObject jsAsset; bool isAssetDefined = getObjectVal(object, "asset", jsAsset, _file.defined); if (isAssetDefined) { - if (!getStringVal(jsAsset, "version", _file.asset.version, + if (!getStringVal(jsAsset, "version", _file.asset.version, _file.asset.defined) || _file.asset.version != "2.0") { return false; } @@ -241,7 +241,7 @@ bool GLTFReader::setAsset(const QJsonObject& object) { bool GLTFReader::addAccessor(const QJsonObject& object) { GLTFAccessor accessor; - + getIntVal(object, "bufferView", accessor.bufferView, accessor.defined); getIntVal(object, "byteOffset", accessor.byteOffset, accessor.defined); getIntVal(object, "componentType", accessor.componentType, accessor.defined); @@ -261,7 +261,7 @@ bool GLTFReader::addAccessor(const QJsonObject& object) { bool GLTFReader::addAnimation(const QJsonObject& object) { GLTFAnimation animation; - + QJsonArray channels; if (getObjectArrayVal(object, "channels", channels, animation.defined)) { foreach(const QJsonValue & v, channels) { @@ -272,7 +272,7 @@ bool GLTFReader::addAnimation(const QJsonObject& object) { if (getObjectVal(v.toObject(), "target", jsChannel, channel.defined)) { getIntVal(jsChannel, "node", channel.target.node, channel.target.defined); getIntVal(jsChannel, "path", channel.target.path, channel.target.defined); - } + } } } } @@ -291,7 +291,7 @@ bool GLTFReader::addAnimation(const QJsonObject& object) { } } } - + _file.animations.push_back(animation); return true; @@ -299,20 +299,20 @@ bool GLTFReader::addAnimation(const QJsonObject& object) { bool GLTFReader::addBufferView(const QJsonObject& object) { GLTFBufferView bufferview; - + getIntVal(object, "buffer", bufferview.buffer, bufferview.defined); getIntVal(object, "byteLength", bufferview.byteLength, bufferview.defined); getIntVal(object, "byteOffset", bufferview.byteOffset, bufferview.defined); getIntVal(object, "target", bufferview.target, bufferview.defined); - + _file.bufferviews.push_back(bufferview); - + return true; } bool GLTFReader::addBuffer(const QJsonObject& object) { GLTFBuffer buffer; - + getIntVal(object, "byteLength", buffer.byteLength, buffer.defined); if (getStringVal(object, "uri", buffer.uri, buffer.defined)) { if (!readBinary(buffer.uri, buffer.blob)) { @@ -320,13 +320,13 @@ bool GLTFReader::addBuffer(const QJsonObject& object) { } } _file.buffers.push_back(buffer); - + return true; } bool GLTFReader::addCamera(const QJsonObject& object) { GLTFCamera camera; - + QJsonObject jsPerspective; QJsonObject jsOrthographic; QString type; @@ -346,28 +346,28 @@ bool GLTFReader::addCamera(const QJsonObject& object) { } else if (getStringVal(object, "type", type, camera.defined)) { camera.type = getCameraType(type); } - + _file.cameras.push_back(camera); - + return true; } bool GLTFReader::addImage(const QJsonObject& object) { GLTFImage image; - + QString mime; getStringVal(object, "uri", image.uri, image.defined); if (getStringVal(object, "mimeType", mime, image.defined)) { image.mimeType = getImageMimeType(mime); } getIntVal(object, "bufferView", image.bufferView, image.defined); - + _file.images.push_back(image); return true; } -bool GLTFReader::getIndexFromObject(const QJsonObject& object, const QString& field, +bool GLTFReader::getIndexFromObject(const QJsonObject& object, const QString& field, int& outidx, QMap& defined) { QJsonObject subobject; if (getObjectVal(object, field, subobject, defined)) { @@ -393,20 +393,20 @@ bool GLTFReader::addMaterial(const QJsonObject& object) { getDoubleVal(object, "alphaCutoff", material.alphaCutoff, material.defined); QJsonObject jsMetallicRoughness; if (getObjectVal(object, "pbrMetallicRoughness", jsMetallicRoughness, material.defined)) { - getDoubleArrayVal(jsMetallicRoughness, "baseColorFactor", - material.pbrMetallicRoughness.baseColorFactor, + getDoubleArrayVal(jsMetallicRoughness, "baseColorFactor", + material.pbrMetallicRoughness.baseColorFactor, material.pbrMetallicRoughness.defined); - getIndexFromObject(jsMetallicRoughness, "baseColorTexture", - material.pbrMetallicRoughness.baseColorTexture, + getIndexFromObject(jsMetallicRoughness, "baseColorTexture", + material.pbrMetallicRoughness.baseColorTexture, material.pbrMetallicRoughness.defined); - getDoubleVal(jsMetallicRoughness, "metallicFactor", - material.pbrMetallicRoughness.metallicFactor, + getDoubleVal(jsMetallicRoughness, "metallicFactor", + material.pbrMetallicRoughness.metallicFactor, material.pbrMetallicRoughness.defined); - getDoubleVal(jsMetallicRoughness, "roughnessFactor", - material.pbrMetallicRoughness.roughnessFactor, + getDoubleVal(jsMetallicRoughness, "roughnessFactor", + material.pbrMetallicRoughness.roughnessFactor, material.pbrMetallicRoughness.defined); - getIndexFromObject(jsMetallicRoughness, "metallicRoughnessTexture", - material.pbrMetallicRoughness.metallicRoughnessTexture, + getIndexFromObject(jsMetallicRoughness, "metallicRoughnessTexture", + material.pbrMetallicRoughness.metallicRoughnessTexture, material.pbrMetallicRoughness.defined); } _file.materials.push_back(material); @@ -428,7 +428,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) { getIntVal(jsPrimitive, "mode", primitive.mode, primitive.defined); getIntVal(jsPrimitive, "indices", primitive.indices, primitive.defined); getIntVal(jsPrimitive, "material", primitive.material, primitive.defined); - + QJsonObject jsAttributes; if (getObjectVal(jsPrimitive, "attributes", jsAttributes, primitive.defined)) { QStringList attrKeys = jsAttributes.keys(); @@ -455,7 +455,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) { primitive.targets.push_back(target); } } - } + } mesh.primitives.push_back(primitive); } } @@ -469,7 +469,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) { bool GLTFReader::addNode(const QJsonObject& object) { GLTFNode node; - + getStringVal(object, "name", node.name, node.defined); getIntVal(object, "camera", node.camera, node.defined); getIntVal(object, "mesh", node.mesh, node.defined); @@ -524,10 +524,10 @@ bool GLTFReader::addSkin(const QJsonObject& object) { } bool GLTFReader::addTexture(const QJsonObject& object) { - GLTFTexture texture; + GLTFTexture texture; getIntVal(object, "sampler", texture.sampler, texture.defined); getIntVal(object, "source", texture.source, texture.defined); - + _file.textures.push_back(texture); return true; @@ -535,7 +535,7 @@ bool GLTFReader::addTexture(const QJsonObject& object) { bool GLTFReader::parseGLTF(const QByteArray& model) { PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr); - + QJsonDocument d = QJsonDocument::fromJson(model); QJsonObject jsFile = d.object(); @@ -707,25 +707,25 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { foreach(int child, node.children) nodeDependencies[child].push_back(nodecount); nodecount++; } - + nodecount = 0; foreach(auto &node, _file.nodes) { // collect node transform - _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); + _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); if (nodeDependencies[nodecount].size() == 1) { int parentidx = nodeDependencies[nodecount][0]; while (true) { // iterate parents // collect parents transforms - _file.nodes[nodecount].transforms.push_back(getModelTransform(_file.nodes[parentidx])); + _file.nodes[nodecount].transforms.push_back(getModelTransform(_file.nodes[parentidx])); if (nodeDependencies[parentidx].size() == 1) { parentidx = nodeDependencies[parentidx][0]; } else break; } } - + nodecount++; } - + //Build default joints geometry.joints.resize(1); geometry.joints[0].isFree = false; @@ -756,7 +756,7 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { setFBXMaterial(fbxMaterial, _file.materials[i]); } - + nodecount = 0; // Build meshes @@ -789,11 +789,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { QVector raw_vertices; QVector raw_normals; - bool success = addArrayOfType(indicesBuffer.blob, - indicesBufferview.byteOffset + indicesAccBoffset, - indicesAccessor.count, - part.triangleIndices, - indicesAccessor.type, + bool success = addArrayOfType(indicesBuffer.blob, + indicesBufferview.byteOffset + indicesAccBoffset, + indicesAccessor.count, + part.triangleIndices, + indicesAccessor.type, indicesAccessor.componentType); if (!success) { @@ -813,10 +813,10 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0; if (key == "POSITION") { QVector vertices; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, vertices, - accessor.type, + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, vertices, + accessor.type, accessor.componentType); if (!success) { qWarning(modelformat) << "There was a problem reading glTF POSITION data for model " << _url; @@ -827,11 +827,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { } } else if (key == "NORMAL") { QVector normals; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - normals, - accessor.type, + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, + normals, + accessor.type, accessor.componentType); if (!success) { qWarning(modelformat) << "There was a problem reading glTF NORMAL data for model " << _url; @@ -842,11 +842,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { } } else if (key == "TEXCOORD_0") { QVector texcoords; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - texcoords, - accessor.type, + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, + texcoords, + accessor.type, accessor.componentType); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_0 data for model " << _url; @@ -857,11 +857,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { } } else if (key == "TEXCOORD_1") { QVector texcoords; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - texcoords, - accessor.type, + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, + texcoords, + accessor.type, accessor.componentType); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_1 data for model " << _url; @@ -888,8 +888,8 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { mesh.meshExtents.addPoint(vertex); geometry.meshExtents.addPoint(vertex); } - - // since mesh.modelTransform seems to not have any effect I apply the transformation the model + + // since mesh.modelTransform seems to not have any effect I apply the transformation the model for (int h = 0; h < mesh.vertices.size(); h++) { glm::vec4 ver = glm::vec4(mesh.vertices[h], 1); if (node.transforms.size() > 0) { @@ -901,18 +901,18 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { mesh.meshIndex = geometry.meshes.size(); FBXReader::buildModelMesh(mesh, url.toString()); } - + } nodecount++; } - + return true; } -FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping, +FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping, const QUrl& url, bool loadLightmaps, float lightmapLevel) { - + _url = url; // Normalize url for local files @@ -928,10 +928,10 @@ FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping FBXGeometry& geometry = *geometryPtr; buildGeometry(geometry, url); - + //fbxDebugDump(geometry); return geometryPtr; - + } bool GLTFReader::readBinary(const QString& url, QByteArray& outdata) { @@ -940,7 +940,7 @@ bool GLTFReader::readBinary(const QString& url, QByteArray& outdata) { qCDebug(modelformat) << "binaryUrl: " << binaryUrl << " OriginalUrl: " << _url; bool success; std::tie(success, outdata) = requestData(binaryUrl); - + return success; } @@ -1000,7 +1000,7 @@ QNetworkReply* GLTFReader::request(QUrl& url, bool isTest) { FBXTexture GLTFReader::getFBXTexture(const GLTFTexture& texture) { FBXTexture fbxtex = FBXTexture(); fbxtex.texcoordSet = 0; - + if (texture.defined["source"]) { QString url = _file.images[texture.source].uri; QString fname = QUrl(url).fileName(); @@ -1020,10 +1020,10 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia if (material.defined["name"]) { fbxmat.name = fbxmat.materialID = material.name; } - + if (material.defined["emissiveFactor"] && material.emissiveFactor.size() == 3) { - glm::vec3 emissive = glm::vec3(material.emissiveFactor[0], - material.emissiveFactor[1], + glm::vec3 emissive = glm::vec3(material.emissiveFactor[0], + material.emissiveFactor[1], material.emissiveFactor[2]); fbxmat._material->setEmissive(emissive); } @@ -1032,12 +1032,12 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia fbxmat.emissiveTexture = getFBXTexture(_file.textures[material.emissiveTexture]); fbxmat.useEmissiveMap = true; } - + if (material.defined["normalTexture"]) { fbxmat.normalTexture = getFBXTexture(_file.textures[material.normalTexture]); fbxmat.useNormalMap = true; } - + if (material.defined["occlusionTexture"]) { fbxmat.occlusionTexture = getFBXTexture(_file.textures[material.occlusionTexture]); fbxmat.useOcclusionMap = true; @@ -1045,7 +1045,7 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia if (material.defined["pbrMetallicRoughness"]) { fbxmat.isPBSMaterial = true; - + if (material.pbrMetallicRoughness.defined["metallicFactor"]) { fbxmat.metallic = material.pbrMetallicRoughness.metallicFactor; } @@ -1063,23 +1063,23 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia if (material.pbrMetallicRoughness.defined["roughnessFactor"]) { fbxmat._material->setRoughness(material.pbrMetallicRoughness.roughnessFactor); } - if (material.pbrMetallicRoughness.defined["baseColorFactor"] && + if (material.pbrMetallicRoughness.defined["baseColorFactor"] && material.pbrMetallicRoughness.baseColorFactor.size() == 4) { - glm::vec3 dcolor = glm::vec3(material.pbrMetallicRoughness.baseColorFactor[0], - material.pbrMetallicRoughness.baseColorFactor[1], + glm::vec3 dcolor = glm::vec3(material.pbrMetallicRoughness.baseColorFactor[0], + material.pbrMetallicRoughness.baseColorFactor[1], material.pbrMetallicRoughness.baseColorFactor[2]); fbxmat.diffuseColor = dcolor; fbxmat._material->setAlbedo(dcolor); fbxmat._material->setOpacity(material.pbrMetallicRoughness.baseColorFactor[3]); - } + } } } template -bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count, +bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count, QVector& outarray, int accessorType) { - + QDataStream blobstream(bin); blobstream.setByteOrder(QDataStream::LittleEndian); blobstream.setVersion(QDataStream::Qt_5_9); @@ -1134,9 +1134,9 @@ bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count, return true; } template -bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count, +bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count, QVector& outarray, int accessorType, int componentType) { - + switch (componentType) { case GLTFAccessorComponentType::BYTE: {} case GLTFAccessorComponentType::UNSIGNED_BYTE: { @@ -1158,8 +1158,8 @@ bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count return false; } -void GLTFReader::retriangulate(const QVector& inIndices, const QVector& in_vertices, - const QVector& in_normals, QVector& outIndices, +void GLTFReader::retriangulate(const QVector& inIndices, const QVector& in_vertices, + const QVector& in_normals, QVector& outIndices, QVector& out_vertices, QVector& out_normals) { for (int i = 0; i < inIndices.size(); i = i + 3) { diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 00109e9030..7a2cbff497 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -15,7 +15,7 @@ #include "OBJReader.h" #include // .obj files are not locale-specific. The C/ASCII charset applies. -#include +#include #include #include @@ -263,16 +263,16 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { default: materials[matName] = currentMaterial; #ifdef WANT_DEBUG - qCDebug(modelformat) << + qCDebug(modelformat) << "OBJ Reader Last material illumination model:" << currentMaterial.illuminationModel << - " shininess:" << currentMaterial.shininess << + " shininess:" << currentMaterial.shininess << " opacity:" << currentMaterial.opacity << - " diffuse color:" << currentMaterial.diffuseColor << - " specular color:" << currentMaterial.specularColor << - " emissive color:" << currentMaterial.emissiveColor << - " diffuse texture:" << currentMaterial.diffuseTextureFilename << - " specular texture:" << currentMaterial.specularTextureFilename << - " emissive texture:" << currentMaterial.emissiveTextureFilename << + " diffuse color:" << currentMaterial.diffuseColor << + " specular color:" << currentMaterial.specularColor << + " emissive color:" << currentMaterial.emissiveColor << + " diffuse texture:" << currentMaterial.diffuseTextureFilename << + " specular texture:" << currentMaterial.specularTextureFilename << + " emissive texture:" << currentMaterial.emissiveTextureFilename << " bump texture:" << currentMaterial.bumpTextureFilename << " opacity texture:" << currentMaterial.opacityTextureFilename; #endif @@ -352,7 +352,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } } } -} +} void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions) { // Texture options reference http://paulbourke.net/dataformats/mtl/ @@ -794,7 +794,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m n0 = checked_at(normals, face.normalIndices[0]); n1 = checked_at(normals, face.normalIndices[1]); n2 = checked_at(normals, face.normalIndices[2]); - } else { + } else { // generate normals from triangle plane if not provided n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); } @@ -924,7 +924,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m bool applyNonMetallic = false; bool fresnelOn = false; - // Illumination model reference http://paulbourke.net/dataformats/mtl/ + // Illumination model reference http://paulbourke.net/dataformats/mtl/ switch (objMaterial.illuminationModel) { case 0: // Color on and Ambient off // We don't support ambient = do nothing? @@ -968,7 +968,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m case 10: // Casts shadows onto invisible surfaces // Do nothing? break; - } + } if (applyTransparency) { fbxMaterial.opacity = std::max(fbxMaterial.opacity, ILLUMINATION_MODEL_MIN_OPACITY); diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 23ab1548a0..6f5b13f98d 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -39,7 +39,7 @@ AssetResourceRequest::~AssetResourceRequest() { if (_assetMappingRequest) { _assetMappingRequest->deleteLater(); } - + if (_assetRequest) { _assetRequest->deleteLater(); } @@ -82,7 +82,7 @@ void AssetResourceRequest::requestMappingForPath(const AssetUtils::AssetPath& pa // make sure we'll hear about the result of the get mapping request connect(_assetMappingRequest, &GetMappingRequest::finished, this, [this, path](GetMappingRequest* request){ auto statTracker = DependencyManager::get(); - + Q_ASSERT(_state == InProgress); Q_ASSERT(request == _assetMappingRequest); diff --git a/libraries/networking/src/FileResourceRequest.h b/libraries/networking/src/FileResourceRequest.h index 12b5b7d72e..fa9a1617a9 100644 --- a/libraries/networking/src/FileResourceRequest.h +++ b/libraries/networking/src/FileResourceRequest.h @@ -12,19 +12,19 @@ #ifndef hifi_FileResourceRequest_h #define hifi_FileResourceRequest_h -#include "ResourceRequest.h" -#include "QUrlAncestry.h" +#include +#include "ResourceRequest.h" class FileResourceRequest : public ResourceRequest { Q_OBJECT public: FileResourceRequest( - const QUrlAncestry& urlAncestry, + const QUrl& url, const bool isObservable = true, const qint64 callerId = -1, const QString& extra = "" - ) : ResourceRequest(urlAncestry, isObservable, callerId, extra) { } + ) : ResourceRequest(url, isObservable, callerId, extra) { } protected: virtual void doSend() override; diff --git a/libraries/networking/src/HTTPResourceRequest.h b/libraries/networking/src/HTTPResourceRequest.h index 41f605e856..c725934f2f 100644 --- a/libraries/networking/src/HTTPResourceRequest.h +++ b/libraries/networking/src/HTTPResourceRequest.h @@ -13,21 +13,20 @@ #define hifi_HTTPResourceRequest_h #include +#include #include #include "ResourceRequest.h" -#include "QUrlAncestry.h" - class HTTPResourceRequest : public ResourceRequest { Q_OBJECT public: HTTPResourceRequest( - const QUrlAncestry& urlAncestry, + const QUrl& url, const bool isObservable = true, const qint64 callerId = -1, const QString& = "" - ) : ResourceRequest(urlAncestry, isObservable, callerId) { } + ) : ResourceRequest(url, isObservable, callerId) { } ~HTTPResourceRequest(); protected: diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index c5229d65ac..f73243e675 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -22,7 +22,7 @@ QNetworkAccessManager& NetworkAccessManager::getInstance() { if (!networkAccessManagers.hasLocalData()) { networkAccessManagers.setLocalData(new QNetworkAccessManager()); } - + return *networkAccessManagers.localData(); } diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 186addbd86..f2fbe41804 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -320,7 +320,7 @@ QVariantList ResourceCache::getResourceList() { return list; } - + void ResourceCache::setRequestLimit(uint32_t limit) { auto sharedItems = DependencyManager::get(); sharedItems->setRequestLimit(limit); @@ -337,7 +337,6 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& QReadLocker locker(&_resourcesLock); resource = _resources.value(url).lock(); } - if (resource) { removeUnusedResource(resource); } @@ -382,7 +381,7 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) return; } reserveUnusedResource(resource->getBytes()); - + resource->setLRUKey(++_lastLRUKey); { @@ -411,7 +410,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { _unusedResourcesSize + resourceSize > _unusedResourcesMaxSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - + it.value()->setCache(nullptr); auto size = it.value()->getBytes(); @@ -477,7 +476,7 @@ void ResourceCache::updateTotalSize(const qint64& deltaSize) { emit dirty(); } - + QList> ResourceCache::getLoadingRequests() { return DependencyManager::get()->getLoadingRequests(); } @@ -592,7 +591,7 @@ void Resource::refresh() { _request = nullptr; ResourceCache::requestCompleted(_self); } - + _activeUrl = _url; init(); ensureLoading(); @@ -606,7 +605,7 @@ void Resource::allReferencesCleared() { } if (_cache && isCacheable()) { - // create and reinsert new shared pointer + // create and reinsert new shared pointer QSharedPointer self(this, &Resource::deleter); setSelf(self); reinsert(); @@ -631,10 +630,10 @@ void Resource::init(bool resetLoaded) { _loaded = false; } _attempts = 0; - + if (_url.isEmpty()) { _startedLoading = _loaded = true; - + } else if (!(_url.isValid())) { _startedLoading = _failedToLoad = true; } @@ -756,7 +755,7 @@ void Resource::handleReplyFinished() { } else { handleFailedRequest(result); } - + _request->disconnect(this); _request->deleteLater(); _request = nullptr; diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index d9774e3437..9539a10c2d 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -26,7 +26,6 @@ #include "NetworkAccessManager.h" #include "NetworkLogging.h" - ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(atpSupportEnabled) { _thread.setObjectName("Resource Manager Thread"); @@ -125,7 +124,6 @@ ResourceRequest* ResourceManager::createResourceRequest( ResourceRequest* request = nullptr; - qDebug() << "!!!! in createResourceRequest " << callerId; if (scheme == URL_SCHEME_FILE || scheme == URL_SCHEME_QRC) { request = new FileResourceRequest(normalizedURL, isObservable, callerId, extra); } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { @@ -146,7 +144,6 @@ ResourceRequest* ResourceManager::createResourceRequest( QObject::connect(parent, &QObject::destroyed, request, &QObject::deleteLater); } request->moveToThread(&_thread); - return request; } diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index a651e9a2b6..acaf657dfe 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -21,9 +21,8 @@ void ResourceRequest::send() { if (_isObservable) { DependencyManager::get()->update( - _urlAncestry, _callerId, _extra + " => ResourceRequest::send" ); + _url, _callerId, _extra + " => ResourceRequest::send" ); } - if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection); return; diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index 3ce1a9da2b..eb306ca5be 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -18,8 +18,6 @@ #include #include "ByteRange.h" -#include "QUrlAncestry.h" - const QString STAT_ATP_REQUEST_STARTED = "StartedATPRequest"; const QString STAT_HTTP_REQUEST_STARTED = "StartedHTTPRequest"; @@ -46,15 +44,14 @@ public: static const bool IS_NOT_OBSERVABLE = false; ResourceRequest( - const QUrlAncestry& urlAncestry, + const QUrl& url, const bool isObservable = IS_OBSERVABLE, const qint64 callerId = -1, const QString& extra = "" - ) : _urlAncestry(urlAncestry), + ) : _url(url), _isObservable(isObservable), _callerId(callerId), - _extra(extra), - _url(urlAncestry.last()) + _extra(extra) { } virtual ~ResourceRequest() = default; @@ -103,7 +100,6 @@ protected: virtual void doSend() = 0; void recordBytesDownloadedInStats(const QString& statName, int64_t bytesReceived); - QUrl _url; QUrl _relativePathURL; State _state { NotStarted }; @@ -119,7 +115,6 @@ protected: bool _isObservable; qint64 _callerId; QString _extra; - QUrlAncestry _urlAncestry; }; #endif diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index a50438dd54..efddf3c14f 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -669,7 +669,7 @@ OctreeElementPointer Octree::getElementEnclosingPoint(const glm::vec3& point, Oc return args.element; } -bool Octree::readFromFile(const char* fileName, const QUrlAncestry& urlAncestry) { +bool Octree::readFromFile(const char* fileName) { QString qFileName = findMostRecentFileExtension(fileName, PERSIST_EXTENSIONS); if (qFileName.endsWith(".json.gz")) { @@ -689,7 +689,7 @@ bool Octree::readFromFile(const char* fileName, const QUrlAncestry& urlAncestry) qCDebug(octree) << "Loading file" << qFileName << "..."; - bool success = readFromStream(fileLength, fileInputStream, "", urlAncestry); + bool success = readFromStream(fileLength, fileInputStream, ""); file.close(); @@ -737,8 +737,7 @@ QString getMarketplaceID(const QString& urlString) { bool Octree::readFromURL( const QString& urlString, const bool isObservable, - const qint64 callerId, - const QUrlAncestry& urlAncestry + const qint64 callerId ) { QString trimmedUrl = urlString.trimmed(); QString marketplaceID = getMarketplaceID(trimmedUrl); @@ -767,19 +766,18 @@ bool Octree::readFromURL( if (wasCompressed) { QDataStream inputStream(uncompressedJsonData); - return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, urlAncestry); + return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID); } QDataStream inputStream(data); - return readFromStream(data.size(), inputStream, marketplaceID, urlAncestry); + return readFromStream(data.size(), inputStream, marketplaceID); } bool Octree::readFromStream( uint64_t streamLength, QDataStream& inputStream, - const QString& marketplaceID, - const QUrlAncestry& urlAncestry + const QString& marketplaceID ) { // decide if this is binary SVO or JSON-formatted SVO QIODevice *device = inputStream.device(); @@ -792,7 +790,7 @@ bool Octree::readFromStream( return false; } else { qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; - return readJSONFromStream(streamLength, inputStream, marketplaceID, urlAncestry); + return readJSONFromStream(streamLength, inputStream, marketplaceID); } } @@ -824,8 +822,7 @@ const int READ_JSON_BUFFER_SIZE = 2048; bool Octree::readJSONFromStream( uint64_t streamLength, QDataStream& inputStream, - const QString& marketplaceID, /*=""*/ - const QUrlAncestry& urlAncestry + const QString& marketplaceID /*=""*/ ) { // if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until // we get an eof. Leave streamLength parameter for consistency. @@ -851,7 +848,7 @@ bool Octree::readJSONFromStream( } QVariant asVariant = asDocument.toVariant(); QVariantMap asMap = asVariant.toMap(); - bool success = readFromMap(asMap, urlAncestry); + bool success = readFromMap(asMap); delete[] rawData; return success; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 53acbc5a60..44b429582a 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -29,7 +29,6 @@ #include "OctreePacketData.h" #include "OctreeSceneStats.h" #include "OctreeUtils.h" -#include "QUrlAncestry.h" class ReadBitstreamToTreeParams; class Octree; @@ -210,13 +209,13 @@ public: bool skipThoseWithBadParents) = 0; // Octree importers - bool readFromFile(const char* filename, const QUrlAncestry& urlAncestry = {}); - bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const QUrlAncestry& urlAncestry = {}); // will support file urls as well... - bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const QUrlAncestry& urlAncestry = {}); + bool readFromFile(const char* filename); + bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1); // will support file urls as well... + bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); bool readSVOFromStream(uint64_t streamLength, QDataStream& inputStream); - bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const QUrlAncestry& urlAncestry = {}); + bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); bool readJSONFromGzippedFile(QString qFileName); - virtual bool readFromMap(QVariantMap& entityDescription, const QUrlAncestry& urlAncestry = {}) = 0; + virtual bool readFromMap(QVariantMap& entityDescription) = 0; uint64_t getOctreeElementsCount(); diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index eccb812f09..cbcafe9c7d 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -258,29 +258,24 @@ void OffscreenSurface::setMaxFps(uint8_t maxFps) { } void OffscreenSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) { - qDebug() << "Here 1"; loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) { QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem)); }); } void OffscreenSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& callback) { - qDebug() << "Here 2"; loadInternal(qmlSource, createNewContext, nullptr, callback); } void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback, const QmlContextCallback& contextCallback) { - qDebug() << "Here 3"; loadInternal(qmlSource, true, nullptr, callback, contextCallback); } void OffscreenSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& callback) { - qDebug() << "Here 4"; load(qmlSource, false, callback); } void OffscreenSurface::load(const QString& qmlSourceFile, const QmlContextObjectCallback& callback) { - qDebug() << "Here 5"; return load(QUrl(qmlSourceFile), callback); } diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 103ed6d232..4e07877d57 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -50,7 +50,7 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool tempDir = zipTemp.path(); path.remove("file:///"); } - + qCDebug(scriptengine) << "Temporary directory at: " + tempDir; if (!isTempDir(tempDir)) { qCDebug(scriptengine) << "Temporary directory mismatch; risk of losing files"; @@ -58,7 +58,7 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool } QStringList fileList = unzipFile(path, tempDir); - + if (!fileList.isEmpty()) { qCDebug(scriptengine) << "First file to upload: " + fileList.first(); } else { diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 297d3bb924..a74d185c6a 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -63,7 +63,7 @@ QScriptValue XMLHttpRequestClass::constructor(QScriptContext* context, QScriptEn QScriptValue XMLHttpRequestClass::getStatus() const { if (_reply) { return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); - } + } return QScriptValue(0); } @@ -144,7 +144,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) { auto accountManager = DependencyManager::get(); - + if (accountManager->hasValidAccessToken()) { static const QString HTTP_AUTHORIZATION_HEADER = "Authorization"; QString bearerString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token; diff --git a/libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h b/libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h deleted file mode 100644 index fd3647b19e..0000000000 --- a/libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// EntityItemWeakPointerWithUrlAncestry.h -// libraries/shared/src/ -// -// Created by Kerry Ivan Kurian 10/15/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_EntityItemWeakPointerWithUrlAncestry_h -#define hifi_EntityItemWeakPointerWithUrlAncestry_h - -#include "EntityTypes.h" -#include "QUrlAncestry.h" - - -struct EntityItemWeakPointerWithUrlAncestry { - EntityItemWeakPointerWithUrlAncestry( - const EntityItemWeakPointer& a, - const QUrlAncestry& b - ) : entityItemWeakPointer(a), urlAncestry(b) {} - - EntityItemWeakPointer entityItemWeakPointer; - QUrlAncestry urlAncestry; -}; - - -#endif // hifi_EntityItemWeakPointerWithUrlAncestry_h - diff --git a/libraries/shared/src/QUrlAncestry.cpp b/libraries/shared/src/QUrlAncestry.cpp deleted file mode 100644 index f38c663803..0000000000 --- a/libraries/shared/src/QUrlAncestry.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// -// QUrlAncestry.cpp -// libraries/shared/src/ -// -// Created by Kerry Ivan Kurian on 10/12/18. -// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#include "QUrlAncestry.h" - - -QUrlAncestry::QUrlAncestry(const QUrl& resource, const QUrl& referrer) { - this->append(referrer); - this->append(resource); -} - -QUrlAncestry::QUrlAncestry( - const QUrl& resource, - const QUrlAncestry& ancestors) : QVector(ancestors) -{ - this->append(resource); -} - -void QUrlAncestry::toJson(QJsonArray& array) const { - for (auto const& qurl : *this) { - array.append(qurl.toDisplayString()); - } -} - -const QUrl QUrlAncestry::url() const { - return this->last(); -} diff --git a/libraries/shared/src/QUrlAncestry.h b/libraries/shared/src/QUrlAncestry.h deleted file mode 100644 index 84c32ff7c1..0000000000 --- a/libraries/shared/src/QUrlAncestry.h +++ /dev/null @@ -1,32 +0,0 @@ -// -// QUrlAncestry.h -// libraries/shared/src/ -// -// Created by Kerry Ivan Kurian on 10/12/18. -// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. -// -// 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_QUrlAncestry_H -#define hifi_QUrlAncestry_H - -#include -#include -#include - - -class QUrlAncestry : public QVector { -public: - QUrlAncestry() {} - QUrlAncestry(const QUrl& resource, const QUrl& referrer = QUrl("__NONE__")); - QUrlAncestry(const QUrl& resource, const QUrlAncestry& ancestors); - - void toJson(QJsonArray& array) const; - const QUrl url() const; -}; - - -#endif // hifi_QUrlVector_H diff --git a/libraries/shared/src/ResourceRequestObserver.cpp b/libraries/shared/src/ResourceRequestObserver.cpp index 6c52fcdc79..5e0925520a 100644 --- a/libraries/shared/src/ResourceRequestObserver.cpp +++ b/libraries/shared/src/ResourceRequestObserver.cpp @@ -15,22 +15,12 @@ #include #include #include "ResourceRequestObserver.h" -#include "QUrlAncestry.h" - -// void ResourceRequestObserver::update(const QNetworkRequest& request, const qint64 callerId, const QString& extra) { -// update(QUrlAncestry(request.url()), callerId, extra); -// } - -void ResourceRequestObserver::update( - const QUrlAncestry& urlAncestry, +void ResourceRequestObserver::update(const QUrl& requestUrl, const qint64 callerId, - const QString& extra -) { + const QString& extra) { QJsonArray array; - urlAncestry.toJson(array); - QJsonObject data { - { "url", array }, + QJsonObject data { { "url", requestUrl.toString() }, { "callerId", callerId }, { "extra", extra } }; diff --git a/libraries/shared/src/ResourceRequestObserver.h b/libraries/shared/src/ResourceRequestObserver.h index edccdb5e48..1b1bc322e5 100644 --- a/libraries/shared/src/ResourceRequestObserver.h +++ b/libraries/shared/src/ResourceRequestObserver.h @@ -15,7 +15,6 @@ #include #include "DependencyManager.h" -#include "QUrlAncestry.h" class ResourceRequestObserver : public QObject, public Dependency { @@ -23,8 +22,7 @@ class ResourceRequestObserver : public QObject, public Dependency { SINGLETON_DEPENDENCY public: - // void update(const QNetworkRequest& request, const qint64 callerId = -1, const QString& extra = ""); - void update(const QUrlAncestry& urlAncestry, const qint64 callerId = -1, const QString& extra = ""); + void update(const QUrl& requestUrl, const qint64 callerId = -1, const QString& extra = ""); signals: void resourceRequestEvent(QVariantMap result); From bccca94111f175e9d9e5daded7e3e219ee9a9f6e Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Oct 2018 13:21:52 -0700 Subject: [PATCH 089/114] Prevent duplicate resources in logs. Thanks to Roxanne! --- libraries/networking/src/ResourceRequest.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index acaf657dfe..c63bd4c563 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -19,15 +19,15 @@ void ResourceRequest::send() { - if (_isObservable) { - DependencyManager::get()->update( - _url, _callerId, _extra + " => ResourceRequest::send" ); - } if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection); return; } + if (_isObservable) { + DependencyManager::get()->update(_url, _callerId, _extra + " => ResourceRequest::send"); + } + Q_ASSERT(_state == NotStarted); _state = InProgress; From d44f9e2ccc9b51a4a93a990997f61cc86c4b6be7 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Oct 2018 15:21:37 -0700 Subject: [PATCH 090/114] Tons of improvements --- .../marketplaceItemTester/ItemUnderTest.qml | 25 ++++++--- .../MarketplaceItemTester.qml | 38 +++----------- interface/src/commerce/QmlCommerce.cpp | 25 ++++++--- interface/src/commerce/QmlCommerce.h | 2 +- .../scripting/ClipboardScriptingInterface.cpp | 10 +--- scripts/system/marketplaces/marketplaces.js | 52 ++++++++++++------- 6 files changed, 79 insertions(+), 73 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml index dcb67f3f12..c5aaf20a8f 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml @@ -29,7 +29,7 @@ Rectangle { "forward": function(resource, assetType, resourceObjectId){ switch(assetType) { case "application": - Commerce.openApp(resource); + Commerce.installApp(resource, true); break; case "avatar": MyAvatar.useFullAvatarURL(resource); @@ -137,7 +137,7 @@ Rectangle { "entity": hifi.glyphs.wand, "trash": hifi.glyphs.trash, "unknown": hifi.glyphs.circleSlash, - "wearable": hifi.glyphs.hat, + "wearable": hifi.glyphs.hat } property int color: hifi.buttons.blue; property int colorScheme: hifi.colorSchemes.dark; @@ -149,7 +149,18 @@ Rectangle { enabled: comboBox.model[comboBox.currentIndex] !== "unknown" onClicked: { - root.actions["forward"](resource, comboBox.currentText, resourceObjectId); + if (model.currentlyRecordingResources) { + model.currentlyRecordingResources = false; + } else { + model.resourceAccessEventText = ""; + model.currentlyRecordingResources = true; + root.actions["forward"](resource, comboBox.currentText, resourceObjectId); + } + sendToScript({ + method: "tester_updateResourceRecordingStatus", + objectId: resourceListModel.get(index).resourceObjectId, + status: model.currentlyRecordingResources + }); } background: Rectangle { @@ -189,7 +200,7 @@ Rectangle { contentItem: Item { HifiStylesUit.HiFiGlyphs { id: rezIcon; - text: actionButton.glyphs[comboBox.model[comboBox.currentIndex]]; + text: model.currentlyRecordingResources ? hifi.glyphs.scriptStop : actionButton.glyphs[comboBox.model[comboBox.currentIndex]]; anchors.fill: parent size: 30; horizontalAlignment: Text.AlignHCenter; @@ -304,9 +315,9 @@ Rectangle { color: hifi.colors.white text: { if (root.detailsExpanded) { - return resourceAccessEventText + return model.resourceAccessEventText } else { - return (resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..." + return (model.resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..." } } font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) @@ -340,7 +351,7 @@ Rectangle { anchors.top: detailsTextContainer.bottom anchors.topMargin: 8 anchors.right: parent.right - width: 150 + width: 160 height: 30 text: "Copy to Clipboard" diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index 5f2268132c..2a4f2d0e22 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -24,17 +24,13 @@ Rectangle { id: root property string installedApps - property string resourceAccessEventText property var nextResourceObjectId: 0 - property var startDate HifiStylesUit.HifiConstants { id: hifi } ListModel { id: resourceListModel } color: hifi.colors.darkGray - Component.onCompleted: startDate = new Date() - // // TITLE BAR START // @@ -147,8 +143,7 @@ Rectangle { model: resourceListModel spacing: 8 - delegate: ItemUnderTest { - } + delegate: ItemUnderTest { } } Item { @@ -194,8 +189,6 @@ Rectangle { if (resource) { print("!!!! building resource object"); var resourceObj = buildResourceObj(resource); - print("!!!! installing resource object"); - installResourceObj(resourceObj); print("!!!! notifying script of resource object"); sendToScript({ method: 'tester_newResourceObject', @@ -235,6 +228,7 @@ Rectangle { switch (message.method) { case "newResourceObjectInTest": var resourceObject = message.resourceObject; + resourceListModel.clear(); // REMOVE THIS once we support specific referrers resourceListModel.append(resourceObject); spinner.visible = false; break; @@ -244,21 +238,9 @@ Rectangle { spinner.visible = false; break; case "resourceRequestEvent": - try { - var date = new Date(JSON.parse(message.data.date)); - } catch(err) { - print("!!!!! Date conversion failed: " + JSON.stringify(message.data)); - } - // XXX Eventually this date check goes away b/c we will - // be able to match up resouce access events to resource - // object ids, ignoring those that have -1 resource - // object ids. - if (date >= startDate) { - resourceAccessEventText += ( - "[" + date.toISOString() + "] " + - message.data.url.toString().replace("__NONE__,", "") + "\n" - ); - } + // When we support multiple items under test simultaneously, + // we'll have to replace "0" with the correct index. + resourceListModel.setProperty(0, "resourceAccessEventText", message.resourceAccessEventText); break; } } @@ -270,17 +252,13 @@ Rectangle { resource.match(/\.json\.gz$/) ? "content set" : resource.match(/\.json$/) ? "entity or wearable" : "unknown"); - return { "resourceObjectId": nextResourceObjectId++, + // Uncomment this once we support more than one item in test at the same time + //nextResourceObjectId++; + return { "resourceObjectId": nextResourceObjectId, "resource": resource, "assetType": assetType }; } - function installResourceObj(resourceObj) { - if ("application" === resourceObj.assetType) { - Commerce.installApp(resourceObj.resource); - } - } - function toUrl(resource) { var httpPattern = /^http/i; return httpPattern.test(resource) ? resource : "file:///" + resource; diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index 83907df103..ffe89ffc5b 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -315,7 +315,7 @@ QString QmlCommerce::getInstalledApps(const QString& justInstalledAppID) { return installedAppsFromMarketplace; } -bool QmlCommerce::installApp(const QString& itemHref) { +bool QmlCommerce::installApp(const QString& itemHref, const bool& alsoOpenImmediately) { if (!QDir(_appsPath).exists()) { if (!QDir().mkdir(_appsPath)) { qCDebug(commerce) << "Couldn't make _appsPath directory."; @@ -325,8 +325,8 @@ bool QmlCommerce::installApp(const QString& itemHref) { QUrl appHref(itemHref); - auto request = DependencyManager::get()->createResourceRequest( - this, appHref, true, -1, "QmlCommerce::installApp"); + auto request = + DependencyManager::get()->createResourceRequest(this, appHref, true, -1, "QmlCommerce::installApp"); if (!request) { qCDebug(commerce) << "Couldn't create resource request for app."; @@ -358,13 +358,22 @@ bool QmlCommerce::installApp(const QString& itemHref) { QJsonObject appFileJsonObject = appFileJsonDocument.object(); QString scriptUrl = appFileJsonObject["scriptURL"].toString(); - if ((DependencyManager::get()->loadScript(scriptUrl.trimmed())).isNull()) { - qCDebug(commerce) << "Couldn't load script."; - return false; + // Don't try to re-load (install) a script if it's already running + QStringList runningScripts = DependencyManager::get()->getRunningScripts(); + if (!runningScripts.contains(scriptUrl)) { + if ((DependencyManager::get()->loadScript(scriptUrl.trimmed())).isNull()) { + qCDebug(commerce) << "Couldn't load script."; + return false; + } + + QFileInfo appFileInfo(appFile); + emit appInstalled(appFileInfo.baseName()); + } + + if (alsoOpenImmediately) { + QmlCommerce::openApp(itemHref); } - QFileInfo appFileInfo(appFile); - emit appInstalled(appFileInfo.baseName()); return true; }); request->send(); diff --git a/interface/src/commerce/QmlCommerce.h b/interface/src/commerce/QmlCommerce.h index bee30e1b62..2e3c0ec24d 100644 --- a/interface/src/commerce/QmlCommerce.h +++ b/interface/src/commerce/QmlCommerce.h @@ -88,7 +88,7 @@ protected: Q_INVOKABLE void replaceContentSet(const QString& itemHref, const QString& certificateID); Q_INVOKABLE QString getInstalledApps(const QString& justInstalledAppID = ""); - Q_INVOKABLE bool installApp(const QString& appHref); + Q_INVOKABLE bool installApp(const QString& appHref, const bool& alsoOpenImmediately = false); Q_INVOKABLE bool uninstallApp(const QString& appHref); Q_INVOKABLE bool openApp(const QString& appHref); diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index c14f4ea895..c2d2b69883 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -46,17 +46,11 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float return retVal; } -bool ClipboardScriptingInterface::importEntities( - const QString& filename, - const bool isObservable, - const qint64 callerId -) { +bool ClipboardScriptingInterface::importEntities(const QString& filename) { bool retVal; BLOCKING_INVOKE_METHOD(qApp, "importEntities", Q_RETURN_ARG(bool, retVal), - Q_ARG(const QString&, filename), - Q_ARG(const bool, isObservable), - Q_ARG(const qint64, callerId)); + Q_ARG(const QString&, filename)); return retVal; } diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index d59a6b89d5..d6056f83a6 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -52,27 +52,30 @@ var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't writ var resourceRequestEvents = []; function signalResourceRequestEvent(data) { + // Once we can tie resource request events to specific resources, + // we will have to update the "0" in here. + resourceObjectsInTest[0].resourceAccessEventText += "[" + data.date.toISOString() + "] " + + data.url.toString().replace("__NONE__,", "") + "\n"; + ui.tablet.sendToQml({ method: "resourceRequestEvent", - data: data }); + data: data, + resourceAccessEventText: resourceObjectsInTest[0].resourceAccessEventText + }); } function onResourceRequestEvent(data) { - var resourceRequestEvent = { - "date": JSON.stringify(new Date()), - "url": data.url, - "callerId": data.callerId, - "extra": data.extra }; - resourceRequestEvents.push(resourceRequestEvent); - signalResourceRequestEvent(resourceRequestEvent); -} - -function pushResourceRequestEvents() { - var length = resourceRequestEvents.length - for (var i = 0; i < length; i++) { - if (i in resourceRequestEvents) { - signalResourceRequestEvent(resourceRequestEvents[i]); - } + // Once we can tie resource request events to specific resources, + // we will have to update the "0" in here. + if (resourceObjectsInTest[0] && resourceObjectsInTest[0].currentlyRecordingResources) { + var resourceRequestEvent = { + "date": new Date(), + "url": data.url, + "callerId": data.callerId, + "extra": data.extra + }; + resourceRequestEvents.push(resourceRequestEvent); + signalResourceRequestEvent(resourceRequestEvent); } } @@ -849,7 +852,8 @@ var resourceObjectsInTest = []; function signalNewResourceObjectInTest(resourceObject) { ui.tablet.sendToQml({ method: "newResourceObjectInTest", - resourceObject: resourceObject }); + resourceObject: resourceObject + }); } var onQmlMessageReceived = function onQmlMessageReceived(message) { @@ -915,6 +919,9 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { break; case 'tester_newResourceObject': var resourceObject = message.resourceObject; + resourceObjectsInTest = []; // REMOVE THIS once we support specific referrers + resourceObject.currentlyRecordingResources = false; + resourceObject.resourceAccessEventText = ""; resourceObjectsInTest[resourceObject.resourceObjectId] = resourceObject; signalNewResourceObjectInTest(resourceObject); break; @@ -924,6 +931,12 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { case 'tester_deleteResourceObject': delete resourceObjectsInTest[message.objectId]; break; + case 'tester_updateResourceRecordingStatus': + resourceObjectsInTest[message.objectId].currentlyRecordingResources = message.status; + if (message.status) { + resourceObjectsInTest[message.objectId].resourceAccessEventText = ""; + } + break; case 'header_marketplaceImageClicked': case 'purchases_backClicked': openMarketplace(message.referrerURL); @@ -1076,7 +1089,9 @@ function pushResourceObjectsInTest() { // that the marketplace item tester QML has heard from us, at least // so that it can indicate to the user that all of the resoruce // objects in test have been transmitted to it. - ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxResourceObjectId + 1 }); + //ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxResourceObjectId + 1 }); + // Since, for now, we only support 1 object in test, always send id: 0 + ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: 0 }); } // Function Name: onTabletScreenChanged() @@ -1165,7 +1180,6 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) { // variable amount of time to come up, in practice less than // 750ms. Script.setTimeout(pushResourceObjectsInTest, 750); - Script.setTimeout(pushResourceRequestEvents, 750); } console.debug(ui.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type + From de93bbb08bcc0f61722cdb10d216fd38eb98ce01 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Oct 2018 15:43:28 -0700 Subject: [PATCH 091/114] Only show unique resources --- .../marketplaceItemTester/ItemUnderTest.qml | 5 ++-- scripts/system/marketplaces/marketplaces.js | 24 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml index c5aaf20a8f..fcb4eaae43 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml @@ -314,10 +314,11 @@ Rectangle { readOnly: true color: hifi.colors.white text: { - if (root.detailsExpanded) { + var numUniqueResources = (model.resourceAccessEventText.split("\n").length - 1); + if (root.detailsExpanded && numUniqueResources > 0) { return model.resourceAccessEventText } else { - return (model.resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..." + return numUniqueResources.toString() + " unique resource" + (numUniqueResources === 1 ? "" : "s") + " loaded - expand for details" } } font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index d6056f83a6..487920b764 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -54,14 +54,24 @@ var resourceRequestEvents = []; function signalResourceRequestEvent(data) { // Once we can tie resource request events to specific resources, // we will have to update the "0" in here. - resourceObjectsInTest[0].resourceAccessEventText += "[" + data.date.toISOString() + "] " + - data.url.toString().replace("__NONE__,", "") + "\n"; + if (!resourceObjectsInTest[0].resourceUrls) { + resourceObjectsInTest[0].resourceUrls = []; + } - ui.tablet.sendToQml({ - method: "resourceRequestEvent", - data: data, - resourceAccessEventText: resourceObjectsInTest[0].resourceAccessEventText - }); + var resourceUrl = data.url.toString().replace("__NONE__,", ""); + + if (resourceObjectsInTest[0].resourceUrls.indexOf(resourceUrl) === -1) { + resourceObjectsInTest[0].resourceUrls.push(resourceUrl); + + resourceObjectsInTest[0].resourceAccessEventText += "[" + data.date.toISOString() + "] " + + resourceUrl + "\n"; + + ui.tablet.sendToQml({ + method: "resourceRequestEvent", + data: data, + resourceAccessEventText: resourceObjectsInTest[0].resourceAccessEventText + }); + } } function onResourceRequestEvent(data) { From f9cc4f5a696c15790ce4c04f4ab89b65cd738fe4 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Oct 2018 16:01:49 -0700 Subject: [PATCH 092/114] Count unique source and url pairs --- .../commerce/marketplaceItemTester/ItemUnderTest.qml | 2 +- scripts/system/marketplaces/marketplaces.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml index fcb4eaae43..27277a28f4 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml @@ -318,7 +318,7 @@ Rectangle { if (root.detailsExpanded && numUniqueResources > 0) { return model.resourceAccessEventText } else { - return numUniqueResources.toString() + " unique resource" + (numUniqueResources === 1 ? "" : "s") + " loaded - expand for details" + return numUniqueResources.toString() + " unique source/resource url pair" + (numUniqueResources === 1 ? "" : "s") + " recorded" } } font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 487920b764..59279bada7 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -54,17 +54,17 @@ var resourceRequestEvents = []; function signalResourceRequestEvent(data) { // Once we can tie resource request events to specific resources, // we will have to update the "0" in here. - if (!resourceObjectsInTest[0].resourceUrls) { - resourceObjectsInTest[0].resourceUrls = []; + if (!resourceObjectsInTest[0].resourceDataArray) { + resourceObjectsInTest[0].resourceDataArray = []; } - var resourceUrl = data.url.toString().replace("__NONE__,", ""); + var resourceData = "from: " + data.extra + ": " + data.url.toString().replace("__NONE__,", ""); - if (resourceObjectsInTest[0].resourceUrls.indexOf(resourceUrl) === -1) { - resourceObjectsInTest[0].resourceUrls.push(resourceUrl); + if (resourceObjectsInTest[0].resourceDataArray.indexOf(resourceData) === -1) { + resourceObjectsInTest[0].resourceDataArray.push(resourceData); resourceObjectsInTest[0].resourceAccessEventText += "[" + data.date.toISOString() + "] " + - resourceUrl + "\n"; + resourceData + "\n"; ui.tablet.sendToQml({ method: "resourceRequestEvent", From 1023e6d2b9ceec7052b1b39e29b3047d7cbe4210 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Oct 2018 16:03:05 -0700 Subject: [PATCH 093/114] Fix ClipboardScriptingInterface: --- .../src/scripting/ClipboardScriptingInterface.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index c2d2b69883..c14f4ea895 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -46,11 +46,17 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float return retVal; } -bool ClipboardScriptingInterface::importEntities(const QString& filename) { +bool ClipboardScriptingInterface::importEntities( + const QString& filename, + const bool isObservable, + const qint64 callerId +) { bool retVal; BLOCKING_INVOKE_METHOD(qApp, "importEntities", Q_RETURN_ARG(bool, retVal), - Q_ARG(const QString&, filename)); + Q_ARG(const QString&, filename), + Q_ARG(const bool, isObservable), + Q_ARG(const qint64, callerId)); return retVal; } From f5a5c0dad3511fe73782dfd92ea7951fe83797ab Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Fri, 19 Oct 2018 16:48:23 -0700 Subject: [PATCH 094/114] Attempt to fix wearable bug? --- scripts/system/marketplaces/marketplaces.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 59279bada7..004f3fcbb8 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -54,10 +54,6 @@ var resourceRequestEvents = []; function signalResourceRequestEvent(data) { // Once we can tie resource request events to specific resources, // we will have to update the "0" in here. - if (!resourceObjectsInTest[0].resourceDataArray) { - resourceObjectsInTest[0].resourceDataArray = []; - } - var resourceData = "from: " + data.extra + ": " + data.url.toString().replace("__NONE__,", ""); if (resourceObjectsInTest[0].resourceDataArray.indexOf(resourceData) === -1) { @@ -933,6 +929,7 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { resourceObject.currentlyRecordingResources = false; resourceObject.resourceAccessEventText = ""; resourceObjectsInTest[resourceObject.resourceObjectId] = resourceObject; + resourceObjectsInTest[resourceObject.resourceObjectId].resourceDataArray = []; signalNewResourceObjectInTest(resourceObject); break; case 'tester_updateResourceObjectAssetType': @@ -944,6 +941,7 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { case 'tester_updateResourceRecordingStatus': resourceObjectsInTest[message.objectId].currentlyRecordingResources = message.status; if (message.status) { + resourceObjectsInTest[message.objectId].resourceDataArray = []; resourceObjectsInTest[message.objectId].resourceAccessEventText = ""; } break; From a1bb68517626d4a31823a9d2782b0ed77d890672 Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Mon, 22 Oct 2018 11:04:31 -0700 Subject: [PATCH 095/114] Remove cruft --- libraries/octree/src/Octree.cpp | 2 +- scripts/system/marketplaces/marketplaces.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index efddf3c14f..06db92bcf7 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -689,7 +689,7 @@ bool Octree::readFromFile(const char* fileName) { qCDebug(octree) << "Loading file" << qFileName << "..."; - bool success = readFromStream(fileLength, fileInputStream, ""); + bool success = readFromStream(fileLength, fileInputStream); file.close(); diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index 004f3fcbb8..3085145176 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -564,7 +564,6 @@ function defaultFor(arg, val) { function rezEntity(itemHref, itemType, marketplaceItemTesterId) { var isWearable = itemType === "wearable"; - print("!!!!! Clipboard.importEntities " + marketplaceItemTesterId); var success = Clipboard.importEntities(itemHref, true, marketplaceItemTesterId); var wearableLocalPosition = null; var wearableLocalRotation = null; @@ -920,7 +919,6 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { case 'checkout_rezClicked': case 'purchases_rezClicked': case 'tester_rezClicked': - print("!!!!! marketplaces tester_rezClicked"); rezEntity(message.itemHref, message.itemType, message.itemId); break; case 'tester_newResourceObject': From a2a6acd45c2d7b5d7a082e84c567ba0ada31802d Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Mon, 22 Oct 2018 14:04:59 -0700 Subject: [PATCH 096/114] Improve code formatting --- libraries/networking/src/ResourceCache.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index f2fbe41804..6f7cad8a04 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -349,7 +349,8 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& resource = createResource( url, fallback.isValid() ? getResource(fallback, QUrl()) : QSharedPointer(), - extra); resource->setSelf(resource); + extra); + resource->setSelf(resource); resource->setCache(this); resource->moveToThread(qApp->thread()); connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); From e3e197ff5c4515e22b11e5e7d23b0db75583c793 Mon Sep 17 00:00:00 2001 From: Clement Date: Mon, 22 Oct 2018 15:32:29 -0700 Subject: [PATCH 097/114] 2 spaces in cmake files --- cmake/macros/ConfigureCCache.cmake | 54 +++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/cmake/macros/ConfigureCCache.cmake b/cmake/macros/ConfigureCCache.cmake index 6107faaa21..bec159ef09 100644 --- a/cmake/macros/ConfigureCCache.cmake +++ b/cmake/macros/ConfigureCCache.cmake @@ -10,36 +10,36 @@ # macro(configure_ccache) - find_program(CCACHE_PROGRAM ccache) - if(CCACHE_PROGRAM) - message(STATUS "Configuring ccache") + find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) + message(STATUS "Configuring ccache") - # Set up wrapper scripts - set(C_LAUNCHER "${CCACHE_PROGRAM}") - set(CXX_LAUNCHER "${CCACHE_PROGRAM}") + # Set up wrapper scripts + set(C_LAUNCHER "${CCACHE_PROGRAM}") + set(CXX_LAUNCHER "${CCACHE_PROGRAM}") + + set(LAUNCH_C_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/launch-c.in") + set(LAUNCH_CXX_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/launch-cxx.in") + set(LAUNCH_C "${CMAKE_BINARY_DIR}/CMakeFiles/launch-c") + set(LAUNCH_CXX "${CMAKE_BINARY_DIR}/CMakeFiles/launch-cxx") - set(LAUNCH_C_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/launch-c.in") - set(LAUNCH_CXX_IN "${CMAKE_CURRENT_SOURCE_DIR}/cmake/templates/launch-cxx.in") - set(LAUNCH_C "${CMAKE_BINARY_DIR}/CMakeFiles/launch-c") - set(LAUNCH_CXX "${CMAKE_BINARY_DIR}/CMakeFiles/launch-cxx") + configure_file(${LAUNCH_C_IN} ${LAUNCH_C}) + configure_file(${LAUNCH_CXX_IN} ${LAUNCH_CXX}) + execute_process(COMMAND chmod a+rx ${LAUNCH_C} ${LAUNCH_CXX}) - configure_file(${LAUNCH_C_IN} ${LAUNCH_C}) - configure_file(${LAUNCH_CXX_IN} ${LAUNCH_CXX}) - execute_process(COMMAND chmod a+rx ${LAUNCH_C} ${LAUNCH_CXX}) - - if(CMAKE_GENERATOR STREQUAL "Xcode") - # Set Xcode project attributes to route compilation and linking - # through our scripts - set(CMAKE_XCODE_ATTRIBUTE_CC ${LAUNCH_C}) - set(CMAKE_XCODE_ATTRIBUTE_CXX ${LAUNCH_CXX}) - set(CMAKE_XCODE_ATTRIBUTE_LD ${LAUNCH_C}) - set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS ${LAUNCH_CXX}) - else() - # Support Unix Makefiles and Ninja - set(CMAKE_C_COMPILER_LAUNCHER ${LAUNCH_C}) - set(CMAKE_CXX_COMPILER_LAUNCHER ${LAUNCH_CXX}) - endif() + if(CMAKE_GENERATOR STREQUAL "Xcode") + # Set Xcode project attributes to route compilation and linking + # through our scripts + set(CMAKE_XCODE_ATTRIBUTE_CC ${LAUNCH_C}) + set(CMAKE_XCODE_ATTRIBUTE_CXX ${LAUNCH_CXX}) + set(CMAKE_XCODE_ATTRIBUTE_LD ${LAUNCH_C}) + set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS ${LAUNCH_CXX}) else() - message(WARNING "Could not find ccache") + # Support Unix Makefiles and Ninja + set(CMAKE_C_COMPILER_LAUNCHER ${LAUNCH_C}) + set(CMAKE_CXX_COMPILER_LAUNCHER ${LAUNCH_CXX}) endif() + else() + message(WARNING "Could not find ccache") + endif() endmacro() From 8cb09c37eed722dd701afa6b4868581381d03762 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 22 Oct 2018 21:26:30 -0700 Subject: [PATCH 098/114] changed the ui to the settings/controls --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index dd40a748af..c55a257d6a 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -533,7 +533,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - + qCDebug(interfaceapp) << "lock " << _lockSitStandState.get() << " sit " << _isInSittingState.get() << " hmd lean "<< _hmdLeanRecenterEnabled; // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 5eccef5e9d..eeca96222b 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -243,6 +243,29 @@ void setupPreferences() { preference->setIndented(true); preferences->addPreference(preference); } + { + auto getter = [myAvatar]()->int { if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::Auto) { + return 0; + } else if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::ForceSit) { + return 1; + } else { + return 2; + }}; + auto setter = [myAvatar](int value) { if (value == 0) { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); + } else if (value == 1) { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); + } else { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); + }}; + auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); + QStringList items; + items << "Auto" << "Force Sitting" << "Disable Recenter"; + preference->setHeading("User Activity mode"); + preference->setItems(items); + preferences->addPreference(preference); + } + { auto getter = [myAvatar]()->int { return myAvatar->getSnapTurn() ? 0 : 1; }; auto setter = [myAvatar](int value) { myAvatar->setSnapTurn(value == 0); }; From 3e8663f8e9dbcf53fe86a8a4baf33681b0c8c4d1 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 22 Oct 2018 22:31:26 -0700 Subject: [PATCH 099/114] removed the dropdown from the avatar app, because it is in settings controls now --- interface/resources/qml/hifi/AvatarApp.qml | 1 - .../resources/qml/hifi/avatarapp/Settings.qml | 40 +++---------------- scripts/system/avatarapp.js | 14 +------ 3 files changed, 7 insertions(+), 48 deletions(-) diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index d68e5bfcd7..39590748cf 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -252,7 +252,6 @@ Rectangle { var avatarSettings = { dominantHand : settings.dominantHandIsLeft ? 'left' : 'right', collisionsEnabled : settings.avatarCollisionsOn, - userRecenterModel : settings.avatarRecenterModelOn, animGraphOverrideUrl : settings.avatarAnimationOverrideJSON, collisionSoundUrl : settings.avatarCollisionSoundUrl }; diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index ec2b176f54..bad1394133 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -20,7 +20,6 @@ Rectangle { property real scaleValue: scaleSlider.value / 10 property alias dominantHandIsLeft: leftHandRadioButton.checked property alias avatarCollisionsOn: collisionsEnabledRadiobutton.checked - property alias avatarRecenterModelOn: userModelComboBox.currentIndex property alias avatarAnimationOverrideJSON: avatarAnimationUrlInputText.text property alias avatarAnimationJSON: avatarAnimationUrlInputText.placeholderText property alias avatarCollisionSoundUrl: avatarCollisionSoundUrlInputText.text @@ -49,7 +48,6 @@ Rectangle { avatarAnimationJSON = settings.animGraphUrl; avatarAnimationOverrideJSON = settings.animGraphOverrideUrl; avatarCollisionSoundUrl = settings.collisionSoundUrl; - avatarRecenterModelOn = settings.userRecenterModel; visible = true; } @@ -191,7 +189,7 @@ Rectangle { anchors.left: parent.left anchors.right: parent.right - rows: 3 + rows: 2 rowSpacing: 25 columns: 3 @@ -214,7 +212,7 @@ Rectangle { Layout.row: 0 Layout.column: 1 - Layout.leftMargin: 20 + Layout.leftMargin: -40 ButtonGroup.group: leftRight checked: true @@ -231,7 +229,7 @@ Rectangle { Layout.row: 0 Layout.column: 2 - Layout.rightMargin: -20 + Layout.rightMargin: 20 ButtonGroup.group: leftRight @@ -260,7 +258,7 @@ Rectangle { Layout.row: 1 Layout.column: 1 - Layout.leftMargin: 20 + Layout.leftMargin: -40 ButtonGroup.group: onOff colorScheme: hifi.colorSchemes.light @@ -281,7 +279,7 @@ Rectangle { Layout.row: 1 Layout.column: 2 - Layout.rightMargin: -20 + Layout.rightMargin: 20 ButtonGroup.group: onOff colorScheme: hifi.colorSchemes.light @@ -291,34 +289,6 @@ Rectangle { text: "OFF" boxSize: 20 } - - // TextStyle9 - - RalewaySemiBold { - size: 17; - Layout.row: 2 - Layout.column: 0 - - text: "User Model:" - } - - - // sit stand combo box - HifiControlsUit.ComboBox { - Layout.row: 2 - Layout.column: 1 - id: userModelComboBox - comboBox.textRole: "text" - currentIndex: 2 - model: ListModel { - id: cbItems - ListElement { text: "Force Sitting"; color: "Yellow" } - ListElement { text: "Force Standing"; color: "Green" } - ListElement { text: "Auto Mode"; color: "Brown" } - ListElement { text: "Disable Recentering"; color: "Red" } - } - width: 200 - } } ColumnLayout { diff --git a/scripts/system/avatarapp.js b/scripts/system/avatarapp.js index 0c99460929..ece35acce7 100644 --- a/scripts/system/avatarapp.js +++ b/scripts/system/avatarapp.js @@ -64,7 +64,6 @@ function getMyAvatarSettings() { return { dominantHand: MyAvatar.getDominantHand(), collisionsEnabled : MyAvatar.getCollisionsEnabled(), - userRecenterModel: MyAvatar.userRecenterModel, collisionSoundUrl : MyAvatar.collisionSoundURL, animGraphUrl: MyAvatar.getAnimGraphUrl(), animGraphOverrideUrl : MyAvatar.getAnimGraphOverrideUrl(), @@ -137,14 +136,6 @@ function onCollisionsEnabledChanged(enabled) { } } -function onUserRecenterModelChanged(modelName) { - if (currentAvatarSettings.userRecenterModel !== modelName) { - currentAvatarSettings.userRecenterModel = modelName; - print("emit user recenter model changed"); - sendToQml({ 'method': 'settingChanged', 'name': 'userRecenterModel', 'value': modelName }) - } -} - function onNewCollisionSoundUrl(url) { if(currentAvatarSettings.collisionSoundUrl !== url) { currentAvatarSettings.collisionSoundUrl = url; @@ -320,11 +311,12 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See case 'saveSettings': MyAvatar.setAvatarScale(message.avatarScale); currentAvatar.avatarScale = message.avatarScale; + MyAvatar.setDominantHand(message.settings.dominantHand); MyAvatar.setCollisionsEnabled(message.settings.collisionsEnabled); - MyAvatar.userRecenterModel = message.settings.userRecenterModel; MyAvatar.collisionSoundURL = message.settings.collisionSoundUrl; MyAvatar.setAnimGraphOverrideUrl(message.settings.animGraphOverrideUrl); + settings = getMyAvatarSettings(); break; default: @@ -497,7 +489,6 @@ function off() { MyAvatar.skeletonModelURLChanged.disconnect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.disconnect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.disconnect(onCollisionsEnabledChanged); - MyAvatar.userRecenterModelChanged.disconnect(onUserRecenterModelChanged); MyAvatar.newCollisionSoundURL.disconnect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.disconnect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.disconnect(onTargetScaleChanged); @@ -512,7 +503,6 @@ function on() { MyAvatar.skeletonModelURLChanged.connect(onSkeletonModelURLChanged); MyAvatar.dominantHandChanged.connect(onDominantHandChanged); MyAvatar.collisionsEnabledChanged.connect(onCollisionsEnabledChanged); - MyAvatar.userRecenterModelChanged.connect(onUserRecenterModelChanged); MyAvatar.newCollisionSoundURL.connect(onNewCollisionSoundUrl); MyAvatar.animGraphUrlChanged.connect(onAnimGraphUrlChanged); MyAvatar.targetScaleChanged.connect(onTargetScaleChanged); From 339b25a36290072c9c7f22f24d93a03e55b45fb7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 23 Oct 2018 08:36:18 -0700 Subject: [PATCH 100/114] Fix access to uniforms at index 0 --- libraries/gl/src/gl/GLShaders.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gl/src/gl/GLShaders.cpp b/libraries/gl/src/gl/GLShaders.cpp index b7e80fbeb4..54a386313b 100644 --- a/libraries/gl/src/gl/GLShaders.cpp +++ b/libraries/gl/src/gl/GLShaders.cpp @@ -14,7 +14,7 @@ using namespace gl; void Uniform::load(GLuint glprogram, int index) { this->index = index; - if (index > 0) { + if (index >= 0) { static const GLint NAME_LENGTH = 1024; GLchar glname[NAME_LENGTH]; memset(glname, 0, NAME_LENGTH); From 8ce2081349c56c6925fccb3c4431bb7b54002198 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 10 Sep 2018 15:47:52 -0700 Subject: [PATCH 101/114] Add python discovery --- BUILD.md | 1 + BUILD_LINUX.md | 5 +++++ BUILD_OSX.md | 8 +++++++- BUILD_WIN.md | 10 ++++++++-- cmake/macros/TargetPython.cmake | 22 ++++++++++++++++++++++ 5 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 cmake/macros/TargetPython.cmake diff --git a/BUILD.md b/BUILD.md index df3f18cf51..4198c39d1a 100644 --- a/BUILD.md +++ b/BUILD.md @@ -9,6 +9,7 @@ - [cmake](https://cmake.org/download/): 3.9 - [Qt](https://www.qt.io/download-open-source): 5.10.1 +- [Python](https://www.python.org/downloads/): 3.6 or higher - [OpenSSL](https://www.openssl.org/): Use the latest available 1.0 version (**NOT** 1.1) of OpenSSL to avoid security vulnerabilities. - [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional) diff --git a/BUILD_LINUX.md b/BUILD_LINUX.md index 1ee3d2b7c8..15c5915c51 100644 --- a/BUILD_LINUX.md +++ b/BUILD_LINUX.md @@ -40,6 +40,11 @@ Install build tools: sudo apt-get install cmake ``` +Install Python 3: +```bash +sudo apt-get install python3.6 +``` + ### Get code and checkout the tag you need diff --git a/BUILD_OSX.md b/BUILD_OSX.md index 62102b3e18..488c38e909 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -6,6 +6,10 @@ Please read the [general build guide](BUILD.md) for information on dependencies brew install cmake openssl qt +### Python 3 + +Download an install Python 3.6.6 or higher from [here](https://www.python.org/downloads/). Execute the `Update Shell Profile.command` script that is provided with the installer. + ### OpenSSL Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations. @@ -28,7 +32,9 @@ Note that this uses the version from the homebrew formula at the time of this wr If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles. - cmake .. -GXcode + cmake .. -G Xcode + +If `cmake` complains about Python 3 being missing, you may need to update your CMake binary with command `brew upgrade cmake`, or by downloading and running the latest CMake installer, depending on how you originally instaled CMake After running cmake, you will have the make files or Xcode project file necessary to build all of the components. Open the hifi.xcodeproj file, choose ALL_BUILD from the Product > Scheme menu (or target drop down), and click Run. diff --git a/BUILD_WIN.md b/BUILD_WIN.md index 90d2995e7d..073b048911 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -5,11 +5,17 @@ Note: We are now using Visual Studio 2017 and Qt 5.10.1. If you are upgrading fr Note: The prerequisites will require about 10 GB of space on your drive. You will also need a system with at least 8GB of main memory. -### Step 1. Visual Studio 2017 +### Step 1. Visual Studio 2017 & Python If you don’t have Community or Professional edition of Visual Studio 2017, download [Visual Studio Community 2017](https://www.visualstudio.com/downloads/). -When selecting components, check "Desktop development with C++." Also on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)". +When selecting components, check "Desktop development with C++". Also on the right on the Summary toolbar, check "Windows 8.1 SDK and UCRT SDK" and "VC++ 2015.3 v140 toolset (x86,x64)". If you do not already have a python development environment installed, also check "Python Development" in this screen. + +If you already have Visual Studio installed and need to add python, open the "Add or remove programs" control panel and find the "Microsoft Visual Studio Installer". Select it and click "Modify". In the installer, select "Modify" again, then check "Python Development" and allow the installer to apply the changes. + +### Step 1a. Alternate Python + +If you do not wish to use the Python installation bundled with Visual Studio, you can download the installer from [here](https://www.python.org/downloads/). Ensure you get version 3.6.6 or higher. ### Step 2. Installing CMake diff --git a/cmake/macros/TargetPython.cmake b/cmake/macros/TargetPython.cmake new file mode 100644 index 0000000000..a7c3344fc0 --- /dev/null +++ b/cmake/macros/TargetPython.cmake @@ -0,0 +1,22 @@ +macro(TARGET_PYTHON) + if (NOT HIFI_PYTHON_EXEC) + # Find the python interpreter + if (CAME_VERSION VERSION_LESS 3.12) + # this logic is deprecated in CMake after 3.12 + # FIXME eventually we should make 3.12 the min cmake verion and just use the Python3 find_package path + set(Python_ADDITIONAL_VERSIONS 3) + find_package(PythonInterp) + set(HIFI_PYTHON_VERSION ${PYTHON_VERSION_STRING}) + set(HIFI_PYTHON_EXEC ${PYTHON_EXECUTABLE}) + else() + # the new hotness + find_package(Python3) + set(HIFI_PYTHON_VERSION ${Python3_VERSION}) + set(HIFI_PYTHON_EXEC ${Python3_EXECUTABLE}) + endif() + + if ((NOT HIFI_PYTHON_EXEC) OR (HIFI_PYTHON_VERSION VERSION_LESS 3.6)) + message(FATAL_ERROR "Unable to locate Python interpreter 3.6 or higher") + endif() + endif() +endmacro() \ No newline at end of file From c8e664a0a1128015fe83d27390e34b8cf4678f20 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 27 Aug 2018 08:14:37 -0700 Subject: [PATCH 102/114] New SPIRV Shader toolchain --- android/app/build.gradle | 1 - android/build.gradle | 42 +- cmake/externals/glslang/CMakeLists.txt | 42 ++ cmake/externals/spirv_binaries/CMakeLists.txt | 34 ++ cmake/externals/spirv_cross/CMakeLists.txt | 35 ++ cmake/externals/spirv_headers/CMakeLists.txt | 18 + cmake/externals/spirv_tools/CMakeLists.txt | 33 ++ cmake/init.cmake | 4 + cmake/macros/AutoScribeShader.cmake | 283 ++++++++--- cmake/macros/TargetPython.cmake | 4 +- cmake/macros/TargetSPIRV.cmake | 15 + cmake/macros/TargetSpirvBinaries.cmake | 10 + cmake/macros/TargetVulkan.cmake | 19 + libraries/avatars-renderer/CMakeLists.txt | 2 +- .../InterleavedSrgbToLinear.slf | 4 +- .../display-plugins/OpenGLDisplayPlugin.cpp | 57 +-- .../src/display-plugins/SrgbToLinear.slf | 6 +- .../src/RenderableShapeEntityItem.cpp | 6 +- .../entities-renderer/src/paintStroke.slf | 2 +- .../src/paintStroke_fade.slf | 4 +- libraries/entities-renderer/src/polyvox.slf | 8 +- .../entities-renderer/src/polyvox_fade.slf | 8 +- .../src/textured_particle.slf | 2 +- .../src/textured_particle.slv | 2 +- libraries/entities/CMakeLists.txt | 2 +- libraries/gpu-gl-common/CMakeLists.txt | 2 +- .../gpu-gl-common/src/gpu/gl/GLBackend.h | 15 +- .../src/gpu/gl/GLBackendPipeline.cpp | 2 +- .../src/gpu/gl/GLBackendShader.cpp | 156 ++---- .../gpu-gl-common/src/gpu/gl/GLPipeline.cpp | 2 +- libraries/gpu-gl-common/src/gpu/gl/GLShader.h | 42 +- libraries/gpu-gl/CMakeLists.txt | 2 +- libraries/gpu-gl/src/gpu/gl41/GL41Backend.h | 3 +- .../gpu-gl/src/gpu/gl41/GL41BackendShader.cpp | 20 +- libraries/gpu-gl/src/gpu/gl45/GL45Backend.h | 21 +- .../gpu-gl/src/gpu/gl45/GL45BackendShader.cpp | 18 +- libraries/gpu-gles/CMakeLists.txt | 2 +- libraries/gpu-gles/src/gpu/gles/GLESBackend.h | 6 +- .../src/gpu/gles/GLESBackendShader.cpp | 12 - .../src/gpu/gles/GLESBackendTransform.cpp | 3 +- libraries/gpu/src/gpu/DrawColor.slf | 2 +- libraries/gpu/src/gpu/DrawColoredTexture.slf | 4 +- .../gpu/DrawTexcoordRectTransformUnitQuad.slv | 2 +- libraries/gpu/src/gpu/DrawTexture.slf | 2 +- .../gpu/{drawTexture.slp => DrawTexture.slp} | 1 - .../gpu/src/gpu/DrawTextureMirroredX.slf | 2 +- .../gpu/src/gpu/DrawTextureMirroredX.slp | 1 + libraries/gpu/src/gpu/DrawTextureOpaque.slf | 2 +- .../gpu/src/gpu/DrawTransformedTexture.slp | 2 + libraries/gpu/src/gpu/Shader.cpp | 232 +++------ libraries/gpu/src/gpu/Shader.h | 180 +------ libraries/gpu/src/gpu/ShaderConstants.h | 15 - libraries/gpu/src/gpu/Transform.slh | 22 +- libraries/graphics/src/graphics/Light.slh | 8 +- libraries/graphics/src/graphics/Material.slh | 2 +- .../src/graphics/MaterialTextures.slh | 17 +- libraries/graphics/src/graphics/skybox.slf | 4 +- libraries/model-networking/CMakeLists.txt | 2 +- .../procedural/src/procedural/Procedural.cpp | 154 ++---- .../procedural/src/procedural/Procedural.h | 18 +- .../src/procedural/ProceduralCommon.slh | 62 ++- .../src/procedural/ProceduralSkybox.cpp | 2 +- .../src/procedural/ShaderConstants.h | 16 +- .../src/procedural/proceduralSkybox.slf | 12 +- .../src/procedural/proceduralSkybox.slp | 1 + libraries/render-utils/src/Blendshape.slh | 6 +- libraries/render-utils/src/BloomApply.slf | 8 +- libraries/render-utils/src/BloomThreshold.slf | 4 +- .../render-utils/src/DebugDeferredBuffer.cpp | 22 +- .../render-utils/src/DebugDeferredBuffer.h | 6 +- .../render-utils/src/DeferredBufferRead.slh | 18 +- .../src/DeferredLightingEffect.cpp | 2 +- .../render-utils/src/DeferredTransform.slh | 4 +- libraries/render-utils/src/Fade.slh | 6 +- libraries/render-utils/src/Haze.slf | 2 +- libraries/render-utils/src/Haze.slh | 2 +- libraries/render-utils/src/Highlight.slh | 6 +- .../render-utils/src/HighlightEffect.cpp | 37 +- .../render-utils/src/Highlight_aabox.slv | 8 +- libraries/render-utils/src/LightAmbient.slh | 2 +- .../render-utils/src/LightClusterGrid.slh | 6 +- libraries/render-utils/src/LightingModel.slh | 2 +- .../render-utils/src/RenderPipelines.cpp | 36 +- libraries/render-utils/src/ShadingModel.slh | 2 +- libraries/render-utils/src/Shadow.slh | 2 +- libraries/render-utils/src/ShadowCore.slh | 2 +- libraries/render-utils/src/Skinning.slh | 2 +- .../render-utils/src/SubsurfaceScattering.cpp | 12 +- .../render-utils/src/SubsurfaceScattering.h | 1 + .../render-utils/src/SubsurfaceScattering.slh | 6 +- .../render-utils/src/WorkloadResource.slh | 24 +- .../src/debug_deferred_buffer.slf | 12 +- .../render-utils/src/deferred_light_point.slv | 2 +- .../render-utils/src/deferred_light_spot.slv | 2 +- .../render-utils/src/drawWorkloadView.slv | 2 +- libraries/render-utils/src/forward_simple.slf | 59 +-- .../src/forward_simple_textured.slf | 2 +- .../forward_simple_textured_transparent.slf | 2 +- .../src/forward_simple_textured_unlit.slf | 2 +- libraries/render-utils/src/fxaa.slf | 2 +- libraries/render-utils/src/fxaa_blend.slf | 4 +- libraries/render-utils/src/glowLine.slv | 2 +- libraries/render-utils/src/grid.slf | 2 +- libraries/render-utils/src/hmd_ui.slf | 4 +- libraries/render-utils/src/hmd_ui.slv | 2 +- libraries/render-utils/src/parabola.slv | 2 +- .../src/render-utils/ShaderConstants.h | 9 - .../render-utils/debug_deferred_buffer.slp | 0 .../render-utils/src/render-utils/simple.slp | 1 - .../src/render-utils/simpleTranslucent.slp | 2 - .../render-utils/simpleTranslucentUnlit.slp | 2 - .../src/render-utils/simpleUnlit.slp | 2 - .../src/render-utils/simple_transparent.slp | 1 + libraries/render-utils/src/sdf_text3D.slf | 4 +- .../src/sdf_text3D_transparent.slf | 4 +- libraries/render-utils/src/simple.slf | 12 +- libraries/render-utils/src/simple_fade.slf | 110 ----- .../src/simple_opaque_web_browser.slf | 2 +- .../render-utils/src/simple_textured.slf | 2 +- .../render-utils/src/simple_textured_fade.slf | 2 +- .../src/simple_textured_unlit.slf | 2 +- .../src/simple_textured_unlit_fade.slf | 2 +- .../render-utils/src/simple_transparent.slf | 13 +- .../src/simple_transparent_textured.slf | 2 +- .../src/simple_transparent_textured_fade.slf | 2 +- .../src/simple_transparent_textured_unlit.slf | 2 +- ...simple_transparent_textured_unlit_fade.slf | 2 +- .../src/simple_transparent_web_browser.slf | 2 +- libraries/render-utils/src/ssao.slh | 6 +- .../render-utils/src/ssao_debugOcclusion.slf | 2 +- .../render-utils/src/ssao_makePyramid.slf | 2 +- .../render-utils/src/standardDrawTexture.slf | 2 +- .../src/standardDrawTextureNoBlend.slf | 2 +- .../subsurfaceScattering_drawScattering.slf | 18 +- .../src/surfaceGeometry_copyDepth.slf | 2 +- .../surfaceGeometry_downsampleDepthNormal.slf | 4 +- .../src/surfaceGeometry_makeCurvature.slf | 6 +- .../src/surfaceGeometry_makeLinearDepth.slf | 2 +- libraries/render-utils/src/taa.slh | 12 +- libraries/render-utils/src/toneMapping.slf | 4 +- .../src/velocityBuffer_cameraMotion.slf | 2 +- .../render-utils/src/zone_drawSkybox.slf | 4 +- libraries/render/src/render/BlurTask.slh | 8 +- libraries/render/src/render/ShapePipeline.cpp | 43 +- libraries/render/src/render/ShapePipeline.h | 2 +- .../render/src/render/drawItemBounds.slv | 8 +- .../render/src/render/drawItemStatus.slf | 2 +- libraries/script-engine/CMakeLists.txt | 2 +- libraries/shaders/CMakeLists.txt | 13 +- libraries/shaders/ShaderEnums.cpp.in | 18 +- libraries/shaders/headers/310es/header.glsl | 15 + libraries/shaders/headers/410/header.glsl | 15 + libraries/shaders/headers/450/header.glsl | 10 + libraries/shaders/headers/mono.glsl | 0 libraries/shaders/headers/stereo.glsl | 4 + libraries/shaders/src/shaders/Shaders.cpp | 412 +++++++++++++--- libraries/shaders/src/shaders/Shaders.h | 156 +++++- plugins/oculus/CMakeLists.txt | 2 +- plugins/oculusLegacy/CMakeLists.txt | 2 +- plugins/openvr/CMakeLists.txt | 2 +- tests-manual/gpu-textures/CMakeLists.txt | 2 +- .../gpu-textures/src/TestTextures.cpp | 6 +- tests-manual/gpu/CMakeLists.txt | 2 +- tests-manual/render-utils/CMakeLists.txt | 2 +- tests/shaders/CMakeLists.txt | 2 + tests/shaders/src/ShaderTests.cpp | 448 +++++++++++++++--- tests/shaders/src/ShaderTests.h | 5 +- tools/CMakeLists.txt | 3 - tools/ktx-tool/CMakeLists.txt | 2 +- tools/scribe/src/TextTemplate.cpp | 7 + tools/scribe/src/TextTemplate.h | 9 +- tools/scribe/src/main.cpp | 52 +- tools/shadergen.py | 254 ++++++++++ tools/shreflect/CMakeLists.txt | 10 - tools/shreflect/src/main.cpp | 204 -------- 175 files changed, 2316 insertions(+), 1697 deletions(-) create mode 100644 cmake/externals/glslang/CMakeLists.txt create mode 100644 cmake/externals/spirv_binaries/CMakeLists.txt create mode 100644 cmake/externals/spirv_cross/CMakeLists.txt create mode 100644 cmake/externals/spirv_headers/CMakeLists.txt create mode 100644 cmake/externals/spirv_tools/CMakeLists.txt create mode 100644 cmake/macros/TargetSPIRV.cmake create mode 100644 cmake/macros/TargetSpirvBinaries.cmake create mode 100644 cmake/macros/TargetVulkan.cmake rename libraries/gpu/src/gpu/{drawTexture.slp => DrawTexture.slp} (57%) create mode 100644 libraries/gpu/src/gpu/DrawTextureMirroredX.slp create mode 100644 libraries/gpu/src/gpu/DrawTransformedTexture.slp create mode 100644 libraries/procedural/src/procedural/proceduralSkybox.slp create mode 100644 libraries/render-utils/src/render-utils/debug_deferred_buffer.slp delete mode 100644 libraries/render-utils/src/render-utils/simpleTranslucent.slp delete mode 100644 libraries/render-utils/src/render-utils/simpleTranslucentUnlit.slp delete mode 100644 libraries/render-utils/src/render-utils/simpleUnlit.slp create mode 100644 libraries/render-utils/src/render-utils/simple_transparent.slp delete mode 100644 libraries/render-utils/src/simple_fade.slf create mode 100644 libraries/shaders/headers/310es/header.glsl create mode 100644 libraries/shaders/headers/410/header.glsl create mode 100644 libraries/shaders/headers/450/header.glsl create mode 100644 libraries/shaders/headers/mono.glsl create mode 100644 libraries/shaders/headers/stereo.glsl create mode 100644 tools/shadergen.py delete mode 100644 tools/shreflect/CMakeLists.txt delete mode 100644 tools/shreflect/src/main.cpp diff --git a/android/app/build.gradle b/android/app/build.gradle index 76f5acfaea..0136736dc3 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -24,7 +24,6 @@ android { '-DANDROID_STL=c++_shared', '-DQT_CMAKE_PREFIX_PATH=' + HIFI_ANDROID_PRECOMPILED + '/qt/lib/cmake', '-DNATIVE_SCRIBE=' + HIFI_ANDROID_PRECOMPILED + '/scribe' + EXEC_SUFFIX, - '-DNATIVE_SHREFLECT=' + HIFI_ANDROID_PRECOMPILED + '/shreflect' + EXEC_SUFFIX, '-DHIFI_ANDROID_PRECOMPILED=' + HIFI_ANDROID_PRECOMPILED, '-DRELEASE_NUMBER=' + RELEASE_NUMBER, '-DRELEASE_TYPE=' + RELEASE_TYPE, diff --git a/android/build.gradle b/android/build.gradle index 14f9e4803f..aafb96689e 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -161,31 +161,19 @@ def packages = [ ] ] - def scribeLocalFile='scribe' + EXEC_SUFFIX def scribeFile='scribe_linux_x86_64' -def scribeChecksum='ca4b904f52f4f993c29175ba96798fa6' -def scribeVersion='u_iTrJDaE95i2abTPXOpPZckGBIim53G' - -def shreflectLocalFile='shreflect' + EXEC_SUFFIX -def shreflectFile='shreflect_linux_x86_64' -def shreflectChecksum='d6094a8580066c0b6f4e80b5adfb1d98' -def shreflectVersion='jnrpudh6fptIg6T2.Z6fgKP2ultAdKmE' +def scribeChecksum='4635c28192724281d2367ce9e94380ab' +def scribeVersion='mPAY_N846oZH1tPY1bwChB_hzqkiYyoC' if (Os.isFamily(Os.FAMILY_MAC)) { scribeFile = 'scribe_osx_x86_64' - scribeChecksum='72db9d32d4e1e50add755570ac5eb749' - scribeVersion='DAW0DmnjCRib4MD8x93bgc2Z2MpPojZC' - shreflectFile='shreflect_osx_x86_64' - shreflectChecksum='d613ef0703c21371fee93fd2e54b964f' - shreflectVersion='.rYNzjSFq6WtWDnE5KIKRIAGyJtr__ad' + scribeChecksum='1ead61c285d265eba9a5ef91ae3b7c26' + scribeVersion='4TAXWdo9fviw60N2wUA8HNyQ9TabjZa3' } else if (Os.isFamily(Os.FAMILY_WINDOWS)) { scribeFile = 'scribe_win32_x86_64.exe' - scribeChecksum='678e43d290c90fda670c6fefe038a06d' - scribeVersion='PuullrA_bPlO9kXZRt8rLe536X1UI.m7' - shreflectFile='shreflect_win32_x86_64.exe' - shreflectChecksum='6f4a77b8cceb3f1bbc655132c3665060' - shreflectVersion='iIyCyza1nelkbI7ihybF59bBlwrfAC3D' + scribeChecksum='9c29a62595daf4844f95f6744d568c15' + scribeVersion='DUoxjufeX8ZAIVRBKRczWTuZwT13enTv' } def options = [ @@ -461,27 +449,11 @@ task fixScribePermissions(type: Exec, dependsOn: verifyScribe) { commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + scribeLocalFile } -task downloadShreflect(type: Download) { - src baseUrl + shreflectFile + '?versionId=' + shreflectVersion - dest new File(baseFolder, shreflectLocalFile) - onlyIfNewer true -} - -task verifyShreflect(type: Verify, dependsOn: downloadShreflect) { - src new File(baseFolder, shreflectLocalFile); - checksum shreflectChecksum -} - -task fixShreflectPermissions(type: Exec, dependsOn: verifyShreflect) { - commandLine 'chmod', 'a+x', HIFI_ANDROID_PRECOMPILED + '/' + shreflectLocalFile -} - -task setupScribe(dependsOn: [verifyScribe, verifyShreflect]) { } +task setupScribe(dependsOn: [verifyScribe]) { } // On Windows, we don't need to set the executable bit, but on OSX and Unix we do if (!Os.isFamily(Os.FAMILY_WINDOWS)) { setupScribe.dependsOn fixScribePermissions - setupScribe.dependsOn fixShreflectPermissions } task extractGvrBinaries(dependsOn: extractDependencies) { diff --git a/cmake/externals/glslang/CMakeLists.txt b/cmake/externals/glslang/CMakeLists.txt new file mode 100644 index 0000000000..4f8a6edf0d --- /dev/null +++ b/cmake/externals/glslang/CMakeLists.txt @@ -0,0 +1,42 @@ +set(EXTERNAL_NAME glslang) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +include(ExternalProject) + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://github.com/KhronosGroup/glslang/archive/7.8.2853.zip + URL_MD5 4f93e3818528176c622c137fba05cbf8 + CMAKE_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=-$ + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +# includes +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$") + +list(APPEND INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include) +#list(APPEND INCLUDE_DIRS ${INSTALL_DIR}/include) +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIR ${INCLUDE_DIRS} CACHE PATH "List of glslang include directories") +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${${EXTERNAL_NAME_UPPER}_INCLUDE_DIR} CACHE PATH "List of glslang include directories") + + +set(LIB_DIR ${SUFFIXED_INSTALL_DIR}/lib) +list(APPEND LIB_NAMES glslang HLSL OGLCompiler OSDependent SPIRV SPVRemapper) +include(SelectLibraryConfigurations) + +foreach(BASE_LIB ${LIB_NAMES}) + string(TOUPPER ${BASE_LIB} BASE_LIB_UPPER) + list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE "${LIB_DIR}/${BASE_LIB}.lib") + list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "${LIB_DIR}/${BASE_LIB}d.lib") +endforeach() + +select_library_configurations(${EXTERNAL_NAME_UPPER}) + +set(${EXTERNAL_NAME_UPPER}_LIBRARY ${${EXTERNAL_NAME_UPPER}_LIBRARY} CACHE FILEPATH "Location of glslang libraries") +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Location of glslang libraries") diff --git a/cmake/externals/spirv_binaries/CMakeLists.txt b/cmake/externals/spirv_binaries/CMakeLists.txt new file mode 100644 index 0000000000..d422eb9f16 --- /dev/null +++ b/cmake/externals/spirv_binaries/CMakeLists.txt @@ -0,0 +1,34 @@ +set(EXTERNAL_NAME spirv_binaries) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +include(ExternalProject) +if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") + set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-win32-1.1.82.1.tar.gz) + set(DOWNLOAD_MD5 3a83ef490bce248b1a4d6726a3e5893e) + set(BIN_DIR "Bin") +elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") + set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-macos-1.1.82.1.tar.gz) + set(DOWNLOAD_MD5 a57d37275b2c5db023ba8e84a63461ff) + set(BIN_DIR "macOS/bin") +else () + set(DOWNLOAD_URL https://public.highfidelity.com/dependencies/vulkan/vulkansdk-linux-x86_64-1.1.82.1.tar.gz) + set(DOWNLOAD_MD5 5a7c9eeda8cee6b36724da7f7cbe5ec6) + set(BIN_DIR "x86_64/bin") +endif () + +ExternalProject_Add( + ${EXTERNAL_NAME} + URL ${DOWNLOAD_URL} + URL_MD5 ${DOWNLOAD_MD5} + BUILD_COMMAND "" + CONFIGURE_COMMAND "" + INSTALL_COMMAND "" + LOG_DOWNLOAD ON +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") +ExternalProject_Get_Property(${EXTERNAL_NAME} SOURCE_DIR) + +set(${EXTERNAL_NAME_UPPER}_DIR "${SOURCE_DIR}/${BIN_DIR}" CACHE FILEPATH "SPIRV binary tools location") + diff --git a/cmake/externals/spirv_cross/CMakeLists.txt b/cmake/externals/spirv_cross/CMakeLists.txt new file mode 100644 index 0000000000..eaa7e4ffa1 --- /dev/null +++ b/cmake/externals/spirv_cross/CMakeLists.txt @@ -0,0 +1,35 @@ +set(EXTERNAL_NAME spirv_cross) + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://github.com/KhronosGroup/SPIRV-Cross/archive/2018-08-07.zip + URL_MD5 11198e4dc6a815ffbdb7a0a56d2d9261 + CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH=-$ ${EXTRA_CMAKE_FLAGS} + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$") + +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include CACHE PATH "List of Draco include directories") + +if (UNIX) + set(LIB_PREFIX "lib") + set(LIB_EXT "a") +elseif (WIN32) + set(LIB_EXT "lib") +endif () + +foreach(lib glsl msl cpp hlsl reflect util core) + list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/spirv-cross-${lib}.${LIB_EXT}) +endforeach() + +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Path to SPIRV-Cross libraries") diff --git a/cmake/externals/spirv_headers/CMakeLists.txt b/cmake/externals/spirv_headers/CMakeLists.txt new file mode 100644 index 0000000000..9613f97991 --- /dev/null +++ b/cmake/externals/spirv_headers/CMakeLists.txt @@ -0,0 +1,18 @@ +set(EXTERNAL_NAME spirv_headers) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://github.com/KhronosGroup/SPIRV-Headers/archive/2c512180ca03b5d4f56283efc85745775b45fdc4.zip + URL_MD5 83e652221b5f21d5fdb61c45f5b4d9f9 + CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_INSTALL_PREFIX:PATH= ${EXTRA_CMAKE_FLAGS} + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(${EXTERNAL_NAME_UPPER}_ROOT ${INSTALL_DIR} CACHE PATH "List of include directories") diff --git a/cmake/externals/spirv_tools/CMakeLists.txt b/cmake/externals/spirv_tools/CMakeLists.txt new file mode 100644 index 0000000000..a58d72502e --- /dev/null +++ b/cmake/externals/spirv_tools/CMakeLists.txt @@ -0,0 +1,33 @@ +set(EXTERNAL_NAME spirv_tools) +string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER) + +include(ExternalProject) +ExternalProject_Add( + ${EXTERNAL_NAME} + URL https://github.com/KhronosGroup/SPIRV-Tools/archive/v2018.4.zip + URL_MD5 7a7c69cf6ff0318910b4bfbdf30bcfc9 + CONFIGURE_COMMAND CMAKE_ARGS ${ANDROID_CMAKE_ARGS} -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DSPIRV-Headers_SOURCE_DIR=${SPIRV_HEADERS_ROOT} -DCMAKE_INSTALL_PREFIX:PATH=-$ ${EXTRA_CMAKE_FLAGS} + LOG_DOWNLOAD 1 + LOG_CONFIGURE 1 + LOG_BUILD 1 +) + +# Hide this external target (for ide users) +set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals") + +ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR) +set(SUFFIXED_INSTALL_DIR "${INSTALL_DIR}-$") + +set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${SUFFIXED_INSTALL_DIR}/include CACHE PATH "List of SPIRV-Tools include directories") + +if (UNIX) + set(LIB_PREFIX "lib") + set(LIB_EXT "a") +elseif (WIN32) + set(LIB_EXT "lib") +endif () + +list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools-opt.${LIB_EXT}) +list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools-link.${LIB_EXT}) +list(APPEND ${EXTERNAL_NAME_UPPER}_LIBRARIES ${SUFFIXED_INSTALL_DIR}/lib/SPIRV-Tools.${LIB_EXT}) +set(${EXTERNAL_NAME_UPPER}_LIBRARIES ${${EXTERNAL_NAME_UPPER}_LIBRARIES} CACHE FILEPATH "Path to SPIRV-Tool libraries") diff --git a/cmake/init.cmake b/cmake/init.cmake index 9adcb167df..3f632b30f8 100644 --- a/cmake/init.cmake +++ b/cmake/init.cmake @@ -10,6 +10,10 @@ if (POLICY CMP0042) cmake_policy(SET CMP0042 NEW) endif () +if (POLICY CMP0074) + cmake_policy(SET CMP0074 OLD) +endif () + set_property(GLOBAL PROPERTY USE_FOLDERS ON) set_property(GLOBAL PROPERTY PREDEFINED_TARGETS_FOLDER "CMakeTargets") # Hide automoc folders (for IDEs) diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index 9c5ad70c78..06c29e06e3 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -8,34 +8,132 @@ # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html # +# FIXME use the built tools + +macro(AUTOSCRIBE_APPEND_QRC) + string(CONCAT SHADER_QRC "${SHADER_QRC}" "${ARGV1}\n") +endmacro() + +set(VULKAN_DIR $ENV{VULKAN_SDK}) +set(GLSLANG_EXEC "${VULKAN_DIR}/Bin/glslangValidator.exe") +set(SPIRV_CROSS_EXEC "${VULKAN_DIR}/Bin/spirv-cross.exe") +set(SPIRV_OPT_EXEC "${VULKAN_DIR}/Bin/spirv-opt.exe") +set(GLSLC_EXEC "${VULKAN_DIR}/Bin/glslc.exe") +set(SCRIBE_EXEC "D:/scribe.exe") + +macro(AUTOSCRIBE_PLATFORM_SHADER) + set(AUTOSCRIBE_PLATFORM_PATH "${ARGV0}") + string(REGEX MATCH "([0-9]+(es)?)(/stereo)?" PLATFORM_PATH_REGEX ${AUTOSCRIBE_PLATFORM_PATH}) + set(AUTOSCRIBE_DIALECT "${CMAKE_MATCH_1}") + if (CMAKE_MATCH_3) + set(AUTOSCRIBE_VARIANT "stereo") + else() + set(AUTOSCRIBE_VARIANT "mono") + endif() + string(REGEX REPLACE "/" "\\\\" SOURCE_GROUP_PATH ${AUTOSCRIBE_PLATFORM_PATH}) + set(SOURCE_GROUP_PATH "${SHADER_LIB}\\${SOURCE_GROUP_PATH}") + set(AUTOSCRIBE_DIALECT_HEADER "${AUTOSCRIBE_HEADER_DIR}/${AUTOSCRIBE_DIALECT}/header.glsl") + set(AUTOSCRIBE_VARIANT_HEADER "${AUTOSCRIBE_HEADER_DIR}/${AUTOSCRIBE_VARIANT}.glsl") + + set(AUTOSCRIBE_OUTPUT_FILE "${SHADERS_DIR}/${SHADER_LIB}/${AUTOSCRIBE_PLATFORM_PATH}/${SHADER_NAME}.${SHADER_TYPE}") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/scribe" "${AUTOSCRIBE_OUTPUT_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_OUTPUT_FILE}) + set_property(SOURCE ${AUTOSCRIBE_OUTPUT_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND SCRIBED_SHADERS ${AUTOSCRIBE_OUTPUT_FILE}) + + set(AUTOSCRIBE_SPIRV_FILE "${AUTOSCRIBE_OUTPUT_FILE}.spv") + # don't add unoptimized spirv to the QRC + #AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/spirv_unopt" "${AUTOSCRIBE_SPIRV_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_FILE}) + set_property(SOURCE ${AUTOSCRIBE_SPIRV_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_FILE}) + + set(AUTOSCRIBE_SPIRV_OPT_FILE "${AUTOSCRIBE_OUTPUT_FILE}.opt.spv") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/spirv" "${AUTOSCRIBE_SPIRV_OPT_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_OPT_FILE}) + set_property(SOURCE ${AUTOSCRIBE_SPIRV_OPT_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_OPT_FILE}) + + set(AUTOSCRIBE_SPIRV_GLSL_FILE "${AUTOSCRIBE_OUTPUT_FILE}.glsl") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/glsl" "${AUTOSCRIBE_SPIRV_GLSL_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_GLSL_FILE}) + set_property(SOURCE ${AUTOSCRIBE_SPIRV_GLSL_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND SPIRV_SHADERS ${AUTOSCRIBE_SPIRV_GLSL_FILE}) + + set(AUTOSCRIBE_SPIRV_JSON_FILE "${AUTOSCRIBE_OUTPUT_FILE}.json") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/${AUTOSCRIBE_PLATFORM_PATH}/json" "${AUTOSCRIBE_SPIRV_JSON_FILE}") + source_group(${SOURCE_GROUP_PATH} FILES ${AUTOSCRIBE_SPIRV_JSON_FILE}) + set_property(SOURCE ${AUTOSCRIBE_SPIRV_JSON_FILE} PROPERTY SKIP_AUTOMOC ON) + list(APPEND REFLECTED_SHADERS ${AUTOSCRIBE_SPIRV_JSON_FILE}) + + unset(SHADER_GEN_LINE) + list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_DIALECT}) + list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_VARIANT}) + file(RELATIVE_PATH TEMP_PATH ${CMAKE_SOURCE_DIR} ${SHADER_FILE}) + list(APPEND SHADER_GEN_LINE ${TEMP_PATH}) + file(RELATIVE_PATH TEMP_PATH ${CMAKE_SOURCE_DIR} ${AUTOSCRIBE_OUTPUT_FILE}) + list(APPEND SHADER_GEN_LINE ${TEMP_PATH}) + list(APPEND SHADER_GEN_LINE ${AUTOSCRIBE_SHADER_SEEN_LIBS}) + string(CONCAT AUTOSCRIBE_SHADERGEN_COMMANDS "${AUTOSCRIBE_SHADERGEN_COMMANDS}" "${SHADER_GEN_LINE}\n") + + # # FIXME need better mechanism for determining the include files + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_OUTPUT_FILE} + # COMMAND ${SCRIBE_COMMAND} ${SHADER_FILE} ${SCRIBE_ARGS} -o ${AUTOSCRIBE_OUTPUT_FILE} -h ${AUTOSCRIBE_DIALECT_HEADER} -h ${AUTOSCRIBE_VARIANT_HEADER} + # DEPENDS ${SCRIBE_COMMAND} ${SHADER_FILE} ${AUTOSCRIBE_DIALECT_HEADER} ${AUTOSCRIBE_VARIANT_HEADER}) + + # # Generate the spirv file + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_SPIRV_FILE} + # COMMAND ${GLSLANG_EXEC} -V110 -o ${AUTOSCRIBE_SPIRV_FILE} ${AUTOSCRIBE_OUTPUT_FILE} + # DEPENDS ${AUTOSCRIBE_OUTPUT_FILE} ${GLSLANG_EXEC}) + + # # Generate the optimized spirv file + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_SPIRV_OPT_FILE} + # COMMAND ${SPIRV_OPT_EXEC} -O ${AUTOSCRIBE_SPIRV_FILE} -o ${AUTOSCRIBE_SPIRV_OPT_FILE} + # DEPENDS ${AUTOSCRIBE_SPIRV_FILE} ${SPIRV_OPT_EXEC}) + + # # Generate the optimized GLSL file + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_SPIRV_GLSL_FILE} + # COMMAND ${SPIRV_CROSS_EXEC} ${SPIRV_CROSS_ARGS} ${AUTOSCRIBE_SPIRV_OPT_FILE} --output ${AUTOSCRIBE_SPIRV_GLSL_FILE} + # DEPENDS ${AUTOSCRIBE_SPIRV_OPT_FILE} ${SPIRV_CROSS_EXEC}) + + # # Generate the optimized spirv file + # add_custom_command( + # OUTPUT ${AUTOSCRIBE_SPIRV_JSON_FILE} + # COMMAND ${SPIRV_CROSS_EXEC} --reflect json ${AUTOSCRIBE_SPIRV_OPT_FILE} --output ${AUTOSCRIBE_SPIRV_JSON_FILE} + # DEPENDS ${AUTOSCRIBE_SPIRV_OPT_FILE} ${SPIRV_CROSS_EXEC}) +endmacro() + macro(AUTOSCRIBE_SHADER) + # + # Set the include paths + # + # FIXME base the include paths off of output from the scribe tool, + # instead of treating every previously seen shader as a possible header unset(SHADER_INCLUDE_FILES) - # Grab include files foreach(includeFile ${ARGN}) list(APPEND SHADER_INCLUDE_FILES ${includeFile}) endforeach() - foreach(SHADER_INCLUDE ${SHADER_INCLUDE_FILES}) get_filename_component(INCLUDE_DIR ${SHADER_INCLUDE} PATH) list(APPEND SHADER_INCLUDES_PATHS ${INCLUDE_DIR}) endforeach() - - list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS) - #Extract the unique include shader paths set(INCLUDES ${HIFI_LIBRARIES_SHADER_INCLUDE_FILES}) foreach(EXTRA_SHADER_INCLUDE ${INCLUDES}) list(APPEND SHADER_INCLUDES_PATHS ${EXTRA_SHADER_INCLUDE}) endforeach() - list(REMOVE_DUPLICATES SHADER_INCLUDES_PATHS) - #message(ready for includes ${SHADER_INCLUDES_PATHS}) - - # make the scribe include arguments - set(SCRIBE_INCLUDES) + unset(SCRIBE_INCLUDES) foreach(INCLUDE_PATH ${SHADER_INCLUDES_PATHS}) set(SCRIBE_INCLUDES ${SCRIBE_INCLUDES} -I ${INCLUDE_PATH}/) endforeach() + # + # Figure out the various output names + # # Define the final name of the generated shader file get_filename_component(SHADER_NAME ${SHADER_FILE} NAME_WE) get_filename_component(SHADER_EXT ${SHADER_FILE} EXT) @@ -46,38 +144,36 @@ macro(AUTOSCRIBE_SHADER) elseif(${SHADER_EXT} STREQUAL .slg) set(SHADER_TYPE geom) endif() - file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}") - set(SHADER_TARGET "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_NAME}.${SHADER_TYPE}") - file(TO_CMAKE_PATH "${SHADER_TARGET}" COMPILED_SHADER) - set(REFLECTED_SHADER "${COMPILED_SHADER}.json") - set(SCRIBE_ARGS -T ${SHADER_TYPE} -D GLPROFILE ${GLPROFILE} ${SCRIBE_INCLUDES} -o ${SHADER_TARGET} ${SHADER_FILE}) + set(SCRIBE_ARGS -D GLPROFILE ${GLPROFILE} -T ${SHADER_TYPE} ${SCRIBE_INCLUDES} ) - # Generate the frag/vert file - add_custom_command( - OUTPUT ${SHADER_TARGET} - COMMAND ${SCRIBE_COMMAND} ${SCRIBE_ARGS} - DEPENDS ${SHADER_FILE} ${SCRIBE_COMMAND} ${SHADER_INCLUDE_FILES}) + # SHADER_SCRIBED -> the output of scribe + set(SHADER_SCRIBED "${SHADERS_DIR}/${SHADER_LIB}/${SHADER_NAME}.${SHADER_TYPE}") - # Generate the json reflection - # FIXME move to spirv-cross for this task after we have spirv compatible shaders - add_custom_command( - OUTPUT ${REFLECTED_SHADER} - COMMAND ${SHREFLECT_COMMAND} ${COMPILED_SHADER} - DEPENDS ${SHREFLECT_DEPENDENCY} ${COMPILED_SHADER}) + # SHADER_NAME_FILE -> a file containing the shader name and extension (useful for debugging and for + # determining the type of shader from the filename) + set(SHADER_NAME_FILE "${SHADER_SCRIBED}.name") + file(TO_CMAKE_PATH "${SHADER_SCRIBED}" SHADER_SCRIBED) + file(WRITE "${SHADER_SCRIBED}.name" "${SHADER_NAME}.${SHADER_TYPE}") + AUTOSCRIBE_APPEND_QRC("${SHADER_COUNT}/name" "${SHADER_NAME_FILE}") - #output the generated file name - source_group("Compiled/${SHADER_LIB}" FILES ${COMPILED_SHADER}) - set_property(SOURCE ${COMPILED_SHADER} PROPERTY SKIP_AUTOMOC ON) - list(APPEND COMPILED_SHADERS ${COMPILED_SHADER}) + if (USE_GLES) + set(SPIRV_CROSS_ARGS --version 310es) + AUTOSCRIBE_PLATFORM_SHADER("310es") + AUTOSCRIBE_PLATFORM_SHADER("310es/stereo") + else() + set(SPIRV_CROSS_ARGS --version 410 --no-420pack-extension) + AUTOSCRIBE_PLATFORM_SHADER("410") + AUTOSCRIBE_PLATFORM_SHADER("410/stereo") + if (NOT APPLE) + set(SPIRV_CROSS_ARGS --version 450) + AUTOSCRIBE_PLATFORM_SHADER("450") + AUTOSCRIBE_PLATFORM_SHADER("450/stereo") + endif() + endif() - source_group("Reflected/${SHADER_LIB}" FILES ${REFLECTED_SHADER}) - list(APPEND REFLECTED_SHADERS ${REFLECTED_SHADER}) - - string(CONCAT SHADER_QRC "${SHADER_QRC}" "${COMPILED_SHADER}\n") - string(CONCAT SHADER_QRC "${SHADER_QRC}" "${REFLECTED_SHADER}\n") string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "${SHADER_NAME} = ${SHADER_COUNT},\n") - + string(CONCAT SHADER_SHADERS_ARRAY "${SHADER_SHADERS_ARRAY}" "${SHADER_COUNT},\n") MATH(EXPR SHADER_COUNT "${SHADER_COUNT}+1") endmacro() @@ -86,6 +182,8 @@ macro(AUTOSCRIBE_SHADER_LIB) message(FATAL_ERROR "AUTOSCRIBE_SHADER_LIB can only be used by the shaders library") endif() + file(MAKE_DIRECTORY "${SHADERS_DIR}/${SHADER_LIB}") + list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES "${CMAKE_SOURCE_DIR}/libraries/${SHADER_LIB}/src") string(REGEX REPLACE "[-]" "_" SHADER_NAMESPACE ${SHADER_LIB}) string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "namespace ${SHADER_NAMESPACE} {\n") @@ -165,66 +263,103 @@ macro(AUTOSCRIBE_SHADER_LIB) # Finish the shader enums string(CONCAT SHADER_ENUMS "${SHADER_ENUMS}" "} // namespace ${SHADER_NAMESPACE}\n") - #file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") - #foreach(HIFI_LIBRARY ${ARGN}) - #list(APPEND HIFI_LIBRARIES_SHADER_INCLUDE_FILES ${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src) - #endforeach() - #endif() endmacro() macro(AUTOSCRIBE_SHADER_LIBS) - set(SCRIBE_COMMAND scribe) - set(SHREFLECT_COMMAND shreflect) - set(SHREFLECT_DEPENDENCY shreflect) - - # Target dependant Custom rule on the SHADER_FILE - if (ANDROID) - set(GLPROFILE LINUX_GL) - set(SCRIBE_COMMAND ${NATIVE_SCRIBE}) - set(SHREFLECT_COMMAND ${NATIVE_SHREFLECT}) - unset(SHREFLECT_DEPENDENCY) - else() - if (APPLE) - set(GLPROFILE MAC_GL) - elseif(UNIX) - set(GLPROFILE LINUX_GL) - else() - set(GLPROFILE PC_GL) - endif() - endif() - + message(STATUS "Shader processing start") + set(AUTOSCRIBE_HEADER_DIR ${CMAKE_CURRENT_SOURCE_DIR}/headers) # Start the shader IDs - set(SHADER_COUNT 1) set(SHADERS_DIR "${CMAKE_CURRENT_BINARY_DIR}/shaders") - set(SHADER_ENUMS "") file(MAKE_DIRECTORY ${SHADERS_DIR}) + set(SHADER_ENUMS "") + set(SHADER_COUNT 1) # # Scribe generation & program defintiion # foreach(SHADER_LIB ${ARGN}) + list(APPEND AUTOSCRIBE_SHADER_SEEN_LIBS ${SHADER_LIB}) AUTOSCRIBE_SHADER_LIB(${SHADER_LIB}) endforeach() # Generate the library files configure_file( ShaderEnums.cpp.in - ${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp) + ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.cpp) configure_file( ShaderEnums.h.in - ${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h) - configure_file( - shaders.qrc.in - ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc) + ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.h) - set(AUTOSCRIBE_SHADER_LIB_SRC "${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.h;${CMAKE_CURRENT_BINARY_DIR}/shaders/ShaderEnums.cpp") - set(QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc) + configure_file(shaders.qrc.in ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc) + list(APPEND QT_RESOURCES_FILE ${CMAKE_CURRENT_BINARY_DIR}/shaders.qrc) + + list(APPEND AUTOSCRIBE_SHADER_HEADERS ${AUTOSCRIBE_HEADER_DIR}/mono.glsl ${AUTOSCRIBE_HEADER_DIR}/stereo.glsl) + list(APPEND AUTOSCRIBE_SHADER_HEADERS ${AUTOSCRIBE_HEADER_DIR}/450/header.glsl ${AUTOSCRIBE_HEADER_DIR}/410/header.glsl ${AUTOSCRIBE_HEADER_DIR}/310es/header.glsl) + source_group("Shader Headers" FILES ${AUTOSCRIBE_HEADER_DIR}/mono.glsl ${AUTOSCRIBE_HEADER_DIR}/stereo.glsl) + source_group("Shader Headers\\450" FILES ${AUTOSCRIBE_HEADER_DIR}/450/header.glsl) + source_group("Shader Headers\\410" FILES ${AUTOSCRIBE_HEADER_DIR}/410/header.glsl) + source_group("Shader Headers\\310es" FILES ${AUTOSCRIBE_HEADER_DIR}/310es/header.glsl) + + list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${AUTOSCRIBE_SHADER_HEADERS}) + list(APPEND AUTOSCRIBE_SHADER_LIB_SRC ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.h ${CMAKE_CURRENT_BINARY_DIR}/ShaderEnums.cpp) + # Write the shadergen command list + set(AUTOSCRIBE_SHADERGEN_COMMANDS_FILE ${CMAKE_CURRENT_BINARY_DIR}/shadergen.txt) + file(WRITE ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE} "${AUTOSCRIBE_SHADERGEN_COMMANDS}") + + # grab the SPIRV binaries we require + # note we don't use the normal ADD_DEPENDENCY_EXTERNAL_PROJECTS macro because only a custom command + # depends on these, not any of our build artifacts, so there's no valid target for the add_dependencies + # call in ADD_DEPENDENCY_EXTERNAL_PROJECTS to use + add_subdirectory(${EXTERNAL_PROJECT_DIR}/spirv_binaries ${EXTERNALS_BINARY_DIR}/spirv_binaries) + + target_python() + + # A custom python script which will generate + if (ANDROID) + add_custom_command( + OUTPUT ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS} + COMMENT "Generating/updating shaders" + COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_SOURCE_DIR}/tools/shadergen.py + --commands ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE} + --spirv-binaries ${SPIRV_BINARIES_DIR} + --scribe ${NATIVE_SCRIBE} + --build-dir ${CMAKE_CURRENT_BINARY_DIR} + --source-dir ${CMAKE_SOURCE_DIR} + DEPENDS ${AUTOSCRIBE_SHADER_HEADERS} spirv_binaries ${CMAKE_SOURCE_DIR}/tools/shadergen.py ${ALL_SCRIBE_SHADERS}) + else() + add_custom_command( + OUTPUT ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS} + COMMENT "Generating/updating shaders" + COMMAND ${HIFI_PYTHON_EXEC} ${CMAKE_SOURCE_DIR}/tools/shadergen.py + --commands ${AUTOSCRIBE_SHADERGEN_COMMANDS_FILE} + --spirv-binaries ${SPIRV_BINARIES_DIR} + --scribe $ + --build-dir ${CMAKE_CURRENT_BINARY_DIR} + --source-dir ${CMAKE_SOURCE_DIR} + DEPENDS ${AUTOSCRIBE_SHADER_HEADERS} scribe spirv_binaries ${CMAKE_SOURCE_DIR}/tools/shadergen.py ${ALL_SCRIBE_SHADERS}) + endif() + + add_custom_target(shadergen DEPENDS ${SCRIBED_SHADERS} ${SPIRV_SHADERS} ${REFLECTED_SHADERS}) + set_target_properties(shadergen PROPERTIES FOLDER "Shaders") + # Custom targets required to force generation of the shaders via scribe - add_custom_target(scribe_shaders SOURCES ${ALL_SCRIBE_SHADERS}) - add_custom_target(compiled_shaders SOURCES ${COMPILED_SHADERS}) - add_custom_target(reflected_shaders SOURCES ${REFLECTED_SHADERS}) + add_custom_target(scribe_shaders SOURCES ${ALL_SCRIBE_SHADERS} ${AUTOSCRIBE_SHADER_HEADERS}) set_target_properties(scribe_shaders PROPERTIES FOLDER "Shaders") - set_target_properties(compiled_shaders PROPERTIES FOLDER "Shaders") + + add_custom_target(scribed_shaders SOURCES ${SCRIBED_SHADERS}) + set_target_properties(scribed_shaders PROPERTIES FOLDER "Shaders") + add_dependencies(scribed_shaders shadergen) + + add_custom_target(spirv_shaders SOURCES ${SPIRV_SHADERS}) + set_target_properties(spirv_shaders PROPERTIES FOLDER "Shaders") + add_dependencies(spirv_shaders shadergen) + + add_custom_target(reflected_shaders SOURCES ${REFLECTED_SHADERS}) set_target_properties(reflected_shaders PROPERTIES FOLDER "Shaders") + add_dependencies(reflected_shaders shadergen) + + message(STATUS "Shader processing end") endmacro() + + diff --git a/cmake/macros/TargetPython.cmake b/cmake/macros/TargetPython.cmake index a7c3344fc0..cd0ea0f34c 100644 --- a/cmake/macros/TargetPython.cmake +++ b/cmake/macros/TargetPython.cmake @@ -15,8 +15,8 @@ macro(TARGET_PYTHON) set(HIFI_PYTHON_EXEC ${Python3_EXECUTABLE}) endif() - if ((NOT HIFI_PYTHON_EXEC) OR (HIFI_PYTHON_VERSION VERSION_LESS 3.6)) - message(FATAL_ERROR "Unable to locate Python interpreter 3.6 or higher") + if ((NOT HIFI_PYTHON_EXEC) OR (HIFI_PYTHON_VERSION VERSION_LESS 3.5)) + message(FATAL_ERROR "Unable to locate Python interpreter 3.5 or higher") endif() endif() endmacro() \ No newline at end of file diff --git a/cmake/macros/TargetSPIRV.cmake b/cmake/macros/TargetSPIRV.cmake new file mode 100644 index 0000000000..94c9df9d13 --- /dev/null +++ b/cmake/macros/TargetSPIRV.cmake @@ -0,0 +1,15 @@ +macro(TARGET_SPIRV) + add_dependency_external_projects(spirv_cross) + target_link_libraries(${TARGET_NAME} ${SPIRV_CROSS_LIBRARIES}) + target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SPIRV_CROSS_INCLUDE_DIRS}) + + # spirv-tools requires spirv-headers + add_dependency_external_projects(spirv_headers) + add_dependency_external_projects(spirv_tools) + target_link_libraries(${TARGET_NAME} ${SPIRV_TOOLS_LIBRARIES}) + target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${SPIRV_TOOLS_INCLUDE_DIRS}) + + add_dependency_external_projects(glslang) + target_link_libraries(${TARGET_NAME} ${GLSLANG_LIBRARIES}) + target_include_directories(${TARGET_NAME} SYSTEM PRIVATE ${GLSLANG_INCLUDE_DIRS}) +endmacro() diff --git a/cmake/macros/TargetSpirvBinaries.cmake b/cmake/macros/TargetSpirvBinaries.cmake new file mode 100644 index 0000000000..6cc102d38e --- /dev/null +++ b/cmake/macros/TargetSpirvBinaries.cmake @@ -0,0 +1,10 @@ +# +# Created by Bradley Austin Davis on 2016/02/16 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_SPIRV_BINARIES) + add_dependency_external_projects(spirv_binaries) +endmacro() + diff --git a/cmake/macros/TargetVulkan.cmake b/cmake/macros/TargetVulkan.cmake new file mode 100644 index 0000000000..4702583ff5 --- /dev/null +++ b/cmake/macros/TargetVulkan.cmake @@ -0,0 +1,19 @@ +# +# Created by Bradley Austin Davis on 2016/02/16 +# +# Distributed under the Apache License, Version 2.0. +# See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +# +macro(TARGET_VULKAN) + find_package(Vulkan) + + if (Vulkan_FOUND) + add_definitions(-DHAVE_VULKAN) + target_include_directories(${TARGET_NAME} PRIVATE ${Vulkan_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${Vulkan_LIBRARIES}) + + add_dependency_external_projects(glslang) + target_include_directories(${TARGET_NAME} PRIVATE ${GLSLANG_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${GLSLANG_LIBRARIES}) + endif() +endmacro() \ No newline at end of file diff --git a/libraries/avatars-renderer/CMakeLists.txt b/libraries/avatars-renderer/CMakeLists.txt index e6b6986e7b..89dcc61805 100644 --- a/libraries/avatars-renderer/CMakeLists.txt +++ b/libraries/avatars-renderer/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME avatars-renderer) setup_hifi_library(Network Script) -link_hifi_libraries(shared gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer) +link_hifi_libraries(shared shaders gpu graphics animation model-networking script-engine render render-utils image trackers entities-renderer) include_hifi_library_headers(avatars) include_hifi_library_headers(networking) include_hifi_library_headers(fbx) diff --git a/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf b/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf index 17dedce7f9..e70053dcd9 100644 --- a/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf +++ b/libraries/display-plugins/src/display-plugins/InterleavedSrgbToLinear.slf @@ -2,11 +2,11 @@ struct TextureData { ivec2 textureSize; }; -layout(std140, binding=0) uniform textureDataBuffer { +LAYOUT_STD140(binding=0) uniform textureDataBuffer { TextureData textureData; }; -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp index 580bea254a..6448c6d3a1 100644 --- a/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/OpenGLDisplayPlugin.cpp @@ -363,56 +363,35 @@ void OpenGLDisplayPlugin::customizeContext() { } if (!_presentPipeline) { + gpu::StatePointer blendState = gpu::StatePointer(new gpu::State()); + blendState->setDepthTest(gpu::State::DepthTest(false)); + blendState->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + gpu::StatePointer scissorState = gpu::StatePointer(new gpu::State()); + scissorState->setDepthTest(gpu::State::DepthTest(false)); + scissorState->setScissorEnable(true); + { - gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::drawTexture); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setScissorEnable(true); - _simplePipeline = gpu::Pipeline::create(program, state); + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTexture); + _simplePipeline = gpu::Pipeline::create(program, scissorState); + _hudPipeline = gpu::Pipeline::create(program, blendState); } { gpu::ShaderPointer program = gpu::Shader::createProgram(shader::display_plugins::program::SrgbToLinear); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setScissorEnable(true); - _presentPipeline = gpu::Pipeline::create(program, state); + _presentPipeline = gpu::Pipeline::create(program, scissorState); } { - auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord); - auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _hudPipeline = gpu::Pipeline::create(program, state); + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTextureMirroredX); + _mirrorHUDPipeline = gpu::Pipeline::create(program, blendState); } { - auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawUnitQuadTexcoord); - auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTextureMirroredX); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _mirrorHUDPipeline = gpu::Pipeline::create(program, state); - } - - { - auto vs = gpu::Shader::createVertex(shader::gpu::vertex::DrawTransformUnitQuad); - auto ps = gpu::Shader::createPixel(shader::gpu::fragment::DrawTexture); - gpu::ShaderPointer program = gpu::Shader::createProgram(vs, ps); - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setDepthTest(gpu::State::DepthTest(false)); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _cursorPipeline = gpu::Pipeline::create(program, state); + gpu::ShaderPointer program = gpu::Shader::createProgram(shader::gpu::program::DrawTransformedTexture); + _cursorPipeline = gpu::Pipeline::create(program, blendState); } } updateCompositeFramebuffer(); diff --git a/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf b/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf index c2bcfb5cb3..aad9e71e0e 100644 --- a/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf +++ b/libraries/display-plugins/src/display-plugins/SrgbToLinear.slf @@ -1,10 +1,10 @@ // OpenGLDisplayPlugin_present.frag -layout(binding = 0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; -layout(location = 0) in vec2 varTexCoord0; +layout(location=0) in vec2 varTexCoord0; -layout(location = 0) out vec4 outFragColor; +layout(location=0) out vec4 outFragColor; float sRGBFloatToLinear(float value) { const float SRGB_ELBOW = 0.04045; diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 5003e36e86..a705b61cd3 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -30,12 +30,14 @@ using namespace render::entities; // is a half unit sphere. However, the geometry cache renders a UNIT sphere, so we need to scale down. static const float SPHERE_ENTITY_SCALE = 0.5f; +static_assert(shader::render_utils::program::simple != 0, "Validate simple program exists"); +static_assert(shader::render_utils::program::simple_transparent != 0, "Validate simple transparent program exists"); ShapeEntityRenderer::ShapeEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { _procedural._vertexSource = gpu::Shader::getVertexShaderSource(shader::render_utils::vertex::simple); // FIXME: Setup proper uniform slots and use correct pipelines for forward rendering - _procedural._opaquefragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple); - _procedural._transparentfragmentSource = gpu::Shader::getFragmentShaderSource(shader::render_utils::fragment::simple_transparent); + _procedural._opaqueFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple); + _procedural._transparentFragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::simple_transparent); _procedural._opaqueState->setCullMode(gpu::State::CULL_NONE); _procedural._opaqueState->setDepthTest(true, true, gpu::LESS_EQUAL); PrepareStencil::testMaskDrawShape(*_procedural._opaqueState); diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 211685a9ba..ea54637b91 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -15,7 +15,7 @@ <@include DeferredBufferWrite.slh@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=0) in vec3 interpolatedNormal; diff --git a/libraries/entities-renderer/src/paintStroke_fade.slf b/libraries/entities-renderer/src/paintStroke_fade.slf index e5f70c8038..1ace04f7b3 100644 --- a/libraries/entities-renderer/src/paintStroke_fade.slf +++ b/libraries/entities-renderer/src/paintStroke_fade.slf @@ -18,7 +18,7 @@ <$declareFadeFragment()$> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=0) in vec3 interpolatedNormal; @@ -30,7 +30,7 @@ struct PolyLineUniforms { vec3 color; }; -layout(binding=0) uniform polyLineBuffer { +LAYOUT(binding=0) uniform polyLineBuffer { PolyLineUniforms polyline; }; diff --git a/libraries/entities-renderer/src/polyvox.slf b/libraries/entities-renderer/src/polyvox.slf index 441dfc11e5..6b1aa25a25 100644 --- a/libraries/entities-renderer/src/polyvox.slf +++ b/libraries/entities-renderer/src/polyvox.slf @@ -20,15 +20,15 @@ layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normal; layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position; layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition; -layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; -layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; -layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; struct PolyvoxParams { vec4 voxelVolumeSize; }; -layout(binding=0) uniform polyvoxParamsBuffer { +LAYOUT(binding=0) uniform polyvoxParamsBuffer { PolyvoxParams params; }; diff --git a/libraries/entities-renderer/src/polyvox_fade.slf b/libraries/entities-renderer/src/polyvox_fade.slf index 6e236193aa..ae2e05c3dc 100644 --- a/libraries/entities-renderer/src/polyvox_fade.slf +++ b/libraries/entities-renderer/src/polyvox_fade.slf @@ -23,15 +23,15 @@ layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _position; layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _worldPosition; layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _worldFadePosition; -layout(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; -layout(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; -layout(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_XMAP) uniform sampler2D xMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_YMAP) uniform sampler2D yMap; +LAYOUT(binding=ENTITIES_TEXTURE_POLYVOX_ZMAP) uniform sampler2D zMap; struct PolyvoxParams { vec4 voxelVolumeSize; }; -layout(binding=0) uniform polyvoxParamsBuffer { +LAYOUT(binding=0) uniform polyvoxParamsBuffer { PolyvoxParams params; }; diff --git a/libraries/entities-renderer/src/textured_particle.slf b/libraries/entities-renderer/src/textured_particle.slf index 7a0cedf011..7dadb6fc49 100644 --- a/libraries/entities-renderer/src/textured_particle.slf +++ b/libraries/entities-renderer/src/textured_particle.slf @@ -10,7 +10,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec4 varColor; layout(location=1) in vec2 varTexcoord; diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 3eacaec3b5..4d17fe132b 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -43,7 +43,7 @@ struct ParticleUniforms { vec2 spare; }; -layout(std140, binding=0) uniform particleBuffer { +LAYOUT_STD140(binding=0) uniform particleBuffer { ParticleUniforms particle; }; diff --git a/libraries/entities/CMakeLists.txt b/libraries/entities/CMakeLists.txt index dca495ee03..c547708ffa 100644 --- a/libraries/entities/CMakeLists.txt +++ b/libraries/entities/CMakeLists.txt @@ -5,4 +5,4 @@ include_hifi_library_headers(fbx) include_hifi_library_headers(gpu) include_hifi_library_headers(image) include_hifi_library_headers(ktx) -link_hifi_libraries(shared networking octree avatars graphics model-networking) \ No newline at end of file +link_hifi_libraries(shared shaders networking octree avatars graphics model-networking) \ No newline at end of file diff --git a/libraries/gpu-gl-common/CMakeLists.txt b/libraries/gpu-gl-common/CMakeLists.txt index 2b6f8d4d40..70cf3536ed 100644 --- a/libraries/gpu-gl-common/CMakeLists.txt +++ b/libraries/gpu-gl-common/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME gpu-gl-common) setup_hifi_library(Concurrent) -link_hifi_libraries(shared gl gpu) +link_hifi_libraries(shared gl gpu shaders) GroupSources("src") target_opengl() diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 267c2a97ad..c309bcb864 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -643,18 +643,21 @@ protected: } } _pipeline; - // Backend dependant compilation of the shader + // Backend dependent compilation of the shader virtual void postLinkProgram(ShaderObject& programObject, const Shader& program) const; virtual GLShader* compileBackendProgram(const Shader& program, const Shader::CompilationHandler& handler); virtual GLShader* compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler); - virtual std::string getBackendShaderHeader() const = 0; - // For a program, this will return a string containing all the source files (without any - // backend headers or defines). For a vertex, fragment or geometry shader, this will - // return the fully customized shader with all the version and backend specific + + // For a program, this will return a string containing all the source files (without any + // backend headers or defines). For a vertex, fragment or geometry shader, this will + // return the fully customized shader with all the version and backend specific // preprocessor directives // The program string returned can be used as a key for a cache of shader binaries // The shader strings can be reliably sent to the low level `compileShader` functions - virtual std::string getShaderSource(const Shader& shader, int version) final; + virtual std::string getShaderSource(const Shader& shader, shader::Variant version) final; + shader::Variant getShaderVariant() const { return isStereo() ? shader::Variant::Stereo : shader::Variant::Mono; } + virtual shader::Dialect getShaderDialect() const = 0; + class ElementResource { public: gpu::Element _element; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp index 7a06b3af86..1e811653f9 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendPipeline.cpp @@ -54,7 +54,7 @@ void GLBackend::do_setPipeline(const Batch& batch, size_t paramOffset) { // check the program cache // pick the program version #ifdef GPU_STEREO_CAMERA_BUFFER - GLuint glprogram = pipelineObject->_program->getProgram((GLShader::Version)isStereo()); + GLuint glprogram = pipelineObject->_program->getProgram(getShaderVariant()); #else GLuint glprogram = pipelineObject->_program->getProgram(); #endif diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendShader.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendShader.cpp index 7267e29be2..f737842ec0 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendShader.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendShader.cpp @@ -25,120 +25,53 @@ static const std::array SHADER_DOMAINS{ { GL_GEOMETRY_SHADER, } }; -// Domain specific defines -// Must match the order of type specified in gpu::Shader::Type -static const std::array DOMAIN_DEFINES{ { - "#define GPU_VERTEX_SHADER", - "#define GPU_PIXEL_SHADER", - "#define GPU_GEOMETRY_SHADER", -} }; - -// Stereo specific defines -static const std::string stereoVersion{ -#ifdef GPU_STEREO_DRAWCALL_INSTANCED -R"SHADER( -#define GPU_TRANSFORM_IS_STEREO -#define GPU_TRANSFORM_STEREO_CAMERA -#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED -#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN -)SHADER" -#endif -#ifdef GPU_STEREO_DRAWCALL_DOUBLED -#ifdef GPU_STEREO_CAMERA_BUFFER -R"SHADER( -#define GPU_TRANSFORM_IS_STEREO -#define GPU_TRANSFORM_STEREO_CAMERA -#define GPU_TRANSFORM_STEREO_CAMERA_ATTRIBUTED -)SHADER" -#else -R"SHADER( -#define GPU_TRANSFORM_IS_STEREO -)SHADER" -#endif -#endif -}; - -// TextureTable specific defines -static const std::string textureTableVersion { - "#extension GL_ARB_bindless_texture : require\n#define GPU_TEXTURE_TABLE_BINDLESS\n" -}; - -// Versions specific of the shader -static const std::array VERSION_DEFINES { { - "", - stereoVersion -} }; - -static std::string getShaderTypeString(Shader::Type type) { - switch (type) { - case Shader::Type::VERTEX: - return "vertex"; - case Shader::Type::PIXEL: - return "pixel"; - case Shader::Type::GEOMETRY: - return "geometry"; - case Shader::Type::PROGRAM: - return "program"; - default: - qFatal("Unexpected shader type %d", type); - Q_UNREACHABLE(); - } -} - -std::string GLBackend::getShaderSource(const Shader& shader, int version) { +std::string GLBackend::getShaderSource(const Shader& shader, shader::Variant variant) { if (shader.isProgram()) { std::string result; - result.append("// VERSION " + std::to_string(version)); for (const auto& subShader : shader.getShaders()) { - result.append("//-------- "); - result.append(getShaderTypeString(subShader->getType())); - result.append("\n"); - result.append(subShader->getSource().getCode()); + if (subShader) { + result += subShader->getSource().getSource(getShaderDialect(), variant); + } } return result; - } - - std::string shaderDefines = getBackendShaderHeader() + "\n" - + (supportsBindless() ? textureTableVersion : "\n") - + DOMAIN_DEFINES[shader.getType()] + "\n" - + VERSION_DEFINES[version]; - - return shaderDefines + "\n" + shader.getSource().getCode(); + } + return shader.getSource().getSource(getShaderDialect(), variant); } GLShader* GLBackend::compileBackendShader(const Shader& shader, const Shader::CompilationHandler& handler) { // Any GLSLprogram ? normally yes... GLenum shaderDomain = SHADER_DOMAINS[shader.getType()]; GLShader::ShaderObjects shaderObjects; - Shader::CompilationLogs compilationLogs(GLShader::NumVersions); + const auto& variants = shader::allVariants(); + Shader::CompilationLogs compilationLogs(variants.size()); shader.incrementCompilationAttempt(); - - for (int version = 0; version < GLShader::NumVersions; version++) { - auto& shaderObject = shaderObjects[version]; - auto shaderSource = getShaderSource(shader, version); + for (const auto& variant : variants) { + auto index = static_cast(variant); + auto shaderSource = getShaderSource(shader, variant); + auto& shaderObject = shaderObjects[index]; if (handler) { bool retest = true; std::string currentSrc = shaderSource; // When a Handler is specified, we can try multiple times to build the shader and let the handler change the source if the compilation fails. - // The retest bool is set to false as soon as the compilation succeed to wexit the while loop. + // The retest bool is set to false as soon as the compilation succeed to exit the while loop. // The handler tells us if we should retry or not while returning a modified version of the source. while (retest) { - bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderObject.glshader, compilationLogs[version].message); - compilationLogs[version].compiled = result; + bool result = ::gl::compileShader(shaderDomain, currentSrc, shaderObject.glshader, compilationLogs[index].message); + compilationLogs[index].compiled = result; if (!result) { std::string newSrc; - retest = handler(shader, currentSrc, compilationLogs[version], newSrc); + retest = handler(shader, currentSrc, compilationLogs[index], newSrc); currentSrc = newSrc; } else { retest = false; } } } else { - compilationLogs[version].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderObject.glshader, compilationLogs[version].message); + compilationLogs[index].compiled = ::gl::compileShader(shaderDomain, shaderSource, shaderObject.glshader, compilationLogs[index].message); } - if (!compilationLogs[version].compiled) { - qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[version].message.c_str(); + if (!compilationLogs[index].compiled) { + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Shader didn't compile:\n" << compilationLogs[index].message.c_str(); shader.setCompilationLogs(compilationLogs); return nullptr; } @@ -162,11 +95,13 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: GLShader::ShaderObjects programObjects; program.incrementCompilationAttempt(); - Shader::CompilationLogs compilationLogs(GLShader::NumVersions); + const auto& variants = shader::allVariants(); + Shader::CompilationLogs compilationLogs(variants.size()); - for (int version = 0; version < GLShader::NumVersions; version++) { - auto& programObject = programObjects[version]; - auto programSource = getShaderSource(program, version); + for (const auto& variant : variants) { + auto index = static_cast(variant); + auto& programObject = programObjects[index]; + auto programSource = getShaderSource(program, variant); auto hash = ::gl::getShaderHash(programSource); CachedShader cachedBinary; @@ -199,11 +134,11 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: for (auto subShader : program.getShaders()) { auto object = GLShader::sync((*this), *subShader, handler); if (object) { - shaderGLObjects.push_back(object->_shaderObjects[version].glshader); + shaderGLObjects.push_back(object->_shaderObjects[index].glshader); } else { qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - One of the shaders of the program is not compiled?"; - compilationLogs[version].compiled = false; - compilationLogs[version].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?"); + compilationLogs[index].compiled = false; + compilationLogs[index].message = std::string("Failed to compile, one of the shaders of the program is not compiled ?"); program.setCompilationLogs(compilationLogs); return nullptr; } @@ -211,9 +146,9 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: glprogram = ::gl::buildProgram(shaderGLObjects); - if (!::gl::linkProgram(glprogram, compilationLogs[version].message)) { - qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str(); - compilationLogs[version].compiled = false; + if (!::gl::linkProgram(glprogram, compilationLogs[index].message)) { + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[index].message.c_str(); + compilationLogs[index].compiled = false; glDeleteProgram(glprogram); glprogram = 0; return nullptr; @@ -228,12 +163,12 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: } if (glprogram == 0) { - qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[version].message.c_str(); + qCWarning(gpugllogging) << "GLBackend::compileBackendProgram - Program didn't link:\n" << compilationLogs[index].message.c_str(); program.setCompilationLogs(compilationLogs); return nullptr; } - compilationLogs[version].compiled = true; + compilationLogs[index].compiled = true; programObject.glprogram = glprogram; postLinkProgram(programObject, program); } @@ -249,7 +184,10 @@ GLShader* GLBackend::compileBackendProgram(const Shader& program, const Shader:: static const GLint INVALID_UNIFORM_INDEX = -1; GLint GLBackend::getRealUniformLocation(GLint location) const { - auto& shader = _pipeline._programShader->_shaderObjects[(GLShader::Version)isStereo()]; + auto variant = isStereo() ? shader::Variant::Stereo : shader::Variant::Mono; + auto index = static_cast(variant); + + auto& shader = _pipeline._programShader->_shaderObjects[index]; auto itr = shader.uniformRemap.find(location); if (itr == shader.uniformRemap.end()) { // This shouldn't happen, because we use reflection to determine all the possible @@ -264,20 +202,23 @@ GLint GLBackend::getRealUniformLocation(GLint location) const { void GLBackend::postLinkProgram(ShaderObject& shaderObject, const Shader& program) const { const auto& glprogram = shaderObject.glprogram; - const auto& expectedUniforms = program.getUniforms(); - const auto expectedLocationsByName = expectedUniforms.getLocationsByName(); - const auto uniforms = ::gl::Uniform::load(glprogram, expectedUniforms.getNames()); - auto& uniformRemap = shaderObject.uniformRemap; + const auto& expectedUniforms = program.getReflection().uniforms; - // Pre-initialize all the uniforms with an invalid location - for (const auto& entry : expectedLocationsByName) { + auto& uniformRemap = shaderObject.uniformRemap; + // initialize all the uniforms with an invalid location + for (const auto& entry : expectedUniforms) { uniformRemap[entry.second] = INVALID_UNIFORM_INDEX; } - // Now load up all the actual found uniform location + + // Get the actual uniform locations from the shader + const auto names = Shader::Reflection::getNames(expectedUniforms); + const auto uniforms = ::gl::Uniform::load(glprogram, names); + + // Now populate the remapping with the found locations for (const auto& uniform : uniforms) { const auto& name = uniform.name; - const auto& expectedLocation = expectedLocationsByName.at(name); + const auto& expectedLocation = expectedUniforms.at(name); const auto& location = uniform.binding; uniformRemap[expectedLocation] = location; } @@ -462,3 +403,4 @@ void GLBackend::initShaderBinaryCache() { void GLBackend::killShaderBinaryCache() { ::gl::saveShaderCache(_shaderBinaryCache._binaries); } + diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLPipeline.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLPipeline.cpp index a099e6e66a..e00dc9fc25 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLPipeline.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLPipeline.cpp @@ -52,7 +52,7 @@ GLPipeline* GLPipeline::sync(GLBackend& backend, const Pipeline& pipeline) { // Special case for view correction matrices, any pipeline that declares the correction buffer // uniform will automatically have it provided without any client code necessary. // Required for stable lighting in the HMD. - object->_cameraCorrection = shader->getUniformBuffers().isValid(gpu::slot::buffer::CameraCorrection); + object->_cameraCorrection = shader->getReflection().validUniformBuffer(gpu::slot::buffer::CameraCorrection); object->_program = programObject; object->_state = stateObject; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLShader.h b/libraries/gpu-gl-common/src/gpu/gl/GLShader.h index 5d5d8a4a3c..1d56bb2122 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLShader.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLShader.h @@ -14,43 +14,45 @@ namespace gpu { namespace gl { struct ShaderObject { - GLuint glshader { 0 }; - GLuint glprogram { 0 }; + enum class BindingType + { + INPUT, + OUTPUT, + TEXTURE, + SAMPLER, + UNIFORM_BUFFER, + RESOURCE_BUFFER, + UNIFORM, + }; - using LocationMap = std::unordered_map ; - LocationMap uniformRemap; + using LocationMap = std::unordered_map; + using ReflectionMap = std::map; + using UniformMap = std::unordered_map; + + GLuint glshader{ 0 }; + GLuint glprogram{ 0 }; + + UniformMap uniformRemap; }; class GLShader : public GPUObject { public: static GLShader* sync(GLBackend& backend, const Shader& shader, const Shader::CompilationHandler& handler = nullptr); - - enum Version { - Mono = 0, - Stereo, - - NumVersions - }; - using ShaderObject = gpu::gl::ShaderObject; - using ShaderObjects = std::array< ShaderObject, NumVersions >; - - using UniformMapping = std::map; - using UniformMappingVersions = std::vector; + using ShaderObjects = std::array; GLShader(const std::weak_ptr& backend); ~GLShader(); ShaderObjects _shaderObjects; - GLuint getProgram(Version version = Mono) const { - return _shaderObjects[version].glprogram; + GLuint getProgram(shader::Variant version = shader::Variant::Mono) const { + return _shaderObjects[static_cast(version)].glprogram; } const std::weak_ptr _backend; }; -} } - +}} // namespace gpu::gl #endif diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index faddab8531..225c795754 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME gpu-gl) setup_hifi_library(Concurrent) -link_hifi_libraries(shared gl gpu gpu-gl-common) +link_hifi_libraries(shared gl gpu gpu-gl-common shaders) if (UNIX) target_link_libraries(${TARGET_NAME} pthread) endif(UNIX) diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index 5d691d032a..881487c9db 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -170,8 +170,7 @@ protected: // Output stage void do_blit(const Batch& batch, size_t paramOffset) override; - std::string getBackendShaderHeader() const override; - + shader::Dialect getShaderDialect() const override { return shader::Dialect::glsl410; } void postLinkProgram(ShaderObject& programObject, const Shader& program) const override; }; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp index 46f91fdc15..f162afc497 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendShader.cpp @@ -12,22 +12,13 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gl41; -// GLSL version -std::string GL41Backend::getBackendShaderHeader() const { - static const std::string header( - R"SHADER(#version 410 core - #define GPU_GL410 - #define BITFIELD int - )SHADER"); - return header; -} - void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& program) const { Parent::postLinkProgram(programObject, program); const auto& glprogram = programObject.glprogram; + const auto& reflection = program.getReflection(); // For the UBOs, use glUniformBlockBinding to fixup the locations based on the reflection { - const auto expectedUbos = program.getUniformBuffers().getLocationsByName(); + const auto& expectedUbos = reflection.uniformBuffers; auto ubos = ::gl::UniformBlock::load(glprogram); for (const auto& ubo : ubos) { const auto& name = ubo.name; @@ -41,7 +32,7 @@ void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& pro // For the Textures, use glUniform1i to fixup the active texture slots based on the reflection { - const auto expectedTextures = program.getTextures().getLocationsByName(); + const auto& expectedTextures = reflection.textures; for (const auto& expectedTexture : expectedTextures) { auto location = glGetUniformLocation(glprogram, expectedTexture.first.c_str()); if (location < 0) { @@ -53,8 +44,9 @@ void GL41Backend::postLinkProgram(ShaderObject& programObject, const Shader& pro // For the resource buffers, do the same as for the textures, since in GL 4.1 that's how they're implemented { - const auto expectedResourceBuffers = program.getResourceBuffers().getLocationsByName(); - const auto resourceBufferUniforms = ::gl::Uniform::loadByName(glprogram, program.getResourceBuffers().getNames()); + const auto& expectedResourceBuffers = reflection.resourceBuffers; + const auto names = Shader::Reflection::getNames(expectedResourceBuffers); + const auto resourceBufferUniforms = ::gl::Uniform::loadByName(glprogram, names); for (const auto& resourceBuffer : resourceBufferUniforms) { const auto& targetBinding = expectedResourceBuffers.at(resourceBuffer.name); glProgramUniform1i(glprogram, resourceBuffer.binding, targetBinding + GL41Backend::RESOURCE_BUFFER_SLOT0_TEX_UNIT); diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 77095375af..c1ce074188 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -23,7 +23,7 @@ #define GPU_BINDLESS_TEXTURES 0 namespace gpu { namespace gl45 { - + using namespace gpu::gl; using TextureWeakPointer = std::weak_ptr; @@ -56,6 +56,7 @@ public: using Parent = GLTexture; friend class GL45Backend; static GLuint allocate(const Texture& texture); + protected: GL45Texture(const std::weak_ptr& backend, const Texture& texture); void generateMips() const override; @@ -88,6 +89,7 @@ public: virtual const Bindless& getBindless() const; void releaseBindless() const; void recreateBindless() const; + private: mutable Bindless _bindless; #endif @@ -98,10 +100,11 @@ public: mutable Sampler _cachedSampler{ getInvalidSampler() }; }; -#if GPU_BINDLESS_TEXTURES +#if GPU_BINDLESS_TEXTURES class GL45TextureTable : public GLObject { static GLuint allocate(); using Parent = GLObject; + public: using BindlessArray = std::array; @@ -116,7 +119,6 @@ public: }; #endif - // // Textures that have fixed allocation sizes and cannot be managed at runtime // @@ -134,12 +136,13 @@ public: void allocateStorage() const; void syncSampler() const override; - const Size _size { 0 }; + const Size _size{ 0 }; }; class GL45AttachmentTexture : public GL45FixedAllocationTexture { using Parent = GL45FixedAllocationTexture; friend class GL45Backend; + protected: GL45AttachmentTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45AttachmentTexture(); @@ -148,6 +151,7 @@ public: class GL45StrictResourceTexture : public GL45FixedAllocationTexture { using Parent = GL45FixedAllocationTexture; friend class GL45Backend; + protected: GL45StrictResourceTexture(const std::weak_ptr& backend, const Texture& texture); ~GL45StrictResourceTexture(); @@ -179,6 +183,7 @@ public: class GL45ResourceTexture : public GL45VariableAllocationTexture { using Parent = GL45VariableAllocationTexture; friend class GL45Backend; + protected: GL45ResourceTexture(const std::weak_ptr& backend, const Texture& texture); @@ -186,7 +191,6 @@ public: size_t promote() override; size_t demote() override; void populateTransferQueue(TransferQueue& pendingTransfers) override; - void allocateStorage(uint16 mip); Size copyMipsFromTexture(); @@ -226,7 +230,6 @@ public: }; #endif - protected: void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override; @@ -244,7 +247,6 @@ protected: GLuint getQueryID(const QueryPointer& query) override; GLQuery* syncGPUObject(const Query& query) override; - // Draw Stage void do_draw(const Batch& batch, size_t paramOffset) override; void do_drawIndexed(const Batch& batch, size_t paramOffset) override; @@ -270,7 +272,7 @@ protected: void do_blit(const Batch& batch, size_t paramOffset) override; // Shader Stage - std::string getBackendShaderHeader() const override; + shader::Dialect getShaderDialect() const override; // Texture Management Stage void initTextureManagementStage() override; @@ -282,9 +284,8 @@ protected: #endif }; -} } +}} // namespace gpu::gl45 Q_DECLARE_LOGGING_CATEGORY(gpugl45logging) #endif - diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp index 6cc0d226d6..cf8279b8e6 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendShader.cpp @@ -7,22 +7,16 @@ // #include "GL45Backend.h" #include -//#include using namespace gpu; using namespace gpu::gl; using namespace gpu::gl45; -// GLSL version -std::string GL45Backend::getBackendShaderHeader() const { - static const std::string header( - R"SHADER(#version 450 core - #define GPU_GL450 - #define BITFIELD int - )SHADER" -#ifdef GPU_SSBO_TRANSFORM_OBJECT - R"SHADER(#define GPU_SSBO_TRANSFORM_OBJECT)SHADER" +shader::Dialect GL45Backend::getShaderDialect() const { +#if defined(Q_OS_MAC) + // We build, but don't actually use GL 4.5 on OSX + throw std::runtime_error("GL 4.5 unavailable on OSX"); +#else + return shader::Dialect::glsl450; #endif - ); - return header; } diff --git a/libraries/gpu-gles/CMakeLists.txt b/libraries/gpu-gles/CMakeLists.txt index 82bf670781..3e529f7dcd 100644 --- a/libraries/gpu-gles/CMakeLists.txt +++ b/libraries/gpu-gles/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME gpu-gles) setup_hifi_library(Gui Concurrent) -link_hifi_libraries(shared gl gpu gpu-gl-common) +link_hifi_libraries(shared shaders gl gpu gpu-gl-common) GroupSources("src") target_opengl() diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h index 7f6765c129..8ecdb2494b 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h @@ -27,11 +27,7 @@ class GLESBackend : public GLBackend { friend class Context; public: - static const GLint TRANSFORM_OBJECT_SLOT { 31 }; static const GLint RESOURCE_TRANSFER_TEX_UNIT { 32 }; - static const GLint RESOURCE_TRANSFER_EXTRA_TEX_UNIT { 33 }; - static const GLint RESOURCE_BUFFER_TEXBUF_TEX_UNIT { 34 }; - static const GLint RESOURCE_BUFFER_SLOT0_TEX_UNIT { 35 }; explicit GLESBackend(bool syncCache) : Parent(syncCache) {} GLESBackend() : Parent() {} virtual ~GLESBackend() { @@ -166,7 +162,7 @@ protected: // Output stage void do_blit(const Batch& batch, size_t paramOffset) override; - std::string getBackendShaderHeader() const override; + shader::Dialect getShaderDialect() const override { return shader::Dialect::glsl310es; } }; } } diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendShader.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendShader.cpp index ee8408c533..dded307249 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackendShader.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendShader.cpp @@ -12,15 +12,3 @@ using namespace gpu; using namespace gpu::gl; using namespace gpu::gles; -// GLSL version -std::string GLESBackend::getBackendShaderHeader() const { - static const std::string header( - R"SHADER(#version 310 es - #extension GL_EXT_texture_buffer : enable - precision highp float; - precision highp samplerBuffer; - precision highp sampler2DShadow; - #define BITFIELD highp int - )SHADER"); - return header; -} diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp index 661eb0de99..7e1ee0da3b 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackendTransform.cpp @@ -60,12 +60,11 @@ void GLESBackend::transferTransformState(const Batch& batch) const { glBindBuffer(GL_ARRAY_BUFFER, 0); } - glActiveTexture(GL_TEXTURE0 + GLESBackend::TRANSFORM_OBJECT_SLOT); + glActiveTexture(GL_TEXTURE0 + slot::texture::ObjectTransforms); glBindTexture(GL_TEXTURE_BUFFER, _transform._objectBufferTexture); if (!batch._objects.empty()) { glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, _transform._objectBuffer); } - CHECK_GL_ERROR(); // Make sure the current Camera offset is unknown before render Draw diff --git a/libraries/gpu/src/gpu/DrawColor.slf b/libraries/gpu/src/gpu/DrawColor.slf index fdea26fa68..3d5b569662 100644 --- a/libraries/gpu/src/gpu/DrawColor.slf +++ b/libraries/gpu/src/gpu/DrawColor.slf @@ -17,7 +17,7 @@ struct DrawColorParams { vec4 color; }; -layout(binding=0) uniform drawColorParamsBuffer { +LAYOUT(binding=0) uniform drawColorParamsBuffer { DrawColorParams params; }; diff --git a/libraries/gpu/src/gpu/DrawColoredTexture.slf b/libraries/gpu/src/gpu/DrawColoredTexture.slf index 0fe3707b1c..a4f03f925d 100755 --- a/libraries/gpu/src/gpu/DrawColoredTexture.slf +++ b/libraries/gpu/src/gpu/DrawColoredTexture.slf @@ -13,13 +13,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; struct DrawColorParams { vec4 color; }; -layout(binding=0) uniform drawColorParams { +LAYOUT(binding=0) uniform drawColorParams { DrawColorParams params; }; diff --git a/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv b/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv index 8849cb494a..a59180ec31 100755 --- a/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv +++ b/libraries/gpu/src/gpu/DrawTexcoordRectTransformUnitQuad.slv @@ -25,7 +25,7 @@ struct TexCoordRectParams { vec4 texcoordRect; }; -layout(binding=0) uniform texcoordRectBuffer { +LAYOUT(binding=0) uniform texcoordRectBuffer { TexCoordRectParams params; }; diff --git a/libraries/gpu/src/gpu/DrawTexture.slf b/libraries/gpu/src/gpu/DrawTexture.slf index 4298729b8b..f8f06eb6ca 100755 --- a/libraries/gpu/src/gpu/DrawTexture.slf +++ b/libraries/gpu/src/gpu/DrawTexture.slf @@ -14,7 +14,7 @@ // -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/gpu/src/gpu/drawTexture.slp b/libraries/gpu/src/gpu/DrawTexture.slp similarity index 57% rename from libraries/gpu/src/gpu/drawTexture.slp rename to libraries/gpu/src/gpu/DrawTexture.slp index e04be84618..f922364b75 100644 --- a/libraries/gpu/src/gpu/drawTexture.slp +++ b/libraries/gpu/src/gpu/DrawTexture.slp @@ -1,2 +1 @@ VERTEX DrawUnitQuadTexcoord -FRAGMENT DrawTexture diff --git a/libraries/gpu/src/gpu/DrawTextureMirroredX.slf b/libraries/gpu/src/gpu/DrawTextureMirroredX.slf index ab6333f08d..abb52cbe7f 100644 --- a/libraries/gpu/src/gpu/DrawTextureMirroredX.slf +++ b/libraries/gpu/src/gpu/DrawTextureMirroredX.slf @@ -14,7 +14,7 @@ // -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/gpu/src/gpu/DrawTextureMirroredX.slp b/libraries/gpu/src/gpu/DrawTextureMirroredX.slp new file mode 100644 index 0000000000..db9a4a4fac --- /dev/null +++ b/libraries/gpu/src/gpu/DrawTextureMirroredX.slp @@ -0,0 +1 @@ +VERTEX DrawUnitQuadTexcoord \ No newline at end of file diff --git a/libraries/gpu/src/gpu/DrawTextureOpaque.slf b/libraries/gpu/src/gpu/DrawTextureOpaque.slf index b3227325bf..e23529e851 100755 --- a/libraries/gpu/src/gpu/DrawTextureOpaque.slf +++ b/libraries/gpu/src/gpu/DrawTextureOpaque.slf @@ -16,7 +16,7 @@ <@include gpu/ShaderConstants.h@> -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; diff --git a/libraries/gpu/src/gpu/DrawTransformedTexture.slp b/libraries/gpu/src/gpu/DrawTransformedTexture.slp new file mode 100644 index 0000000000..daeafe6012 --- /dev/null +++ b/libraries/gpu/src/gpu/DrawTransformedTexture.slp @@ -0,0 +1,2 @@ +VERTEX DrawTransformUnitQuad +FRAGMENT DrawTexture diff --git a/libraries/gpu/src/gpu/Shader.cpp b/libraries/gpu/src/gpu/Shader.cpp index 0191d9d4f1..d4236ac66c 100755 --- a/libraries/gpu/src/gpu/Shader.cpp +++ b/libraries/gpu/src/gpu/Shader.cpp @@ -10,44 +10,49 @@ // #include "Shader.h" -#include -#include -#include - -#include -#include - -#include #include "Context.h" using namespace gpu; -std::atomic Shader::_nextShaderID( 1 ); -Shader::DomainShaderMaps Shader::_domainShaderMaps; Shader::ProgramMap Shader::_programMap; -Shader::Shader(Type type, const Source& source) : - _source(source), - _type(type), - _ID(_nextShaderID++) +Shader::Shader(Type type, const Source& source, bool dynamic) : + _type(type) { + auto& thisSource = const_cast(_source); + thisSource = source; + if (!dynamic) { + thisSource.id = source.id; + } } -Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel): - _type(type), - _ID(_nextShaderID++) +Shader::Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel) : + _type(type) { + + auto& shaders = const_cast(_shaders); if (geometry) { - _shaders.resize(3); - _shaders[VERTEX] = vertex; - _shaders[GEOMETRY] = geometry; - _shaders[PIXEL] = pixel; + shaders.resize(3); + shaders[VERTEX] = vertex; + shaders[GEOMETRY] = geometry; + shaders[PIXEL] = pixel; } else { - _shaders.resize(2); - _shaders[VERTEX] = vertex; - _shaders[PIXEL] = pixel; + shaders.resize(2); + shaders[VERTEX] = vertex; + shaders[PIXEL] = pixel; + } + + auto& reflection = const_cast(getReflection()); + for (const auto& subShader : _shaders) { + reflection.merge(subShader->getReflection()); + } + if (_shaders[VERTEX]) { + reflection.inputs = _shaders[VERTEX]->getReflection().inputs; + } + if (_shaders[PIXEL]) { + reflection.outputs = _shaders[PIXEL]->getReflection().outputs; } } @@ -55,46 +60,27 @@ Shader::~Shader() { } -void populateSlotSet(Shader::SlotSet& slotSet, const Shader::LocationMap& map) { - for (const auto& entry : map) { - const auto& name = entry.first; - const auto& location = entry.second; - slotSet.insert({ name, location, Element() }); - } +static std::unordered_map> _shaderCache; + +Shader::ID Shader::getID() const { + if (isProgram()) { + return (_shaders[VERTEX]->getID() << 16) | (_shaders[PIXEL]->getID()); + } + + return _source.id; } -Shader::Pointer Shader::createOrReuseDomainShader(Type type, const Source& source) { - auto found = _domainShaderMaps[type].find(source); - if (found != _domainShaderMaps[type].end()) { +Shader::Pointer Shader::createOrReuseDomainShader(Type type, uint32_t sourceId) { + // Don't attempt to cache non-static shaders + auto found = _shaderCache.find(sourceId); + if (found != _shaderCache.end()) { auto sharedShader = (*found).second.lock(); if (sharedShader) { return sharedShader; } } - auto shader = Pointer(new Shader(type, source)); - const auto& reflection = source.getReflection(); - if (0 != reflection.count(BindingType::INPUT)) { - populateSlotSet(shader->_inputs, reflection.find(BindingType::INPUT)->second); - } - if (0 != reflection.count(BindingType::OUTPUT)) { - populateSlotSet(shader->_outputs, reflection.find(BindingType::OUTPUT)->second); - } - if (0 != reflection.count(BindingType::UNIFORM_BUFFER)) { - populateSlotSet(shader->_uniformBuffers, reflection.find(BindingType::UNIFORM_BUFFER)->second); - } - if (0 != reflection.count(BindingType::RESOURCE_BUFFER)) { - populateSlotSet(shader->_resourceBuffers, reflection.find(BindingType::RESOURCE_BUFFER)->second); - } - if (0 != reflection.count(BindingType::TEXTURE)) { - populateSlotSet(shader->_textures, reflection.find(BindingType::TEXTURE)->second); - } - if (0 != reflection.count(BindingType::SAMPLER)) { - populateSlotSet(shader->_samplers, reflection.find(BindingType::SAMPLER)->second); - } - if (0 != reflection.count(BindingType::UNIFORM)) { - populateSlotSet(shader->_uniforms, reflection.find(BindingType::UNIFORM)->second); - } - _domainShaderMaps[type].emplace(source, std::weak_ptr(shader)); + auto shader = Pointer(new Shader(type, getShaderSource(sourceId), false)); + _shaderCache.insert({ sourceId, shader }); return shader; } @@ -137,28 +123,6 @@ ShaderPointer Shader::createOrReuseProgramShader(Type type, const Pointer& verte // Program is a new one, let's create it auto program = Pointer(new Shader(type, vertexShader, geometryShader, pixelShader)); - - // Combine the slots from the sub-shaders - for (const auto& shader : program->_shaders) { - const auto& reflection = shader->_source.getReflection(); - if (0 != reflection.count(BindingType::UNIFORM_BUFFER)) { - populateSlotSet(program->_uniformBuffers, reflection.find(BindingType::UNIFORM_BUFFER)->second); - } - if (0 != reflection.count(BindingType::RESOURCE_BUFFER)) { - populateSlotSet(program->_resourceBuffers, reflection.find(BindingType::RESOURCE_BUFFER)->second); - } - if (0 != reflection.count(BindingType::TEXTURE)) { - populateSlotSet(program->_textures, reflection.find(BindingType::TEXTURE)->second); - } - if (0 != reflection.count(BindingType::SAMPLER)) { - populateSlotSet(program->_samplers, reflection.find(BindingType::SAMPLER)->second); - } - if (0 != reflection.count(BindingType::UNIFORM)) { - populateSlotSet(program->_uniforms, reflection.find(BindingType::UNIFORM)->second); - } - - } - _programMap.emplace(key, std::weak_ptr(program)); return program; } @@ -175,24 +139,21 @@ void Shader::incrementCompilationAttempt() const { } Shader::Pointer Shader::createVertex(const Source& source) { - return createOrReuseDomainShader(VERTEX, source); + return Pointer(new Shader(VERTEX, source, true)); } Shader::Pointer Shader::createPixel(const Source& source) { - return createOrReuseDomainShader(FRAGMENT, source); + return Pointer(new Shader(FRAGMENT, source, true)); } Shader::Pointer Shader::createVertex(uint32_t id) { - return createVertex(getShaderSource(id)); + return createOrReuseDomainShader(VERTEX, id); } Shader::Pointer Shader::createPixel(uint32_t id) { - return createPixel(getShaderSource(id)); + return createOrReuseDomainShader(FRAGMENT, id); } -Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) { - return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, pixelShader); -} Shader::Pointer Shader::createProgram(uint32_t programId) { auto vertexShader = createVertex(shader::getVertexId(programId)); @@ -200,98 +161,15 @@ Shader::Pointer Shader::createProgram(uint32_t programId) { return createOrReuseProgramShader(PROGRAM, vertexShader, nullptr, fragmentShader); } +Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) { + return Pointer(new Shader(PROGRAM, vertexShader, nullptr, pixelShader)); +} + +// Dynamic program, bypass caching Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& geometryShader, const Pointer& pixelShader) { - return createOrReuseProgramShader(PROGRAM, vertexShader, geometryShader, pixelShader); + return Pointer(new Shader(PROGRAM, vertexShader, geometryShader, pixelShader)); } -static const std::string IGNORED_BINDING = "transformObjectBuffer"; - -void updateBindingsFromJsonObject(Shader::LocationMap& inOutSet, const QJsonObject& json) { - for (const auto& key : json.keys()) { - auto keyStr = key.toStdString(); - if (IGNORED_BINDING == keyStr) { - continue; - } - inOutSet[keyStr] = json[key].toInt(); - } -} - -void updateTextureAndResourceBuffersFromJsonObjects(Shader::LocationMap& inOutTextures, Shader::LocationMap& inOutResourceBuffers, - const QJsonObject& json, const QJsonObject& types) { - static const std::string RESOURCE_BUFFER_TEXTURE_TYPE = "samplerBuffer"; - for (const auto& key : json.keys()) { - auto keyStr = key.toStdString(); - if (keyStr == IGNORED_BINDING) { - continue; - } - auto location = json[key].toInt(); - auto type = types[key].toString().toStdString(); - if (type == RESOURCE_BUFFER_TEXTURE_TYPE) { - inOutResourceBuffers[keyStr] = location; - } else { - inOutTextures[key.toStdString()] = location; - } - } -} - -Shader::ReflectionMap getShaderReflection(const std::string& reflectionJson) { - if (reflectionJson.empty() && reflectionJson != std::string("null")) { - return {}; - } - -#define REFLECT_KEY_INPUTS "inputs" -#define REFLECT_KEY_OUTPUTS "outputs" -#define REFLECT_KEY_UBOS "uniformBuffers" -#define REFLECT_KEY_SSBOS "storageBuffers" -#define REFLECT_KEY_UNIFORMS "uniforms" -#define REFLECT_KEY_TEXTURES "textures" -#define REFLECT_KEY_TEXTURE_TYPES "textureTypes" - - auto doc = QJsonDocument::fromJson(reflectionJson.c_str()); - if (doc.isNull()) { - qWarning() << "Invalid shader reflection JSON" << reflectionJson.c_str(); - return {}; - } - - Shader::ReflectionMap result; - auto json = doc.object(); - if (json.contains(REFLECT_KEY_INPUTS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::INPUT], json[REFLECT_KEY_INPUTS].toObject()); - } - if (json.contains(REFLECT_KEY_OUTPUTS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::OUTPUT], json[REFLECT_KEY_OUTPUTS].toObject()); - } - // FIXME eliminate the last of the uniforms - if (json.contains(REFLECT_KEY_UNIFORMS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::UNIFORM], json[REFLECT_KEY_UNIFORMS].toObject()); - } - if (json.contains(REFLECT_KEY_UBOS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::UNIFORM_BUFFER], json[REFLECT_KEY_UBOS].toObject()); - } - - // SSBOs need to come BEFORE the textures. In GL 4.5 the reflection slots aren't really used, but in 4.1 the slots - // are used to explicitly setup bindings after shader linkage, so we want the resource buffer slots to contain the - // texture locations, not the SSBO locations - if (json.contains(REFLECT_KEY_SSBOS)) { - updateBindingsFromJsonObject(result[Shader::BindingType::RESOURCE_BUFFER], json[REFLECT_KEY_SSBOS].toObject()); - } - - // samplerBuffer textures map to gpu ResourceBuffer, while all other textures map to regular gpu Texture - if (json.contains(REFLECT_KEY_TEXTURES)) { - updateTextureAndResourceBuffersFromJsonObjects( - result[Shader::BindingType::TEXTURE], - result[Shader::BindingType::RESOURCE_BUFFER], - json[REFLECT_KEY_TEXTURES].toObject(), - json[REFLECT_KEY_TEXTURE_TYPES].toObject()); - } - - - return result; -} - -Shader::Source Shader::getShaderSource(uint32_t id) { - auto source = shader::loadShaderSource(id); - auto reflectionJson = shader::loadShaderReflection(id); - auto reflection = getShaderReflection(reflectionJson); - return { source, reflection }; +const Shader::Source& Shader::getShaderSource(uint32_t id) { + return shader::Source::get(id); } diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index ad828a0cff..35426bed20 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -19,6 +19,7 @@ #include #include #include +#include #include namespace gpu { @@ -42,58 +43,10 @@ public: typedef std::shared_ptr Pointer; typedef std::vector Shaders; - // Needs to match values in shaders/Shaders.h - enum class BindingType - { - INVALID = -1, - INPUT = 0, - OUTPUT, - TEXTURE, - SAMPLER, - UNIFORM_BUFFER, - RESOURCE_BUFFER, - UNIFORM, - }; - - using LocationMap = std::unordered_map; - using ReflectionMap = std::map; - - class Source { - public: - enum Language - { - INVALID = -1, - GLSL = 0, - SPIRV = 1, - MSL = 2, - HLSL = 3, - }; - - Source() {} - Source(const std::string& code, const ReflectionMap& reflection, Language lang = GLSL) : - _code(code), _reflection(reflection), _lang(lang) {} - Source(const Source& source) : _code(source._code), _reflection(source._reflection), _lang(source._lang) {} - virtual ~Source() {} - - virtual const std::string& getCode() const { return _code; } - virtual const ReflectionMap& getReflection() const { return _reflection; } - - class Less { - public: - bool operator()(const Source& x, const Source& y) const { - if (x._lang == y._lang) { - return x._code < y._code; - } else { - return (x._lang < y._lang); - } - } - }; - - protected: - std::string _code; - ReflectionMap _reflection; - Language _lang; - }; + using Source = shader::Source; + using Reflection = shader::Reflection; + using Dialect = shader::Dialect; + using Variant = shader::Variant; struct CompilationLog { std::string message; @@ -112,85 +65,13 @@ public: bool operator()(const T& x, const T& y) const { return x._name < y._name; } }; - class Slot { - public: - std::string _name; - int32 _location{ INVALID_LOCATION }; - Element _element; - uint16 _resourceType{ Resource::BUFFER }; - uint32 _size{ 0 }; - - Slot(const Slot& s) : - _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {} - Slot(Slot&& s) : - _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType), _size(s._size) {} - Slot(const std::string& name, - int32 location, - const Element& element, - uint16 resourceType = Resource::BUFFER, - uint32 size = 0) : - _name(name), - _location(location), _element(element), _resourceType(resourceType), _size(size) {} - Slot(const std::string& name) : _name(name) {} - - Slot& operator=(const Slot& s) { - _name = s._name; - _location = s._location; - _element = s._element; - _resourceType = s._resourceType; - _size = s._size; - return (*this); - } - }; - - class SlotSet : protected std::set> { - using Parent = std::set>; - - public: - void insert(const Parent::value_type& value) { - Parent::insert(value); - if (value._location != INVALID_LOCATION) { - _validSlots.insert(value._location); - } - } - - using Parent::begin; - using Parent::empty; - using Parent::end; - using Parent::size; - - using LocationMap = std::unordered_map; - using NameVector = std::vector; - - NameVector getNames() const { - NameVector result; - for (const auto& entry : *this) { - result.push_back(entry._name); - } - return result; - } - - LocationMap getLocationsByName() const { - LocationMap result; - for (const auto& entry : *this) { - result.insert({ entry._name, entry._location }); - } - return result; - } - - bool isValid(int32 slot) const { return 0 != _validSlots.count(slot); } - - protected: - std::unordered_set _validSlots; - }; - - static Source getShaderSource(uint32_t id); - static Source getVertexShaderSource(uint32_t id) { return getShaderSource(id); } - static Source getFragmentShaderSource(uint32_t id) { return getShaderSource(id); } - + static const Source& getShaderSource(uint32_t id); + static const Source& getVertexShaderSource(uint32_t id) { return getShaderSource(id); } + static const Source& getFragmentShaderSource(uint32_t id) { return getShaderSource(id); } static Pointer createVertex(const Source& source); static Pointer createPixel(const Source& source); static Pointer createGeometry(const Source& source); + static Pointer createVertex(uint32_t shaderId); static Pointer createPixel(uint32_t shaderId); static Pointer createGeometry(uint32_t shaderId); @@ -201,8 +82,7 @@ public: ~Shader(); - ID getID() const { return _ID; } - + ID getID() const; Type getType() const { return _type; } bool isProgram() const { return getType() > NUM_DOMAINS; } bool isDomain() const { return getType() < NUM_DOMAINS; } @@ -211,17 +91,12 @@ public: const Shaders& getShaders() const { return _shaders; } - // Access the exposed uniform, input and output slot - const SlotSet& getUniforms() const { return _uniforms; } - const SlotSet& getUniformBuffers() const { return _uniformBuffers; } - const SlotSet& getResourceBuffers() const { return _resourceBuffers; } - const SlotSet& getTextures() const { return _textures; } - const SlotSet& getSamplers() const { return _samplers; } + const Reflection& getReflection() const { return _source.reflection; } // Compilation Handler can be passed while compiling a shader (in the makeProgram call) to be able to give the hand to - // the caller thread if the comilation fails and to prvide a different version of the source for it + // the caller thread if the compilation fails and to provide a different version of the source for it // @param0 the Shader object that just failed to compile - // @param1 the original source code as submited to the compiler + // @param1 the original source code as submitted to the compiler // @param2 the compilation log containing the error message // @param3 a new string ready to be filled with the new version of the source that could be proposed from the handler functor // @return boolean true if the backend should keep trying to compile the shader with the new source returned or false to stop and fail that shader compilation @@ -240,32 +115,21 @@ public: const GPUObjectPointer gpuObject{}; protected: - Shader(Type type, const Source& source); + Shader(Type type, const Source& source, bool dynamic); Shader(Type type, const Pointer& vertex, const Pointer& geometry, const Pointer& pixel); Shader(const Shader& shader); // deep copy of the sysmem shader Shader& operator=(const Shader& shader); // deep copy of the sysmem texture // Source contains the actual source code or nothing if the shader is a program - Source _source; + const Source _source; // if shader is composed of sub shaders, here they are - Shaders _shaders; - - // List of exposed uniform, input and output slots - SlotSet _uniforms; - SlotSet _uniformBuffers; - SlotSet _resourceBuffers; - SlotSet _textures; - SlotSet _samplers; - SlotSet _inputs; - SlotSet _outputs; + const Shaders _shaders; + // The type of the shader, the master key - Type _type; - - // The unique identifier of a shader in the GPU lib - uint32_t _ID{ 0 }; + const Type _type; // Number of attempts to compile the shader mutable uint32_t _numCompilationAttempts{ 0 }; @@ -277,13 +141,9 @@ protected: // Global maps of the shaders // Unique shader ID - static std::atomic _nextShaderID; + //static std::atomic _nextShaderID; - using ShaderMap = std::map, Source::Less>; - using DomainShaderMaps = std::array; - static DomainShaderMaps _domainShaderMaps; - - static ShaderPointer createOrReuseDomainShader(Type type, const Source& source); + static ShaderPointer createOrReuseDomainShader(Type type, uint32_t sourceId); using ProgramMapKey = glm::uvec3; // The IDs of the shaders in a program make its key class ProgramKeyLess { diff --git a/libraries/gpu/src/gpu/ShaderConstants.h b/libraries/gpu/src/gpu/ShaderConstants.h index 0724b4eb40..e9a1821ef4 100644 --- a/libraries/gpu/src/gpu/ShaderConstants.h +++ b/libraries/gpu/src/gpu/ShaderConstants.h @@ -98,21 +98,6 @@ enum Attribute { }; } // namespace attr -namespace uniform { -enum Uniform { - Extra0 = GPU_UNIFORM_EXTRA0, - Extra1 = GPU_UNIFORM_EXTRA1, - Extra2 = GPU_UNIFORM_EXTRA2, - Extra3 = GPU_UNIFORM_EXTRA3, - Extra4 = GPU_UNIFORM_EXTRA4, - Extra5 = GPU_UNIFORM_EXTRA5, - Extra6 = GPU_UNIFORM_EXTRA6, - Extra7 = GPU_UNIFORM_EXTRA7, - Extra8 = GPU_UNIFORM_EXTRA8, - Extra9 = GPU_UNIFORM_EXTRA9, -}; -} // namespace uniform - } } // namespace gpu::slot // !> diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index fd2cb86177..43205ba4c2 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -16,7 +16,7 @@ #define TransformCamera _TransformCamera -layout(std140, binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffer { +LAYOUT_STD140(binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffer { #ifdef GPU_TRANSFORM_IS_STEREO #ifdef GPU_TRANSFORM_STEREO_CAMERA TransformCamera _camera[2]; @@ -26,7 +26,7 @@ layout(std140, binding=GPU_BUFFER_TRANSFORM_CAMERA) uniform transformCameraBuffe #else TransformCamera _camera; #endif -}; +} _cameraBlock; #ifdef GPU_VERTEX_SHADER #ifdef GPU_TRANSFORM_IS_STEREO @@ -76,12 +76,12 @@ TransformCamera getTransformCamera() { _stereoSide = gl_InstanceID % 2; #endif #endif - return _camera[_stereoSide]; + return _cameraBlock._camera[_stereoSide]; #else - return _camera; + return _cameraBlock._camera; #endif #else - return _camera; + return _cameraBlock._camera; #endif } @@ -93,7 +93,7 @@ bool cam_isStereo() { #ifdef GPU_TRANSFORM_IS_STEREO return getTransformCamera()._stereoInfo.x > 0.0; #else - return _camera._stereoInfo.x > 0.0; + return _cameraBlock._camera._stereoInfo.x > 0.0; #endif } @@ -102,10 +102,10 @@ float cam_getStereoSide() { #ifdef GPU_TRANSFORM_STEREO_CAMERA return getTransformCamera()._stereoInfo.y; #else - return _camera._stereoInfo.y; + return _cameraBlock._camera._stereoInfo.y; #endif #else - return _camera._stereoInfo.y; + return _cameraBlock._camera._stereoInfo.y; #endif } @@ -120,7 +120,7 @@ struct TransformObject { layout(location=GPU_ATTR_DRAW_CALL_INFO) in ivec2 _drawCallInfo; #if defined(GPU_SSBO_TRANSFORM_OBJECT) -layout(std140, binding=GPU_STORAGE_TRANSFORM_OBJECT) buffer transformObjectBuffer { +LAYOUT_STD140(binding=GPU_STORAGE_TRANSFORM_OBJECT) buffer transformObjectBuffer { TransformObject _object[]; }; TransformObject getTransformObject() { @@ -128,7 +128,7 @@ TransformObject getTransformObject() { return transformObject; } #else -layout(binding=GPU_TEXTURE_TRANSFORM_OBJECT) uniform samplerBuffer transformObjectBuffer; +LAYOUT(binding=GPU_TEXTURE_TRANSFORM_OBJECT) uniform samplerBuffer transformObjectBuffer; TransformObject getTransformObject() { int offset = 8 * _drawCallInfo.x; @@ -167,7 +167,9 @@ TransformObject getTransformObject() { vec4 eyeClipEdge[2]= vec4[2](vec4(-1,0,0,1), vec4(1,0,0,1)); vec2 eyeOffsetScale = vec2(-0.5, +0.5); uint eyeIndex = uint(_stereoSide); +#ifndef GPU_GLES gl_ClipDistance[0] = dot(<$clipPos$>, eyeClipEdge[eyeIndex]); +#endif float newClipPosX = <$clipPos$>.x * 0.5 + eyeOffsetScale[eyeIndex] * <$clipPos$>.w; <$clipPos$>.x = newClipPosX; #endif diff --git a/libraries/graphics/src/graphics/Light.slh b/libraries/graphics/src/graphics/Light.slh index d22da44c66..c00bfea6a2 100644 --- a/libraries/graphics/src/graphics/Light.slh +++ b/libraries/graphics/src/graphics/Light.slh @@ -51,7 +51,7 @@ float getLightAmbientMapNumMips(LightAmbient l) { return l._ambient.y; } <@if N@> -layout(binding=GRAPHICS_BUFFER_LIGHT) uniform lightBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_LIGHT) uniform lightBuffer { Light lightArray[<$N$>]; }; Light getLight(int index) { @@ -59,7 +59,7 @@ Light getLight(int index) { } <@else@> -layout(binding=GRAPHICS_BUFFER_KEY_LIGHT) uniform keyLightBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_KEY_LIGHT) uniform keyLightBuffer { Light light; }; Light getKeyLight() { @@ -79,7 +79,7 @@ Light getKeyLight() { <@if N@> -layout(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer { LightAmbient lightAmbientArray[<$N$>]; }; @@ -88,7 +88,7 @@ LightAmbient getLightAmbient(int index) { } <@else@> -layout(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_AMBIENT_LIGHT) uniform lightAmbientBuffer { LightAmbient lightAmbient; }; diff --git a/libraries/graphics/src/graphics/Material.slh b/libraries/graphics/src/graphics/Material.slh index ea59059cf1..d2055b9a59 100644 --- a/libraries/graphics/src/graphics/Material.slh +++ b/libraries/graphics/src/graphics/Material.slh @@ -48,7 +48,7 @@ struct Material { vec4 _scatteringSpare2Key; }; -layout(binding=GRAPHICS_BUFFER_MATERIAL) uniform materialBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_MATERIAL) uniform materialBuffer { Material _mat; TexMapArray _texMapArray; }; diff --git a/libraries/graphics/src/graphics/MaterialTextures.slh b/libraries/graphics/src/graphics/MaterialTextures.slh index 0a60feccfc..db329c3852 100644 --- a/libraries/graphics/src/graphics/MaterialTextures.slh +++ b/libraries/graphics/src/graphics/MaterialTextures.slh @@ -11,6 +11,7 @@ <@if not MODEL_MATERIAL_TEXTURES_SLH@> <@def MODEL_MATERIAL_TEXTURES_SLH@> +<@include graphics/ShaderConstants.h@> <@include graphics/Material.slh@> <@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion, withScattering)@> @@ -91,21 +92,21 @@ float fetchScatteringMap(vec2 uv) { #else <@if withAlbedo@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_ALBEDO) uniform sampler2D albedoMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ALBEDO) uniform sampler2D albedoMap; vec4 fetchAlbedoMap(vec2 uv) { return texture(albedoMap, uv, TAA_TEXTURE_LOD_BIAS); } <@endif@> <@if withRoughness@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS) uniform sampler2D roughnessMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_ROUGHNESS) uniform sampler2D roughnessMap; float fetchRoughnessMap(vec2 uv) { return (texture(roughnessMap, uv, TAA_TEXTURE_LOD_BIAS).r); } <@endif@> <@if withNormal@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_NORMAL) uniform sampler2D normalMap; vec3 fetchNormalMap(vec2 uv) { // unpack normal, swizzle to get into hifi tangent space with Y axis pointing out vec2 t = 2.0 * (texture(normalMap, uv, TAA_TEXTURE_LOD_BIAS).rg - vec2(0.5, 0.5)); @@ -115,28 +116,28 @@ vec3 fetchNormalMap(vec2 uv) { <@endif@> <@if withMetallic@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_METALLIC) uniform sampler2D metallicMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_METALLIC) uniform sampler2D metallicMap; float fetchMetallicMap(vec2 uv) { return (texture(metallicMap, uv, TAA_TEXTURE_LOD_BIAS).r); } <@endif@> <@if withEmissive@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap; vec3 fetchEmissiveMap(vec2 uv) { return texture(emissiveMap, uv, TAA_TEXTURE_LOD_BIAS).rgb; } <@endif@> <@if withOcclusion@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_OCCLUSION) uniform sampler2D occlusionMap; float fetchOcclusionMap(vec2 uv) { return texture(occlusionMap, uv).r; } <@endif@> <@if withScattering@> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_SCATTERING) uniform sampler2D scatteringMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_SCATTERING) uniform sampler2D scatteringMap; float fetchScatteringMap(vec2 uv) { float scattering = texture(scatteringMap, uv, TAA_TEXTURE_LOD_BIAS).r; // boolean scattering for now return max(((scattering - 0.1) / 0.9), 0.0); @@ -185,7 +186,7 @@ float fetchScatteringMap(vec2 uv) { <$declareMaterialTexMapArrayBuffer()$> -layout(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap; +LAYOUT(binding=GRAPHICS_TEXTURE_MATERIAL_EMISSIVE_LIGHTMAP) uniform sampler2D emissiveMap; vec3 fetchLightmapMap(vec2 uv) { vec2 lightmapParams = getTexMapArray()._lightmapParams.xy; return (vec3(lightmapParams.x) + lightmapParams.y * texture(emissiveMap, uv).rgb); diff --git a/libraries/graphics/src/graphics/skybox.slf b/libraries/graphics/src/graphics/skybox.slf index 2b81a433f1..b24bf0f583 100755 --- a/libraries/graphics/src/graphics/skybox.slf +++ b/libraries/graphics/src/graphics/skybox.slf @@ -12,13 +12,13 @@ // <@include graphics/ShaderConstants.h@> -layout(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap; +LAYOUT(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap; struct Skybox { vec4 color; }; -layout(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer { Skybox skybox; }; diff --git a/libraries/model-networking/CMakeLists.txt b/libraries/model-networking/CMakeLists.txt index 9a4bc780a6..12181651db 100644 --- a/libraries/model-networking/CMakeLists.txt +++ b/libraries/model-networking/CMakeLists.txt @@ -1,4 +1,4 @@ set(TARGET_NAME model-networking) setup_hifi_library() -link_hifi_libraries(shared networking graphics fbx ktx image gl) +link_hifi_libraries(shared shaders networking graphics fbx ktx image gl) include_hifi_library_headers(gpu) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 79c0b31dff..426c9ff893 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -27,7 +27,7 @@ Q_LOGGING_CATEGORY(proceduralLog, "hifi.gpu.procedural") -// Userdata parsing constants +// User-data parsing constants static const QString PROCEDURAL_USER_DATA_KEY = "ProceduralEntity"; static const QString URL_KEY = "shaderUrl"; static const QString VERSION_KEY = "version"; @@ -39,11 +39,8 @@ static const std::string PROCEDURAL_BLOCK = "//PROCEDURAL_BLOCK"; static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION"; bool operator==(const ProceduralData& a, const ProceduralData& b) { - return ( - (a.version == b.version) && - (a.shaderUrl == b.shaderUrl) && - (a.uniforms == b.uniforms) && - (a.channels == b.channels)); + return ((a.version == b.version) && (a.shaderUrl == b.shaderUrl) && (a.uniforms == b.uniforms) && + (a.channels == b.channels)); } QJsonValue ProceduralData::getProceduralData(const QString& proceduralJson) { @@ -109,6 +106,8 @@ Procedural::Procedural() { _transparentState->setDepthTest(true, true, gpu::LESS_EQUAL); _transparentState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + + _standardInputsBuffer = std::make_shared(sizeof(StandardInputs), nullptr); } void Procedural::setProceduralData(const ProceduralData& proceduralData) { @@ -119,7 +118,7 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) { _dirty = true; _enabled = false; - if (proceduralData.version != _data.version ) { + if (proceduralData.version != _data.version) { _data.version = proceduralData.version; _shaderDirty = true; } @@ -144,7 +143,6 @@ void Procedural::setProceduralData(const ProceduralData& proceduralData) { _channels[channel] = textureCache->getTexture(QUrl()); } } - _channelsDirty = true; } if (proceduralData.shaderUrl != _data.shaderUrl) { @@ -212,23 +210,6 @@ bool Procedural::isReady() const { return true; } -std::string Procedural::replaceProceduralBlock(const std::string& fragmentSource) { - std::string result = fragmentSource; - auto replaceIndex = result.find(PROCEDURAL_VERSION); - if (replaceIndex != std::string::npos) { - if (_data.version == 1) { - result.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V1 1"); - } else if (_data.version == 2) { - result.replace(replaceIndex, PROCEDURAL_VERSION.size(), "#define PROCEDURAL_V2 1"); - } - } - replaceIndex = result.find(PROCEDURAL_BLOCK); - if (replaceIndex != std::string::npos) { - result.replace(replaceIndex, PROCEDURAL_BLOCK.size(), _shaderSource.toLocal8Bit().data()); - } - return result; -} - void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size, @@ -256,19 +237,21 @@ void Procedural::prepare(gpu::Batch& batch, } // Build the fragment shader - std::string opaqueShaderSource = replaceProceduralBlock(_opaquefragmentSource.getCode()); - auto opaqueReflection = _opaquefragmentSource.getReflection(); - auto& opaqueUniforms = opaqueReflection[gpu::Shader::BindingType::UNIFORM]; - std::string transparentShaderSource = replaceProceduralBlock(_transparentfragmentSource.getCode()); - auto transparentReflection = _transparentfragmentSource.getReflection(); - auto& transparentUniforms = transparentReflection[gpu::Shader::BindingType::UNIFORM]; + _opaqueFragmentSource.replacements.clear(); + if (_data.version == 1) { + _opaqueFragmentSource.replacements[PROCEDURAL_VERSION] = "#define PROCEDURAL_V1 1"; + } else if (_data.version == 2) { + _opaqueFragmentSource.replacements[PROCEDURAL_VERSION] = "#define PROCEDURAL_V2 1"; + } + _opaqueFragmentSource.replacements[PROCEDURAL_BLOCK] = _shaderSource.toStdString(); + _transparentFragmentSource.replacements = _opaqueFragmentSource.replacements; // Set any userdata specified uniforms int customSlot = procedural::slot::uniform::Custom; for (const auto& key : _data.uniforms.keys()) { std::string uniformName = key.toLocal8Bit().data(); - opaqueUniforms[uniformName] = customSlot; - transparentUniforms[uniformName] = customSlot; + _opaqueFragmentSource.reflection.uniforms[uniformName] = customSlot; + _transparentFragmentSource.reflection.uniforms[uniformName] = customSlot; ++customSlot; } @@ -276,18 +259,18 @@ void Procedural::prepare(gpu::Batch& batch, // qCDebug(procedural) << "FragmentShader:\n" << fragmentShaderSource.c_str(); // TODO: THis is a simple fix, we need a cleaner way to provide the "hosting" program for procedural custom shaders to be defined together with the required bindings. - _opaqueFragmentShader = gpu::Shader::createPixel({ opaqueShaderSource, opaqueReflection }); + _opaqueFragmentShader = gpu::Shader::createPixel(_opaqueFragmentSource); _opaqueShader = gpu::Shader::createProgram(_vertexShader, _opaqueFragmentShader); - if (!transparentShaderSource.empty() && transparentShaderSource != opaqueShaderSource) { - _transparentFragmentShader = gpu::Shader::createPixel({ transparentShaderSource, transparentReflection }); + _opaquePipeline = gpu::Pipeline::create(_opaqueShader, _opaqueState); + if (_transparentFragmentSource.valid()) { + _transparentFragmentShader = gpu::Shader::createPixel(_transparentFragmentSource); _transparentShader = gpu::Shader::createProgram(_vertexShader, _transparentFragmentShader); + _transparentPipeline = gpu::Pipeline::create(_transparentShader, _transparentState); } else { _transparentFragmentShader = _opaqueFragmentShader; _transparentShader = _opaqueShader; + _transparentPipeline = _opaquePipeline; } - - _opaquePipeline = gpu::Pipeline::create(_opaqueShader, _opaqueState); - _transparentPipeline = gpu::Pipeline::create(_transparentShader, _transparentState); _start = usecTimestampNow(); _frameCount = 0; } @@ -299,12 +282,8 @@ void Procedural::prepare(gpu::Batch& batch, setupUniforms(transparent); } - if (_shaderDirty || _uniformsDirty || _channelsDirty || _prevTransparent != transparent) { - setupChannels(_shaderDirty || _uniformsDirty, transparent); - } - _prevTransparent = transparent; - _shaderDirty = _uniformsDirty = _channelsDirty = false; + _shaderDirty = _uniformsDirty = false; for (auto lambda : _uniforms) { lambda(batch); @@ -331,16 +310,10 @@ void Procedural::prepare(gpu::Batch& batch, void Procedural::setupUniforms(bool transparent) { _uniforms.clear(); - auto& pipeline = transparent ? _transparentShader : _opaqueShader; - const auto& uniformSlots = pipeline->getUniforms(); auto customUniformCount = _data.uniforms.keys().size(); - // Set any userdata specified uniforms for (int i = 0; i < customUniformCount; ++i) { int slot = procedural::slot::uniform::Custom + i; - if (!uniformSlots.isValid(slot)) { - continue; - } QString key = _data.uniforms.keys().at(i); std::string uniformName = key.toLocal8Bit().data(); QJsonValue value = _data.uniforms[key]; @@ -390,73 +363,42 @@ void Procedural::setupUniforms(bool transparent) { } } - if (uniformSlots.isValid(procedural::slot::uniform::Time)) { - _uniforms.push_back([=](gpu::Batch& batch) { + _uniforms.push_back([=](gpu::Batch& batch) { + // Time and position + { // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; - batch._glUniform(procedural::slot::uniform::Time, time); - }); - } + _standardInputs.posAndTime = vec4(_entityPosition, time); + } - if (uniformSlots.isValid(procedural::slot::uniform::Date)) { - _uniforms.push_back([=](gpu::Batch& batch) { + // Date + { QDateTime now = QDateTime::currentDateTimeUtc(); QDate date = now.date(); QTime time = now.time(); - vec4 v; - v.x = date.year(); + _standardInputs.date.x = date.year(); // Shadertoy month is 0 based - v.y = date.month() - 1; + _standardInputs.date.y = date.month() - 1; // But not the day... go figure - v.z = date.day(); + _standardInputs.date.z = date.day(); float fractSeconds = (time.msec() / 1000.0f); - v.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds; - batch._glUniform(procedural::slot::uniform::Date, v); - }); - } - - if (uniformSlots.isValid(procedural::slot::uniform::FrameCount)) { - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform(procedural::slot::uniform::FrameCount, ++_frameCount); }); - } - - if (uniformSlots.isValid(procedural::slot::uniform::Scale)) { - // FIXME move into the 'set once' section, since this doesn't change over time - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform(procedural::slot::uniform::Scale, _entityDimensions); }); - } - - if (uniformSlots.isValid(procedural::slot::uniform::Orientation)) { - // FIXME move into the 'set once' section, since this doesn't change over time - _uniforms.push_back( - [=](gpu::Batch& batch) { batch._glUniform(procedural::slot::uniform::Orientation, _entityOrientation); }); - } - - if (uniformSlots.isValid(procedural::slot::uniform::Position)) { - // FIXME move into the 'set once' section, since this doesn't change over time - _uniforms.push_back( - [=](gpu::Batch& batch) { batch._glUniform(procedural::slot::uniform::Orientation, _entityPosition); }); - } -} - -void Procedural::setupChannels(bool shouldCreate, bool transparent) { - auto& pipeline = transparent ? _transparentShader : _opaqueShader; - const auto& uniformSlots = pipeline->getUniforms(); - - if (uniformSlots.isValid(procedural::slot::uniform::ChannelResolution)) { - if (!shouldCreate) { - // Instead of modifying the last element, just remove and recreate it. - _uniforms.pop_back(); + _standardInputs.date.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds; } - _uniforms.push_back([=](gpu::Batch& batch) { - vec3 channelSizes[MAX_PROCEDURAL_TEXTURE_CHANNELS]; - for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { - if (_channels[i]) { - channelSizes[i] = vec3(_channels[i]->getWidth(), _channels[i]->getHeight(), 1.0); - } + + _standardInputs.scaleAndCount = vec4(_entityDimensions, ++_frameCount); + _standardInputs.orientation = mat4(_entityOrientation); + + for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { + if (_channels[i]) { + _standardInputs.resolution[i] = vec4(_channels[i]->getWidth(), _channels[i]->getHeight(), 1.0f, 1.0f); + } else { + _standardInputs.resolution[i] = vec4(1.0f); } - batch._glUniform3fv(procedural::slot::uniform::ChannelResolution, MAX_PROCEDURAL_TEXTURE_CHANNELS, - &channelSizes[0].x); - }); - } + } + + _standardInputsBuffer->setSubData(0, _standardInputs); + batch.setUniformBuffer(0, _standardInputsBuffer, 0, sizeof(StandardInputs)); + }); } glm::vec4 Procedural::getColor(const glm::vec4& entityColor) { diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index 973b323f60..c92725b61b 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -65,14 +65,22 @@ public: void setDoesFade(bool doesFade) { _doesFade = doesFade; } gpu::Shader::Source _vertexSource; - gpu::Shader::Source _opaquefragmentSource; - gpu::Shader::Source _transparentfragmentSource; + gpu::Shader::Source _opaqueFragmentSource; + gpu::Shader::Source _transparentFragmentSource; gpu::StatePointer _opaqueState { std::make_shared() }; gpu::StatePointer _transparentState { std::make_shared() }; protected: + struct StandardInputs { + vec4 date; + vec4 posAndTime; + vec4 scaleAndCount; + mat4 orientation; + vec4 resolution[4]; + }; + // Procedural metadata ProceduralData _data; @@ -88,13 +96,14 @@ protected: bool _dirty { false }; bool _shaderDirty { true }; bool _uniformsDirty { true }; - bool _channelsDirty { true }; // Rendering objects UniformLambdas _uniforms; NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; gpu::PipelinePointer _opaquePipeline; gpu::PipelinePointer _transparentPipeline; + StandardInputs _standardInputs; + gpu::BufferPointer _standardInputsBuffer; gpu::ShaderPointer _vertexShader; gpu::ShaderPointer _opaqueFragmentShader; gpu::ShaderPointer _transparentFragmentShader; @@ -109,9 +118,6 @@ protected: private: // This should only be called from the render thread, as it shares data with Procedural::prepare void setupUniforms(bool transparent); - void setupChannels(bool shouldCreate, bool transparent); - - std::string replaceProceduralBlock(const std::string& fragmentSource); mutable quint64 _fadeStartTime { 0 }; mutable bool _hasStartedFade { false }; diff --git a/libraries/procedural/src/procedural/ProceduralCommon.slh b/libraries/procedural/src/procedural/ProceduralCommon.slh index c36f2da1d3..fbfba81329 100644 --- a/libraries/procedural/src/procedural/ProceduralCommon.slh +++ b/libraries/procedural/src/procedural/ProceduralCommon.slh @@ -14,18 +14,51 @@ <$declareStandardCameraTransform()$> -#define PROCEDURAL 1 +#ifdef GL_EXT_shader_non_constant_global_initializers +#extension GL_EXT_shader_non_constant_global_initializers : enable +#endif -//PROCEDURAL_VERSION +LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL0) uniform sampler2D iChannel0; +LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL1) uniform sampler2D iChannel1; +LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL2) uniform sampler2D iChannel2; +LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL3) uniform sampler2D iChannel3; -#ifdef PROCEDURAL_V1 +struct StandardInputs { + vec4 date; + vec4 posAndTime; + vec4 scaleAndCount; + mat4 orientation; + vec4 resolution[4]; +}; + + +LAYOUT(binding=0) uniform standardInputsBuffer { + StandardInputs params; +}; // shader playback time (in seconds) -layout(location=PROCEDURAL_UNIFORM_TIME) uniform float iGlobalTime; -// the dimensions of the object being rendered -layout(location=PROCEDURAL_UNIFORM_SCALE) uniform vec3 iWorldScale; +float iGlobalTime = params.posAndTime.w; + +vec4 iDate = params.date; + +int iFrameCount = int(params.scaleAndCount.w); + +// the position of the object being rendered +vec3 iWorldPosition = params.posAndTime.xyz; + +// the dimensions of the object being rendered +vec3 iWorldScale = params.scaleAndCount.xyz; + +// the orientation of the object being rendered +mat3 iWorldOrientation = mat3(params.orientation); + +vec3 iChannelResolution[4] = vec3[4]( + params.resolution[0].xyz, + params.resolution[1].xyz, + params.resolution[2].xyz, + params.resolution[3].xyz +); -#else // Unimplemented uniforms // Resolution doesn't make sense in the VR context @@ -37,20 +70,9 @@ const float iSampleRate = 1.0; // No support for video input const vec4 iChannelTime = vec4(0.0); +#define PROCEDURAL 1 -layout(location=PROCEDURAL_UNIFORM_TIME) uniform float iGlobalTime; // shader playback time (in seconds) -layout(location=PROCEDURAL_UNIFORM_DATE) uniform vec4 iDate; -layout(location=PROCEDURAL_UNIFORM_FRAME_COUNT) uniform int iFrameCount; -layout(location=PROCEDURAL_UNIFORM_POSITION) uniform vec3 iWorldPosition; // the position of the object being rendered -layout(location=PROCEDURAL_UNIFORM_SCALE) uniform vec3 iWorldScale; // the dimensions of the object being rendered -layout(location=PROCEDURAL_UNIFORM_ORIENTATION) uniform mat3 iWorldOrientation; // the orientation of the object being rendered -layout(location=PROCEDURAL_UNIFORM_CHANNEL_RESOLUTION) uniform vec3 iChannelResolution[4]; -layout(binding=PROCEDURAL_TEXTURE_CHANNEL0) uniform sampler2D iChannel0; -layout(binding=PROCEDURAL_TEXTURE_CHANNEL1) uniform sampler2D iChannel1; -layout(binding=PROCEDURAL_TEXTURE_CHANNEL2) uniform sampler2D iChannel2; -layout(binding=PROCEDURAL_TEXTURE_CHANNEL3) uniform sampler2D iChannel3; - -#endif +//PROCEDURAL_VERSION // hack comment for extra whitespace diff --git a/libraries/procedural/src/procedural/ProceduralSkybox.cpp b/libraries/procedural/src/procedural/ProceduralSkybox.cpp index 0addb57fcf..ea5be23eb8 100644 --- a/libraries/procedural/src/procedural/ProceduralSkybox.cpp +++ b/libraries/procedural/src/procedural/ProceduralSkybox.cpp @@ -19,7 +19,7 @@ ProceduralSkybox::ProceduralSkybox() : graphics::Skybox() { _procedural._vertexSource = gpu::Shader::createVertex(shader::graphics::vertex::skybox)->getSource(); - _procedural._opaquefragmentSource = gpu::Shader::createPixel(shader::procedural::fragment::proceduralSkybox)->getSource(); + _procedural._opaqueFragmentSource = shader::Source::get(shader::procedural::fragment::proceduralSkybox); // Adjust the pipeline state for background using the stencil test _procedural.setDoesFade(false); // Must match PrepareStencil::STENCIL_BACKGROUND diff --git a/libraries/procedural/src/procedural/ShaderConstants.h b/libraries/procedural/src/procedural/ShaderConstants.h index bfbf2a2691..cd0d997050 100644 --- a/libraries/procedural/src/procedural/ShaderConstants.h +++ b/libraries/procedural/src/procedural/ShaderConstants.h @@ -14,14 +14,6 @@ #ifndef PROCEDURAL_SHADER_CONSTANTS_H #define PROCEDURAL_SHADER_CONSTANTS_H -#define PROCEDURAL_UNIFORM_TIME 200 -#define PROCEDURAL_UNIFORM_DATE 201 -#define PROCEDURAL_UNIFORM_FRAME_COUNT 202 -#define PROCEDURAL_UNIFORM_POSITION 203 -#define PROCEDURAL_UNIFORM_SCALE 204 -#define PROCEDURAL_UNIFORM_ORIENTATION 205 -// Additional space because orientation will take up 3-4 locations, being a matrix -#define PROCEDURAL_UNIFORM_CHANNEL_RESOLUTION 209 #define PROCEDURAL_UNIFORM_CUSTOM 220 #define PROCEDURAL_TEXTURE_CHANNEL0 0 @@ -33,15 +25,9 @@ namespace procedural { namespace slot { + namespace uniform { enum Uniform { - Time = PROCEDURAL_UNIFORM_TIME, - Date = PROCEDURAL_UNIFORM_DATE, - FrameCount = PROCEDURAL_UNIFORM_FRAME_COUNT, - Position = PROCEDURAL_UNIFORM_POSITION, - Scale = PROCEDURAL_UNIFORM_SCALE, - Orientation = PROCEDURAL_UNIFORM_ORIENTATION, - ChannelResolution = PROCEDURAL_UNIFORM_CHANNEL_RESOLUTION, Custom = PROCEDURAL_UNIFORM_CUSTOM, }; } diff --git a/libraries/procedural/src/procedural/proceduralSkybox.slf b/libraries/procedural/src/procedural/proceduralSkybox.slf index e18b7abef6..12e8de9dc3 100644 --- a/libraries/procedural/src/procedural/proceduralSkybox.slf +++ b/libraries/procedural/src/procedural/proceduralSkybox.slf @@ -12,13 +12,13 @@ // <@include graphics/ShaderConstants.h@> -layout(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap; +LAYOUT(binding=GRAPHICS_TEXTURE_SKYBOX) uniform samplerCube cubeMap; struct Skybox { vec4 color; }; -layout(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer { +LAYOUT(binding=GRAPHICS_BUFFER_SKYBOX_PARAMS) uniform skyboxBuffer { Skybox skybox; }; @@ -28,9 +28,13 @@ layout(location=0) out vec4 _fragColor; <@include procedural/ProceduralCommon.slh@> #line 1001 -//PROCEDURAL_BLOCK +//PROCEDURAL_BLOCK_BEGIN +vec3 getSkyboxColor() { + return vec3(abs(sin(iGlobalTime / 5.0)), 1.0, 0.0); +} +//PROCEDURAL_BLOCK_END -#line 2033 +#line 2038 void main(void) { vec3 color = getSkyboxColor(); // Protect from NaNs and negative values diff --git a/libraries/procedural/src/procedural/proceduralSkybox.slp b/libraries/procedural/src/procedural/proceduralSkybox.slp new file mode 100644 index 0000000000..5247547850 --- /dev/null +++ b/libraries/procedural/src/procedural/proceduralSkybox.slp @@ -0,0 +1 @@ +VERTEX graphics::vertex::skybox \ No newline at end of file diff --git a/libraries/render-utils/src/Blendshape.slh b/libraries/render-utils/src/Blendshape.slh index df62af5a77..73a561c73f 100644 --- a/libraries/render-utils/src/Blendshape.slh +++ b/libraries/render-utils/src/Blendshape.slh @@ -10,13 +10,13 @@ <@func declareBlendshape(USE_NORMAL, USE_TANGENT)@> -#if defined(GPU_GL410) -layout(binding=0) uniform samplerBuffer blendshapeOffsetsBuffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=0) uniform samplerBuffer blendshapeOffsetsBuffer; uvec4 getPackedBlendshapeOffset(int i) { return floatBitsToUint(texelFetch(blendshapeOffsetsBuffer, i)); } #else -layout(std140, binding=0) buffer blendshapeOffsetsBuffer { +LAYOUT_STD140(binding=0) buffer blendshapeOffsetsBuffer { uvec4 _packedBlendshapeOffsets[]; }; uvec4 getPackedBlendshapeOffset(int i) { diff --git a/libraries/render-utils/src/BloomApply.slf b/libraries/render-utils/src/BloomApply.slf index a53894de60..dcdb989780 100644 --- a/libraries/render-utils/src/BloomApply.slf +++ b/libraries/render-utils/src/BloomApply.slf @@ -12,11 +12,11 @@ <@include BloomApply.shared.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=0) uniform sampler2D blurMap0; -layout(binding=1) uniform sampler2D blurMap1; -layout(binding=2) uniform sampler2D blurMap2; +LAYOUT(binding=0) uniform sampler2D blurMap0; +LAYOUT(binding=1) uniform sampler2D blurMap1; +LAYOUT(binding=2) uniform sampler2D blurMap2; -layout(std140, binding=RENDER_UTILS_BUFFER_BLOOM_PARAMS) uniform parametersBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_BLOOM_PARAMS) uniform parametersBuffer { Parameters parameters; }; diff --git a/libraries/render-utils/src/BloomThreshold.slf b/libraries/render-utils/src/BloomThreshold.slf index 47a1fb0d9f..bbf863994f 100644 --- a/libraries/render-utils/src/BloomThreshold.slf +++ b/libraries/render-utils/src/BloomThreshold.slf @@ -12,8 +12,8 @@ <@include BloomThreshold.shared.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=RENDER_UTILS_TEXTURE_BLOOM_COLOR) uniform sampler2D colorMap; -layout(std140, binding=RENDER_UTILS_BUFFER_BLOOM_PARAMS) uniform parametersBuffer { +LAYOUT(binding=RENDER_UTILS_TEXTURE_BLOOM_COLOR) uniform sampler2D colorMap; +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_BLOOM_PARAMS) uniform parametersBuffer { Parameters parameters; }; diff --git a/libraries/render-utils/src/DebugDeferredBuffer.cpp b/libraries/render-utils/src/DebugDeferredBuffer.cpp index be9e75a9a5..9597ce1052 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.cpp +++ b/libraries/render-utils/src/DebugDeferredBuffer.cpp @@ -243,7 +243,7 @@ static const std::string DEFAULT_CUSTOM_SHADER{ " }" }; -static std::string getFileContent(std::string fileName, std::string defaultContent = std::string()) { +static std::string getFileContent(const std::string& fileName, const std::string& defaultContent = std::string()) { QFile customFile(QString::fromStdString(fileName)); if (customFile.open(QIODevice::ReadOnly)) { return customFile.readAll().toStdString(); @@ -270,7 +270,7 @@ DebugDeferredBuffer::~DebugDeferredBuffer() { } } -std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string customFile) { +std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, const std::string& customFile) { switch (mode) { case AlbedoMode: return DEFAULT_ALBEDO_SHADER; @@ -334,7 +334,7 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust return std::string(); } -bool DebugDeferredBuffer::pipelineNeedsUpdate(Mode mode, std::string customFile) const { +bool DebugDeferredBuffer::pipelineNeedsUpdate(Mode mode, const std::string& customFile) const { if (mode != CustomMode) { return !_pipelines[mode]; } @@ -351,19 +351,17 @@ bool DebugDeferredBuffer::pipelineNeedsUpdate(Mode mode, std::string customFile) return true; } -const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, std::string customFile) { +const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Mode mode, const std::string& customFile) { if (pipelineNeedsUpdate(mode, customFile)) { - static const auto FRAGMENT_SHADER_SOURCE = - gpu::Shader::createPixel(shader::render_utils::fragment::debug_deferred_buffer)->getSource(); - static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" }; - static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER_SOURCE.getCode().find(SOURCE_PLACEHOLDER); - Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, "Could not find source placeholder"); + static_assert(shader::render_utils::program::debug_deferred_buffer != 0, "Validate debug deferred program"); - auto bakedFragmentShader = FRAGMENT_SHADER_SOURCE.getCode(); - bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), getShaderSourceCode(mode, customFile)); + static const std::string REPLACEMENT_MARKER{ "//SOURCE_PLACEHOLDER" }; + shader::Source resolvedFragmentSource; + resolvedFragmentSource = shader::Source::get(shader::render_utils::fragment::debug_deferred_buffer); + resolvedFragmentSource.replacements[REPLACEMENT_MARKER] = getShaderSourceCode(mode, customFile); const auto vs = gpu::Shader::createVertex(shader::render_utils::vertex::debug_deferred_buffer); - const auto ps = gpu::Shader::createPixel({ bakedFragmentShader, FRAGMENT_SHADER_SOURCE.getReflection() }); + const auto ps = gpu::Shader::createPixel(resolvedFragmentSource); const auto program = gpu::Shader::createProgram(vs, ps); auto pipeline = gpu::Pipeline::create(program, std::make_shared()); diff --git a/libraries/render-utils/src/DebugDeferredBuffer.h b/libraries/render-utils/src/DebugDeferredBuffer.h index dba3ff8532..cdaf5db83a 100644 --- a/libraries/render-utils/src/DebugDeferredBuffer.h +++ b/libraries/render-utils/src/DebugDeferredBuffer.h @@ -112,9 +112,9 @@ private: using StandardPipelines = std::array; using CustomPipelines = std::unordered_map; - bool pipelineNeedsUpdate(Mode mode, std::string customFile = std::string()) const; - const gpu::PipelinePointer& getPipeline(Mode mode, std::string customFile = std::string()); - std::string getShaderSourceCode(Mode mode, std::string customFile = std::string()); + bool pipelineNeedsUpdate(Mode mode, const std::string& customFile = std::string()) const; + const gpu::PipelinePointer& getPipeline(Mode mode, const std::string& customFile = std::string()); + std::string getShaderSourceCode(Mode mode, const std::string& customFile = std::string()); ParametersBuffer _parameters; StandardPipelines _pipelines; diff --git a/libraries/render-utils/src/DeferredBufferRead.slh b/libraries/render-utils/src/DeferredBufferRead.slh index e5a7c39d54..f3b8c0404a 100644 --- a/libraries/render-utils/src/DeferredBufferRead.slh +++ b/libraries/render-utils/src/DeferredBufferRead.slh @@ -17,23 +17,23 @@ // See DeferredShader_MapSlot in DeferredLightingEffect.cpp for constants // the albedo texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_COLOR) uniform sampler2D albedoMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_COLOR) uniform sampler2D albedoMap; // the normal texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_NORMAL) uniform sampler2D normalMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_NORMAL) uniform sampler2D normalMap; // the specular texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_SPECULAR) uniform sampler2D specularMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_SPECULAR) uniform sampler2D specularMap; // the depth texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_DEPTH) uniform sampler2D depthMap; -layout(binding=RENDER_UTILS_TEXTURE_DEFERRRED_LINEAR_Z_EYE) uniform sampler2D linearZeyeMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_DEPTH) uniform sampler2D depthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRRED_LINEAR_Z_EYE) uniform sampler2D linearZeyeMap; // the obscurance texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRED_OBSCURANCE) uniform sampler2D obscuranceMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRED_OBSCURANCE) uniform sampler2D obscuranceMap; // the lighting texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRED_LIGHTING) uniform sampler2D lightingMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRED_LIGHTING) uniform sampler2D lightingMap; struct DeferredFragment { @@ -170,14 +170,14 @@ DeferredFragment unpackDeferredFragment(DeferredFrameTransform deferredTransform <@func declareDeferredCurvature()@> // the curvature texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRED_CURVATURE) uniform sampler2D curvatureMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRED_CURVATURE) uniform sampler2D curvatureMap; vec4 fetchCurvature(vec2 texcoord) { return texture(curvatureMap, texcoord); } // the curvature texture -layout(binding=RENDER_UTILS_TEXTURE_DEFERRED_DIFFUSED_CURVATURE) uniform sampler2D diffusedCurvatureMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_DEFERRED_DIFFUSED_CURVATURE) uniform sampler2D diffusedCurvatureMap; vec4 fetchDiffusedCurvature(vec2 texcoord) { return texture(diffusedCurvatureMap, texcoord); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index a10949e0e6..8cf56ec7ad 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -44,7 +44,7 @@ using namespace render; struct LightLocations { bool shadowTransform{ false }; void initialize(const gpu::ShaderPointer& program) { - shadowTransform = program->getUniformBuffers().isValid(ru::Buffer::ShadowParams); + shadowTransform = program->getReflection().validUniformBuffer(ru::Buffer::ShadowParams); } }; diff --git a/libraries/render-utils/src/DeferredTransform.slh b/libraries/render-utils/src/DeferredTransform.slh index 19986805f6..8a8805e928 100644 --- a/libraries/render-utils/src/DeferredTransform.slh +++ b/libraries/render-utils/src/DeferredTransform.slh @@ -24,7 +24,7 @@ struct CameraCorrection { mat4 _prevViewInverse; }; -layout(binding=GPU_BUFFER_CAMERA_CORRECTION) uniform cameraCorrectionBuffer { +LAYOUT(binding=GPU_BUFFER_CAMERA_CORRECTION) uniform cameraCorrectionBuffer { CameraCorrection cameraCorrection; }; @@ -42,7 +42,7 @@ struct DeferredFrameTransform { mat4 _invProjectionUnJittered[2]; }; -layout(binding=RENDER_UTILS_BUFFER_DEFERRED_FRAME_TRANSFORM) uniform deferredFrameTransformBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_DEFERRED_FRAME_TRANSFORM) uniform deferredFrameTransformBuffer { DeferredFrameTransform frameTransform; }; diff --git a/libraries/render-utils/src/Fade.slh b/libraries/render-utils/src/Fade.slh index 47347ba135..a7523f969b 100644 --- a/libraries/render-utils/src/Fade.slh +++ b/libraries/render-utils/src/Fade.slh @@ -19,12 +19,12 @@ <@include FadeObjectParams.shared.slh@> // See ShapePipeline::Slot::BUFFER in ShapePipeline.h -layout(std140, binding=RENDER_UTILS_BUFFER_FADE_PARAMS) uniform fadeParametersBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_FADE_PARAMS) uniform fadeParametersBuffer { FadeParameters fadeParameters[CATEGORY_COUNT]; }; // See ShapePipeline::Slot::MAP in ShapePipeline.h -layout(binding=RENDER_UTILS_TEXTURE_FADE_MASK) uniform sampler2D fadeMaskMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_FADE_MASK) uniform sampler2D fadeMaskMap; vec3 getNoiseInverseSize(int category) { return fadeParameters[category]._noiseInvSizeAndLevel.xyz; @@ -117,7 +117,7 @@ void applyFade(FadeObjectParams params, vec3 position, out vec3 emissive) { <@func declareFadeFragmentUniform()@> -layout(std140, binding=RENDER_UTILS_BUFFER_FADE_OBJECT_PARAMS) uniform fadeObjectParametersBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_FADE_OBJECT_PARAMS) uniform fadeObjectParametersBuffer { FadeObjectParams fadeObjectParams; }; diff --git a/libraries/render-utils/src/Haze.slf b/libraries/render-utils/src/Haze.slf index bb3c0bc769..8d90b4c816 100644 --- a/libraries/render-utils/src/Haze.slf +++ b/libraries/render-utils/src/Haze.slf @@ -21,7 +21,7 @@ <@include Haze.slh@> -layout(binding=RENDER_UTILS_TEXTURE_HAZE_LINEAR_DEPTH) uniform sampler2D linearDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_HAZE_LINEAR_DEPTH) uniform sampler2D linearDepthMap; vec4 unpackPositionFromZeye(vec2 texcoord) { float Zeye = -texture(linearDepthMap, texcoord).x; diff --git a/libraries/render-utils/src/Haze.slh b/libraries/render-utils/src/Haze.slh index b7bcfcefcd..a7654da8d2 100644 --- a/libraries/render-utils/src/Haze.slh +++ b/libraries/render-utils/src/Haze.slh @@ -39,7 +39,7 @@ struct HazeParams { }; // See ShapePipeline::Slot::BUFFER in ShapePipeline.h -layout(std140, binding=RENDER_UTILS_BUFFER_HAZE_PARAMS) uniform hazeBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_HAZE_PARAMS) uniform hazeBuffer { HazeParams hazeParams; }; diff --git a/libraries/render-utils/src/Highlight.slh b/libraries/render-utils/src/Highlight.slh index 885df34d26..264b57acbb 100644 --- a/libraries/render-utils/src/Highlight.slh +++ b/libraries/render-utils/src/Highlight.slh @@ -15,12 +15,12 @@ <@include Highlight_shared.slh@> -layout(std140, binding=RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS) uniform highlightParamsBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_HIGHLIGHT_PARAMS) uniform highlightParamsBuffer { HighlightParameters params; }; -layout(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH) uniform sampler2D sceneDepthMap; -layout(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH) uniform sampler2D highlightedDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_SCENE_DEPTH) uniform sampler2D sceneDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_HIGHLIGHT_DEPTH) uniform sampler2D highlightedDepthMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 2d4aee7880..0cb08971ff 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -402,36 +402,31 @@ void DebugHighlight::run(const render::RenderContextPointer& renderContext, cons } void DebugHighlight::initializePipelines() { - static const auto FRAGMENT_SHADER_SOURCE = gpu::Shader::createPixel(shader::render_utils::fragment::debug_deferred_buffer)->getSource(); - static const std::string SOURCE_PLACEHOLDER{ "//SOURCE_PLACEHOLDER" }; - static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER_SOURCE.getCode().find(SOURCE_PLACEHOLDER); - Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO, - "Could not find source placeholder"); - - auto state = std::make_shared(); - state->setDepthTest(gpu::State::DepthTest(false, false)); - state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); - state->setColorWriteMask(true, true, true, true); - - const auto vs = gpu::Shader::createVertex(shader::render_utils::vertex::debug_deferred_buffer); - + static const std::string REPLACEMENT_MARKER{ "//SOURCE_PLACEHOLDER" }; // Depth shader - { - static const std::string DEPTH_SHADER{ R"SHADER( + static const std::string DEPTH_SHADER{ R"SHADER( vec4 getFragmentColor() { float Zdb = texelFetch(depthMap, ivec2(gl_FragCoord.xy), 0).x; Zdb = 1.0-(1.0-Zdb)*100; return vec4(Zdb, Zdb, Zdb, 1.0); } )SHADER" }; + static const auto& vs = gpu::Shader::createVertex(shader::render_utils::vertex::debug_deferred_buffer); - auto fragmentShader = FRAGMENT_SHADER_SOURCE.getCode(); - fragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(), DEPTH_SHADER); - const auto ps = gpu::Shader::createPixel({ fragmentShader, FRAGMENT_SHADER_SOURCE.getReflection() }); - const auto program = gpu::Shader::createProgram(vs, ps); - _depthPipeline = gpu::Pipeline::create(program, state); - } + gpu::Shader::Source fragmentSource; + fragmentSource = gpu::Shader::Source::get(shader::render_utils::fragment::debug_deferred_buffer); + fragmentSource.replacements[REPLACEMENT_MARKER] = DEPTH_SHADER; + + const auto ps = gpu::Shader::createPixel(fragmentSource); + const auto program = gpu::Shader::createProgram(vs, ps); + + auto state = std::make_shared(); + state->setDepthTest(gpu::State::DepthTest(false, false)); + state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); + state->setColorWriteMask(true, true, true, true); + + _depthPipeline = gpu::Pipeline::create(program, state); } const gpu::PipelinePointer& DebugHighlight::getDepthPipeline() { diff --git a/libraries/render-utils/src/Highlight_aabox.slv b/libraries/render-utils/src/Highlight_aabox.slv index 2ecebdea51..17ef7b6e07 100644 --- a/libraries/render-utils/src/Highlight_aabox.slv +++ b/libraries/render-utils/src/Highlight_aabox.slv @@ -22,8 +22,8 @@ struct ItemBound { vec4 boundDim_s; }; -#if defined(GPU_GL410) -layout(binding=0) uniform samplerBuffer ssbo0Buffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=0) uniform samplerBuffer ssbo0Buffer; ItemBound getItemBound(int i) { int offset = 2 * i; ItemBound bound; @@ -32,7 +32,7 @@ ItemBound getItemBound(int i) { return bound; } #else -layout(std140, binding=0) buffer ssbo0Buffer { +LAYOUT_STD140(binding=0) buffer ssbo0Buffer { ItemBound bounds[]; }; ItemBound getItemBound(int i) { @@ -45,7 +45,7 @@ struct HighlightParameters { vec2 outlineWidth; }; -layout(std140, binding=0) uniform parametersBuffer { +LAYOUT_STD140(binding=0) uniform parametersBuffer { HighlightParameters _parameters; }; diff --git a/libraries/render-utils/src/LightAmbient.slh b/libraries/render-utils/src/LightAmbient.slh index 797595bf47..4ea9c0cd4c 100644 --- a/libraries/render-utils/src/LightAmbient.slh +++ b/libraries/render-utils/src/LightAmbient.slh @@ -9,7 +9,7 @@ <@include render-utils/ShaderConstants.h@> <@func declareSkyboxMap()@> // declareSkyboxMap -layout(binding=RENDER_UTILS_TEXTURE_SKYBOX) uniform samplerCube skyboxMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SKYBOX) uniform samplerCube skyboxMap; vec4 evalSkyboxLight(vec3 direction, float lod) { // textureQueryLevels is not available until #430, so we require explicit lod diff --git a/libraries/render-utils/src/LightClusterGrid.slh b/libraries/render-utils/src/LightClusterGrid.slh index 8f57169ace..62af92e6ce 100644 --- a/libraries/render-utils/src/LightClusterGrid.slh +++ b/libraries/render-utils/src/LightClusterGrid.slh @@ -24,7 +24,7 @@ struct FrustumGrid { mat4 eyeToWorldMat; }; -layout(std140, binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_FRUSTUM_GRID) uniform frustumGridBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_FRUSTUM_GRID) uniform frustumGridBuffer { FrustumGrid frustumGrid; }; @@ -60,11 +60,11 @@ float projection_getFar(mat4 projection) { #define GRID_FETCH_BUFFER(i) i!> <@endif@> -layout(std140, binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_GRID) uniform clusterGridBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_GRID) uniform clusterGridBuffer { GRID_INDEX_TYPE _clusterGridTable[GRID_NUM_ELEMENTS]; }; -layout(std140, binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_CONTENT) uniform clusterContentBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_LIGHT_CLUSTER_CONTENT) uniform clusterContentBuffer { GRID_INDEX_TYPE _clusterGridContent[GRID_NUM_ELEMENTS]; }; diff --git a/libraries/render-utils/src/LightingModel.slh b/libraries/render-utils/src/LightingModel.slh index d10a52be60..61c74c7e50 100644 --- a/libraries/render-utils/src/LightingModel.slh +++ b/libraries/render-utils/src/LightingModel.slh @@ -23,7 +23,7 @@ struct LightingModel { }; // See DeferredShader_BufferSlot in DeferredLightingEffect.cpp -layout(binding=RENDER_UTILS_BUFFER_LIGHT_MODEL) uniform lightingModelBuffer{ +LAYOUT(binding=RENDER_UTILS_BUFFER_LIGHT_MODEL) uniform lightingModelBuffer{ LightingModel lightingModel; }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 5551bbdfa8..a3f06c8942 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -229,7 +229,7 @@ void initDeferredPipelines(render::ShapePlumber& plumber, const render::ShapePip } void initForwardPipelines(ShapePlumber& plumber) { - using namespace shader::render_utils::program; + using namespace shader::render_utils; using Key = render::ShapeKey; auto addPipelineBind = std::bind(&addPlumberPipeline, std::ref(plumber), _1, _2, _3, _4); @@ -244,33 +244,33 @@ void initForwardPipelines(ShapePlumber& plumber) { forceLightBatchSetter = true; // Simple Opaques - addPipeline(Key::Builder(), simple); - addPipeline(Key::Builder().withUnlit(), simpleUnlit); + addPipeline(Key::Builder(), program::forward_simple_textured); + addPipeline(Key::Builder().withUnlit(), program::forward_simple_textured_unlit); // Simple Translucents - addPipeline(Key::Builder().withTranslucent(), simpleTranslucent); - addPipeline(Key::Builder().withTranslucent().withUnlit(), simpleTranslucentUnlit); + addPipeline(Key::Builder().withTranslucent(), program::forward_simple_textured_transparent); + addPipeline(Key::Builder().withTranslucent().withUnlit(), program::simple_transparent_textured_unlit); // Opaques - addPipeline(Key::Builder().withMaterial(), forward_model); - addPipeline(Key::Builder().withMaterial().withUnlit(), forward_model_unlit); - addPipeline(Key::Builder().withMaterial().withTangents(), forward_model_translucent); + addPipeline(Key::Builder().withMaterial(), program::forward_model); + addPipeline(Key::Builder().withMaterial().withUnlit(), program::forward_model_unlit); + addPipeline(Key::Builder().withMaterial().withTangents(), program::forward_model_translucent); // Deformed Opaques - addPipeline(Key::Builder().withMaterial().withDeformed(), forward_deformed_model); - addPipeline(Key::Builder().withMaterial().withDeformed().withTangents(), forward_deformed_model_normal_map); - addPipeline(Key::Builder().withMaterial().withDeformed().withDualQuatSkinned(), forward_deformed_model_dq); - addPipeline(Key::Builder().withMaterial().withDeformed().withTangents().withDualQuatSkinned(), forward_deformed_model_normal_map_dq); + addPipeline(Key::Builder().withMaterial().withDeformed(), program::forward_deformed_model); + addPipeline(Key::Builder().withMaterial().withDeformed().withTangents(), program::forward_deformed_model_normal_map); + addPipeline(Key::Builder().withMaterial().withDeformed().withDualQuatSkinned(), program::forward_deformed_model_dq); + addPipeline(Key::Builder().withMaterial().withDeformed().withTangents().withDualQuatSkinned(), program::forward_deformed_model_normal_map_dq); // Translucents - addPipeline(Key::Builder().withMaterial().withTranslucent(), forward_model_translucent); - addPipeline(Key::Builder().withMaterial().withTranslucent().withTangents(), forward_model_normal_map_translucent); + addPipeline(Key::Builder().withMaterial().withTranslucent(), program::forward_model_translucent); + addPipeline(Key::Builder().withMaterial().withTranslucent().withTangents(), program::forward_model_normal_map_translucent); // Deformed Translucents - addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent(), forward_deformed_translucent); - addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withTangents(), forward_deformed_translucent_normal_map); - addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withDualQuatSkinned(), forward_deformed_translucent_dq); - addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withTangents().withDualQuatSkinned(), forward_deformed_translucent_normal_map_dq); + addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent(), program::forward_deformed_translucent); + addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withTangents(), program::forward_deformed_translucent_normal_map); + addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withDualQuatSkinned(), program::forward_deformed_translucent_dq); + addPipeline(Key::Builder().withMaterial().withDeformed().withTranslucent().withTangents().withDualQuatSkinned(), program::forward_deformed_translucent_normal_map_dq); forceLightBatchSetter = false; } diff --git a/libraries/render-utils/src/ShadingModel.slh b/libraries/render-utils/src/ShadingModel.slh index 6b0b7bca18..99aa01cc5e 100644 --- a/libraries/render-utils/src/ShadingModel.slh +++ b/libraries/render-utils/src/ShadingModel.slh @@ -15,7 +15,7 @@ <@func declareBeckmannSpecular()@> -layout(binding=RENDER_UTILS_TEXTURE_SSSC_SPECULAR_BECKMANN) uniform sampler2D scatteringSpecularBeckmann; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSSC_SPECULAR_BECKMANN) uniform sampler2D scatteringSpecularBeckmann; float fetchSpecularBeckmann(float ndoth, float roughness) { return pow(2.0 * texture(scatteringSpecularBeckmann, vec2(ndoth, roughness)).r, 10.0); diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 5115a876fe..9506c9805d 100644 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -19,7 +19,7 @@ #define SHADOW_SCREEN_SPACE_DITHER 1 // the shadow texture -layout(binding=RENDER_UTILS_TEXTURE_SHADOW) uniform sampler2DArrayShadow shadowMaps; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SHADOW) uniform sampler2DArrayShadow shadowMaps; // Sample the shadowMap with PCF (built-in) float fetchShadow(int cascadeIndex, vec3 shadowTexcoord) { diff --git a/libraries/render-utils/src/ShadowCore.slh b/libraries/render-utils/src/ShadowCore.slh index 99c4b923f4..9819dac38c 100644 --- a/libraries/render-utils/src/ShadowCore.slh +++ b/libraries/render-utils/src/ShadowCore.slh @@ -13,7 +13,7 @@ <@include Shadows_shared.slh@> -layout(std140, binding=RENDER_UTILS_BUFFER_SHADOW_PARAMS) uniform shadowTransformBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_SHADOW_PARAMS) uniform shadowTransformBuffer { ShadowParameters shadow; }; diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 622ca946c2..63246e85a1 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -18,7 +18,7 @@ const int MAX_CLUSTERS = 128; const int INDICES_PER_VERTEX = 4; -layout(std140, binding=GRAPHICS_BUFFER_SKINNING) uniform skinClusterBuffer { +LAYOUT_STD140(binding=GRAPHICS_BUFFER_SKINNING) uniform skinClusterBuffer { mat4 clusterMatrices[MAX_CLUSTERS]; }; diff --git a/libraries/render-utils/src/SubsurfaceScattering.cpp b/libraries/render-utils/src/SubsurfaceScattering.cpp index 84b51d626a..e004e66501 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.cpp +++ b/libraries/render-utils/src/SubsurfaceScattering.cpp @@ -421,6 +421,10 @@ void DebugSubsurfaceScattering::configure(const Config& config) { _showSpecularTable = config.showSpecularTable; _showCursorPixel = config.showCursorPixel; _debugCursorTexcoord = config.debugCursorTexcoord; + if (!_debugParams) { + _debugParams = std::make_shared(sizeof(glm::vec4), nullptr); + } + _debugParams->setSubData(0, _debugCursorTexcoord); } @@ -479,6 +483,10 @@ void DebugSubsurfaceScattering::run(const render::RenderContextPointer& renderCo assert(lightStage); // const auto light = DependencyManager::get()->getLightStage()->getLight(0); const auto light = lightStage->getLight(0); + if (!_debugParams) { + _debugParams = std::make_shared(sizeof(glm::vec4), nullptr); + _debugParams->setSubData(0, _debugCursorTexcoord); + } gpu::doInBatch("DebugSubsurfaceScattering::run", args->_context, [=](gpu::Batch& batch) { batch.enableStereo(false); @@ -521,9 +529,7 @@ void DebugSubsurfaceScattering::run(const render::RenderContextPointer& renderCo batch.setResourceTexture(ru::Texture::DeferredNormal, deferredFramebuffer->getDeferredNormalTexture()); batch.setResourceTexture(ru::Texture::DeferredColor, deferredFramebuffer->getDeferredColorTexture()); batch.setResourceTexture(ru::Texture::DeferredDepth, linearDepthTexture); - - - batch._glUniform2f(gpu::slot::uniform::Extra0, _debugCursorTexcoord.x, _debugCursorTexcoord.y); + batch.setUniformBuffer(1, _debugParams); batch.draw(gpu::TRIANGLE_STRIP, 4); } } diff --git a/libraries/render-utils/src/SubsurfaceScattering.h b/libraries/render-utils/src/SubsurfaceScattering.h index 780ce34d7f..e0073d23e8 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.h +++ b/libraries/render-utils/src/SubsurfaceScattering.h @@ -179,6 +179,7 @@ private: gpu::PipelinePointer _showLUTPipeline; gpu::PipelinePointer getShowLUTPipeline(); + gpu::BufferPointer _debugParams; bool _showProfile{ false }; bool _showLUT{ false }; bool _showSpecularTable{ false }; diff --git a/libraries/render-utils/src/SubsurfaceScattering.slh b/libraries/render-utils/src/SubsurfaceScattering.slh index 3d37f52e4d..66b3ab1ea0 100644 --- a/libraries/render-utils/src/SubsurfaceScattering.slh +++ b/libraries/render-utils/src/SubsurfaceScattering.slh @@ -56,7 +56,7 @@ vec3 generateProfile(vec2 uv) { <@func declareSubsurfaceScatteringProfileMap()@> -layout(binding=RENDER_UTILS_TEXTURE_SSSC_PROFILE) uniform sampler2D scatteringProfile; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSSC_PROFILE) uniform sampler2D scatteringProfile; vec3 scatter(float r) { return texture(scatteringProfile, vec2(r * 0.5, 0.5)).rgb; @@ -104,7 +104,7 @@ vec3 integrate(float cosTheta, float skinRadius) { <@func declareSubsurfaceScatteringResource()@> -layout(binding=RENDER_UTILS_TEXTURE_SSSC_LUT) uniform sampler2D scatteringLUT; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSSC_LUT) uniform sampler2D scatteringLUT; vec3 fetchBRDF(float LdotN, float curvature) { return texture(scatteringLUT, vec2( clamp(LdotN * 0.5 + 0.5, 0.0, 1.0), clamp(2.0 * curvature, 0.0, 1.0))).xyz; @@ -124,7 +124,7 @@ struct ScatteringParameters { vec4 debugFlags; }; -layout(binding=RENDER_UTILS_BUFFER_SSSC_PARAMS) uniform subsurfaceScatteringParametersBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_SSSC_PARAMS) uniform subsurfaceScatteringParametersBuffer { ScatteringParameters parameters; }; diff --git a/libraries/render-utils/src/WorkloadResource.slh b/libraries/render-utils/src/WorkloadResource.slh index 81b6ed78ce..ed23abd5ae 100644 --- a/libraries/render-utils/src/WorkloadResource.slh +++ b/libraries/render-utils/src/WorkloadResource.slh @@ -25,8 +25,8 @@ struct WorkloadProxy { vec4 region; }; -#if defined(GPU_GL410) -layout(binding=0) uniform samplerBuffer workloadProxiesBuffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=0) uniform samplerBuffer workloadProxiesBuffer; WorkloadProxy getWorkloadProxy(int i) { int offset = 2 * i; WorkloadProxy proxy; @@ -35,7 +35,7 @@ WorkloadProxy getWorkloadProxy(int i) { return proxy; } #else -layout(std140, binding=0) buffer workloadProxiesBuffer { +LAYOUT_STD140(binding=0) buffer workloadProxiesBuffer { WorkloadProxy _proxies[]; }; WorkloadProxy getWorkloadProxy(int i) { @@ -57,17 +57,23 @@ struct WorkloadView { vec4 regions[3]; }; -#if defined(GPU_GL410) -layout(binding=1) uniform samplerBuffer workloadViewsBuffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=1) uniform samplerBuffer workloadViewsBuffer; WorkloadView getWorkloadView(int i) { - int offset = 2 * i; + int offset = 8 * i; WorkloadView view; - view.origin = texelFetch(workloadViewsBuffer, offset); - view.radiuses = texelFetch(workloadViewsBuffer, offset + 1); + view.direction_far = texelFetch(workloadViewsBuffer, offset + 0); + view.fov = texelFetch(workloadViewsBuffer, offset + 1); + view.origin = texelFetch(workloadViewsBuffer, offset + 2); + view.backFront[0] = texelFetch(workloadViewsBuffer, offset + 3); + view.backFront[1] = texelFetch(workloadViewsBuffer, offset + 4); + view.regions[0] = texelFetch(workloadViewsBuffer, offset + 5); + view.regions[1] = texelFetch(workloadViewsBuffer, offset + 6); + view.regions[2] = texelFetch(workloadViewsBuffer, offset + 7); return view; } #else -layout(std140, binding=1) buffer workloadViewsBuffer { +LAYOUT_STD140(binding=1) buffer workloadViewsBuffer { WorkloadView _views[]; }; WorkloadView getWorkloadView(int i) { diff --git a/libraries/render-utils/src/debug_deferred_buffer.slf b/libraries/render-utils/src/debug_deferred_buffer.slf index 013640d910..c6e3c49e54 100644 --- a/libraries/render-utils/src/debug_deferred_buffer.slf +++ b/libraries/render-utils/src/debug_deferred_buffer.slf @@ -16,8 +16,8 @@ <@include gpu/Color.slh@> <$declareColorWheel()$> -layout(binding=RENDER_UTILS_DEBUG_TEXTURE0) uniform sampler2D debugTexture0; -layout(binding=RENDER_UTILS_TEXTURE_SHADOW) uniform sampler2DArrayShadow shadowMaps; +LAYOUT(binding=RENDER_UTILS_DEBUG_TEXTURE0) uniform sampler2D debugTexture0; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SHADOW) uniform sampler2DArrayShadow shadowMaps; <@include ShadowCore.slh@> @@ -36,7 +36,13 @@ float curvatureAO(float k) { layout(location=0) in vec2 uv; layout(location=0) out vec4 outFragColor; -//SOURCE_PLACEHOLDER +//SOURCE_PLACEHOLDER_BEGIN +vec4 getFragmentColor() { + DeferredFragment frag = unpackDeferredFragmentNoPosition(uv); + return vec4(pow(frag.albedo, vec3(1.0 / 2.2)), 1.0); +} +//SOURCE_PLACEHOLDER_END + void main(void) { outFragColor = getFragmentColor(); diff --git a/libraries/render-utils/src/deferred_light_point.slv b/libraries/render-utils/src/deferred_light_point.slv index 1f4c66b6e5..3e6329be83 100644 --- a/libraries/render-utils/src/deferred_light_point.slv +++ b/libraries/render-utils/src/deferred_light_point.slv @@ -22,7 +22,7 @@ <$declareLightBuffer(256)$> -layout(binding=RENDER_UTILS_BUFFER_LIGHT_INDEX) uniform lightIndexBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_LIGHT_INDEX) uniform lightIndexBuffer { int lightIndex[256]; }; diff --git a/libraries/render-utils/src/deferred_light_spot.slv b/libraries/render-utils/src/deferred_light_spot.slv index c86551936b..0370acc6bc 100644 --- a/libraries/render-utils/src/deferred_light_spot.slv +++ b/libraries/render-utils/src/deferred_light_spot.slv @@ -21,7 +21,7 @@ <$declareLightBuffer(256)$> -layout(binding=RENDER_UTILS_BUFFER_LIGHT_INDEX) uniform lightIndexBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_LIGHT_INDEX) uniform lightIndexBuffer { int lightIndex[256]; }; layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord0; diff --git a/libraries/render-utils/src/drawWorkloadView.slv b/libraries/render-utils/src/drawWorkloadView.slv index db4a33c450..2fdf3d773e 100644 --- a/libraries/render-utils/src/drawWorkloadView.slv +++ b/libraries/render-utils/src/drawWorkloadView.slv @@ -32,7 +32,7 @@ struct DrawMesh { vec4 verts[NUM_SEGMENT_PER_VIEW_REGION]; }; -layout(std140, binding=0) uniform DrawMeshBuffer { +LAYOUT_STD140(binding=0) uniform DrawMeshBuffer { DrawMesh _drawMeshBuffer; }; diff --git a/libraries/render-utils/src/forward_simple.slf b/libraries/render-utils/src/forward_simple.slf index ca3a13c024..9c86f9dff1 100644 --- a/libraries/render-utils/src/forward_simple.slf +++ b/libraries/render-utils/src/forward_simple.slf @@ -14,8 +14,10 @@ <@include DefaultMaterials.slh@> <@include ForwardGlobalLight.slh@> -<$declareEvalSkyboxGlobalColor()$> +<@include gpu/Transform.slh@> +<$declareEvalSkyboxGlobalColor()$> +<$declareStandardCameraTransform()$> // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; @@ -35,12 +37,6 @@ layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; layout(location=0) out vec4 _fragColor0; -<@include procedural/ProceduralCommon.slh@> - -#line 1001 -//PROCEDURAL_BLOCK - -#line 2030 void main(void) { vec3 normal = normalize(_normalWS.xyz); vec3 diffuse = _color.rgb; @@ -48,45 +44,18 @@ void main(void) { float shininess = DEFAULT_SHININESS; float emissiveAmount = 0.0; -#ifdef PROCEDURAL - -#ifdef PROCEDURAL_V1 - diffuse = getProceduralColor().rgb; - // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline - //diffuse = pow(diffuse, vec3(2.2)); - emissiveAmount = 1.0; -#else - emissiveAmount = getProceduralColors(diffuse, specular, shininess); -#endif - -#endif - TransformCamera cam = getTransformCamera(); vec3 fragPosition = _positionES.xyz; - if (emissiveAmount > 0.0) { - _fragColor0 = vec4(evalSkyboxGlobalColor( - cam._viewInverse, - 1.0, - DEFAULT_OCCLUSION, - fragPosition, - normal, - diffuse, - specular, - DEFAULT_METALLIC, - max(0.0, 1.0 - shininess / 128.0)), - 1.0); - } else { - _fragColor0 = vec4(evalSkyboxGlobalColor( - cam._viewInverse, - 1.0, - DEFAULT_OCCLUSION, - fragPosition, - normal, - diffuse, - DEFAULT_FRESNEL, - length(specular), - max(0.0, 1.0 - shininess / 128.0)), - 1.0); - } + _fragColor0 = vec4(evalSkyboxGlobalColor( + cam._viewInverse, + 1.0, + DEFAULT_OCCLUSION, + fragPosition, + normal, + diffuse, + DEFAULT_FRESNEL, + length(specular), + max(0.0, 1.0 - shininess / 128.0)), + 1.0); } diff --git a/libraries/render-utils/src/forward_simple_textured.slf b/libraries/render-utils/src/forward_simple_textured.slf index 8570ae6183..ca31550b40 100644 --- a/libraries/render-utils/src/forward_simple_textured.slf +++ b/libraries/render-utils/src/forward_simple_textured.slf @@ -22,7 +22,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/forward_simple_textured_transparent.slf b/libraries/render-utils/src/forward_simple_textured_transparent.slf index 11c44c18a2..11d51bbd78 100644 --- a/libraries/render-utils/src/forward_simple_textured_transparent.slf +++ b/libraries/render-utils/src/forward_simple_textured_transparent.slf @@ -22,7 +22,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/forward_simple_textured_unlit.slf b/libraries/render-utils/src/forward_simple_textured_unlit.slf index 8ca46da499..ddbc5ae4d7 100644 --- a/libraries/render-utils/src/forward_simple_textured_unlit.slf +++ b/libraries/render-utils/src/forward_simple_textured_unlit.slf @@ -20,7 +20,7 @@ layout(location=0) out vec4 _fragColor0; // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; diff --git a/libraries/render-utils/src/fxaa.slf b/libraries/render-utils/src/fxaa.slf index f1096a3054..1539a87550 100644 --- a/libraries/render-utils/src/fxaa.slf +++ b/libraries/render-utils/src/fxaa.slf @@ -22,7 +22,7 @@ precision mediump float; precision mediump int; #endif -layout(binding=0) uniform sampler2D colorTexture; +LAYOUT(binding=0) uniform sampler2D colorTexture; //uniform sampler2D historyTexture; // FIXME make into a uniform buffer or push constant if this shader ever comes into use diff --git a/libraries/render-utils/src/fxaa_blend.slf b/libraries/render-utils/src/fxaa_blend.slf index c051801659..c22982bc3f 100644 --- a/libraries/render-utils/src/fxaa_blend.slf +++ b/libraries/render-utils/src/fxaa_blend.slf @@ -17,13 +17,13 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; -layout(binding=0) uniform sampler2D colorTexture; +LAYOUT(binding=0) uniform sampler2D colorTexture; struct FxaaBlendParams { vec4 sharpenIntensity; }; -layout(binding=0) uniform fxaaBlendParamsBuffer { +LAYOUT(binding=0) uniform fxaaBlendParamsBuffer { FxaaBlendParams params; }; diff --git a/libraries/render-utils/src/glowLine.slv b/libraries/render-utils/src/glowLine.slv index 075b291589..167aeb8c9e 100644 --- a/libraries/render-utils/src/glowLine.slv +++ b/libraries/render-utils/src/glowLine.slv @@ -21,7 +21,7 @@ struct LineData { float width; }; -layout(std140, binding=0) uniform LineDataBuffer { +LAYOUT_STD140(binding=0) uniform LineDataBuffer { LineData _lineData; }; diff --git a/libraries/render-utils/src/grid.slf b/libraries/render-utils/src/grid.slf index c2380c980d..8e9b35dace 100644 --- a/libraries/render-utils/src/grid.slf +++ b/libraries/render-utils/src/grid.slf @@ -20,7 +20,7 @@ struct Grid { vec4 edge; }; -layout(binding=0) uniform gridBuffer { +LAYOUT(binding=0) uniform gridBuffer { Grid grid; }; diff --git a/libraries/render-utils/src/hmd_ui.slf b/libraries/render-utils/src/hmd_ui.slf index eebeb2e060..6895a90f9e 100644 --- a/libraries/render-utils/src/hmd_ui.slf +++ b/libraries/render-utils/src/hmd_ui.slf @@ -13,13 +13,13 @@ // <@include render-utils/ShaderConstants.h@> -layout(binding=0) uniform sampler2D hudTexture; +LAYOUT(binding=0) uniform sampler2D hudTexture; struct HUDData { float alpha; }; -layout(std140, binding=0) uniform hudBuffer { +LAYOUT_STD140(binding=0) uniform hudBuffer { HUDData hud; }; diff --git a/libraries/render-utils/src/hmd_ui.slv b/libraries/render-utils/src/hmd_ui.slv index ab0d77c42a..6e782d1672 100644 --- a/libraries/render-utils/src/hmd_ui.slv +++ b/libraries/render-utils/src/hmd_ui.slv @@ -22,7 +22,7 @@ struct HUDData { float alpha; }; -layout(std140, binding=0) uniform hudBuffer { +LAYOUT_STD140(binding=0) uniform hudBuffer { HUDData hud; }; diff --git a/libraries/render-utils/src/parabola.slv b/libraries/render-utils/src/parabola.slv index 31b3ab8fae..53dfc75cfe 100644 --- a/libraries/render-utils/src/parabola.slv +++ b/libraries/render-utils/src/parabola.slv @@ -22,7 +22,7 @@ struct ParabolaData { ivec3 spare; }; -layout(std140, binding=0) uniform parabolaData { +LAYOUT_STD140(binding=0) uniform parabolaData { ParabolaData _parabolaData; }; diff --git a/libraries/render-utils/src/render-utils/ShaderConstants.h b/libraries/render-utils/src/render-utils/ShaderConstants.h index ccf6314a39..2d777d502f 100644 --- a/libraries/render-utils/src/render-utils/ShaderConstants.h +++ b/libraries/render-utils/src/render-utils/ShaderConstants.h @@ -131,15 +131,6 @@ namespace render_utils { namespace slot { -namespace uniform { -enum Uniform { - TextColor = RENDER_UTILS_UNIFORM_TEXT_COLOR, - TextOutline = RENDER_UTILS_UNIFORM_TEXT_OUTLINE, - TaaSharpenIntensity = GPU_UNIFORM_EXTRA0, - HighlightOutlineWidth = GPU_UNIFORM_EXTRA0, -}; -} - namespace buffer { enum Buffer { DeferredFrameTransform = RENDER_UTILS_BUFFER_DEFERRED_FRAME_TRANSFORM, diff --git a/libraries/render-utils/src/render-utils/debug_deferred_buffer.slp b/libraries/render-utils/src/render-utils/debug_deferred_buffer.slp new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libraries/render-utils/src/render-utils/simple.slp b/libraries/render-utils/src/render-utils/simple.slp index 8a6e2e4f99..e69de29bb2 100644 --- a/libraries/render-utils/src/render-utils/simple.slp +++ b/libraries/render-utils/src/render-utils/simple.slp @@ -1 +0,0 @@ -FRAGMENT forward_simple_textured diff --git a/libraries/render-utils/src/render-utils/simpleTranslucent.slp b/libraries/render-utils/src/render-utils/simpleTranslucent.slp deleted file mode 100644 index 0163b09b84..0000000000 --- a/libraries/render-utils/src/render-utils/simpleTranslucent.slp +++ /dev/null @@ -1,2 +0,0 @@ -VERTEX simple -FRAGMENT forward_simple_textured_transparent diff --git a/libraries/render-utils/src/render-utils/simpleTranslucentUnlit.slp b/libraries/render-utils/src/render-utils/simpleTranslucentUnlit.slp deleted file mode 100644 index f1d1ec39be..0000000000 --- a/libraries/render-utils/src/render-utils/simpleTranslucentUnlit.slp +++ /dev/null @@ -1,2 +0,0 @@ -VERTEX simple -FRAGMENT simple_transparent_textured_unlit diff --git a/libraries/render-utils/src/render-utils/simpleUnlit.slp b/libraries/render-utils/src/render-utils/simpleUnlit.slp deleted file mode 100644 index ab491aa290..0000000000 --- a/libraries/render-utils/src/render-utils/simpleUnlit.slp +++ /dev/null @@ -1,2 +0,0 @@ -VERTEX simple -FRAGMENT forward_simple_textured_unlit diff --git a/libraries/render-utils/src/render-utils/simple_transparent.slp b/libraries/render-utils/src/render-utils/simple_transparent.slp new file mode 100644 index 0000000000..10e6b388c4 --- /dev/null +++ b/libraries/render-utils/src/render-utils/simple_transparent.slp @@ -0,0 +1 @@ +VERTEX simple diff --git a/libraries/render-utils/src/sdf_text3D.slf b/libraries/render-utils/src/sdf_text3D.slf index d35396e469..35e670eef8 100644 --- a/libraries/render-utils/src/sdf_text3D.slf +++ b/libraries/render-utils/src/sdf_text3D.slf @@ -13,14 +13,14 @@ <@include DeferredBufferWrite.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=0) uniform sampler2D Font; +LAYOUT(binding=0) uniform sampler2D Font; struct TextParams { vec4 color; vec4 outline; }; -layout(binding=0) uniform textParamsBuffer { +LAYOUT(binding=0) uniform textParamsBuffer { TextParams params; }; diff --git a/libraries/render-utils/src/sdf_text3D_transparent.slf b/libraries/render-utils/src/sdf_text3D_transparent.slf index 9dffca2038..6e271e1463 100644 --- a/libraries/render-utils/src/sdf_text3D_transparent.slf +++ b/libraries/render-utils/src/sdf_text3D_transparent.slf @@ -13,14 +13,14 @@ <@include DeferredBufferWrite.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=0) uniform sampler2D Font; +LAYOUT(binding=0) uniform sampler2D Font; struct TextParams { vec4 color; vec4 outline; }; -layout(binding=0) uniform textParamsBuffer { +LAYOUT(binding=0) uniform textParamsBuffer { TextParams params; }; diff --git a/libraries/render-utils/src/simple.slf b/libraries/render-utils/src/simple.slf index a7f5151880..039dbc4278 100644 --- a/libraries/render-utils/src/simple.slf +++ b/libraries/render-utils/src/simple.slf @@ -35,7 +35,17 @@ layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; <@include procedural/ProceduralCommon.slh@> #line 1001 -//PROCEDURAL_BLOCK +//PROCEDURAL_BLOCK_BEGIN + +vec3 getProceduralColor() { + return _color.rgb; +} + +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + return 1.0; +} + +//PROCEDURAL_BLOCK_END #line 2030 void main(void) { diff --git a/libraries/render-utils/src/simple_fade.slf b/libraries/render-utils/src/simple_fade.slf deleted file mode 100644 index 97ed0c570c..0000000000 --- a/libraries/render-utils/src/simple_fade.slf +++ /dev/null @@ -1,110 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// -// simple_fade.frag -// fragment shader -// -// Created by Olivier Prat on 06/05/17. -// Copyright 2017 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 DeferredBufferWrite.slh@> - -<@include Fade.slh@> -<$declareFadeFragmentInstanced()$> - -<@include render-utils/ShaderConstants.h@> - -// the interpolated normal -layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; -layout(location=RENDER_UTILS_ATTR_NORMAL_MS) in vec3 _normalMS; -layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; -layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; -#define _texCoord0 _texCoord01.xy -#define _texCoord1 _texCoord01.zw -layout(location=RENDER_UTILS_ATTR_POSITION_MS) in vec4 _positionMS; -layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; -layout(location=RENDER_UTILS_ATTR_POSITION_WS) in vec4 _positionWS; - -// For retro-compatibility -#define _normal _normalWS -#define _modelNormal _normalMS -#define _position _positionMS -#define _eyePosition _positionES - -<@include procedural/ProceduralCommon.slh@> - -#line 1001 -//PROCEDURAL_BLOCK - -#line 2030 -void main(void) { - vec3 fadeEmissive; - FadeObjectParams fadeParams; - - <$fetchFadeObjectParamsInstanced(fadeParams)$> - applyFade(fadeParams, _positionWS.xyz, fadeEmissive); - - vec3 normal = normalize(_normalWS.xyz); - vec3 diffuse = _color.rgb; - vec3 specular = DEFAULT_SPECULAR; - float shininess = DEFAULT_SHININESS; - float emissiveAmount = 0.0; - -#ifdef PROCEDURAL - -#ifdef PROCEDURAL_V1 - specular = getProceduralColor().rgb; - // Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline - //specular = pow(specular, vec3(2.2)); - emissiveAmount = 1.0; -#else - emissiveAmount = getProceduralColors(diffuse, specular, shininess); -#endif - -#endif - - const float ALPHA_THRESHOLD = 0.999; - if (_color.a < ALPHA_THRESHOLD) { - if (emissiveAmount > 0.0) { - packDeferredFragmentTranslucent( - normal, - _color.a, - specular+fadeEmissive, - DEFAULT_FRESNEL, - DEFAULT_ROUGHNESS); - } else { - packDeferredFragmentTranslucent( - normal, - _color.a, - diffuse+fadeEmissive, - DEFAULT_FRESNEL, - DEFAULT_ROUGHNESS); - } - } else { - if (emissiveAmount > 0.0) { - packDeferredFragmentLightmap( - normal, - 1.0, - diffuse+fadeEmissive, - max(0.0, 1.0 - shininess / 128.0), - DEFAULT_METALLIC, - specular, - specular); - } else { - packDeferredFragment( - normal, - 1.0, - diffuse, - max(0.0, 1.0 - shininess / 128.0), - length(specular), - DEFAULT_EMISSIVE+fadeEmissive, - DEFAULT_OCCLUSION, - DEFAULT_SCATTERING); - } - } -} diff --git a/libraries/render-utils/src/simple_opaque_web_browser.slf b/libraries/render-utils/src/simple_opaque_web_browser.slf index cf4828d3b3..36b0c825ad 100644 --- a/libraries/render-utils/src/simple_opaque_web_browser.slf +++ b/libraries/render-utils/src/simple_opaque_web_browser.slf @@ -18,7 +18,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_textured.slf b/libraries/render-utils/src/simple_textured.slf index 7676844084..b308b57345 100644 --- a/libraries/render-utils/src/simple_textured.slf +++ b/libraries/render-utils/src/simple_textured.slf @@ -17,7 +17,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_textured_fade.slf b/libraries/render-utils/src/simple_textured_fade.slf index 600f19be0f..ad2b636708 100644 --- a/libraries/render-utils/src/simple_textured_fade.slf +++ b/libraries/render-utils/src/simple_textured_fade.slf @@ -20,7 +20,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_textured_unlit.slf b/libraries/render-utils/src/simple_textured_unlit.slf index e3d9b9daf6..f33cb704dc 100644 --- a/libraries/render-utils/src/simple_textured_unlit.slf +++ b/libraries/render-utils/src/simple_textured_unlit.slf @@ -18,7 +18,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_textured_unlit_fade.slf b/libraries/render-utils/src/simple_textured_unlit_fade.slf index bffadbe819..494920b363 100644 --- a/libraries/render-utils/src/simple_textured_unlit_fade.slf +++ b/libraries/render-utils/src/simple_textured_unlit_fade.slf @@ -20,7 +20,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_transparent.slf b/libraries/render-utils/src/simple_transparent.slf index 5db54aa770..0e29ed7470 100644 --- a/libraries/render-utils/src/simple_transparent.slf +++ b/libraries/render-utils/src/simple_transparent.slf @@ -39,7 +39,18 @@ layout(location=0) out vec4 _fragColor0; <@include procedural/ProceduralCommon.slh@> #line 1001 -//PROCEDURAL_BLOCK + +//PROCEDURAL_BLOCK_BEGIN + +vec3 getProceduralColor() { + return _color.rgb; +} + +float getProceduralColors(inout vec3 diffuse, inout vec3 specular, inout float shininess) { + return 1.0; +} + +//PROCEDURAL_BLOCK_END #line 2030 void main(void) { diff --git a/libraries/render-utils/src/simple_transparent_textured.slf b/libraries/render-utils/src/simple_transparent_textured.slf index 5573a7aa22..ef83914096 100644 --- a/libraries/render-utils/src/simple_transparent_textured.slf +++ b/libraries/render-utils/src/simple_transparent_textured.slf @@ -17,7 +17,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_transparent_textured_fade.slf b/libraries/render-utils/src/simple_transparent_textured_fade.slf index 44a3fe2e01..5fac67e1d2 100644 --- a/libraries/render-utils/src/simple_transparent_textured_fade.slf +++ b/libraries/render-utils/src/simple_transparent_textured_fade.slf @@ -26,7 +26,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; layout(location=RENDER_UTILS_ATTR_POSITION_ES) in vec4 _positionES; layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/simple_transparent_textured_unlit.slf b/libraries/render-utils/src/simple_transparent_textured_unlit.slf index 9d43e41c2f..bf3dbbdf88 100644 --- a/libraries/render-utils/src/simple_transparent_textured_unlit.slf +++ b/libraries/render-utils/src/simple_transparent_textured_unlit.slf @@ -17,7 +17,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; diff --git a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf index 43c28c41c3..943f361ead 100644 --- a/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf +++ b/libraries/render-utils/src/simple_transparent_textured_unlit_fade.slf @@ -19,7 +19,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; layout(location=RENDER_UTILS_ATTR_COLOR) in vec4 _color; layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01; diff --git a/libraries/render-utils/src/simple_transparent_web_browser.slf b/libraries/render-utils/src/simple_transparent_web_browser.slf index df92d238bf..2adc16e278 100644 --- a/libraries/render-utils/src/simple_transparent_web_browser.slf +++ b/libraries/render-utils/src/simple_transparent_web_browser.slf @@ -18,7 +18,7 @@ <@include render-utils/ShaderConstants.h@> // the albedo texture -layout(binding=0) uniform sampler2D originalTexture; +LAYOUT(binding=0) uniform sampler2D originalTexture; // the interpolated normal layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS; diff --git a/libraries/render-utils/src/ssao.slh b/libraries/render-utils/src/ssao.slh index b149d8f912..f0d522a41c 100644 --- a/libraries/render-utils/src/ssao.slh +++ b/libraries/render-utils/src/ssao.slh @@ -44,7 +44,7 @@ struct AmbientOcclusionParams { float _gaussianCoefs[8]; }; -layout(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_SSAO_PARAMS) uniform ambientOcclusionParamsBuffer { AmbientOcclusionParams params; }; @@ -232,7 +232,7 @@ vec3 getTapLocationClamped(int sampleNumber, float spinAngle, float outerRadius, // the depth pyramid texture -layout(binding=RENDER_UTILS_TEXTURE_SSAO_PYRAMID) uniform sampler2D pyramidMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_PYRAMID) uniform sampler2D pyramidMap; float getZEye(ivec2 pixel, int level) { return -texelFetch(pyramidMap, pixel, level).x; @@ -313,7 +313,7 @@ float evalAO(in vec3 C, in vec3 n_C, in vec3 Q) { <$declareAmbientOcclusion()$> // the source occlusion texture -layout(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SSAO_OCCLUSION) uniform sampler2D occlusionMap; vec2 fetchOcclusionDepthRaw(ivec2 coords, out vec3 raw) { raw = texelFetch(occlusionMap, coords, 0).xyz; diff --git a/libraries/render-utils/src/ssao_debugOcclusion.slf b/libraries/render-utils/src/ssao_debugOcclusion.slf index ab7989e35e..e15e52f448 100644 --- a/libraries/render-utils/src/ssao_debugOcclusion.slf +++ b/libraries/render-utils/src/ssao_debugOcclusion.slf @@ -26,7 +26,7 @@ struct DebugParams{ vec4 pixelInfo; }; -layout(binding=RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS) uniform debugAmbientOcclusionBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_SSAO_DEBUG_PARAMS) uniform debugAmbientOcclusionBuffer { DebugParams debugParams; }; diff --git a/libraries/render-utils/src/ssao_makePyramid.slf b/libraries/render-utils/src/ssao_makePyramid.slf index c87fe1e682..eae1b853f9 100644 --- a/libraries/render-utils/src/ssao_makePyramid.slf +++ b/libraries/render-utils/src/ssao_makePyramid.slf @@ -14,7 +14,7 @@ <@include ssao.slh@> <$declareAmbientOcclusion()$> -layout(binding=0) uniform sampler2D depthMap; +LAYOUT(binding=0) uniform sampler2D depthMap; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/standardDrawTexture.slf b/libraries/render-utils/src/standardDrawTexture.slf index 1a8af0f71c..620c811f75 100644 --- a/libraries/render-utils/src/standardDrawTexture.slf +++ b/libraries/render-utils/src/standardDrawTexture.slf @@ -14,7 +14,7 @@ <@include gpu/ShaderConstants.h@> // the texture -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=GPU_ATTR_POSITION) in vec3 varPosition; layout(location=GPU_ATTR_NORMAL) in vec3 varNormal; diff --git a/libraries/render-utils/src/standardDrawTextureNoBlend.slf b/libraries/render-utils/src/standardDrawTextureNoBlend.slf index 95138d123f..83915cd856 100644 --- a/libraries/render-utils/src/standardDrawTextureNoBlend.slf +++ b/libraries/render-utils/src/standardDrawTextureNoBlend.slf @@ -14,7 +14,7 @@ <@include gpu/ShaderConstants.h@> // the texture -layout(binding=0) uniform sampler2D colorMap; +LAYOUT(binding=0) uniform sampler2D colorMap; layout(location=GPU_ATTR_POSITION) in vec3 varPosition; layout(location=GPU_ATTR_NORMAL) in vec3 varNormal; diff --git a/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf b/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf index 8664fa16fd..877c31c23d 100644 --- a/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf +++ b/libraries/render-utils/src/subsurfaceScattering_drawScattering.slf @@ -26,10 +26,14 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 _fragColor; -// FIXME make into a uniform buffer or push constant if this shader ever comes into use -vec2 uniformCursorTexcoord = vec2(0.5); +struct SSSDebugParams { + vec4 cursorTexCoordSpare2; +}; -//uniform vec3 uniformLightVector = vec3(1.0); +// Deferred frame transform uses slot 0 +LAYOUT_STD140(binding=1) uniform sssDebugParamsBuffer { + SSSDebugParams sssDebugParams; +}; vec3 evalScatteringBRDF(vec2 texcoord) { DeferredFragment fragment = unpackDeferredFragmentNoPosition(texcoord); @@ -76,8 +80,6 @@ vec3 drawScatteringTableUV(vec2 cursor, vec2 texcoord) { vec3 bentNdotL = evalScatteringBentNdotL(normal, midNormal, lowNormal, fragLightDir); - // return clamp(bentNdotL * 0.5 + 0.5, 0.0, 1.0); - vec3 distance = vec3(0.0); for (int c = 0; c < 3; c++) { vec2 BRDFuv = vec2(clamp(bentNdotL[c] * 0.5 + 0.5, 0.0, 1.0), clamp(2.0 * curvature, 0.0, 1.0)); @@ -104,10 +106,8 @@ vec3 drawScatteringTableUV(vec2 cursor, vec2 texcoord) { } void main(void) { - // _fragColor = vec4(evalScatteringBRDF(varTexCoord0), 1.0); - // _fragColor = vec4(uniformCursorTexcoord, 0.0, 1.0); - - _fragColor = vec4(drawScatteringTableUV(uniformCursorTexcoord, varTexCoord0), 1.0); + vec2 cursorTexcoord = sssDebugParams.cursorTexCoordSpare2.xy; + _fragColor = vec4(drawScatteringTableUV(cursorTexcoord, varTexCoord0), 1.0); } diff --git a/libraries/render-utils/src/surfaceGeometry_copyDepth.slf b/libraries/render-utils/src/surfaceGeometry_copyDepth.slf index f018ee1105..efff6e913c 100644 --- a/libraries/render-utils/src/surfaceGeometry_copyDepth.slf +++ b/libraries/render-utils/src/surfaceGeometry_copyDepth.slf @@ -11,7 +11,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -layout(binding=0) uniform sampler2D depthMap; +LAYOUT(binding=0) uniform sampler2D depthMap; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf b/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf index 34e78ea4ff..e4020dbdec 100644 --- a/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf +++ b/libraries/render-utils/src/surfaceGeometry_downsampleDepthNormal.slf @@ -15,8 +15,8 @@ <@include gpu/PackedNormal.slh@> <@include render-utils/ShaderConstants.h@> -layout(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D linearDepthMap; -layout(binding=RENDER_UTILS_TEXTURE_SG_NORMAL) uniform sampler2D normalMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D linearDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_NORMAL) uniform sampler2D normalMap; layout(location=0) in vec2 varTexCoord0; diff --git a/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf b/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf index b49bd618da..363fd0d4f8 100644 --- a/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf +++ b/libraries/render-utils/src/surfaceGeometry_makeCurvature.slf @@ -25,7 +25,7 @@ struct SurfaceGeometryParams { vec4 curvatureInfo; }; -layout(binding= RENDER_UTILS_BUFFER_SG_PARAMS) uniform surfaceGeometryParamsBuffer { +LAYOUT(binding= RENDER_UTILS_BUFFER_SG_PARAMS) uniform surfaceGeometryParamsBuffer { SurfaceGeometryParams params; }; @@ -46,7 +46,7 @@ bool isFullResolution() { } -layout(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D linearDepthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D linearDepthMap; float getZEye(ivec2 pixel) { return -texelFetch(linearDepthMap, pixel, 0).x; @@ -59,7 +59,7 @@ vec2 sideToFrameTexcoord(vec2 side, vec2 texcoordPos) { return vec2((texcoordPos.x + side.x) * side.y, texcoordPos.y); } -layout(binding=RENDER_UTILS_TEXTURE_SG_NORMAL) uniform sampler2D normalMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_NORMAL) uniform sampler2D normalMap; vec3 getRawNormal(vec2 texcoord) { return texture(normalMap, texcoord).xyz; diff --git a/libraries/render-utils/src/surfaceGeometry_makeLinearDepth.slf b/libraries/render-utils/src/surfaceGeometry_makeLinearDepth.slf index 116f3b7686..fe0c320d1b 100644 --- a/libraries/render-utils/src/surfaceGeometry_makeLinearDepth.slf +++ b/libraries/render-utils/src/surfaceGeometry_makeLinearDepth.slf @@ -16,7 +16,7 @@ <@include DeferredTransform.slh@> <$declareDeferredFrameTransform()$> -layout(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D depthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SG_DEPTH) uniform sampler2D depthMap; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/taa.slh b/libraries/render-utils/src/taa.slh index 2161ad9524..784c0824d5 100644 --- a/libraries/render-utils/src/taa.slh +++ b/libraries/render-utils/src/taa.slh @@ -16,11 +16,11 @@ <@include render-utils/ShaderConstants.h@> <@include gpu/Color.slh@> -layout(binding=RENDER_UTILS_TEXTURE_TAA_HISTORY) uniform sampler2D historyMap; -layout(binding=RENDER_UTILS_TEXTURE_TAA_SOURCE) uniform sampler2D sourceMap; -layout(binding=RENDER_UTILS_TEXTURE_TAA_VELOCITY) uniform sampler2D velocityMap; -layout(binding=RENDER_UTILS_TEXTURE_TAA_DEPTH) uniform sampler2D depthMap; -layout(binding=RENDER_UTILS_TEXTURE_TAA_NEXT) uniform sampler2D nextMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_HISTORY) uniform sampler2D historyMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_SOURCE) uniform sampler2D sourceMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_VELOCITY) uniform sampler2D velocityMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_DEPTH) uniform sampler2D depthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_NEXT) uniform sampler2D nextMap; struct TAAParams { @@ -33,7 +33,7 @@ struct TAAParams vec4 regionInfo; }; -layout(std140, binding=RENDER_UTILS_BUFFER_TAA_PARAMS) uniform taaParamsBuffer { +LAYOUT_STD140(binding=RENDER_UTILS_BUFFER_TAA_PARAMS) uniform taaParamsBuffer { TAAParams params; }; diff --git a/libraries/render-utils/src/toneMapping.slf b/libraries/render-utils/src/toneMapping.slf index 8d89e54a1b..29f618c2f0 100644 --- a/libraries/render-utils/src/toneMapping.slf +++ b/libraries/render-utils/src/toneMapping.slf @@ -26,7 +26,7 @@ const int ToneCurveGamma22 = 1; const int ToneCurveReinhard = 2; const int ToneCurveFilmic = 3; -layout(binding=RENDER_UTILS_BUFFER_TM_PARAMS) uniform toneMappingParamsBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_TM_PARAMS) uniform toneMappingParamsBuffer { ToneMappingParams params; }; float getTwoPowExposure() { @@ -36,7 +36,7 @@ int getToneCurve() { return params._toneCurve_s0_s1_s2.x; } -layout(binding=RENDER_UTILS_TEXTURE_TM_COLOR) uniform sampler2D colorMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TM_COLOR) uniform sampler2D colorMap; layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; diff --git a/libraries/render-utils/src/velocityBuffer_cameraMotion.slf b/libraries/render-utils/src/velocityBuffer_cameraMotion.slf index 083440dbf8..0ec63a7b1d 100644 --- a/libraries/render-utils/src/velocityBuffer_cameraMotion.slf +++ b/libraries/render-utils/src/velocityBuffer_cameraMotion.slf @@ -17,7 +17,7 @@ layout(location=0) in vec2 varTexCoord0; layout(location=0) out vec4 outFragColor; -layout(binding=RENDER_UTILS_TEXTURE_TAA_DEPTH) uniform sampler2D depthMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_TAA_DEPTH) uniform sampler2D depthMap; void main(void) { diff --git a/libraries/render-utils/src/zone_drawSkybox.slf b/libraries/render-utils/src/zone_drawSkybox.slf index 77de75a305..f8d1326b3a 100644 --- a/libraries/render-utils/src/zone_drawSkybox.slf +++ b/libraries/render-utils/src/zone_drawSkybox.slf @@ -12,13 +12,13 @@ <@include render-utils/ShaderConstants.h@> // FIXME use declareSkyboxMap from LightAmbient.slh? -layout(binding=RENDER_UTILS_TEXTURE_SKYBOX) uniform samplerCube skyboxMap; +LAYOUT(binding=RENDER_UTILS_TEXTURE_SKYBOX) uniform samplerCube skyboxMap; struct Skybox { vec4 color; }; -layout(binding=RENDER_UTILS_BUFFER_DEBUG_SKYBOX) uniform skyboxBuffer { +LAYOUT(binding=RENDER_UTILS_BUFFER_DEBUG_SKYBOX) uniform skyboxBuffer { Skybox skybox; }; diff --git a/libraries/render/src/render/BlurTask.slh b/libraries/render/src/render/BlurTask.slh index c07e71688a..db6b8e3bab 100644 --- a/libraries/render/src/render/BlurTask.slh +++ b/libraries/render/src/render/BlurTask.slh @@ -21,7 +21,7 @@ struct BlurParameters { vec2 taps[BLUR_MAX_NUM_TAPS]; }; -layout(binding=0) uniform blurParamsBuffer { +LAYOUT(binding=0) uniform blurParamsBuffer { BlurParameters parameters; }; @@ -76,7 +76,7 @@ float getPosLinearDepthFar() { <$declareBlurUniforms()$> -layout(binding=0) uniform sampler2D sourceMap; +LAYOUT(binding=0) uniform sampler2D sourceMap; vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) { texcoord = evalTexcoordTransformed(texcoord); @@ -112,8 +112,8 @@ vec4 pixelShaderGaussian(vec2 texcoord, vec2 direction, vec2 pixelStep) { <$declareBlurUniforms()$> -layout(binding=0) uniform sampler2D sourceMap; -layout(binding=1) uniform sampler2D depthMap; +LAYOUT(binding=0) uniform sampler2D sourceMap; +LAYOUT(binding=1) uniform sampler2D depthMap; vec4 pixelShaderGaussianDepthAware(vec2 texcoord, vec2 direction, vec2 pixelStep) { texcoord = evalTexcoordTransformed(texcoord); diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 2b2accde37..d742428897 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -86,29 +86,30 @@ void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state, BatchSetter batchSetter, ItemSetter itemSetter) { ShapeKey key{ filter._flags }; + const auto& reflection = program->getReflection(); auto locations = std::make_shared(); - locations->albedoTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialAlbedo); - locations->roughnessTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialRoughness); - locations->normalTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialNormal); - locations->metallicTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialMetallic); - locations->emissiveTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialEmissiveLightmap); - locations->occlusionTextureUnit = program->getTextures().isValid(graphics::slot::texture::MaterialOcclusion); - locations->lightingModelBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::LightModel); - locations->skinClusterBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::Skinning); - locations->materialBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::Material); - locations->texMapArrayBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::TexMapArray); - locations->keyLightBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::KeyLight); - locations->lightBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::Light); - locations->lightAmbientBufferUnit = program->getUniformBuffers().isValid(graphics::slot::buffer::AmbientLight); - locations->lightAmbientMapUnit = program->getTextures().isValid(graphics::slot::texture::Skybox); - locations->fadeMaskTextureUnit = program->getTextures().isValid(render_utils::slot::texture::FadeMask); - locations->fadeParameterBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::FadeParameters); - locations->fadeObjectParameterBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::FadeObjectParameters); - locations->hazeParameterBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::HazeParams); + locations->albedoTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialAlbedo); + locations->roughnessTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialRoughness); + locations->normalTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialNormal); + locations->metallicTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialMetallic); + locations->emissiveTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialEmissiveLightmap); + locations->occlusionTextureUnit = reflection.validTexture(graphics::slot::texture::MaterialOcclusion); + locations->lightingModelBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::LightModel); + locations->skinClusterBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::Skinning); + locations->materialBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::Material); + locations->texMapArrayBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::TexMapArray); + locations->keyLightBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::KeyLight); + locations->lightBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::Light); + locations->lightAmbientBufferUnit = reflection.validUniformBuffer(graphics::slot::buffer::AmbientLight); + locations->lightAmbientMapUnit = reflection.validTexture(graphics::slot::texture::Skybox); + locations->fadeMaskTextureUnit = reflection.validTexture(render_utils::slot::texture::FadeMask); + locations->fadeParameterBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::FadeParameters); + locations->fadeObjectParameterBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::FadeObjectParameters); + locations->hazeParameterBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::HazeParams); if (key.isTranslucent()) { - locations->lightClusterGridBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::LightClusterGrid); - locations->lightClusterContentBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::LightClusterContent); - locations->lightClusterFrustumBufferUnit = program->getUniformBuffers().isValid(render_utils::slot::buffer::LightClusterFrustumGrid); + locations->lightClusterGridBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::LightClusterGrid); + locations->lightClusterContentBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::LightClusterContent); + locations->lightClusterFrustumBufferUnit = reflection.validUniformBuffer(render_utils::slot::buffer::LightClusterFrustumGrid); } { diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index bd6ac6521a..24c17d43f1 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -258,7 +258,7 @@ public: using ItemSetter = std::function; - ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr) : + ShapePipeline(const gpu::PipelinePointer& pipeline, const LocationsPointer& locations, const BatchSetter& batchSetter = nullptr, const ItemSetter& itemSetter = nullptr) : pipeline(pipeline), locations(locations), _batchSetter(batchSetter), diff --git a/libraries/render/src/render/drawItemBounds.slv b/libraries/render/src/render/drawItemBounds.slv index ea4d0f24e6..0a9615c9c2 100644 --- a/libraries/render/src/render/drawItemBounds.slv +++ b/libraries/render/src/render/drawItemBounds.slv @@ -24,7 +24,7 @@ struct DrawItemBoundsParams { vec4 color; }; -layout(binding=0) uniform drawItemBoundsParamsBuffer { +LAYOUT(binding=0) uniform drawItemBoundsParamsBuffer { DrawItemBoundsParams params; }; @@ -34,8 +34,8 @@ struct ItemBound { vec4 boundDim_s; }; -#if defined(GPU_GL410) -layout(binding=0) uniform samplerBuffer ssbo0Buffer; +#if !defined(GPU_SSBO_TRANSFORM_OBJECT) +LAYOUT(binding=0) uniform samplerBuffer ssbo0Buffer; ItemBound getItemBound(int i) { int offset = 2 * i; ItemBound bound; @@ -44,7 +44,7 @@ ItemBound getItemBound(int i) { return bound; } #else -layout(std140, binding=0) buffer ssbo0Buffer { +LAYOUT_STD140(binding=0) buffer ssbo0Buffer { ItemBound bounds[]; }; ItemBound getItemBound(int i) { diff --git a/libraries/render/src/render/drawItemStatus.slf b/libraries/render/src/render/drawItemStatus.slf index 9409ee6171..e88cf4c920 100644 --- a/libraries/render/src/render/drawItemStatus.slf +++ b/libraries/render/src/render/drawItemStatus.slf @@ -15,7 +15,7 @@ layout(location=0) in vec4 varColor; layout(location=1) in vec3 varTexcoord; layout(location=0) out vec4 outFragColor; -layout(binding=0) uniform sampler2D _icons; +LAYOUT(binding=0) uniform sampler2D _icons; vec2 getIconTexcoord(float icon, vec2 uv) { const vec2 ICON_COORD_SIZE = vec2(0.0625, 1.0); return vec2((uv.x + icon) * ICON_COORD_SIZE.x, uv.y * ICON_COORD_SIZE.y); diff --git a/libraries/script-engine/CMakeLists.txt b/libraries/script-engine/CMakeLists.txt index 31436bbf8b..588377c072 100644 --- a/libraries/script-engine/CMakeLists.txt +++ b/libraries/script-engine/CMakeLists.txt @@ -17,6 +17,6 @@ if (NOT ANDROID) endif () -link_hifi_libraries(shared networking octree gpu procedural graphics model-networking ktx recording avatars fbx entities controllers animation audio physics image midi) +link_hifi_libraries(shared networking octree shaders gpu procedural graphics model-networking ktx recording avatars fbx entities controllers animation audio physics image midi) # ui includes gl, but link_hifi_libraries does not use transitive includes, so gl must be explicit include_hifi_library_headers(gl) diff --git a/libraries/shaders/CMakeLists.txt b/libraries/shaders/CMakeLists.txt index a065c635e7..1d9c4d59a4 100644 --- a/libraries/shaders/CMakeLists.txt +++ b/libraries/shaders/CMakeLists.txt @@ -1,16 +1,7 @@ set(TARGET_NAME shaders) autoscribe_shader_libs(gpu graphics display-plugins procedural render render-utils entities-renderer) setup_hifi_library(Gui) - -add_dependencies(${TARGET_NAME} compiled_shaders reflected_shaders) - -# Despite the dependency above, the autogen logic will attempt to compile the QRC before -# the compiled_shaders project is built causing an error on a clean workspace because the -# QRC references files generated by the compiled_shaders target -# To fix that we need to explicitly add every shader as a dependnecy of the autogen process -foreach(COMPILED_SHADER ${COMPILED_SHADERS}) - set_property(TARGET ${TARGET_NAME} APPEND PROPERTY AUTOGEN_TARGET_DEPENDS "${COMPILED_SHADER}") -endforeach() +add_dependencies(${TARGET_NAME} scribed_shaders spirv_shaders reflected_shaders) link_hifi_libraries(shared gl) - +target_json() diff --git a/libraries/shaders/ShaderEnums.cpp.in b/libraries/shaders/ShaderEnums.cpp.in index 7f4751f116..042362288d 100644 --- a/libraries/shaders/ShaderEnums.cpp.in +++ b/libraries/shaders/ShaderEnums.cpp.in @@ -1,11 +1,19 @@ #include "ShaderEnums.h" +#include namespace shader { - -uint32_t all_programs[] = { +const std::vector& allPrograms() { + static const std::vector ALL_PROGRAMS{{ @SHADER_PROGRAMS_ARRAY@ - (uint32_t)-1 -}; - + }}; + return ALL_PROGRAMS; } +const std::vector& allShaders() { + static const std::vector ALL_SHADERS{{ +@SHADER_SHADERS_ARRAY@ + }}; + return ALL_SHADERS; +} + +} \ No newline at end of file diff --git a/libraries/shaders/headers/310es/header.glsl b/libraries/shaders/headers/310es/header.glsl new file mode 100644 index 0000000000..ac48d5c94c --- /dev/null +++ b/libraries/shaders/headers/310es/header.glsl @@ -0,0 +1,15 @@ +#version 310 es +#define GPU_GLES +#define GPU_GLES_310 +#define BITFIELD highp int +#define LAYOUT(X) layout(X) +#define LAYOUT_STD140(X) layout(std140, X) +#ifdef VULKAN + #define gl_InstanceID gl_InstanceIndex + #define gl_VertexID gl_VertexIndex +#endif +#extension GL_EXT_texture_buffer : enable +precision highp float; +precision highp samplerBuffer; +precision highp sampler2DShadow; +precision highp sampler2DArrayShadow; diff --git a/libraries/shaders/headers/410/header.glsl b/libraries/shaders/headers/410/header.glsl new file mode 100644 index 0000000000..901ae6f9db --- /dev/null +++ b/libraries/shaders/headers/410/header.glsl @@ -0,0 +1,15 @@ +#version 410 core +#define GPU_GL410 +#define BITFIELD int +#if defined(VULKAN) + #extension GL_ARB_shading_language_420pack : require + #define LAYOUT(X) layout(X) + #define LAYOUT_STD140(X) layout(std140, X) +#else + #define LAYOUT(X) + #define LAYOUT_STD140(X) layout(std140) +#endif +#ifdef VULKAN +#define gl_InstanceID gl_InstanceIndex +#define gl_VertexID gl_VertexIndex +#endif diff --git a/libraries/shaders/headers/450/header.glsl b/libraries/shaders/headers/450/header.glsl new file mode 100644 index 0000000000..6ce61b4378 --- /dev/null +++ b/libraries/shaders/headers/450/header.glsl @@ -0,0 +1,10 @@ +#version 450 core +#define GPU_GL450 +#define GPU_SSBO_TRANSFORM_OBJECT +#define BITFIELD int +#define LAYOUT(X) layout(X) +#define LAYOUT_STD140(X) layout(std140, X) +#ifdef VULKAN +#define gl_InstanceID gl_InstanceIndex +#define gl_VertexID gl_VertexIndex +#endif diff --git a/libraries/shaders/headers/mono.glsl b/libraries/shaders/headers/mono.glsl new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libraries/shaders/headers/stereo.glsl b/libraries/shaders/headers/stereo.glsl new file mode 100644 index 0000000000..090035b4a4 --- /dev/null +++ b/libraries/shaders/headers/stereo.glsl @@ -0,0 +1,4 @@ +#define GPU_TRANSFORM_IS_STEREO +#define GPU_TRANSFORM_STEREO_CAMERA +#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED +#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN diff --git a/libraries/shaders/src/shaders/Shaders.cpp b/libraries/shaders/src/shaders/Shaders.cpp index ac4810a896..c385fadb37 100644 --- a/libraries/shaders/src/shaders/Shaders.cpp +++ b/libraries/shaders/src/shaders/Shaders.cpp @@ -8,101 +8,357 @@ #include "Shaders.h" -#include #include #include #include #include -#include -#include -#include -#include +#include +#include +#include + +#include #include -static bool cleanShaders() { -#if defined(Q_OS_MAC) - static const bool CLEAN_SHADERS = true; -#else - static const bool CLEAN_SHADERS = ::gl::disableGl45(); - -#endif - return CLEAN_SHADERS; -} - // Can't use the Q_INIT_RESOURCE macro inside a namespace on Mac, // so this is done out of line -void initShaders() { - static std::once_flag once; - std::call_once(once, [] { - Q_INIT_RESOURCE(shaders); - }); -} -static std::vector splitStringIntoLines(const std::string& s) { - std::stringstream ss(s); - std::vector result; - - std::string line; - while (std::getline(ss, line, '\n')) { - result.push_back(line); - } - return result; -} - -static std::string loadResource(const std::string& path) { - return FileUtils::readFile(path.c_str()).toStdString(); +static void initShadersResources() { + Q_INIT_RESOURCE(shaders); } namespace shader { -void cleanShaderSource(std::string& shaderSource) { - static const std::regex LAYOUT_REGEX{ R"REGEX(^layout\((\s*std140\s*,\s*)?(?:binding|location)\s*=\s*(?:\b\w+\b)\)\s*(?!(?:flat\s+)?(?:out|in|buffer))\b(.*)$)REGEX" }; - static const int GROUP_STD140 = 1; - static const int THE_REST_OF_THE_OWL = 2; - std::vector lines = splitStringIntoLines(shaderSource); - std::vector outLines; - std::unordered_map locationDefines; - for (const auto& line : lines) { - std::cmatch m; - if (std::regex_match(line.c_str(), m, LAYOUT_REGEX)) { - std::string outLine; - if (m[GROUP_STD140].matched) { - outLine = "layout(std140) "; - } - outLine += m[THE_REST_OF_THE_OWL].str(); - outLines.push_back(outLine); - continue; - // On mac we have to strip out all the explicit binding location layouts, - // because GL 4.1 doesn't support them - } - outLines.push_back(line); - } - std::ostringstream joined; - std::copy(outLines.begin(), outLines.end(), std::ostream_iterator(joined, "\n")); - shaderSource = joined.str(); +#if defined(USE_GLES) + +static const Dialect DEFAULT_DIALECT = Dialect::glsl310es; + +const std::vector& allDialects() { + static const std::vector ALL_DIALECTS{ { Dialect::glsl310es } }; + return ALL_DIALECTS; } -std::string loadShaderSource(uint32_t shaderId) { - initShaders(); - auto shaderStr = loadResource(std::string(":/shaders/") + std::to_string(shaderId)); - if (cleanShaders()) { - // OSX only supports OpenGL 4.1 without ARB_shading_language_420pack or - // ARB_explicit_uniform_location or basically anything useful that's - // been released in the last 8 fucking years, so in that case we need to - // strip out all explicit locations and do a bunch of background magic to - // make the system seem like it is using the explicit locations - cleanShaderSource(shaderStr); - } - return shaderStr; -} - -std::string loadShaderReflection(uint32_t shaderId) { - initShaders(); - auto path = std::string(":/shaders/") + std::to_string(shaderId) + std::string("_reflection"); - auto json = loadResource(path); - return json; +#elif defined(Q_OS_MAC) + +static const Dialect DEFAULT_DIALECT = Dialect::glsl410; + +const std::vector& allDialects() { + static const std::vector ALL_DIALECTS{ Dialect::glsl410 }; + return ALL_DIALECTS; } +#else + +static const Dialect DEFAULT_DIALECT = Dialect::glsl450; + +const std::vector & allDialects() { + static const std::vector ALL_DIALECTS{ { Dialect::glsl450, Dialect::glsl410 } }; + return ALL_DIALECTS; } +#endif + +const std::vector& allVariants() { + static const std::vector ALL_VARIANTS{ { Variant::Mono, Variant::Stereo } }; + return ALL_VARIANTS; +} + +const std::string& dialectPath(Dialect dialect) { + static const std::string e310esPath { "/310es/" }; + static const std::string e410Path { "/410/" }; + static const std::string e450Path { "/450/" }; + switch (dialect) { +#if defined(USE_GLES) + case Dialect::glsl310es: return e310esPath; +#else +#if !defined(Q_OS_MAC) + case Dialect::glsl450: return e450Path; +#endif + case Dialect::glsl410: return e410Path; +#endif + default: break; + } + throw std::runtime_error("Invalid dialect"); +} + +static std::string loadResource(const std::string& path) { + if (!QFileInfo(path.c_str()).exists()) { + return {}; + } + return FileUtils::readFile(path.c_str()).toStdString(); +} + +static Binary loadSpirvResource(const std::string& path) { + Binary result; + { + QFile file(path.c_str()); + + if (file.open(QFile::ReadOnly)) { + QByteArray bytes = file.readAll(); + result.resize(bytes.size()); + memcpy(bytes.data(), result.data(), bytes.size()); + } + } + return result; +} + +DialectVariantSource loadDialectVariantSource(const std::string& basePath) { + DialectVariantSource result; + result.scribe = loadResource(basePath + "scribe"); + result.spirv = loadSpirvResource(basePath + "spirv"); + result.glsl = loadResource(basePath + "glsl"); + String reflectionJson = loadResource(basePath + "json"); + result.reflection.parse(reflectionJson); + return result; +} + +DialectSource loadDialectSource(Dialect dialect, uint32_t shaderId) { + std::string basePath = std::string(":/shaders/") + std::to_string(shaderId) + dialectPath(dialect); + DialectSource result; + result.variantSources[Variant::Mono] = loadDialectVariantSource(basePath); + auto stereo = loadDialectVariantSource(basePath + "stereo/"); + if (stereo.valid()) { + result.variantSources[Variant::Stereo] = stereo; + } + return result; +} + +Source::Pointer Source::loadSource(uint32_t shaderId) { + auto result = std::make_shared(); + result->id = shaderId; + const auto& dialects = allDialects(); + result->name = loadResource(std::string(":/shaders/") + std::to_string(shaderId) + std::string("/name")); + for (const auto& dialect : dialects) { + result->dialectSources[dialect] = loadDialectSource(dialect, shaderId); + } + result->reflection = result->dialectSources[DEFAULT_DIALECT].variantSources[Variant::Mono].reflection; + return result; +} + +Source& Source::operator=(const Source& other) { + // DO NOT COPY the shader ID + name = other.name; + dialectSources = other.dialectSources; + replacements = other.replacements; + reflection = other.reflection; + return *this; +} + +const Source& Source::get(uint32_t shaderId) { + static std::once_flag once; + static const std::unordered_map shadersById; + std::call_once(once, [] { + initShadersResources(); + auto& map = const_cast&>(shadersById); + for (const auto& shaderId : allShaders()) { + map[shaderId] = loadSource(shaderId); + } + }); + const auto itr = shadersById.find(shaderId); + static const Source EMPTY_SHADER; + if (itr == shadersById.end()) { + return EMPTY_SHADER; + } + return *(itr->second); +} + +bool Source::doReplacement(String& source) const { + bool replaced = false; + for (const auto& entry : replacements) { + const auto& key = entry.first; + // First try search for a block to replace + // Blocks are required because oftentimes we need a stub function + // in the original source code to allow it to compile. As such we + // need to replace the stub with our own code rather than just inject + // some code. + const auto beginMarker = key + "_BEGIN"; + auto beginIndex = source.find(beginMarker); + if (beginIndex != std::string::npos) { + const auto endMarker = key + "_END"; + auto endIndex = source.find(endMarker, beginIndex); + if (endIndex != std::string::npos) { + auto size = endIndex - beginIndex; + source.replace(beginIndex, size, entry.second); + replaced = true; + continue; + } + } + + // If no block is found, try for a simple line replacement + beginIndex = source.find(key); + if (beginIndex != std::string::npos) { + source.replace(beginIndex, key.size(), entry.second); + replaced = true; + continue; + } + } + + return replaced; +} + +const DialectVariantSource& Source::getDialectVariantSource(Dialect dialect, Variant variant) const { + auto dialectEntry = dialectSources.find(dialect); + if (dialectEntry == dialectSources.end()) { + throw std::runtime_error("Dialect source not found"); + } + + const auto& dialectSource = dialectEntry->second; + auto variantEntry = dialectSource.variantSources.find(variant); + // FIXME revert to mono if stereo source is requested but not present + // (for when mono and stereo sources are the same) + if (variantEntry == dialectSource.variantSources.end()) { + throw std::runtime_error("Variant source not found"); + } + + return variantEntry->second; +} + + +String Source::getSource(Dialect dialect, Variant variant) const { + String result; + const auto& variantSource = getDialectVariantSource(dialect, variant); + if (!replacements.empty()) { + std::string result = variantSource.scribe; + if (doReplacement(result)) { + return result; + } + } + + if (variantSource.glsl.empty()) { + return variantSource.scribe; + } + + return variantSource.glsl; +} + +const Reflection& Source::getReflection(Dialect dialect, Variant variant) const { + const auto& variantSource = getDialectVariantSource(dialect, variant); + return variantSource.reflection; +} + +static const std::string NAME_KEY{ "name" }; +static const std::string INPUTS_KEY{ "inputs" }; +static const std::string OUTPUTS_KEY{ "outputs" }; +static const std::string UBOS_KEY{ "ubos" }; +static const std::string SSBOS_KEY{ "ssbos" }; + +static const std::string TEXTURES_KEY{ "textures" }; +static const std::string LOCATION_KEY{ "location" }; +static const std::string BINDING_KEY{ "binding" }; +static const std::string TYPE_KEY{ "type" }; + +std::unordered_set populateBufferTextureSet(const nlohmann::json& input) { + std::unordered_set result; + static const std::string SAMPLER_BUFFER{ "samplerBuffer" }; + auto arraySize = input.size(); + for (size_t i = 0; i < arraySize; ++i) { + auto entry = input[i]; + std::string name = entry[NAME_KEY]; + std::string type = entry[TYPE_KEY]; + if (type == SAMPLER_BUFFER) { + result.insert(name); + } + } + return result; +} + +Reflection::LocationMap populateLocationMap(const nlohmann::json& input, const std::string& locationKey) { + Reflection::LocationMap result; + auto arraySize = input.size(); + for (size_t i = 0; i < arraySize; ++i) { + auto entry = input[i]; + std::string name = entry[NAME_KEY]; + // Location or binding, depending on the locationKey parameter + int32_t location = entry[locationKey]; + result[name] = location; + } + return result; +} + +void Reflection::parse(const std::string& jsonString) { + if (jsonString.empty()) { + return; + } + using json = nlohmann::json; + auto root = json::parse(jsonString); + + if (root.count(INPUTS_KEY)) { + inputs = populateLocationMap(root[INPUTS_KEY], LOCATION_KEY); + } + if (root.count(OUTPUTS_KEY)) { + outputs = populateLocationMap(root[OUTPUTS_KEY], LOCATION_KEY); + } + if (root.count(SSBOS_KEY)) { + resourceBuffers = populateLocationMap(root[SSBOS_KEY], BINDING_KEY); + } + if (root.count(UBOS_KEY)) { + uniformBuffers = populateLocationMap(root[UBOS_KEY], BINDING_KEY); + } + if (root.count(TEXTURES_KEY)) { + textures = populateLocationMap(root[TEXTURES_KEY], BINDING_KEY); + auto bufferTextures = populateBufferTextureSet(root[TEXTURES_KEY]); + if (!bufferTextures.empty()) { + if (!resourceBuffers.empty()) { + throw std::runtime_error("Input shader has both SSBOs and texture buffers defined"); + } + for (const auto& bufferTexture : bufferTextures){ + resourceBuffers[bufferTexture] = textures[bufferTexture]; + textures.erase(bufferTexture); + } + } + } + updateValid(); + +} + + +static void mergeMap(Reflection::LocationMap& output, const Reflection::LocationMap& input) { + for (const auto& entry : input) { + if (0 != output.count(entry.first)) { + if (output[entry.first] != entry.second) { + throw std::runtime_error("Invalid reflection for merging"); + } + } else { + output[entry.first] = entry.second; + } + } +} + +static void updateValidSet(Reflection::ValidSet& output, const Reflection::LocationMap& input) { + output.clear(); + output.reserve(input.size()); + for (const auto& entry : input) { + output.insert(entry.second); + } +} + +void Reflection::merge(const Reflection& reflection) { + mergeMap(textures, reflection.textures); + mergeMap(uniforms, reflection.uniforms); + mergeMap(uniformBuffers, reflection.uniformBuffers); + mergeMap(resourceBuffers, reflection.resourceBuffers); + updateValid(); +} + +void Reflection::updateValid() { + updateValidSet(validInputs, inputs); + updateValidSet(validOutputs, outputs); + updateValidSet(validTextures, textures); + updateValidSet(validUniformBuffers, uniformBuffers); + updateValidSet(validResourceBuffers, resourceBuffers); + updateValidSet(validUniforms, uniforms); +} + + +std::vector Reflection::getNames(const LocationMap& locations) { + std::vector result; + result.reserve(locations.size()); + for (const auto& entry : locations) { + result.push_back(entry.first); + } + return result; +} + + +} // namespace shader + diff --git a/libraries/shaders/src/shaders/Shaders.h b/libraries/shaders/src/shaders/Shaders.h index 1335c1b49b..025abf7b0b 100644 --- a/libraries/shaders/src/shaders/Shaders.h +++ b/libraries/shaders/src/shaders/Shaders.h @@ -8,27 +8,169 @@ #pragma once #include +#include #include +#include #include -#include +#include + +#include + +#include namespace shader { static const uint32_t INVALID_SHADER = (uint32_t)-1; static const uint32_t INVALID_PROGRAM = (uint32_t)-1; -extern uint32_t all_programs[]; +const std::vector& allPrograms(); +const std::vector& allShaders(); -std::string loadShaderSource(uint32_t shaderId); -std::string loadShaderReflection(uint32_t shaderId); +enum class Dialect +{ +#if defined(USE_GLES) + // GLES only support 3.1 es + glsl310es, +#elif defined(Q_OS_MAC) + // Mac only supports 4.1 + glsl410, +#else + // Everything else supports 4.1 and 4.5 + glsl450, + glsl410, +#endif +}; + +const std::vector& allDialects(); +const std::string& dialectPath(Dialect dialect); + +enum class Variant { + Mono, + Stereo, +}; + +const std::vector& allVariants(); + +static const uint32_t NUM_VARIANTS = 2; + +using Binary = std::vector; +using String = std::string; + +struct EnumClassHash +{ + template + std::size_t operator()(T t) const + { + return static_cast(t); + } +}; + +struct Reflection { + using LocationMap = std::unordered_map; + using ValidSet = std::unordered_set; + + void parse(const std::string& json); + void merge(const Reflection& reflection); + + bool validInput(int32_t location) const { return validLocation(validInputs, location); } + bool validOutput(int32_t location) const { return validLocation(validOutputs, location); } + bool validTexture(int32_t location) const { return validLocation(validTextures, location); } + bool validUniform(int32_t location) const { return validLocation(validUniforms, location); } + bool validUniformBuffer(int32_t location) const { return validLocation(validUniformBuffers, location); } + bool validResourceBuffer(int32_t location) const { return validLocation(validResourceBuffers, location); } + + + LocationMap inputs; + + LocationMap outputs; + + LocationMap textures; + + LocationMap uniformBuffers; + + // Either SSBOs or Textures with the type samplerBuffer, depending on dialect + LocationMap resourceBuffers; + + // Needed for procedural code, will map to push constants for Vulkan + LocationMap uniforms; + + static std::vector getNames(const LocationMap& locations); + +private: + + bool validLocation(const ValidSet& locations, int32_t location) const { + return locations.count(location) != 0; + } + + void updateValid(); + + ValidSet validInputs; + ValidSet validOutputs; + ValidSet validTextures; + ValidSet validUniformBuffers; + ValidSet validResourceBuffers; + ValidSet validUniforms; +}; + +struct DialectVariantSource { + // The output of the scribe application with platforms specific headers + String scribe; + // Optimized SPIRV version of the shader + Binary spirv; + // Regenerated GLSL from the optimized SPIRV + String glsl; + // Shader reflection from the optimized SPIRV + Reflection reflection; + + bool valid() const { return !scribe.empty(); } +}; + +struct DialectSource { + std::unordered_map variantSources; +}; + +struct Source { + using Pointer = std::shared_ptr; + Source() = default; + Source& operator=(const Source& other); + + uint32_t id{ INVALID_SHADER }; + + // The name of the shader file, with extension, i.e. DrawColor.frag + std::string name; + + // Generic reflection, copied from the 450 dialect / mono variant + Reflection reflection; + + // Map of platforms to their specific shaders + std::unordered_map dialectSources; + + // Support for swapping out code blocks for procedural and debugging shaders + std::unordered_map replacements; + + String getSource(Dialect dialect, Variant variant) const; + const Reflection& getReflection(Dialect dialect, Variant variant) const; + bool valid() const { return !dialectSources.empty(); } + static Source generate(const std::string& glsl) { throw std::runtime_error("Implement me"); } + static const Source& get(uint32_t shaderId); + +private: + // Disallow copy construction and assignment + Source(const Source& other) = default; + + static Source::Pointer loadSource(uint32_t shaderId) ; + + bool doReplacement(String& source) const; + const DialectVariantSource& getDialectVariantSource(Dialect dialect, Variant variant) const; + +}; inline uint32_t getVertexId(uint32_t programId) { return (programId >> 16) & UINT16_MAX; } - + inline uint32_t getFragmentId(uint32_t programId) { return programId & UINT16_MAX; } -} - +} // namespace shader diff --git a/plugins/oculus/CMakeLists.txt b/plugins/oculus/CMakeLists.txt index 893b7f48b1..664f9fe906 100644 --- a/plugins/oculus/CMakeLists.txt +++ b/plugins/oculus/CMakeLists.txt @@ -19,7 +19,7 @@ if (WIN32 AND (NOT USE_GLES)) set(TARGET_NAME oculus) setup_hifi_plugin(Multimedia) link_hifi_libraries( - shared task gl gpu ${PLATFORM_GL_BACKEND} controllers ui qml + shared task gl shaders gpu ${PLATFORM_GL_BACKEND} controllers ui qml plugins ui-plugins display-plugins input-plugins audio-client networking render-utils ${PLATFORM_GL_BACKEND} diff --git a/plugins/oculusLegacy/CMakeLists.txt b/plugins/oculusLegacy/CMakeLists.txt index 00e90fb6d7..33d27c4e9d 100644 --- a/plugins/oculusLegacy/CMakeLists.txt +++ b/plugins/oculusLegacy/CMakeLists.txt @@ -13,7 +13,7 @@ if (APPLE) set(TARGET_NAME oculusLegacy) setup_hifi_plugin() - link_hifi_libraries(shared gl gpu plugins ui ui-plugins display-plugins input-plugins midi ${PLATFORM_GL_BACKEND}) + link_hifi_libraries(shared shaders gl gpu plugins ui ui-plugins display-plugins input-plugins midi ${PLATFORM_GL_BACKEND}) include_hifi_library_headers(octree) diff --git a/plugins/openvr/CMakeLists.txt b/plugins/openvr/CMakeLists.txt index ff94152d57..eea08e66d5 100644 --- a/plugins/openvr/CMakeLists.txt +++ b/plugins/openvr/CMakeLists.txt @@ -13,7 +13,7 @@ if (WIN32 AND (NOT USE_GLES)) setup_hifi_plugin(Gui Qml Multimedia) link_hifi_libraries(shared task gl qml networking controllers ui plugins display-plugins ui-plugins input-plugins script-engine - audio-client render-utils graphics gpu render model-networking fbx ktx image procedural ${PLATFORM_GL_BACKEND}) + audio-client render-utils graphics shaders gpu render model-networking fbx ktx image procedural ${PLATFORM_GL_BACKEND}) include_hifi_library_headers(octree) diff --git a/tests-manual/gpu-textures/CMakeLists.txt b/tests-manual/gpu-textures/CMakeLists.txt index 84f5027411..907690748a 100644 --- a/tests-manual/gpu-textures/CMakeLists.txt +++ b/tests-manual/gpu-textures/CMakeLists.txt @@ -4,7 +4,7 @@ setup_hifi_project(Quick Gui Script) setup_memory_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries( - shared task networking gl + shared shaders task networking gl ktx gpu octree ${PLATFORM_GL_BACKEND} ) diff --git a/tests-manual/gpu-textures/src/TestTextures.cpp b/tests-manual/gpu-textures/src/TestTextures.cpp index 701e60fab8..5d5ddce6fa 100644 --- a/tests-manual/gpu-textures/src/TestTextures.cpp +++ b/tests-manual/gpu-textures/src/TestTextures.cpp @@ -81,8 +81,10 @@ TexturesTest::TexturesTest() { connect(&stats, &TextureTestStats::prevTexture, this, &TexturesTest::onPrevTexture); connect(&stats, &TextureTestStats::maxTextureMemory, this, &TexturesTest::onMaxTextureMemory); { - auto VS = gpu::Shader::createVertex({ vertexShaderSource, {} }); - auto PS = gpu::Shader::createPixel({ fragmentShaderSource, {} }); + shader::Source vertexSource; + + auto VS = gpu::Shader::createVertex(shader::Source::generate(vertexShaderSource)); + auto PS = gpu::Shader::createPixel(shader::Source::generate(fragmentShaderSource)); auto program = gpu::Shader::createProgram(VS, PS); // If the pipeline did not exist, make it auto state = std::make_shared(); diff --git a/tests-manual/gpu/CMakeLists.txt b/tests-manual/gpu/CMakeLists.txt index 30218f3f97..8fd0316c05 100644 --- a/tests-manual/gpu/CMakeLists.txt +++ b/tests-manual/gpu/CMakeLists.txt @@ -5,7 +5,7 @@ setup_memory_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries( shared task networking gl - ktx gpu procedural octree image + ktx shaders gpu procedural octree image graphics model-networking fbx animation script-engine render render-utils ${PLATFORM_GL_BACKEND} diff --git a/tests-manual/render-utils/CMakeLists.txt b/tests-manual/render-utils/CMakeLists.txt index be75c53f2e..9f575ee8ca 100644 --- a/tests-manual/render-utils/CMakeLists.txt +++ b/tests-manual/render-utils/CMakeLists.txt @@ -8,7 +8,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") setup_memory_debugger() # link in the shared libraries -link_hifi_libraries(render-utils gl gpu shared ${PLATFORM_GL_BACKEND}) +link_hifi_libraries(render-utils shaders gl gpu shared ${PLATFORM_GL_BACKEND}) target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) if (WIN32) diff --git a/tests/shaders/CMakeLists.txt b/tests/shaders/CMakeLists.txt index 08678c1c26..e238405d62 100644 --- a/tests/shaders/CMakeLists.txt +++ b/tests/shaders/CMakeLists.txt @@ -3,7 +3,9 @@ macro (setup_testcase_dependencies) # link in the shared libraries link_hifi_libraries(shared test-utils gpu shaders gl ${PLATFORM_GL_BACKEND}) + #target_spirv() package_libraries_for_deployment() endmacro () setup_hifi_testcase(Gui) + diff --git a/tests/shaders/src/ShaderTests.cpp b/tests/shaders/src/ShaderTests.cpp index 03dc034cd0..692771f0fc 100644 --- a/tests/shaders/src/ShaderTests.cpp +++ b/tests/shaders/src/ShaderTests.cpp @@ -31,22 +31,24 @@ #include #include +#define RUNTIME_SHADER_COMPILE_TEST 0 + +#if RUNTIME_SHADER_COMPILE_TEST +#include +#include +#include +#include +#endif + QTEST_MAIN(ShaderTests) -#pragma optimize("", off) void ShaderTests::initTestCase() { - _window = new QWindow(); - _window->setSurfaceType(QSurface::SurfaceType::OpenGLSurface); - _context = new ::gl::Context(_window); + _context = new ::gl::OffscreenContext(); getDefaultOpenGLSurfaceFormat(); _context->create(); if (!_context->makeCurrent()) { qFatal("Unable to make test GL context current"); } - QOpenGLContextWrapper(_context->qglContext()).makeCurrent(_window); - if (!_context->makeCurrent()) { - qFatal("Unable to make test GL context current"); - } gl::initModuleGl(); if (!_context->makeCurrent()) { qFatal("Unable to make test GL context current"); @@ -62,6 +64,8 @@ void ShaderTests::cleanupTestCase() { qDebug() << "Done"; } +#if RUNTIME_SHADER_COMPILE_TEST + template QStringList toQStringList(const C& c) { QStringList result; @@ -80,7 +84,7 @@ std::unordered_set toStringSet(const C& c, F f) { return result; } -template +template bool isSubset(const C& parent, const C& child) { for (const auto& v : child) { if (0 == parent.count(v)) { @@ -120,6 +124,7 @@ gpu::Shader::ReflectionMap mergeReflection(const std::initializer_list std::unordered_map invertMap(const std::unordered_map& map) { @@ -127,58 +132,52 @@ std::unordered_map invertMap(const std::unordered_map& map) { for (const auto& entry : map) { result[entry.second] = entry.first; } + if (result.size() != map.size()) { + throw std::runtime_error("Map inversion failure, result size does not match input size"); + } return result; } -static void verifyBindings(const gpu::Shader::Source& source) { - const auto reflection = source.getReflection(); - for (const auto& entry : reflection) { - const auto& map = entry.second; - const auto reverseMap = invertMap(map); - if (map.size() != reverseMap.size()) { - QFAIL("Bindings are not unique"); - } - } - -} - - -static void verifyInterface(const gpu::Shader::Source& vertexSource, const gpu::Shader::Source& fragmentSource) { - if (0 == fragmentSource.getReflection().count(gpu::Shader::BindingType::INPUT)) { +static void verifyInterface(const gpu::Shader::Source& vertexSource, + const gpu::Shader::Source& fragmentSource, + shader::Dialect dialect, + shader::Variant variant) { + const auto& fragmentReflection = fragmentSource.getReflection(dialect, variant); + if (fragmentReflection.inputs.empty()) { return; } - auto fragIn = fragmentSource.getReflection().at(gpu::Shader::BindingType::INPUT); - if (0 == vertexSource.getReflection().count(gpu::Shader::BindingType::OUTPUT)) { - qDebug() << "No vertex output for fragment input"; - //QFAIL("No vertex output for fragment input"); - return; + + const auto& vertexReflection = vertexSource.getReflection(dialect, variant); + const auto& fragIn = fragmentReflection.inputs; + if (vertexReflection.outputs.empty()) { + throw std::runtime_error("No vertex outputs for fragment inputs"); } - auto vout = vertexSource.getReflection().at(gpu::Shader::BindingType::OUTPUT); + + const auto& vout = vertexReflection.outputs; auto vrev = invertMap(vout); - static const std::string IN_STEREO_SIDE_STRING = "_inStereoSide"; for (const auto entry : fragIn) { const auto& name = entry.first; - // The presence of "_inStereoSide" in fragment shaders is a bug due to the way we do reflection - // and use preprocessor macros in the shaders - if (name == IN_STEREO_SIDE_STRING) { - continue; - } if (0 == vout.count(name)) { - qDebug() << "Vertex output missing"; - //QFAIL("Vertex output missing"); - continue; + throw std::runtime_error("Vertex outputs missing"); } const auto& inLocation = entry.second; const auto& outLocation = vout.at(name); if (inLocation != outLocation) { - qDebug() << "Mismatch in vertex / fragment interface"; - //QFAIL("Mismatch in vertex / fragment interface"); - continue; + throw std::runtime_error("Mismatch in vertex / fragment interface"); } } } -template +static void verifyInterface(const gpu::Shader::Source& vertexSource, const gpu::Shader::Source& fragmentSource) { + for (const auto& dialect : shader::allDialects()) { + for (const auto& variant : shader::allVariants()) { + verifyInterface(vertexSource, fragmentSource, dialect, variant); + } + } +} + +#if RUNTIME_SHADER_COMPILE_TEST +template bool compareBindings(const C& actual, const gpu::Shader::LocationMap& expected) { if (actual.size() != expected.size()) { auto actualNames = toStringSet(actual, [](const auto& v) { return v.name; }); @@ -192,48 +191,341 @@ bool compareBindings(const C& actual, const gpu::Shader::LocationMap& expected) return true; } -void ShaderTests::testShaderLoad() { - std::set usedShaders; - uint32_t maxShader = 0; - try { +void configureGLSLCompilerResources(TBuiltInResource* glslCompilerResources) { + glslCompilerResources->maxLights = 32; + glslCompilerResources->maxClipPlanes = 6; + glslCompilerResources->maxTextureUnits = 32; + glslCompilerResources->maxTextureCoords = 32; + glslCompilerResources->maxVertexAttribs = 64; + glslCompilerResources->maxVertexUniformComponents = 4096; + glslCompilerResources->maxVaryingFloats = 64; + glslCompilerResources->maxVertexTextureImageUnits = 32; + glslCompilerResources->maxCombinedTextureImageUnits = 80; + glslCompilerResources->maxTextureImageUnits = 32; + glslCompilerResources->maxFragmentUniformComponents = 4096; + glslCompilerResources->maxDrawBuffers = 32; + glslCompilerResources->maxVertexUniformVectors = 128; + glslCompilerResources->maxVaryingVectors = 8; + glslCompilerResources->maxFragmentUniformVectors = 16; + glslCompilerResources->maxVertexOutputVectors = 16; + glslCompilerResources->maxFragmentInputVectors = 15; + glslCompilerResources->minProgramTexelOffset = -8; + glslCompilerResources->maxProgramTexelOffset = 7; + glslCompilerResources->maxClipDistances = 8; + glslCompilerResources->maxComputeWorkGroupCountX = 65535; + glslCompilerResources->maxComputeWorkGroupCountY = 65535; + glslCompilerResources->maxComputeWorkGroupCountZ = 65535; + glslCompilerResources->maxComputeWorkGroupSizeX = 1024; + glslCompilerResources->maxComputeWorkGroupSizeY = 1024; + glslCompilerResources->maxComputeWorkGroupSizeZ = 64; + glslCompilerResources->maxComputeUniformComponents = 1024; + glslCompilerResources->maxComputeTextureImageUnits = 16; + glslCompilerResources->maxComputeImageUniforms = 8; + glslCompilerResources->maxComputeAtomicCounters = 8; + glslCompilerResources->maxComputeAtomicCounterBuffers = 1; + glslCompilerResources->maxVaryingComponents = 60; + glslCompilerResources->maxVertexOutputComponents = 64; + glslCompilerResources->maxGeometryInputComponents = 64; + glslCompilerResources->maxGeometryOutputComponents = 128; + glslCompilerResources->maxFragmentInputComponents = 128; + glslCompilerResources->maxImageUnits = 8; + glslCompilerResources->maxCombinedImageUnitsAndFragmentOutputs = 8; + glslCompilerResources->maxCombinedShaderOutputResources = 8; + glslCompilerResources->maxImageSamples = 0; + glslCompilerResources->maxVertexImageUniforms = 0; + glslCompilerResources->maxTessControlImageUniforms = 0; + glslCompilerResources->maxTessEvaluationImageUniforms = 0; + glslCompilerResources->maxGeometryImageUniforms = 0; + glslCompilerResources->maxFragmentImageUniforms = 8; + glslCompilerResources->maxCombinedImageUniforms = 8; + glslCompilerResources->maxGeometryTextureImageUnits = 16; + glslCompilerResources->maxGeometryOutputVertices = 256; + glslCompilerResources->maxGeometryTotalOutputComponents = 1024; + glslCompilerResources->maxGeometryUniformComponents = 1024; + glslCompilerResources->maxGeometryVaryingComponents = 64; + glslCompilerResources->maxTessControlInputComponents = 128; + glslCompilerResources->maxTessControlOutputComponents = 128; + glslCompilerResources->maxTessControlTextureImageUnits = 16; + glslCompilerResources->maxTessControlUniformComponents = 1024; + glslCompilerResources->maxTessControlTotalOutputComponents = 4096; + glslCompilerResources->maxTessEvaluationInputComponents = 128; + glslCompilerResources->maxTessEvaluationOutputComponents = 128; + glslCompilerResources->maxTessEvaluationTextureImageUnits = 16; + glslCompilerResources->maxTessEvaluationUniformComponents = 1024; + glslCompilerResources->maxTessPatchComponents = 120; + glslCompilerResources->maxPatchVertices = 32; + glslCompilerResources->maxTessGenLevel = 64; + glslCompilerResources->maxViewports = 16; + glslCompilerResources->maxVertexAtomicCounters = 0; + glslCompilerResources->maxTessControlAtomicCounters = 0; + glslCompilerResources->maxTessEvaluationAtomicCounters = 0; + glslCompilerResources->maxGeometryAtomicCounters = 0; + glslCompilerResources->maxFragmentAtomicCounters = 8; + glslCompilerResources->maxCombinedAtomicCounters = 8; + glslCompilerResources->maxAtomicCounterBindings = 1; + glslCompilerResources->maxVertexAtomicCounterBuffers = 0; + glslCompilerResources->maxTessControlAtomicCounterBuffers = 0; + glslCompilerResources->maxTessEvaluationAtomicCounterBuffers = 0; + glslCompilerResources->maxGeometryAtomicCounterBuffers = 0; + glslCompilerResources->maxFragmentAtomicCounterBuffers = 1; + glslCompilerResources->maxCombinedAtomicCounterBuffers = 1; + glslCompilerResources->maxAtomicCounterBufferSize = 16384; + glslCompilerResources->maxTransformFeedbackBuffers = 4; + glslCompilerResources->maxTransformFeedbackInterleavedComponents = 64; + glslCompilerResources->maxCullDistances = 8; + glslCompilerResources->maxCombinedClipAndCullDistances = 8; + glslCompilerResources->maxSamples = 4; + glslCompilerResources->limits.nonInductiveForLoops = 1; + glslCompilerResources->limits.whileLoops = 1; + glslCompilerResources->limits.doWhileLoops = 1; + glslCompilerResources->limits.generalUniformIndexing = 1; + glslCompilerResources->limits.generalAttributeMatrixVectorIndexing = 1; + glslCompilerResources->limits.generalVaryingIndexing = 1; + glslCompilerResources->limits.generalSamplerIndexing = 1; + glslCompilerResources->limits.generalVariableIndexing = 1; + glslCompilerResources->limits.generalConstantMatrixVectorIndexing = 1; +} -#if 0 - uint32_t testPrograms[] = { - shader::render_utils::program::parabola, - shader::INVALID_PROGRAM, - }; -#else - const auto& testPrograms = shader::all_programs; +void writeSpirv(const std::string& filename, const std::vector& spirv) { + std::ofstream o(filename, std::ios::trunc | std::ios::binary); + for (const auto& word : spirv) { + o.write((const char*)&word, sizeof(word)); + } + o.close(); +} + +void write(const std::string& filename, const std::string& text) { + std::ofstream o(filename, std::ios::trunc); + o.write(text.c_str(), text.size()); + o.close(); +} + +bool endsWith(const std::string& s, const std::string& f) { + auto end = s.substr(s.size() - f.size()); + return (end == f); +} + +EShLanguage getShaderStage(const std::string& shaderName) { + static const std::string VERT_EXT{ ".vert" }; + static const std::string FRAG_EXT{ ".frag" }; + static const std::string GEOM_EXT{ ".geom" }; + static const size_t EXT_SIZE = VERT_EXT.size(); + if (shaderName.size() < EXT_SIZE) { + throw std::runtime_error("Invalid shader name"); + } + std::string ext = shaderName.substr(shaderName.size() - EXT_SIZE); + if (ext == VERT_EXT) { + return EShLangVertex; + } else if (ext == FRAG_EXT) { + return EShLangFragment; + } else if (ext == GEOM_EXT) { + return EShLangGeometry; + } + throw std::runtime_error("Invalid shader name"); +} + +const gpu::Shader::Source& loadShader(uint32_t shaderId); + +bool compileSpirv(uint32_t shaderId, bool stereo) { + const gpu::Shader::Source& source = loadShader(shaderId); + using namespace glslang; + + static const std::string CORE_HEADER( + R"SHADER(#version 450 core +#define GPU_GL450 +#define BITFIELD int +#define GPU_SSBO_TRANSFORM_OBJECT +#define gl_VertexID gl_VertexIndex +#define gl_InstanceID gl_InstanceIndex +)SHADER"); + + static const std::string DOMAIN_HEADER[] = { + "#define GPU_VERTEX_SHADER\r\n", + "#define GPU_PIXEL_SHADER\r\n", + "#define GPU_GEOMETRY_SHADER\r\n", + }; + + static const std::string STEREO_HEADER( + R"SHADER( +#define GPU_TRANSFORM_IS_STEREO +#define GPU_TRANSFORM_STEREO_CAMERA +#define GPU_TRANSFORM_STEREO_CAMERA_INSTANCED +#define GPU_TRANSFORM_STEREO_SPLIT_SCREEN +)SHADER"); + + static std::once_flag once; + static TBuiltInResource glslCompilerResources; + std::call_once(once, [&] { configureGLSLCompilerResources(&glslCompilerResources); }); + + static const EShMessages messages = (EShMessages)(EShMsgDefault | EShMsgSpvRules | EShMsgVulkanRules); + auto shaderName = shader::loadShaderName(shaderId); + auto stage = getShaderStage(shaderName); + + TShader shader(stage); + std::vector strings; + strings.push_back(CORE_HEADER.c_str()); + strings.push_back(DOMAIN_HEADER[stage == EShLangVertex ? 0 : 1].c_str()); + if (stereo) { + strings.push_back(STEREO_HEADER.c_str()); + } + strings.push_back(source.getCode().c_str()); + shader.setStrings(strings.data(), (int)strings.size()); + shader.setEnvInput(EShSourceGlsl, stage, EShClientOpenGL, 450); + shader.setEnvClient(EShClientVulkan, EShTargetVulkan_1_1); + shader.setEnvTarget(EShTargetSpv, EShTargetSpv_1_3); + bool success = shader.parse(&glslCompilerResources, 450, false, messages); + if (!success) { + qWarning() << "Failed to parse shader " << shaderName.c_str(); + qWarning() << shader.getInfoLog(); + qWarning() << shader.getInfoDebugLog(); + return false; + } + + // Create and link a shader program containing the single shader + glslang::TProgram program; + program.addShader(&shader); + if (!program.link(messages)) { + qWarning() << "Failed to compile shader " << shaderName.c_str(); + qWarning() << program.getInfoLog(); + qWarning() << program.getInfoDebugLog(); + return false; + } + + std::string baseOutName = "d:/shaders/" + shaderName; + if (stereo) { + baseOutName += ".stereo"; + } + + // Output the SPIR-V code from the shader program + std::vector spirv; + glslang::GlslangToSpv(*program.getIntermediate(stage), spirv); + + spvtools::SpirvTools core(SPV_ENV_VULKAN_1_1); + spvtools::Optimizer opt(SPV_ENV_VULKAN_1_1); + + auto outputLambda = [](spv_message_level_t, const char*, const spv_position_t&, const char* m) { qWarning() << m; }; + core.SetMessageConsumer(outputLambda); + opt.SetMessageConsumer(outputLambda); + + if (!core.Validate(spirv)) { + throw std::runtime_error("invalid spirv"); + } + writeSpirv(baseOutName + ".spv", spirv); + + opt.RegisterPass(spvtools::CreateFreezeSpecConstantValuePass()) + .RegisterPass(spvtools::CreateStrengthReductionPass()) + .RegisterPass(spvtools::CreateEliminateDeadConstantPass()) + .RegisterPass(spvtools::CreateEliminateDeadFunctionsPass()) + .RegisterPass(spvtools::CreateUnifyConstantPass()); + + std::vector optspirv; + if (!opt.Run(spirv.data(), spirv.size(), &optspirv)) { + throw std::runtime_error("bad optimize run"); + } + writeSpirv(baseOutName + ".opt.spv", optspirv); + + std::string disassembly; + if (!core.Disassemble(optspirv, &disassembly)) { + throw std::runtime_error("bad disassembly"); + } + + write(baseOutName + ".spv.txt", disassembly); + + return true; +} #endif - size_t index = 0; - while (shader::INVALID_PROGRAM != testPrograms[index]) { - auto programId = testPrograms[index]; - ++index; +void validateDialectVariantSource(const shader::DialectVariantSource& source) { + if (source.scribe.empty()) { + throw std::runtime_error("Missing scribe source"); + } - uint32_t vertexId = shader::getVertexId(programId); - uint32_t fragmentId = shader::getFragmentId(programId); - usedShaders.insert(vertexId); - usedShaders.insert(fragmentId); - maxShader = std::max(maxShader, std::max(fragmentId, vertexId)); - auto vertexSource = gpu::Shader::getShaderSource(vertexId); - QVERIFY(!vertexSource.getCode().empty()); - verifyBindings(vertexSource); - auto fragmentSource = gpu::Shader::getShaderSource(fragmentId); - QVERIFY(!fragmentSource.getCode().empty()); - verifyBindings(fragmentSource); + if (source.spirv.empty()) { + throw std::runtime_error("Missing SPIRV"); + } + + if (source.glsl.empty()) { + throw std::runtime_error("Missing GLSL"); + } +} + +void validaDialectSource(const shader::DialectSource& dialectSource) { + for (const auto& variant : shader::allVariants()) { + validateDialectVariantSource(dialectSource.variantSources.find(variant)->second); + } +} + +void validateSource(const shader::Source& shader) { + if (shader.id == shader::INVALID_SHADER) { + throw std::runtime_error("Missing stored shader ID"); + } + + if (shader.name.empty()) { + throw std::runtime_error("Missing shader name"); + } + + static const auto& dialects = shader::allDialects(); + for (const auto dialect : dialects) { + if (!shader.dialectSources.count(dialect)) { + throw std::runtime_error("Missing platform shader"); + } + const auto& platformShader = shader.dialectSources.find(dialect)->second; + validaDialectSource(platformShader); + } +} + +void ShaderTests::testShaderLoad() { + try { + const auto& shaderIds = shader::allShaders(); + + // For debugging compile or link failures on individual programs, enable the following block and change the array values + // Be sure to end with the sentinal value of shader::INVALID_PROGRAM + const auto& programIds = shader::allPrograms(); + + for (auto shaderId : shaderIds) { + validateSource(shader::Source::get(shaderId)); + } + + { + std::unordered_set programUsedShaders; +#pragma omp parallel for + for (auto programId : programIds) { + auto vertexId = shader::getVertexId(programId); + shader::Source::get(vertexId); + programUsedShaders.insert(vertexId); + auto fragmentId = shader::getFragmentId(programId); + shader::Source::get(fragmentId); + programUsedShaders.insert(fragmentId); + } + + for (const auto& shaderId : shaderIds) { + if (programUsedShaders.count(shaderId)) { + continue; + } + const auto& shader = shader::Source::get(shaderId); + qDebug() << "Unused shader found" << shader.name.c_str(); + } + } + + // Traverse all programs again to do program level tests + for (const auto& programId : programIds) { + auto vertexId = shader::getVertexId(programId); + const auto& vertexSource = shader::Source::get(vertexId); + auto fragmentId = shader::getFragmentId(programId); + const auto& fragmentSource = shader::Source::get(fragmentId); verifyInterface(vertexSource, fragmentSource); - auto expectedBindings = mergeReflection({ vertexSource, fragmentSource }); - auto program = gpu::Shader::createProgram(programId); auto glBackend = std::static_pointer_cast(_gpuContext->getBackend()); auto glshader = gpu::gl::GLShader::sync(*glBackend, *program); + if (!glshader) { - qWarning() << "Failed to compile or link vertex " << vertexId << " fragment " << fragmentId; + qWarning() << "Failed to compile or link vertex " << vertexSource.name.c_str() << " fragment " + << fragmentSource.name.c_str(); QFAIL("Program link error"); } - +#if RUNTIME_SHADER_COMPILE_TEST + auto expectedBindings = mergeReflection({ vertexSource, fragmentSource }); QVERIFY(glshader != nullptr); for (const auto& shaderObject : glshader->_shaderObjects) { const auto& program = shaderObject.glprogram; @@ -260,9 +552,10 @@ void ShaderTests::testShaderLoad() { // Textures { auto textures = gl::Uniform::loadTextures(program); - auto expiredBegin = std::remove_if(textures.begin(), textures.end(), [&](const gl::Uniform& uniform) -> bool { - return uniform.name == "transformObjectBuffer"; - }); + auto expiredBegin = + std::remove_if(textures.begin(), textures.end(), [&](const gl::Uniform& uniform) -> bool { + return uniform.name == "transformObjectBuffer"; + }); textures.erase(expiredBegin, textures.end()); const auto expectedTextures = expectedBindings[gpu::Shader::BindingType::TEXTURE]; @@ -296,11 +589,13 @@ void ShaderTests::testShaderLoad() { // FIXME add storage buffer validation } +#endif } } catch (const std::runtime_error& error) { QFAIL(error.what()); } +#if RUNTIME_SHADER_COMPILE_TEST for (uint32_t i = 1; i <= maxShader; ++i) { auto used = usedShaders.count(i); if (0 != usedShaders.count(i)) { @@ -310,6 +605,7 @@ void ShaderTests::testShaderLoad() { auto name = QJsonDocument::fromJson(reflectionJson.c_str()).object()["name"].toString(); qDebug() << "Unused shader" << name; } +#endif qDebug() << "Completed all shaders"; } diff --git a/tests/shaders/src/ShaderTests.h b/tests/shaders/src/ShaderTests.h index d109341c1f..fd361d9e60 100644 --- a/tests/shaders/src/ShaderTests.h +++ b/tests/shaders/src/ShaderTests.h @@ -23,9 +23,8 @@ private slots: void testShaderLoad(); private: - QWindow* _window{ nullptr }; - gl::Context* _context{ nullptr }; + gl::OffscreenContext* _context{ nullptr }; gpu::ContextPointer _gpuContext; }; -#endif // hifi_ViewFruxtumTests_h +#endif // hifi_ViewFruxtumTests_h diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 9b36180bc2..1c36306410 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -2,9 +2,6 @@ add_subdirectory(scribe) set_target_properties(scribe PROPERTIES FOLDER "Tools") -add_subdirectory(shreflect) -set_target_properties(shreflect PROPERTIES FOLDER "Tools") - find_npm() if (NPM_EXECUTABLE) add_subdirectory(jsdoc) diff --git a/tools/ktx-tool/CMakeLists.txt b/tools/ktx-tool/CMakeLists.txt index 9daf8e0a1a..6bb09e0a9e 100644 --- a/tools/ktx-tool/CMakeLists.txt +++ b/tools/ktx-tool/CMakeLists.txt @@ -2,7 +2,7 @@ set(TARGET_NAME ktx-tool) setup_hifi_project(Quick Gui Concurrent) -link_hifi_libraries(shared networking image gl gpu ktx) +link_hifi_libraries(shared networking image gl shaders gpu ktx) target_gli() diff --git a/tools/scribe/src/TextTemplate.cpp b/tools/scribe/src/TextTemplate.cpp index 89937c4da6..aad508487c 100755 --- a/tools/scribe/src/TextTemplate.cpp +++ b/tools/scribe/src/TextTemplate.cpp @@ -81,6 +81,7 @@ bool TextTemplate::loadFile(const ConfigPointer& config, const char* filename, S std::ifstream ifs; ifs.open(fullfilename.c_str()); if (ifs.is_open()) { + config->_includeFullPaths.insert(fullfilename); std::string str((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); source = str; ifs.close(); @@ -1003,3 +1004,9 @@ void TextTemplate::Config::displayTree(std::ostream& dst, int& level) const { } level--; } + +void TextTemplate::Config::displayMakefileDeps(std::ostream& dst) const { + for (const auto& include : _includeFullPaths) { + std::cout << include << std::endl; + } +} diff --git a/tools/scribe/src/TextTemplate.h b/tools/scribe/src/TextTemplate.h index 44edc23c12..b3b767176c 100755 --- a/tools/scribe/src/TextTemplate.h +++ b/tools/scribe/src/TextTemplate.h @@ -18,6 +18,7 @@ #include #include #include +#include class TextTemplate { public: @@ -26,6 +27,7 @@ public: typedef std::vector< String > StringVector; typedef std::map< String, String > Vars; typedef std::map< String, TextTemplate::Pointer > Includes; + using PathSet = std::unordered_set; class Tag { public: @@ -123,7 +125,7 @@ public: public: typedef std::shared_ptr< Config > Pointer; typedef bool (*IncluderCallback) (const Config::Pointer& config, const char* filename, String& source); - + PathSet _includeFullPaths; Includes _includes; Funcs _funcs; std::ostream* _logStream; @@ -139,6 +141,8 @@ public: void addIncludePath(const char* path); void displayTree(std::ostream& dst, int& level) const; + + void displayMakefileDeps(std::ostream& dst) const; }; static bool loadFile(const Config::Pointer& config, const char* filename, String& source); @@ -156,9 +160,12 @@ public: void displayTree(std::ostream& dst, int& level) const; + void displayMakefileDeps(std::ostream& dst) const { _config->displayMakefileDeps(dst); } + protected: Config::Pointer _config; Block::Pointer _root; + PathSet _includeFullPaths; int _numErrors; bool _steppingStarted; diff --git a/tools/scribe/src/main.cpp b/tools/scribe/src/main.cpp index c8c540c362..c1ade05bb1 100755 --- a/tools/scribe/src/main.cpp +++ b/tools/scribe/src/main.cpp @@ -25,10 +25,12 @@ int main (int argc, char** argv) { std::string srcFilename; std::string destFilename; std::string targetName; + std::list headerFiles; TextTemplate::Vars vars; std::string lastVarName; bool listVars = false; + bool makefileDeps = false; bool showParseTree = false; bool makeCPlusPlus = false; @@ -42,6 +44,7 @@ int main (int argc, char** argv) { GRAB_INCLUDE_PATH, GRAB_TARGET_NAME, GRAB_SHADER_TYPE, + GRAB_HEADER, EXIT, } mode = READY; @@ -65,6 +68,8 @@ int main (int argc, char** argv) { case READY: { if (inputs.back() == "-o") { mode = GRAB_OUTPUT; + } else if (inputs.back() == "-H") { + mode = GRAB_HEADER; } else if (inputs.back() == "-t") { mode = GRAB_TARGET_NAME; } else if (inputs.back() == "-D") { @@ -74,6 +79,9 @@ int main (int argc, char** argv) { } else if (inputs.back() == "-listVars") { listVars = true; mode = READY; + } else if (inputs.back() == "-M") { + makefileDeps = true; + mode = READY; } else if (inputs.back() == "-showParseTree") { showParseTree = true; mode = READY; @@ -85,7 +93,7 @@ int main (int argc, char** argv) { } else { // just grabbed the source filename, stop parameter parsing srcFilename = inputs.back(); - mode = EXIT; + mode = READY; } } break; @@ -102,6 +110,12 @@ int main (int argc, char** argv) { } break; + case GRAB_HEADER: { + headerFiles.push_back(inputs.back()); + mode = READY; + } + break; + case GRAB_VAR_NAME: { // grab first the name of the var lastVarName = inputs.back(); @@ -155,6 +169,9 @@ int main (int argc, char** argv) { cerr << " -I include_directory: Declare a directory to be added to the includes search pool." << endl; cerr << " -D varname varvalue: Declare a var used to generate the output file." << endl; cerr << " varname and varvalue must be made of alpha numerical characters with no spaces." << endl; + cerr << " -H : Prepend the contents of header file to the scribe output " << endl; + cerr << " This can be specified multiple times and the headers will be applied in the specified order" << endl; + cerr << " -M : Emit a list of files that the scribe output depends on, for make and similar build tools " << endl; cerr << " -listVars : Will list the vars name and value in the standard output." << endl; cerr << " -showParseTree : Draw the tree obtained while parsing the source" << endl; cerr << " -c++ : Generate a c++ source file containing the output file stream stored as a char[] variable" << endl; @@ -204,8 +221,37 @@ int main (int argc, char** argv) { auto scribe = std::make_shared(srcFilename, config); + std::string header; + if (!headerFiles.empty()) { + for (const auto& headerFile : headerFiles) { + std::fstream headerStream; + headerStream.open(headerFile, std::fstream::in); + if (!headerStream.is_open()) { + cerr << "Failed to open source file <" << headerFile << ">" << endl; + return 1; + } + header += std::string((std::istreambuf_iterator(headerStream)), std::istreambuf_iterator()); + } + } + + // Add the type define to the shader + switch (type) { + case VERTEX: + header += "#define GPU_VERTEX_SHADER\n"; + break; + + case FRAGMENT: + header += "#define GPU_PIXEL_SHADER\n"; + break; + + case GEOMETRY: + header += "#define GPU_GEOMETRY_SHADER\n"; + break; + } + // ready to parse and generate std::stringstream destStringStream; + destStringStream << header; int numErrors = scribe->scribe(destStringStream, srcStream, vars); if (numErrors) { cerr << "Scribe " << srcFilename << "> failed: " << numErrors << " errors." << endl; @@ -222,7 +268,9 @@ int main (int argc, char** argv) { scribe->displayTree(cerr, level); } - if (makeCPlusPlus) { + if (makefileDeps) { + scribe->displayMakefileDeps(cout); + } else if (makeCPlusPlus) { // Because there is a maximum size for literal strings declared in source we need to partition the // full source string stream into pages that seems to be around that value... const int MAX_STRING_LITERAL = 10000; diff --git a/tools/shadergen.py b/tools/shadergen.py new file mode 100644 index 0000000000..9f69e6d0bc --- /dev/null +++ b/tools/shadergen.py @@ -0,0 +1,254 @@ +import re +import subprocess +import sys +import time +import os +import json +import argparse +import concurrent +from os.path import expanduser +from concurrent.futures import ThreadPoolExecutor +from argparse import ArgumentParser +from pathlib import Path +from threading import Lock + + # # Target dependant Custom rule on the SHADER_FILE + # if (ANDROID) + # set(GLPROFILE LINUX_GL) + # else() + # if (APPLE) + # set(GLPROFILE MAC_GL) + # elseif(UNIX) + # set(GLPROFILE LINUX_GL) + # else() + # set(GLPROFILE PC_GL) + # endif() + # endif() + +def getTypeForScribeFile(scribefilename): + last = scribefilename.rfind('.') + extension = scribefilename[last:] + switcher = { + '.slv': 'vert', + '.slf': 'frag', + '.slg': 'geom', + '.slc': 'comp', + } + if not extension in switcher: + raise ValueError("Unknown scribe file type for " + scribefilename) + return switcher.get(extension) + +def getCommonScribeArgs(scribefile, includeLibs): + scribeArgs = [args.scribe] + # FIXME use the sys.platform to set the correct value + scribeArgs.extend(['-D', 'GLPROFILE', 'PC_GL']) + scribeArgs.extend(['-T', getTypeForScribeFile(scribefile)]) + for lib in includeLibs: + scribeArgs.extend(['-I', args.source_dir + '/libraries/' + lib + '/src/' + lib + '/']) + scribeArgs.extend(['-I', args.source_dir + '/libraries/' + lib + '/src/']) + scribeArgs.append(scribefile) + return scribeArgs + +def getDialectAndVariantHeaders(dialect, variant): + headerPath = args.source_dir + '/libraries/shaders/headers/' + variantHeader = headerPath + ('stereo.glsl' if (variant == 'stereo') else 'mono.glsl') + dialectHeader = headerPath + dialect + '/header.glsl' + return [dialectHeader, variantHeader] + +class ScribeDependenciesCache: + cache = {} + lock = Lock() + filename = '' + + def __init__(self, filename): + self.filename = filename + + def load(self): + jsonstr = '{}' + if (os.path.exists(self.filename)): + with open(self.filename) as f: + jsonstr = f.read() + self.cache = json.loads(jsonstr) + + def save(self): + with open(self.filename, "w") as f: + f.write(json.dumps(self.cache)) + + def get(self, scribefile, dialect, variant): + self.lock.acquire() + key = self.key(scribefile, dialect, variant) + try: + if key in self.cache: + return self.cache[key].copy() + finally: + self.lock.release() + return None + + def key(self, scribeFile, dialect, variant): + return ':'.join([scribeFile, dialect, variant]) + + def getOrGen(self, scribefile, includeLibs, dialect, variant): + result = self.get(scribefile, dialect, variant) + if (None == result): + result = self.gen(scribefile, includeLibs, dialect, variant) + return result + + def gen(self, scribefile, includeLibs, dialect, variant): + scribeArgs = getCommonScribeArgs(scribefile, includeLibs) + scribeArgs.extend(['-M']) + processResult = subprocess.run(scribeArgs, stdout=subprocess.PIPE) + if (0 != processResult.returncode): + raise RuntimeError("Unable to parse scribe dependencies") + result = processResult.stdout.decode("utf-8").splitlines(False) + result.append(scribefile) + result.extend(getDialectAndVariantHeaders(dialect, variant)) + key = self.key(scribefile, dialect, variant) + self.lock.acquire() + self.cache[key] = result.copy() + self.lock.release() + return result + +def getFileTimes(files): + if isinstance(files, str): + files = [files] + return list(map(lambda f: os.path.getmtime(f) if os.path.isfile(f) else -1, files)) + +def outOfDate(inputs, output): + oldestInput = max(getFileTimes(inputs)) + youngestOutput = min(getFileTimes(output)) + diff = youngestOutput - oldestInput + return oldestInput >= youngestOutput + +def executeSubprocess(processArgs): + processResult = subprocess.run(processArgs, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + if (0 != processResult.returncode): + raise RuntimeError('Call to "{}" failed.\n\narguments:\n{}\n\nstdout:\n{}\n\nstderr:\n{}'.format( + processArgs[0], + ' '.join(processArgs[1:]), + processResult.stdout.decode('utf-8'), + processResult.stderr.decode('utf-8'))) + +folderMutex = Lock() + +def processCommand(line): + global args + global scribeDepCache + glslangExec = args.spirv_binaries + '/glslangValidator' + spirvCrossExec = args.spirv_binaries + '/spirv-cross' + spirvOptExec = args.spirv_binaries + '/spirv-opt' + params = line.split(';') + dialect = params.pop(0) + variant = params.pop(0) + scribeFile = args.source_dir + '/' + params.pop(0) + unoptGlslFile = args.source_dir + '/' + params.pop(0) + libs = params + + upoptSpirvFile = unoptGlslFile + '.spv' + spirvFile = unoptGlslFile + '.opt.spv' + reflectionFile = unoptGlslFile + '.json' + glslFile = unoptGlslFile + '.glsl' + outputFiles = [unoptGlslFile, spirvFile, reflectionFile, glslFile] + + scribeOutputDir = os.path.abspath(os.path.join(unoptGlslFile, os.pardir)) + + # Serialize checking and creation of the output directory to avoid occasional + # crashes + global folderMutex + folderMutex.acquire() + if not os.path.exists(scribeOutputDir): + os.makedirs(scribeOutputDir) + folderMutex.release() + + scribeDeps = scribeDepCache.getOrGen(scribeFile, libs, dialect, variant) + + # if the scribe sources (slv, slf, slh, etc), or the dialect/ variant headers are out of date + # regenerate the scribe GLSL output + if args.force or outOfDate(scribeDeps, outputFiles): + print('Processing file {} dialect {} variant {}'.format(scribeFile, dialect, variant)) + if args.dry_run: + return True + + scribeDepCache.gen(scribeFile, libs, dialect, variant) + scribeArgs = getCommonScribeArgs(scribeFile, libs) + headerFlag = '-H' + # using the old flag on Android builds for now + if (dialect == '310es'): headerFlag = '-h' + for header in getDialectAndVariantHeaders(dialect, variant): + scribeArgs.extend([headerFlag, header]) + scribeArgs.extend(['-o', unoptGlslFile]) + executeSubprocess(scribeArgs) + + # Generate the un-optimized output + executeSubprocess([glslangExec, '-V110', '-o', upoptSpirvFile, unoptGlslFile]) + + # Optimize the SPIRV + executeSubprocess([spirvOptExec, '-O', '-o', spirvFile, upoptSpirvFile]) + + # Generation JSON reflection + executeSubprocess([spirvCrossExec, '--reflect', 'json', '--output', reflectionFile, spirvFile]) + + # Generate the optimized GLSL output + spirvCrossArgs = [spirvCrossExec, '--output', glslFile, spirvFile, '--version', dialect] + if (dialect == '410'): spirvCrossArgs.append('--no-420pack-extension') + executeSubprocess(spirvCrossArgs) + else: + # This logic is necessary because cmake will agressively keep re-executing the shadergen + # code otherwise + Path(unoptGlslFile).touch() + Path(upoptSpirvFile).touch() + Path(spirvFile).touch() + Path(glslFile).touch() + Path(reflectionFile).touch() + return True + + + +def main(): + commands = args.commands.read().splitlines(False) + if args.debug or True: + for command in commands: + processCommand(command) + else: + workers = max(1, os.cpu_count() - 2) + with ThreadPoolExecutor(max_workers=workers) as executor: + for result in executor.map(processCommand, commands): + if not result: + raise RuntimeError("Failed to execute all subprocesses") + executor.shutdown() + + +parser = ArgumentParser(description='Generate shader artifacts.') +parser.add_argument('--commands', type=argparse.FileType('r'), help='list of commands to execute') +parser.add_argument('--spirv-binaries', type=str, help='location of the SPIRV binaries') +parser.add_argument('--build-dir', type=str, help='The build directory base path') +parser.add_argument('--source-dir', type=str, help='The root directory of the git repository') +parser.add_argument('--scribe', type=str, help='The scribe executable path') +parser.add_argument('--debug', action='store_true') +parser.add_argument('--force', action='store_true', help='Ignore timestamps and force regeneration of all files') +parser.add_argument('--dry-run', action='store_true', help='Report the files that would be process, but do not output') + +args = None +if len(sys.argv) == 1: + # for debugging + spirvPath = os.environ['VULKAN_SDK'] + '/bin' + #spirvPath = expanduser('~//VulkanSDK/1.1.82.1/x86_64/bin') + sourceDir = expanduser('~/git/hifi') + buildPath = sourceDir + '/build_noui' + scribePath = buildPath + '/tools/scribe/Release/scribe' + commandsPath = buildPath + '/libraries/shaders/shadergen.txt' + shaderDir = buildPath + '/libraries/shaders' + testArgs = '--commands {} --spirv-binaries {} --scribe {} --build-dir {} --source-dir {}'.format( + commandsPath, spirvPath, scribePath, shaderDir, sourceDir + ).split() + #testArgs.append('--debug') + #testArgs.append('--force') + #testArgs.append('--dry-run') + args = parser.parse_args(testArgs) +else: + args = parser.parse_args() + +scribeDepCache = ScribeDependenciesCache(args.build_dir + '/shaderDeps.json') +scribeDepCache.load() +main() +scribeDepCache.save() + diff --git a/tools/shreflect/CMakeLists.txt b/tools/shreflect/CMakeLists.txt deleted file mode 100644 index 0748f59d31..0000000000 --- a/tools/shreflect/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -set(TARGET_NAME shreflect) - -# don't use the setup_hifi_project macro as we don't want Qt or GLM dependencies -file(GLOB TARGET_SRCS src/*) -add_executable(${TARGET_NAME} ${TARGET_SRCS}) -target_json() - -if (WIN32) - set_property(TARGET ${TARGET_NAME} APPEND_STRING PROPERTY LINK_FLAGS_DEBUG "/OPT:NOREF /OPT:NOICF") -endif() diff --git a/tools/shreflect/src/main.cpp b/tools/shreflect/src/main.cpp deleted file mode 100644 index e13f937102..0000000000 --- a/tools/shreflect/src/main.cpp +++ /dev/null @@ -1,204 +0,0 @@ -// -// Bradley Austin Davis on 2018/05/24 -// Copyright 2013 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using json = nlohmann::json; - -std::vector splitStringIntoLines(const std::string& s) { - std::stringstream ss(s); - std::vector result; - std::string line; - while (std::getline(ss, line, '\n')) { - result.push_back(line); - } - return result; -} - -std::string readFile(const std::string& file) { - std::ifstream t(file); - std::string str((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - return str; -} - -void writeFile(const std::string& file, const std::string& out) { - std::ofstream t(file, std::ios::trunc); - t << out; - t.close(); -} - -// Convert a Perl style multi-line commented regex into a C++ style regex -// All whitespace will be removed and lines with '#' comments will have the comments removed -std::string getUnformattedRegex(const std::string& formatted) { - static const std::regex WHITESPACE = std::regex("\\s+"); - static const std::string EMPTY; - std::string result; - result.reserve(formatted.size()); - auto lines = splitStringIntoLines(formatted); - for (auto line : lines) { - auto commentStart = line.find('#'); - if (std::string::npos != commentStart) { - line = line.substr(0, commentStart); - } - line = std::regex_replace(line, WHITESPACE, EMPTY); - result += line; - } - - return result; -} - -static std::string LAYOUT_REGEX_STRING{ R"REGEX( -^layout\( # BEGIN layout declaration block - (\s*std140\s*,\s*)? # Optional std140 marker - (binding|location) # binding / location - \s*=\s* - (?: - (\b\d+\b) # literal numeric binding like binding=1 - | - (\b[A-Z_0-9]+\b) # Preprocessor macro binding like binding=GPU_TEXTURE_FOO - ) -\)\s* # END layout declaration block -(?: - ( # Texture or simple uniform like `layout(binding=0) uniform sampler2D originalTexture;` - uniform\s+ - (\b\w+\b)\s+ - (\b\w+\b)\s* - (?:\[\d*\])? - (?:\s*=.*)? - \s*;.*$ - ) - | - ( # UBO or SSBO like `layout(std140, binding=GPU_STORAGE_TRANSFORM_OBJECT) buffer transformObjectBuffer {` - \b(uniform|buffer)\b\s+ - \b(\w+\b) - \s*\{.*$ - ) - | - ( # Input or output attribute like `layout(location=GPU_ATTR_POSITION) in vec4 inPosition;` - \b(in|out)\b\s+ - \b(\w+)\b\s+ - \b(\w+)\b\s*;\s*$ - ) -) -)REGEX" }; - -enum Groups { - STD140 = 1, - LOCATION_TYPE = 2, - LOCATION_LITERAL = 3, - LOCATION_DEFINE = 4, - DECL_SIMPLE = 5, - SIMPLE_TYPE = 6, - SIMPLE_NAME = 7, - DECL_STRUCT = 8, - STRUCT_TYPE = 9, - STRUCT_NAME = 10, - DECL_INOUT = 11, - INOUT_DIRECTION = 12, - INOUT_TYPE = 13, - INOUT_NAME = 14, -}; - -json reflectShader(const std::string& shaderPath) { - static const std::regex DEFINE("^#define\\s+([_A-Z0-9]+)\\s+(\\d+)\\s*$"); - static const std::regex LAYOUT_QUALIFIER{ getUnformattedRegex(LAYOUT_REGEX_STRING) }; - - - auto shaderSource = readFile(shaderPath); - std::vector lines = splitStringIntoLines(shaderSource); - using Map = std::unordered_map; - - json inputs; - json outputs; - json textures; - json textureTypes; - json uniforms; - json storageBuffers; - json uniformBuffers; - Map locationDefines; - for (const auto& line : lines) { - std::cmatch m; - if (std::regex_match(line.c_str(), m, DEFINE)) { - locationDefines[m[1].str()] = std::stoi(m[2].first); - } else if (std::regex_match(line.c_str(), m, LAYOUT_QUALIFIER)) { - int binding = -1; - if (m[LOCATION_LITERAL].matched) { - binding = std::stoi(m[LOCATION_LITERAL].str()); - } else { - binding = locationDefines[m[LOCATION_DEFINE].str()]; - } - if (m[DECL_SIMPLE].matched) { - auto name = m[SIMPLE_NAME].str(); - auto type = m[SIMPLE_TYPE].str(); - bool isTexture = 0 == type.find("sampler"); - auto& map = isTexture ? textures : uniforms; - map[name] = binding; - if (isTexture) { - textureTypes[name] = type; - } - } else if (m[DECL_STRUCT].matched) { - auto name = m[STRUCT_NAME].str(); - auto type = m[STRUCT_TYPE].str(); - auto& map = (type == "buffer") ? storageBuffers : uniformBuffers; - map[name] = binding; - } else if (m[DECL_INOUT].matched) { - auto name = m[INOUT_NAME].str(); - auto& map = (m[INOUT_DIRECTION].str() == "in") ? inputs : outputs; - map[name] = binding; - } - } - } - - json result; - if (!inputs.empty()) { - result["inputs"] = inputs; - } - if (!outputs.empty()) { - result["outputs"] = outputs; - } - if (!textures.empty()) { - result["textures"] = textures; - } - if (!textureTypes.empty()) { - result["texturesTypes"] = textureTypes; - } - if (!uniforms.empty()) { - result["uniforms"] = uniforms; - } - if (!storageBuffers.empty()) { - result["storageBuffers"] = storageBuffers; - } - if (!uniformBuffers.empty()) { - result["uniformBuffers"] = uniformBuffers; - } - - result["name"] = shaderPath; - - return result; -} - -int main (int argc, char** argv) { - auto path = std::string(argv[1]); - auto shaderReflection = reflectShader(path); - writeFile(path + ".json", shaderReflection.dump(4)); - return 0; -} From 3f2f5b18ec71e5f3e5f8588e8e8a739a769bb480 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 19 Oct 2018 14:39:32 -0700 Subject: [PATCH 103/114] Reimplement procedural uniforms without extension requirements --- .../procedural/src/procedural/Procedural.cpp | 89 +++++++++---------- .../procedural/src/procedural/Procedural.h | 21 ++++- .../src/procedural/ProceduralCommon.slh | 69 +++++++------- 3 files changed, 97 insertions(+), 82 deletions(-) diff --git a/libraries/procedural/src/procedural/Procedural.cpp b/libraries/procedural/src/procedural/Procedural.cpp index 426c9ff893..1c082ed250 100644 --- a/libraries/procedural/src/procedural/Procedural.cpp +++ b/libraries/procedural/src/procedural/Procedural.cpp @@ -40,7 +40,7 @@ static const std::string PROCEDURAL_VERSION = "//PROCEDURAL_VERSION"; bool operator==(const ProceduralData& a, const ProceduralData& b) { return ((a.version == b.version) && (a.shaderUrl == b.shaderUrl) && (a.uniforms == b.uniforms) && - (a.channels == b.channels)); + (a.channels == b.channels)); } QJsonValue ProceduralData::getProceduralData(const QString& proceduralJson) { @@ -105,7 +105,7 @@ Procedural::Procedural() { _transparentState->setCullMode(gpu::State::CULL_NONE); _transparentState->setDepthTest(true, true, gpu::LESS_EQUAL); _transparentState->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); _standardInputsBuffer = std::make_shared(sizeof(StandardInputs), nullptr); } @@ -211,10 +211,10 @@ bool Procedural::isReady() const { } void Procedural::prepare(gpu::Batch& batch, - const glm::vec3& position, - const glm::vec3& size, - const glm::quat& orientation, - const glm::vec4& color) { + const glm::vec3& position, + const glm::vec3& size, + const glm::quat& orientation, + const glm::vec4& color) { _entityDimensions = size; _entityPosition = position; _entityOrientation = glm::mat3_cast(orientation); @@ -308,6 +308,7 @@ void Procedural::prepare(gpu::Batch& batch, } } + void Procedural::setupUniforms(bool transparent) { _uniforms.clear(); auto customUniformCount = _data.uniforms.keys().size(); @@ -323,53 +324,50 @@ void Procedural::setupUniforms(bool transparent) { } else if (value.isArray()) { auto valueArray = value.toArray(); switch (valueArray.size()) { - case 0: - break; + case 0: + break; - case 1: { - float v = valueArray[0].toDouble(); - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); - break; - } + case 1: { + float v = valueArray[0].toDouble(); + _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform1f(slot, v); }); + break; + } - case 2: { - glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); - break; - } + case 2: { + glm::vec2 v{ valueArray[0].toDouble(), valueArray[1].toDouble() }; + _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform2f(slot, v.x, v.y); }); + break; + } - case 3: { - glm::vec3 v{ - valueArray[0].toDouble(), - valueArray[1].toDouble(), - valueArray[2].toDouble(), - }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); }); - break; - } + case 3: { + glm::vec3 v{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + }; + _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform3f(slot, v.x, v.y, v.z); }); + break; + } - default: - case 4: { - glm::vec4 v{ - valueArray[0].toDouble(), - valueArray[1].toDouble(), - valueArray[2].toDouble(), - valueArray[3].toDouble(), - }; - _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); }); - break; - } + default: + case 4: { + glm::vec4 v{ + valueArray[0].toDouble(), + valueArray[1].toDouble(), + valueArray[2].toDouble(), + valueArray[3].toDouble(), + }; + _uniforms.push_back([=](gpu::Batch& batch) { batch._glUniform4f(slot, v.x, v.y, v.z, v.w); }); + break; + } } } } _uniforms.push_back([=](gpu::Batch& batch) { - // Time and position - { - // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds - float time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; - _standardInputs.posAndTime = vec4(_entityPosition, time); - } + _standardInputs.position = vec4(_entityPosition, 1.0f); + // Minimize floating point error by doing an integer division to milliseconds, before the floating point division to seconds + _standardInputs.time = (float)((usecTimestampNow() - _start) / USECS_PER_MSEC) / MSECS_PER_SECOND; // Date { @@ -385,7 +383,8 @@ void Procedural::setupUniforms(bool transparent) { _standardInputs.date.w = (time.hour() * 3600) + (time.minute() * 60) + time.second() + fractSeconds; } - _standardInputs.scaleAndCount = vec4(_entityDimensions, ++_frameCount); + _standardInputs.scale = vec4(_entityDimensions, 1.0f); + _standardInputs.frameCount = ++_frameCount; _standardInputs.orientation = mat4(_entityOrientation); for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { diff --git a/libraries/procedural/src/procedural/Procedural.h b/libraries/procedural/src/procedural/Procedural.h index c92725b61b..781ac25249 100644 --- a/libraries/procedural/src/procedural/Procedural.h +++ b/libraries/procedural/src/procedural/Procedural.h @@ -73,14 +73,29 @@ public: protected: + // DO NOT TOUCH + // We have to pack these in a particular way to match the ProceduralCommon.slh + // layout. struct StandardInputs { vec4 date; - vec4 posAndTime; - vec4 scaleAndCount; - mat4 orientation; + vec4 position; + vec4 scale; + float time; + int frameCount; + vec2 _spare1; vec4 resolution[4]; + mat4 orientation; }; + static_assert(0 == offsetof(StandardInputs, date), "ProceduralOffsets"); + static_assert(16 == offsetof(StandardInputs, position), "ProceduralOffsets"); + static_assert(32 == offsetof(StandardInputs, scale), "ProceduralOffsets"); + static_assert(48 == offsetof(StandardInputs, time), "ProceduralOffsets"); + static_assert(52 == offsetof(StandardInputs, frameCount), "ProceduralOffsets"); + static_assert(56 == offsetof(StandardInputs, _spare1), "ProceduralOffsets"); + static_assert(64 == offsetof(StandardInputs, resolution), "ProceduralOffsets"); + static_assert(128 == offsetof(StandardInputs, orientation), "ProceduralOffsets"); + // Procedural metadata ProceduralData _data; diff --git a/libraries/procedural/src/procedural/ProceduralCommon.slh b/libraries/procedural/src/procedural/ProceduralCommon.slh index fbfba81329..ee5a5de688 100644 --- a/libraries/procedural/src/procedural/ProceduralCommon.slh +++ b/libraries/procedural/src/procedural/ProceduralCommon.slh @@ -23,42 +23,43 @@ LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL1) uniform sampler2D iChannel1; LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL2) uniform sampler2D iChannel2; LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL3) uniform sampler2D iChannel3; -struct StandardInputs { +// DO NOT TOUCH +// This block does not follow our normal rules of always using a struct and +// always using 16 byte aligned types like vec4 and mat4 +// +// This is because this block must be EXACTLY how it is in order to maintain +// comptability with existing procedural shaders that previously relied on these +// inputs as uniforms, not members of a UBO + +LAYOUT_STD140(binding=0) uniform standardInputsBuffer { + // Offset 0 vec4 date; - vec4 posAndTime; - vec4 scaleAndCount; - mat4 orientation; - vec4 resolution[4]; -}; - - -LAYOUT(binding=0) uniform standardInputsBuffer { - StandardInputs params; -}; - -// shader playback time (in seconds) -float iGlobalTime = params.posAndTime.w; - -vec4 iDate = params.date; - -int iFrameCount = int(params.scaleAndCount.w); - -// the position of the object being rendered -vec3 iWorldPosition = params.posAndTime.xyz; - -// the dimensions of the object being rendered -vec3 iWorldScale = params.scaleAndCount.xyz; - -// the orientation of the object being rendered -mat3 iWorldOrientation = mat3(params.orientation); - -vec3 iChannelResolution[4] = vec3[4]( - params.resolution[0].xyz, - params.resolution[1].xyz, - params.resolution[2].xyz, - params.resolution[3].xyz -); + // Offset 16, acts as vec4 for alignment purposes + vec3 worldPosition; + // Offset 32, acts as vec4 for alignment purposes + vec3 worldScale; + // Offset 48 + float globalTime; + // Offset 52 + int frameCount; + // Offset 56 + vec2 _spare1; + // Offset 64, acts as vec4[4] for alignment purposes + vec3 channelResolution[4]; + // Offset 128, acts as vec4[3] for alignment purposes + // Also, each individual component is aligned as a vec4 + mat3 worldOrientation; + // Offset 176 + vec4 _spare2; +} standardInputs; +#define iDate standardInputs.date +#define iWorldPosition standardInputs.worldPosition +#define iWorldScale standardInputs.worldScale +#define iGlobalTime standardInputs.globalTime +#define iFrameCount standardInputs.frameCount +#define iChannelResolution standardInputs.channelResolution +#define iWorldOrientation standardInputs.worldOrientation // Unimplemented uniforms // Resolution doesn't make sense in the VR context From 4cf4a5582d4ce30a43e89af41ce11e37118de7a7 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 22 Oct 2018 11:22:30 -0700 Subject: [PATCH 104/114] Fix Android build on Windows hosts --- libraries/ui/src/InteractiveWindow.cpp | 4 ++-- libraries/ui/src/InteractiveWindow.h | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libraries/ui/src/InteractiveWindow.cpp b/libraries/ui/src/InteractiveWindow.cpp index 6c7f2d503f..5f7999f826 100644 --- a/libraries/ui/src/InteractiveWindow.cpp +++ b/libraries/ui/src/InteractiveWindow.cpp @@ -292,8 +292,8 @@ int InteractiveWindow::getPresentationMode() const { return _qmlWindow->property(PRESENTATION_MODE_PROPERTY).toInt(); } -#ifdef Q_OS_WIN void InteractiveWindow::parentNativeWindowToMainWindow() { +#ifdef Q_OS_WIN if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "parentNativeWindowToMainWindow"); return; @@ -307,8 +307,8 @@ void InteractiveWindow::parentNativeWindowToMainWindow() { } const auto nativeWindow = qvariant_cast(nativeWindowProperty); SetWindowLongPtr((HWND)nativeWindow->winId(), GWLP_HWNDPARENT, (LONG)MainWindow::findMainWindow()->winId()); -} #endif +} void InteractiveWindow::setPresentationMode(int presentationMode) { if (QThread::currentThread() != thread()) { diff --git a/libraries/ui/src/InteractiveWindow.h b/libraries/ui/src/InteractiveWindow.h index f456b32e8d..a25d559557 100644 --- a/libraries/ui/src/InteractiveWindow.h +++ b/libraries/ui/src/InteractiveWindow.h @@ -84,9 +84,7 @@ private: Q_INVOKABLE void setPresentationMode(int presentationMode); Q_INVOKABLE int getPresentationMode() const; -#ifdef Q_OS_WIN Q_INVOKABLE void parentNativeWindowToMainWindow(); -#endif public slots: From 85b92a372df5fdf6f3a4b02edcad4f0eba60ae72 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 22 Oct 2018 11:22:59 -0700 Subject: [PATCH 105/114] Don't use optimized GLSL on android for now --- libraries/shaders/src/shaders/Shaders.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/shaders/src/shaders/Shaders.cpp b/libraries/shaders/src/shaders/Shaders.cpp index c385fadb37..549bf65f80 100644 --- a/libraries/shaders/src/shaders/Shaders.cpp +++ b/libraries/shaders/src/shaders/Shaders.cpp @@ -224,11 +224,16 @@ String Source::getSource(Dialect dialect, Variant variant) const { } } +#ifdef Q_OS_ANDROID + // SPIRV cross injects "#extension GL_OES_texture_buffer : require" into the GLSL shaders, + // which breaks android rendering + return variantSource.scribe; +#else if (variantSource.glsl.empty()) { return variantSource.scribe; } - return variantSource.glsl; +#endif } const Reflection& Source::getReflection(Dialect dialect, Variant variant) const { From dd97c4fcd2580e3236f99b49836ff4b82d51ebd9 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Mon, 22 Oct 2018 11:37:08 -0700 Subject: [PATCH 106/114] Fix shadergen parallelism --- tools/shadergen.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/shadergen.py b/tools/shadergen.py index 9f69e6d0bc..7450aebcb3 100644 --- a/tools/shadergen.py +++ b/tools/shadergen.py @@ -188,7 +188,10 @@ def processCommand(line): executeSubprocess([spirvCrossExec, '--reflect', 'json', '--output', reflectionFile, spirvFile]) # Generate the optimized GLSL output - spirvCrossArgs = [spirvCrossExec, '--output', glslFile, spirvFile, '--version', dialect] + spirvCrossDialect = dialect + # 310es causes spirv-cross to inject "#extension GL_OES_texture_buffer : require" into the output + if (dialect == '310es'): spirvCrossDialect = '320es' + spirvCrossArgs = [spirvCrossExec, '--output', glslFile, spirvFile, '--version', spirvCrossDialect] if (dialect == '410'): spirvCrossArgs.append('--no-420pack-extension') executeSubprocess(spirvCrossArgs) else: @@ -205,7 +208,7 @@ def processCommand(line): def main(): commands = args.commands.read().splitlines(False) - if args.debug or True: + if args.debug: for command in commands: processCommand(command) else: From 5a4346221823a536f74172a174fb7140c9df7793 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Tue, 23 Oct 2018 09:28:30 -0700 Subject: [PATCH 107/114] Remove unneeded shader directive --- libraries/procedural/src/procedural/ProceduralCommon.slh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/procedural/src/procedural/ProceduralCommon.slh b/libraries/procedural/src/procedural/ProceduralCommon.slh index ee5a5de688..64a4fdd1f9 100644 --- a/libraries/procedural/src/procedural/ProceduralCommon.slh +++ b/libraries/procedural/src/procedural/ProceduralCommon.slh @@ -14,10 +14,6 @@ <$declareStandardCameraTransform()$> -#ifdef GL_EXT_shader_non_constant_global_initializers -#extension GL_EXT_shader_non_constant_global_initializers : enable -#endif - LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL0) uniform sampler2D iChannel0; LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL1) uniform sampler2D iChannel1; LAYOUT(binding=PROCEDURAL_TEXTURE_CHANNEL2) uniform sampler2D iChannel2; From 39a16703e4c6efafd1e8f2beb4ec0b88964fdbf9 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 10:52:14 -0700 Subject: [PATCH 108/114] updated wording for the radio buttons for avatar leaning model --- interface/src/avatar/MyAvatar.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 45 +++++++++++++------------- 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c55a257d6a..dd40a748af 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -533,7 +533,7 @@ void MyAvatar::update(float deltaTime) { float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); - qCDebug(interfaceapp) << "lock " << _lockSitStandState.get() << " sit " << _isInSittingState.get() << " hmd lean "<< _hmdLeanRecenterEnabled; + // put the average hand azimuth into sensor space. // then mix it with head facing direction to determine rotation recenter if (getControllerPoseInAvatarFrame(controller::Action::LEFT_HAND).isValid() && getControllerPoseInAvatarFrame(controller::Action::RIGHT_HAND).isValid()) { diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index eeca96222b..92628c23b7 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -243,29 +243,6 @@ void setupPreferences() { preference->setIndented(true); preferences->addPreference(preference); } - { - auto getter = [myAvatar]()->int { if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::Auto) { - return 0; - } else if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::ForceSit) { - return 1; - } else { - return 2; - }}; - auto setter = [myAvatar](int value) { if (value == 0) { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); - } else if (value == 1) { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); - } else { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); - }}; - auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); - QStringList items; - items << "Auto" << "Force Sitting" << "Disable Recenter"; - preference->setHeading("User Activity mode"); - preference->setItems(items); - preferences->addPreference(preference); - } - { auto getter = [myAvatar]()->int { return myAvatar->getSnapTurn() ? 0 : 1; }; auto setter = [myAvatar](int value) { myAvatar->setSnapTurn(value == 0); }; @@ -282,6 +259,28 @@ void setupPreferences() { auto preference = new CheckPreference(VR_MOVEMENT, "Show room boundaries while teleporting", getter, setter); preferences->addPreference(preference); } + { + auto getter = [myAvatar]()->int { if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::Auto) { + return 0; + } else if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::ForceSit) { + return 1; + } else { + return 2; + }}; + auto setter = [myAvatar](int value) { if (value == 0) { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); + } else if (value == 1) { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); + } else { + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); + }}; + auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); + QStringList items; + items << "Auto - turns on avatar leaning when standing in real world" << "Seated - disables all avatar leaning while sitting in real world" << "Disabled - allows avatar sitting on the floor [Experimental]"; + preference->setHeading("Avatar leaning behavior"); + preference->setItems(items); + preferences->addPreference(preference); + } { auto getter = [=]()->float { return myAvatar->getUserHeight(); }; auto setter = [=](float value) { myAvatar->setUserHeight(value); }; From 405b1d5725fda3c3455401f60b775d511d449607 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Tue, 23 Oct 2018 10:58:28 -0700 Subject: [PATCH 109/114] Revert "Better imports for controls and styles" --- .../QtWebEngine/UIDelegates/Menu.qml | 4 +- .../QtWebEngine/UIDelegates/MenuItem.qml | 4 +- .../QtWebEngine/UIDelegates/PromptDialog.qml | 4 +- interface/resources/qml/AudioScopeUI.qml | 4 +- interface/resources/qml/Browser.qml | 4 +- interface/resources/qml/CurrentAPI.qml | 4 +- interface/resources/qml/InfoView.qml | 2 +- interface/resources/qml/InteractiveWindow.qml | 4 +- interface/resources/qml/LoginDialog.qml | 4 +- .../LoginDialog/+android/LinkAccountBody.qml | 4 +- .../qml/LoginDialog/+android/SignUpBody.qml | 4 +- .../qml/LoginDialog/CompleteProfileBody.qml | 4 +- .../qml/LoginDialog/LinkAccountBody.qml | 5 +- .../resources/qml/LoginDialog/SignInBody.qml | 4 +- .../resources/qml/LoginDialog/SignUpBody.qml | 4 +- .../qml/LoginDialog/UsernameCollisionBody.qml | 4 +- .../resources/qml/LoginDialog/WelcomeBody.qml | 4 +- interface/resources/qml/QmlWebWindow.qml | 4 +- interface/resources/qml/QmlWindow.qml | 4 +- interface/resources/qml/TabletBrowser.qml | 4 +- interface/resources/qml/UpdateDialog.qml | 4 +- .../+android/ImageButton.qml | 6 +- .../AttachmentsTable.qml | 4 +- .../BaseWebView.qml | 0 .../{controlsUit => controls-uit}/Button.qml | 2 +- .../CheckBox.qml | 2 +- .../CheckBoxQQC2.qml | 4 +- .../ComboBox.qml | 4 +- .../ContentSection.qml | 2 +- .../FilterBar.qml | 4 +- .../GlyphButton.qml | 2 +- .../HorizontalRule.qml | 0 .../HorizontalSpacer.qml | 2 +- .../ImageMessageBox.qml | 2 +- .../qml/{controlsUit => controls-uit}/Key.qml | 0 .../Keyboard.qml | 0 .../{controlsUit => controls-uit}/Label.qml | 2 +- .../QueuedButton.qml | 2 +- .../RadioButton.qml | 4 +- .../ScrollBar.qml | 2 +- .../Separator.qml | 2 +- .../{controlsUit => controls-uit}/Slider.qml | 4 +- .../{controlsUit => controls-uit}/SpinBox.qml | 4 +- .../{controlsUit => controls-uit}/Switch.qml | 2 +- .../{controlsUit => controls-uit}/Table.qml | 2 +- .../TabletContentSection.qml | 2 +- .../TabletHeader.qml | 2 +- .../TextAction.qml | 4 +- .../TextEdit.qml | 2 +- .../TextField.qml | 4 +- .../{controlsUit => controls-uit}/ToolTip.qml | 0 .../{controlsUit => controls-uit}/Tree.qml | 2 +- .../VerticalSpacer.qml | 2 +- .../WebGlyphButton.qml | 2 +- .../WebSpinner.qml | 0 .../{controlsUit => controls-uit}/WebView.qml | 0 .../qml/{controlsUit => controls-uit}/qmldir | 0 interface/resources/qml/controls/Button.qml | 1 + .../qml/controls/FlickableWebViewCore.qml | 2 +- .../qml/controls/TabletWebButton.qml | 2 +- .../qml/controls/TabletWebScreen.qml | 2 +- .../resources/qml/controls/TabletWebView.qml | 4 +- interface/resources/qml/controls/WebView.qml | 2 +- .../resources/qml/dialogs/AssetDialog.qml | 2 +- .../qml/dialogs/CustomQueryDialog.qml | 4 +- .../resources/qml/dialogs/FileDialog.qml | 4 +- .../resources/qml/dialogs/MessageDialog.qml | 4 +- .../qml/dialogs/PreferencesDialog.qml | 4 +- .../resources/qml/dialogs/QueryDialog.qml | 4 +- .../qml/dialogs/TabletAssetDialog.qml | 2 +- .../qml/dialogs/TabletCustomQueryDialog.qml | 4 +- .../qml/dialogs/TabletFileDialog.qml | 4 +- .../qml/dialogs/TabletLoginDialog.qml | 4 +- .../qml/dialogs/TabletMessageBox.qml | 4 +- .../qml/dialogs/TabletQueryDialog.qml | 4 +- .../assetDialog/AssetDialogContent.qml | 4 +- .../dialogs/fileDialog/FileTypeSelection.qml | 2 +- .../messageDialog/MessageDialogButton.qml | 2 +- .../dialogs/preferences/AvatarPreference.qml | 2 +- .../preferences/BrowsablePreference.qml | 2 +- .../dialogs/preferences/ButtonPreference.qml | 2 +- .../preferences/CheckBoxPreference.qml | 2 +- .../preferences/ComboBoxPreference.qml | 4 +- .../preferences/EditablePreference.qml | 2 +- .../preferences/PrimaryHandPreference.qml | 2 +- .../preferences/RadioButtonsPreference.qml | 4 +- .../qml/dialogs/preferences/Section.qml | 4 +- .../dialogs/preferences/SliderPreference.qml | 2 +- .../dialogs/preferences/SpinBoxPreference.qml | 2 +- .../preferences/SpinnerSliderPreference.qml | 2 +- .../resources/qml/hifi/+android/ActionBar.qml | 4 +- .../resources/qml/hifi/+android/AudioBar.qml | 4 +- .../qml/hifi/+android/AvatarOption.qml | 2 +- .../resources/qml/hifi/+android/StatsBar.qml | 4 +- .../qml/hifi/+android/WindowHeader.qml | 4 +- .../qml/hifi/+android/bottomHudOptions.qml | 4 +- .../resources/qml/hifi/+android/modesbar.qml | 4 +- interface/resources/qml/hifi/AssetServer.qml | 4 +- interface/resources/qml/hifi/AvatarApp.qml | 4 +- interface/resources/qml/hifi/Card.qml | 2 +- interface/resources/qml/hifi/ComboDialog.qml | 4 +- interface/resources/qml/hifi/Desktop.qml | 2 +- .../qml/hifi/DesktopLetterboxMessage.qml | 2 +- interface/resources/qml/hifi/Feed.qml | 2 +- .../resources/qml/hifi/LetterboxMessage.qml | 2 +- interface/resources/qml/hifi/NameCard.qml | 4 +- interface/resources/qml/hifi/Pal.qml | 4 +- .../resources/qml/hifi/SkyboxChanger.qml | 4 +- .../resources/qml/hifi/SpectatorCamera.qml | 4 +- .../resources/qml/hifi/TabletTextButton.qml | 2 +- interface/resources/qml/hifi/TextButton.qml | 2 +- interface/resources/qml/hifi/WebBrowser.qml | 4 +- interface/resources/qml/hifi/audio/Audio.qml | 4 +- .../qml/hifi/audio/AudioTabButton.qml | 4 +- .../resources/qml/hifi/audio/CheckBox.qml | 2 +- .../qml/hifi/audio/PlaySampleSound.qml | 4 +- .../qml/hifi/avatarapp/AdjustWearables.qml | 5 +- .../qml/hifi/avatarapp/AvatarAppHeader.qml | 2 +- .../qml/hifi/avatarapp/AvatarAppStyle.qml | 2 +- .../avatarapp/AvatarWearablesIndicator.qml | 4 +- .../qml/hifi/avatarapp/BlueButton.qml | 4 +- .../hifi/avatarapp/CreateFavoriteDialog.qml | 4 +- .../qml/hifi/avatarapp/InputField.qml | 4 +- .../qml/hifi/avatarapp/InputTextStyle4.qml | 4 +- .../qml/hifi/avatarapp/MessageBox.qml | 4 +- .../resources/qml/hifi/avatarapp/Settings.qml | 4 +- .../qml/hifi/avatarapp/ShadowGlyph.qml | 2 +- .../qml/hifi/avatarapp/ShadowImage.qml | 2 +- .../qml/hifi/avatarapp/ShadowRectangle.qml | 2 +- .../qml/hifi/avatarapp/SquareLabel.qml | 4 +- .../resources/qml/hifi/avatarapp/Vector3.qml | 4 +- .../qml/hifi/avatarapp/WhiteButton.qml | 4 +- .../qml/hifi/commerce/checkout/Checkout.qml | 4 +- .../hifi/commerce/common/CommerceLightbox.qml | 4 +- .../common/EmulatedMarketplaceHeader.qml | 4 +- .../hifi/commerce/common/FirstUseTutorial.qml | 4 +- .../common/sendAsset/ConnectionItem.qml | 4 +- .../common/sendAsset/RecipientDisplay.qml | 4 +- .../commerce/common/sendAsset/SendAsset.qml | 4 +- .../InspectionCertificate.qml | 4 +- .../MarketplaceItemTester.qml | 4 +- .../hifi/commerce/purchases/PurchasedItem.qml | 4 +- .../qml/hifi/commerce/purchases/Purchases.qml | 4 +- .../qml/hifi/commerce/wallet/Help.qml | 4 +- .../qml/hifi/commerce/wallet/NeedsLogIn.qml | 4 +- .../hifi/commerce/wallet/PassphraseChange.qml | 4 +- .../hifi/commerce/wallet/PassphraseModal.qml | 4 +- .../commerce/wallet/PassphraseSelection.qml | 4 +- .../qml/hifi/commerce/wallet/Security.qml | 4 +- .../commerce/wallet/SecurityImageChange.qml | 4 +- .../wallet/SecurityImageSelection.qml | 4 +- .../qml/hifi/commerce/wallet/Wallet.qml | 4 +- .../qml/hifi/commerce/wallet/WalletChoice.qml | 4 +- .../qml/hifi/commerce/wallet/WalletHome.qml | 4 +- .../qml/hifi/commerce/wallet/WalletSetup.qml | 4 +- .../qml/hifi/dialogs/AboutDialog.qml | 2 +- .../qml/hifi/dialogs/RunningScripts.qml | 4 +- .../qml/hifi/dialogs/TabletAboutDialog.qml | 2 +- .../qml/hifi/dialogs/TabletAssetServer.qml | 4 +- .../qml/hifi/dialogs/TabletDCDialog.qml | 4 +- .../qml/hifi/dialogs/TabletDebugWindow.qml | 4 +- .../hifi/dialogs/TabletEntityStatistics.qml | 4 +- .../dialogs/TabletEntityStatisticsItem.qml | 4 +- .../qml/hifi/dialogs/TabletLODTools.qml | 4 +- .../qml/hifi/dialogs/TabletRunningScripts.qml | 4 +- .../dialogs/content/ModelBrowserContent.qml | 2 +- .../qml/hifi/tablet/CalibratingScreen.qml | 4 +- .../qml/hifi/tablet/ControllerSettings.qml | 4 +- .../qml/hifi/tablet/EditEntityList.qml | 4 +- .../qml/hifi/tablet/EditTabButton.qml | 4 +- .../resources/qml/hifi/tablet/EditTabView.qml | 4 +- .../qml/hifi/tablet/EditToolsTabView.qml | 4 +- .../qml/hifi/tablet/InputRecorder.qml | 4 +- .../qml/hifi/tablet/NewMaterialDialog.qml | 4 +- .../qml/hifi/tablet/NewModelDialog.qml | 4 +- .../qml/hifi/tablet/OpenVrConfiguration.qml | 4 +- .../qml/hifi/tablet/TabletAddressDialog.qml | 4 +- .../resources/qml/hifi/tablet/TabletHome.qml | 2 +- .../resources/qml/hifi/tablet/TabletMenu.qml | 2 +- .../qml/hifi/tablet/TabletMenuItem.qml | 4 +- .../qml/hifi/tablet/TabletMenuView.qml | 2 +- .../hifi/tablet/TabletModelBrowserDialog.qml | 4 +- .../tablet/tabletWindows/TabletFileDialog.qml | 4 +- .../tabletWindows/TabletPreferencesDialog.qml | 4 +- .../tabletWindows/preferences/Section.qml | 4 +- .../preferences/TabletBrowsablePreference.qml | 2 +- .../+android/HifiConstants.qml | 0 .../AnonymousProRegular.qml | 0 .../{stylesUit => styles-uit}/ButtonLabel.qml | 0 .../FiraSansRegular.qml | 0 .../FiraSansSemiBold.qml | 0 .../{stylesUit => styles-uit}/HiFiGlyphs.qml | 0 .../HifiConstants.qml | 0 .../{stylesUit => styles-uit}/IconButton.qml | 0 .../{stylesUit => styles-uit}/InfoItem.qml | 0 .../{stylesUit => styles-uit}/InputLabel.qml | 0 .../{stylesUit => styles-uit}/ListItem.qml | 0 .../qml/{stylesUit => styles-uit}/Logs.qml | 0 .../OverlayTitle.qml | 0 .../{stylesUit => styles-uit}/RalewayBold.qml | 0 .../RalewayLight.qml | 0 .../RalewayRegular.qml | 0 .../RalewaySemiBold.qml | 0 .../{stylesUit => styles-uit}/SectionName.qml | 0 .../{stylesUit => styles-uit}/Separator.qml | 2 +- .../ShortcutText.qml | 0 .../qml/{stylesUit => styles-uit}/TabName.qml | 0 .../TextFieldInput.qml | 0 .../qml/{stylesUit => styles-uit}/qmldir | 0 .../resources/qml/windows/Decoration.qml | 2 +- .../resources/qml/windows/DefaultFrame.qml | 2 +- .../qml/windows/DefaultFrameDecoration.qml | 2 +- interface/resources/qml/windows/Fadable.qml | 2 +- interface/resources/qml/windows/Frame.qml | 2 +- .../resources/qml/windows/ModalFrame.qml | 4 +- .../resources/qml/windows/ScrollingWindow.qml | 4 +- .../qml/windows/TabletModalFrame.qml | 4 +- interface/resources/qml/windows/ToolFrame.qml | 2 +- .../qml/windows/ToolFrameDecoration.qml | 2 +- interface/resources/qml/windows/Window.qml | 2 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 1 - scripts/developer/tests/ControlsGallery.qml | 11 +- scripts/developer/utilities/audio/Stats.qml | 2 +- .../developer/utilities/audio/TabletStats.qml | 3 +- .../utilities/lib/jet/qml/TaskList.qml | 4 +- .../utilities/lib/jet/qml/TaskListView.qml | 4 +- .../utilities/lib/plotperf/Color.qml | 4 +- .../utilities/render/antialiasing.qml | 4 +- .../render/configSlider/ConfigSlider.qml | 4 +- .../render/configSlider/RichSlider.qml | 4 +- .../utilities/render/deferredLighting.qml | 4 +- .../utilities/render/engineInspector.qml | 4 +- .../developer/utilities/render/highlight.qml | 4 +- .../render/highlight/HighlightStyle.qml | 4 +- scripts/developer/utilities/render/lod.qml | 4 +- scripts/developer/utilities/render/shadow.qml | 4 +- .../developer/utilities/render/transition.qml | 4 +- .../utilities/workload/workloadInspector.qml | 4 +- tests-manual/ui/qml/ControlsGalleryWindow.qml | 14 - tests-manual/ui/qml/Palettes.qml | 150 ++++ tests-manual/ui/qml/ScrollingGraph.qml | 111 +++ tests-manual/ui/qml/StubMenu.qml | 730 ++++++++++++++++++ tests-manual/ui/qml/Stubs.qml | 346 +++++++++ tests-manual/ui/qml/TestControllers.qml | 160 ++++ tests-manual/ui/qml/TestDialog.qml | 94 +++ tests-manual/ui/qml/TestMenu.qml | 10 + tests-manual/ui/qml/TestRoot.qml | 43 ++ .../ui/qml/controlDemo/ButtonPage.qml | 128 +++ tests-manual/ui/qml/controlDemo/InputPage.qml | 114 +++ .../ui/qml/controlDemo/ProgressPage.qml | 90 +++ tests-manual/ui/qml/controlDemo/main.qml | 161 ++++ tests-manual/ui/qml/main.qml | 461 +++++++++++ tests-manual/ui/qmlscratch.pro | 28 +- tests-manual/ui/src/main.cpp | 125 ++- .../spectator-camera/SpectatorCamera.qml | 4 +- 255 files changed, 3082 insertions(+), 389 deletions(-) rename interface/resources/qml/{controlsUit => controls-uit}/+android/ImageButton.qml (96%) rename interface/resources/qml/{controlsUit => controls-uit}/AttachmentsTable.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/BaseWebView.qml (100%) rename interface/resources/qml/{controlsUit => controls-uit}/Button.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/CheckBox.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/CheckBoxQQC2.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/ComboBox.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/ContentSection.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/FilterBar.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/GlyphButton.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/HorizontalRule.qml (100%) rename interface/resources/qml/{controlsUit => controls-uit}/HorizontalSpacer.qml (94%) rename interface/resources/qml/{controlsUit => controls-uit}/ImageMessageBox.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/Key.qml (100%) rename interface/resources/qml/{controlsUit => controls-uit}/Keyboard.qml (100%) rename interface/resources/qml/{controlsUit => controls-uit}/Label.qml (97%) rename interface/resources/qml/{controlsUit => controls-uit}/QueuedButton.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/RadioButton.qml (97%) rename interface/resources/qml/{controlsUit => controls-uit}/ScrollBar.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/Separator.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/Slider.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/SpinBox.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/Switch.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/Table.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/TabletContentSection.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/TabletHeader.qml (96%) rename interface/resources/qml/{controlsUit => controls-uit}/TextAction.qml (96%) rename interface/resources/qml/{controlsUit => controls-uit}/TextEdit.qml (95%) rename interface/resources/qml/{controlsUit => controls-uit}/TextField.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/ToolTip.qml (100%) rename interface/resources/qml/{controlsUit => controls-uit}/Tree.qml (99%) rename interface/resources/qml/{controlsUit => controls-uit}/VerticalSpacer.qml (94%) rename interface/resources/qml/{controlsUit => controls-uit}/WebGlyphButton.qml (98%) rename interface/resources/qml/{controlsUit => controls-uit}/WebSpinner.qml (100%) rename interface/resources/qml/{controlsUit => controls-uit}/WebView.qml (100%) rename interface/resources/qml/{controlsUit => controls-uit}/qmldir (100%) rename interface/resources/qml/{stylesUit => styles-uit}/+android/HifiConstants.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/AnonymousProRegular.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/ButtonLabel.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/FiraSansRegular.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/FiraSansSemiBold.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/HiFiGlyphs.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/HifiConstants.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/IconButton.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/InfoItem.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/InputLabel.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/ListItem.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/Logs.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/OverlayTitle.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/RalewayBold.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/RalewayLight.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/RalewayRegular.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/RalewaySemiBold.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/SectionName.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/Separator.qml (97%) rename interface/resources/qml/{stylesUit => styles-uit}/ShortcutText.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/TabName.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/TextFieldInput.qml (100%) rename interface/resources/qml/{stylesUit => styles-uit}/qmldir (100%) delete mode 100644 tests-manual/ui/qml/ControlsGalleryWindow.qml create mode 100644 tests-manual/ui/qml/Palettes.qml create mode 100644 tests-manual/ui/qml/ScrollingGraph.qml create mode 100644 tests-manual/ui/qml/StubMenu.qml create mode 100644 tests-manual/ui/qml/Stubs.qml create mode 100644 tests-manual/ui/qml/TestControllers.qml create mode 100644 tests-manual/ui/qml/TestDialog.qml create mode 100644 tests-manual/ui/qml/TestMenu.qml create mode 100644 tests-manual/ui/qml/TestRoot.qml create mode 100644 tests-manual/ui/qml/controlDemo/ButtonPage.qml create mode 100644 tests-manual/ui/qml/controlDemo/InputPage.qml create mode 100644 tests-manual/ui/qml/controlDemo/ProgressPage.qml create mode 100644 tests-manual/ui/qml/controlDemo/main.qml create mode 100644 tests-manual/ui/qml/main.qml diff --git a/interface/resources/QtWebEngine/UIDelegates/Menu.qml b/interface/resources/QtWebEngine/UIDelegates/Menu.qml index adfd29df9e..46c00e758e 100644 --- a/interface/resources/QtWebEngine/UIDelegates/Menu.qml +++ b/interface/resources/QtWebEngine/UIDelegates/Menu.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 -import controlsUit 1.0 -import stylesUit 1.0 +import "../../qml/controls-uit" +import "../../qml/styles-uit" Item { id: menu diff --git a/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml b/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml index b4d3ca4bb2..6014b6834b 100644 --- a/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml +++ b/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 -import controlsUit 1.0 -import stylesUit 1.0 +import "../../qml/controls-uit" +import "../../qml/styles-uit" Item { id: root diff --git a/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml b/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml index 089c745571..e4ab3037ef 100644 --- a/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml +++ b/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 -import controlsUit 1.0 -import stylesUit 1.0 +import "../../qml/controls-uit" +import "../../qml/styles-uit" import "../../qml/dialogs" QtObject { diff --git a/interface/resources/qml/AudioScopeUI.qml b/interface/resources/qml/AudioScopeUI.qml index 91908807e2..aa181dbf8d 100644 --- a/interface/resources/qml/AudioScopeUI.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "styles-uit" +import "controls-uit" as HifiControlsUit Item { id: root diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 01de7a36f9..4474cfb2cd 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -2,9 +2,9 @@ import QtQuick 2.5 import QtWebChannel 1.0 import QtWebEngine 1.5 -import controlsUit 1.0 +import "controls-uit" import "styles" as HifiStyles -import stylesUit 1.0 +import "styles-uit" import "windows" ScrollingWindow { diff --git a/interface/resources/qml/CurrentAPI.qml b/interface/resources/qml/CurrentAPI.qml index 4ea45041c3..96bfb5c36b 100644 --- a/interface/resources/qml/CurrentAPI.qml +++ b/interface/resources/qml/CurrentAPI.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "styles-uit" +import "controls-uit" as HifiControls Item { id: root diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml index 8c5900b4c3..f18969fb2f 100644 --- a/interface/resources/qml/InfoView.qml +++ b/interface/resources/qml/InfoView.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import Hifi 1.0 as Hifi -import controlsUit 1.0 +import "controls-uit" import "windows" as Windows Windows.ScrollingWindow { diff --git a/interface/resources/qml/InteractiveWindow.qml b/interface/resources/qml/InteractiveWindow.qml index c217238e93..e8ddbf823d 100644 --- a/interface/resources/qml/InteractiveWindow.qml +++ b/interface/resources/qml/InteractiveWindow.qml @@ -12,9 +12,9 @@ import QtQuick 2.3 import "windows" as Windows import "controls" -import controlsUit 1.0 as Controls +import "controls-uit" as Controls import "styles" -import stylesUit 1.0 +import "styles-uit" Windows.Window { id: root; diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index 12117aaba4..336858502d 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.4 -import controlsUit 1.0 -import stylesUit 1.0 +import "controls-uit" +import "styles-uit" import "windows" import "LoginDialog" diff --git a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml index a40110b1e9..96b638c911 100644 --- a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml @@ -13,8 +13,8 @@ import QtQuick 2.4 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import controlsUit 1.0 -import stylesUit 1.0 +import "../../controls-uit" +import "../../styles-uit" Item { id: linkAccountBody diff --git a/interface/resources/qml/LoginDialog/+android/SignUpBody.qml b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml index 10909e4c85..3a44a8d741 100644 --- a/interface/resources/qml/LoginDialog/+android/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml @@ -13,8 +13,8 @@ import QtQuick 2.4 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import controlsUit 1.0 -import stylesUit 1.0 +import "../../controls-uit" +import "../../styles-uit" Item { id: signupBody diff --git a/interface/resources/qml/LoginDialog/CompleteProfileBody.qml b/interface/resources/qml/LoginDialog/CompleteProfileBody.qml index 3a57061de4..fe4c511f1d 100644 --- a/interface/resources/qml/LoginDialog/CompleteProfileBody.qml +++ b/interface/resources/qml/LoginDialog/CompleteProfileBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.4 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" Item { id: completeProfileBody diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 7951d45c0e..48cf124127 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -13,9 +13,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import controlsUit 1.0 -import stylesUit 1.0 - +import "../controls-uit" +import "../styles-uit" Item { id: linkAccountBody clip: true diff --git a/interface/resources/qml/LoginDialog/SignInBody.qml b/interface/resources/qml/LoginDialog/SignInBody.qml index 7fe29e13f6..9cb1add704 100644 --- a/interface/resources/qml/LoginDialog/SignInBody.qml +++ b/interface/resources/qml/LoginDialog/SignInBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.7 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" Item { id: signInBody diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index d3c898d76f..bb30696e4c 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.7 import QtQuick.Controls 1.4 -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" Item { id: signupBody diff --git a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml index 2a41353534..bf05a36ce1 100644 --- a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml +++ b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.4 import QtQuick.Controls 1.4 -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" Item { id: usernameCollisionBody diff --git a/interface/resources/qml/LoginDialog/WelcomeBody.qml b/interface/resources/qml/LoginDialog/WelcomeBody.qml index 020e6db002..551ec263b7 100644 --- a/interface/resources/qml/LoginDialog/WelcomeBody.qml +++ b/interface/resources/qml/LoginDialog/WelcomeBody.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.4 -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" Item { id: welcomeBody diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index 322535641d..8c4d6145ec 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -13,8 +13,8 @@ import QtWebEngine 1.1 import QtWebChannel 1.0 import "windows" as Windows -import controlsUit 1.0 as Controls -import stylesUit 1.0 +import "controls-uit" as Controls +import "styles-uit" Windows.ScrollingWindow { id: root diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index 53e6bcc37d..bef6423e25 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -2,9 +2,9 @@ import QtQuick 2.3 import "windows" as Windows import "controls" -import controlsUit 1.0 as Controls +import "controls-uit" as Controls import "styles" -import stylesUit 1.0 +import "styles-uit" Windows.Window { id: root diff --git a/interface/resources/qml/TabletBrowser.qml b/interface/resources/qml/TabletBrowser.qml index 720a904231..141c1f25a7 100644 --- a/interface/resources/qml/TabletBrowser.qml +++ b/interface/resources/qml/TabletBrowser.qml @@ -3,9 +3,9 @@ import QtWebChannel 1.0 import QtWebEngine 1.5 import "controls" -import controlsUit 1.0 as HifiControls +import "controls-uit" as HifiControls import "styles" as HifiStyles -import stylesUit 1.0 +import "styles-uit" import "windows" Item { diff --git a/interface/resources/qml/UpdateDialog.qml b/interface/resources/qml/UpdateDialog.qml index 9c22d0b65b..5e05601ce4 100644 --- a/interface/resources/qml/UpdateDialog.qml +++ b/interface/resources/qml/UpdateDialog.qml @@ -4,9 +4,9 @@ import QtQuick.Controls 1.3 import QtQuick.Controls.Styles 1.3 import QtGraphicalEffects 1.0 -import controlsUit 1.0 +import "controls-uit" import "styles" as HifiStyles -import stylesUit 1.0 +import "styles-uit" import "windows" ScrollingWindow { diff --git a/interface/resources/qml/controlsUit/+android/ImageButton.qml b/interface/resources/qml/controls-uit/+android/ImageButton.qml similarity index 96% rename from interface/resources/qml/controlsUit/+android/ImageButton.qml rename to interface/resources/qml/controls-uit/+android/ImageButton.qml index 88eaf95d76..5ebf7cd3e9 100644 --- a/interface/resources/qml/controlsUit/+android/ImageButton.qml +++ b/interface/resources/qml/controls-uit/+android/ImageButton.qml @@ -1,6 +1,6 @@ // // ImageButton.qml -// interface/resources/qml/controlsUit +// interface/resources/qml/controls-uit // // Created by Gabriel Calero & Cristian Duarte on 12 Oct 2017 // Copyright 2017 High Fidelity, Inc. @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtQuick.Layouts 1.3 -import "../stylesUit" as HifiStyles +import "../styles-uit" as HifiStyles Item { id: button @@ -79,4 +79,4 @@ Item { } } ] -} +} \ No newline at end of file diff --git a/interface/resources/qml/controlsUit/AttachmentsTable.qml b/interface/resources/qml/controls-uit/AttachmentsTable.qml similarity index 98% rename from interface/resources/qml/controlsUit/AttachmentsTable.qml rename to interface/resources/qml/controls-uit/AttachmentsTable.qml index a2677962da..8ee9909ab8 100644 --- a/interface/resources/qml/controlsUit/AttachmentsTable.qml +++ b/interface/resources/qml/controls-uit/AttachmentsTable.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.XmlListModel 2.0 -import "../stylesUit" -import "." as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls import "../windows" import "../hifi/models" diff --git a/interface/resources/qml/controlsUit/BaseWebView.qml b/interface/resources/qml/controls-uit/BaseWebView.qml similarity index 100% rename from interface/resources/qml/controlsUit/BaseWebView.qml rename to interface/resources/qml/controls-uit/BaseWebView.qml diff --git a/interface/resources/qml/controlsUit/Button.qml b/interface/resources/qml/controls-uit/Button.qml similarity index 99% rename from interface/resources/qml/controlsUit/Button.qml rename to interface/resources/qml/controls-uit/Button.qml index 6ea7ce4b4c..f1a6e4bb4a 100644 --- a/interface/resources/qml/controlsUit/Button.qml +++ b/interface/resources/qml/controls-uit/Button.qml @@ -12,7 +12,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 as Original import TabletScriptingInterface 1.0 -import "../stylesUit" +import "../styles-uit" Original.Button { id: control; diff --git a/interface/resources/qml/controlsUit/CheckBox.qml b/interface/resources/qml/controls-uit/CheckBox.qml similarity index 99% rename from interface/resources/qml/controlsUit/CheckBox.qml rename to interface/resources/qml/controls-uit/CheckBox.qml index abf08908fb..6e4a3df010 100644 --- a/interface/resources/qml/controlsUit/CheckBox.qml +++ b/interface/resources/qml/controls-uit/CheckBox.qml @@ -11,7 +11,7 @@ import QtQuick 2.2 import QtQuick.Controls 2.2 as Original -import "../stylesUit" +import "../styles-uit" import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/controlsUit/CheckBoxQQC2.qml b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml similarity index 98% rename from interface/resources/qml/controlsUit/CheckBoxQQC2.qml rename to interface/resources/qml/controls-uit/CheckBoxQQC2.qml index 91d35ecd58..8a9686ff5e 100644 --- a/interface/resources/qml/controlsUit/CheckBoxQQC2.qml +++ b/interface/resources/qml/controls-uit/CheckBoxQQC2.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../stylesUit" -import "." as HiFiControls +import "../styles-uit" +import "../controls-uit" as HiFiControls import TabletScriptingInterface 1.0 CheckBox { diff --git a/interface/resources/qml/controlsUit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml similarity index 99% rename from interface/resources/qml/controlsUit/ComboBox.qml rename to interface/resources/qml/controls-uit/ComboBox.qml index 8d1d7a5262..245b565a62 100644 --- a/interface/resources/qml/controlsUit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../stylesUit" -import "." as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls FocusScope { id: root diff --git a/interface/resources/qml/controlsUit/ContentSection.qml b/interface/resources/qml/controls-uit/ContentSection.qml similarity index 99% rename from interface/resources/qml/controlsUit/ContentSection.qml rename to interface/resources/qml/controls-uit/ContentSection.qml index 262c29220f..47a13e9262 100644 --- a/interface/resources/qml/controlsUit/ContentSection.qml +++ b/interface/resources/qml/controls-uit/ContentSection.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../stylesUit" +import "../styles-uit" Column { property string name: "Content Section" diff --git a/interface/resources/qml/controlsUit/FilterBar.qml b/interface/resources/qml/controls-uit/FilterBar.qml similarity index 99% rename from interface/resources/qml/controlsUit/FilterBar.qml rename to interface/resources/qml/controls-uit/FilterBar.qml index 3e407040bc..ecae790b22 100644 --- a/interface/resources/qml/controlsUit/FilterBar.qml +++ b/interface/resources/qml/controls-uit/FilterBar.qml @@ -12,8 +12,8 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 -import "../stylesUit" -import "." as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls Item { id: root; diff --git a/interface/resources/qml/controlsUit/GlyphButton.qml b/interface/resources/qml/controls-uit/GlyphButton.qml similarity index 99% rename from interface/resources/qml/controlsUit/GlyphButton.qml rename to interface/resources/qml/controls-uit/GlyphButton.qml index 17f7fba2d6..9129486720 100644 --- a/interface/resources/qml/controlsUit/GlyphButton.qml +++ b/interface/resources/qml/controls-uit/GlyphButton.qml @@ -12,7 +12,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 as Original import TabletScriptingInterface 1.0 -import "../stylesUit" +import "../styles-uit" Original.Button { id: control diff --git a/interface/resources/qml/controlsUit/HorizontalRule.qml b/interface/resources/qml/controls-uit/HorizontalRule.qml similarity index 100% rename from interface/resources/qml/controlsUit/HorizontalRule.qml rename to interface/resources/qml/controls-uit/HorizontalRule.qml diff --git a/interface/resources/qml/controlsUit/HorizontalSpacer.qml b/interface/resources/qml/controls-uit/HorizontalSpacer.qml similarity index 94% rename from interface/resources/qml/controlsUit/HorizontalSpacer.qml rename to interface/resources/qml/controls-uit/HorizontalSpacer.qml index efcabf2699..545154ab44 100644 --- a/interface/resources/qml/controlsUit/HorizontalSpacer.qml +++ b/interface/resources/qml/controls-uit/HorizontalSpacer.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../stylesUit" +import "../styles-uit" Item { id: root diff --git a/interface/resources/qml/controlsUit/ImageMessageBox.qml b/interface/resources/qml/controls-uit/ImageMessageBox.qml similarity index 98% rename from interface/resources/qml/controlsUit/ImageMessageBox.qml rename to interface/resources/qml/controls-uit/ImageMessageBox.qml index 46d93383a4..74313f7ffe 100644 --- a/interface/resources/qml/controlsUit/ImageMessageBox.qml +++ b/interface/resources/qml/controls-uit/ImageMessageBox.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "../stylesUit" +import "../styles-uit" Item { id: imageBox diff --git a/interface/resources/qml/controlsUit/Key.qml b/interface/resources/qml/controls-uit/Key.qml similarity index 100% rename from interface/resources/qml/controlsUit/Key.qml rename to interface/resources/qml/controls-uit/Key.qml diff --git a/interface/resources/qml/controlsUit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml similarity index 100% rename from interface/resources/qml/controlsUit/Keyboard.qml rename to interface/resources/qml/controls-uit/Keyboard.qml diff --git a/interface/resources/qml/controlsUit/Label.qml b/interface/resources/qml/controls-uit/Label.qml similarity index 97% rename from interface/resources/qml/controlsUit/Label.qml rename to interface/resources/qml/controls-uit/Label.qml index 7f208cde88..4c7051b495 100644 --- a/interface/resources/qml/controlsUit/Label.qml +++ b/interface/resources/qml/controls-uit/Label.qml @@ -10,7 +10,7 @@ import QtQuick 2.7 -import "../stylesUit" +import "../styles-uit" RalewaySemiBold { HifiConstants { id: hifi } diff --git a/interface/resources/qml/controlsUit/QueuedButton.qml b/interface/resources/qml/controls-uit/QueuedButton.qml similarity index 98% rename from interface/resources/qml/controlsUit/QueuedButton.qml rename to interface/resources/qml/controls-uit/QueuedButton.qml index 70ad9eb112..6612d582df 100644 --- a/interface/resources/qml/controlsUit/QueuedButton.qml +++ b/interface/resources/qml/controls-uit/QueuedButton.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../stylesUit" +import "../styles-uit" import "." as HifiControls HifiControls.Button { diff --git a/interface/resources/qml/controlsUit/RadioButton.qml b/interface/resources/qml/controls-uit/RadioButton.qml similarity index 97% rename from interface/resources/qml/controlsUit/RadioButton.qml rename to interface/resources/qml/controls-uit/RadioButton.qml index ad62a77aa7..56324c55d7 100644 --- a/interface/resources/qml/controlsUit/RadioButton.qml +++ b/interface/resources/qml/controls-uit/RadioButton.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 as Original -import "../stylesUit" -import "." as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/controlsUit/ScrollBar.qml b/interface/resources/qml/controls-uit/ScrollBar.qml similarity index 98% rename from interface/resources/qml/controlsUit/ScrollBar.qml rename to interface/resources/qml/controls-uit/ScrollBar.qml index bcb1f62429..125e84e585 100644 --- a/interface/resources/qml/controlsUit/ScrollBar.qml +++ b/interface/resources/qml/controls-uit/ScrollBar.qml @@ -11,7 +11,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../stylesUit" +import "../styles-uit" ScrollBar { visible: size < 1.0 diff --git a/interface/resources/qml/controlsUit/Separator.qml b/interface/resources/qml/controls-uit/Separator.qml similarity index 98% rename from interface/resources/qml/controlsUit/Separator.qml rename to interface/resources/qml/controls-uit/Separator.qml index da6b9adf57..3350764ae9 100644 --- a/interface/resources/qml/controlsUit/Separator.qml +++ b/interface/resources/qml/controls-uit/Separator.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "../stylesUit" +import "../styles-uit" Item { property int colorScheme: 0; diff --git a/interface/resources/qml/controlsUit/Slider.qml b/interface/resources/qml/controls-uit/Slider.qml similarity index 98% rename from interface/resources/qml/controlsUit/Slider.qml rename to interface/resources/qml/controls-uit/Slider.qml index 8cb08b69e2..2a5d4c137d 100644 --- a/interface/resources/qml/controlsUit/Slider.qml +++ b/interface/resources/qml/controls-uit/Slider.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../stylesUit" -import "." as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls Slider { id: slider diff --git a/interface/resources/qml/controlsUit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml similarity index 98% rename from interface/resources/qml/controlsUit/SpinBox.qml rename to interface/resources/qml/controls-uit/SpinBox.qml index d24c7c5e8c..3d3ea7a75e 100644 --- a/interface/resources/qml/controlsUit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../stylesUit" -import "." as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls SpinBox { id: spinBox diff --git a/interface/resources/qml/controlsUit/Switch.qml b/interface/resources/qml/controls-uit/Switch.qml similarity index 99% rename from interface/resources/qml/controlsUit/Switch.qml rename to interface/resources/qml/controls-uit/Switch.qml index 0961ef2500..bfe86b1420 100644 --- a/interface/resources/qml/controlsUit/Switch.qml +++ b/interface/resources/qml/controls-uit/Switch.qml @@ -11,7 +11,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 as Original -import "../stylesUit" +import "../styles-uit" Item { id: rootSwitch; diff --git a/interface/resources/qml/controlsUit/Table.qml b/interface/resources/qml/controls-uit/Table.qml similarity index 99% rename from interface/resources/qml/controlsUit/Table.qml rename to interface/resources/qml/controls-uit/Table.qml index ab74361046..ce4e1c376a 100644 --- a/interface/resources/qml/controlsUit/Table.qml +++ b/interface/resources/qml/controls-uit/Table.qml @@ -13,7 +13,7 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Controls 2.3 as QQC2 -import "../stylesUit" +import "../styles-uit" TableView { id: tableView diff --git a/interface/resources/qml/controlsUit/TabletContentSection.qml b/interface/resources/qml/controls-uit/TabletContentSection.qml similarity index 99% rename from interface/resources/qml/controlsUit/TabletContentSection.qml rename to interface/resources/qml/controls-uit/TabletContentSection.qml index dccaf31bbe..c34f4afdd6 100644 --- a/interface/resources/qml/controlsUit/TabletContentSection.qml +++ b/interface/resources/qml/controls-uit/TabletContentSection.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../stylesUit" +import "../styles-uit" Column { property string name: "Content Section" diff --git a/interface/resources/qml/controlsUit/TabletHeader.qml b/interface/resources/qml/controls-uit/TabletHeader.qml similarity index 96% rename from interface/resources/qml/controlsUit/TabletHeader.qml rename to interface/resources/qml/controls-uit/TabletHeader.qml index f626700742..56203de286 100644 --- a/interface/resources/qml/controlsUit/TabletHeader.qml +++ b/interface/resources/qml/controls-uit/TabletHeader.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../stylesUit" +import "../styles-uit" Rectangle { diff --git a/interface/resources/qml/controlsUit/TextAction.qml b/interface/resources/qml/controls-uit/TextAction.qml similarity index 96% rename from interface/resources/qml/controlsUit/TextAction.qml rename to interface/resources/qml/controls-uit/TextAction.qml index a0a1bb7d07..1745a6c273 100644 --- a/interface/resources/qml/controlsUit/TextAction.qml +++ b/interface/resources/qml/controls-uit/TextAction.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import "../stylesUit" -import "." as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls Item { property string icon: "" diff --git a/interface/resources/qml/controlsUit/TextEdit.qml b/interface/resources/qml/controls-uit/TextEdit.qml similarity index 95% rename from interface/resources/qml/controlsUit/TextEdit.qml rename to interface/resources/qml/controls-uit/TextEdit.qml index 7446c5040f..a72a3b13d8 100644 --- a/interface/resources/qml/controlsUit/TextEdit.qml +++ b/interface/resources/qml/controls-uit/TextEdit.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "../stylesUit" +import "../styles-uit" TextEdit { diff --git a/interface/resources/qml/controlsUit/TextField.qml b/interface/resources/qml/controls-uit/TextField.qml similarity index 99% rename from interface/resources/qml/controlsUit/TextField.qml rename to interface/resources/qml/controls-uit/TextField.qml index d78f3a1340..917068ac01 100644 --- a/interface/resources/qml/controlsUit/TextField.qml +++ b/interface/resources/qml/controls-uit/TextField.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import "../stylesUit" -import "." as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls TextField { id: textField diff --git a/interface/resources/qml/controlsUit/ToolTip.qml b/interface/resources/qml/controls-uit/ToolTip.qml similarity index 100% rename from interface/resources/qml/controlsUit/ToolTip.qml rename to interface/resources/qml/controls-uit/ToolTip.qml diff --git a/interface/resources/qml/controlsUit/Tree.qml b/interface/resources/qml/controls-uit/Tree.qml similarity index 99% rename from interface/resources/qml/controlsUit/Tree.qml rename to interface/resources/qml/controls-uit/Tree.qml index f2c49095b1..5199a10a27 100644 --- a/interface/resources/qml/controlsUit/Tree.qml +++ b/interface/resources/qml/controls-uit/Tree.qml @@ -15,7 +15,7 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Controls 2.2 as QQC2 -import "../stylesUit" +import "../styles-uit" TreeView { id: treeView diff --git a/interface/resources/qml/controlsUit/VerticalSpacer.qml b/interface/resources/qml/controls-uit/VerticalSpacer.qml similarity index 94% rename from interface/resources/qml/controlsUit/VerticalSpacer.qml rename to interface/resources/qml/controls-uit/VerticalSpacer.qml index 4c93aa1801..2df65f1002 100644 --- a/interface/resources/qml/controlsUit/VerticalSpacer.qml +++ b/interface/resources/qml/controls-uit/VerticalSpacer.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../stylesUit" +import "../styles-uit" Item { id: root diff --git a/interface/resources/qml/controlsUit/WebGlyphButton.qml b/interface/resources/qml/controls-uit/WebGlyphButton.qml similarity index 98% rename from interface/resources/qml/controlsUit/WebGlyphButton.qml rename to interface/resources/qml/controls-uit/WebGlyphButton.qml index 7739ecd5e7..fd7cd001b2 100644 --- a/interface/resources/qml/controlsUit/WebGlyphButton.qml +++ b/interface/resources/qml/controls-uit/WebGlyphButton.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 as Original -import "../stylesUit" +import "../styles-uit" Original.Button { id: control diff --git a/interface/resources/qml/controlsUit/WebSpinner.qml b/interface/resources/qml/controls-uit/WebSpinner.qml similarity index 100% rename from interface/resources/qml/controlsUit/WebSpinner.qml rename to interface/resources/qml/controls-uit/WebSpinner.qml diff --git a/interface/resources/qml/controlsUit/WebView.qml b/interface/resources/qml/controls-uit/WebView.qml similarity index 100% rename from interface/resources/qml/controlsUit/WebView.qml rename to interface/resources/qml/controls-uit/WebView.qml diff --git a/interface/resources/qml/controlsUit/qmldir b/interface/resources/qml/controls-uit/qmldir similarity index 100% rename from interface/resources/qml/controlsUit/qmldir rename to interface/resources/qml/controls-uit/qmldir diff --git a/interface/resources/qml/controls/Button.qml b/interface/resources/qml/controls/Button.qml index b677822c0e..6cbdec5644 100644 --- a/interface/resources/qml/controls/Button.qml +++ b/interface/resources/qml/controls/Button.qml @@ -3,6 +3,7 @@ import QtQuick.Controls 2.2 as Original import "." import "../styles" +import "../controls-uit" Original.Button { id: control diff --git a/interface/resources/qml/controls/FlickableWebViewCore.qml b/interface/resources/qml/controls/FlickableWebViewCore.qml index cce32c137a..943f15e1de 100644 --- a/interface/resources/qml/controls/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/FlickableWebViewCore.qml @@ -4,7 +4,7 @@ import QtWebChannel 1.0 import QtQuick.Controls 2.2 -import stylesUit 1.0 as StylesUIt +import "../styles-uit" as StylesUIt Item { id: flick diff --git a/interface/resources/qml/controls/TabletWebButton.qml b/interface/resources/qml/controls/TabletWebButton.qml index 140461d817..d016f71f2d 100644 --- a/interface/resources/qml/controls/TabletWebButton.qml +++ b/interface/resources/qml/controls/TabletWebButton.qml @@ -10,7 +10,7 @@ import Hifi 1.0 import QtQuick 2.4 -import stylesUit 1.0 +import "../styles-uit" Rectangle { property alias text: label.text diff --git a/interface/resources/qml/controls/TabletWebScreen.qml b/interface/resources/qml/controls/TabletWebScreen.qml index be11f16498..bb037ad478 100644 --- a/interface/resources/qml/controls/TabletWebScreen.qml +++ b/interface/resources/qml/controls/TabletWebScreen.qml @@ -1,5 +1,5 @@ import QtQuick 2.7 -import controlsUit 1.0 as HiFiControls +import "../controls-uit" as HiFiControls Item { id: root diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index 0c5ca37e00..db695dbfb2 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -1,8 +1,8 @@ import QtQuick 2.7 import QtWebEngine 1.5 -import controlsUit 1.0 as HiFiControls +import "../controls-uit" as HiFiControls import "../styles" as HifiStyles -import stylesUit 1.0 +import "../styles-uit" Item { id: root diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 375bcd50e0..71bf69fdc8 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -1,5 +1,5 @@ import QtQuick 2.7 -import controlsUit 1.0 as HiFiControls +import "../controls-uit" as HiFiControls Item { width: parent !== null ? parent.width : undefined diff --git a/interface/resources/qml/dialogs/AssetDialog.qml b/interface/resources/qml/dialogs/AssetDialog.qml index b8eaab0b8d..e8d28e9b37 100644 --- a/interface/resources/qml/dialogs/AssetDialog.qml +++ b/interface/resources/qml/dialogs/AssetDialog.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import Qt.labs.settings 1.0 -import stylesUit 1.0 +import "../styles-uit" import "../windows" import "assetDialog" diff --git a/interface/resources/qml/dialogs/CustomQueryDialog.qml b/interface/resources/qml/dialogs/CustomQueryDialog.qml index 026068eee1..0c86b93c4b 100644 --- a/interface/resources/qml/dialogs/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/CustomQueryDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.7; import QtQuick.Dialogs 1.2 as OriginalDialogs; import QtQuick.Controls 2.3 -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit"; +import "../styles-uit"; import "../windows"; ModalWindow { diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index b7340575dd..6651af0db3 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -16,8 +16,8 @@ import QtQuick.Controls 1.4 as QQC1 import QtQuick.Controls 2.3 import ".." -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" import "../windows" import "fileDialog" diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index 9428e3ab6e..b5ac6cab72 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Dialogs 1.2 as OriginalDialogs -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" import "../windows" import "messageDialog" diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index 9df1d0b963..fffd0e2ed9 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 +import "../controls-uit" as HifiControls +import "../styles-uit" import "../windows" import "preferences" diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index 9cfb3011bd..41ee30e6d5 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" import "../windows" ModalWindow { diff --git a/interface/resources/qml/dialogs/TabletAssetDialog.qml b/interface/resources/qml/dialogs/TabletAssetDialog.qml index b3bd45f972..897378e40c 100644 --- a/interface/resources/qml/dialogs/TabletAssetDialog.qml +++ b/interface/resources/qml/dialogs/TabletAssetDialog.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import stylesUit 1.0 +import "../styles-uit" import "../windows" import "assetDialog" diff --git a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml index c7772984ab..81a2c5c1e0 100644 --- a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Dialogs 1.2 as OriginalDialogs import QtQuick.Controls 2.3 -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" import "../windows" TabletModalWindow { diff --git a/interface/resources/qml/dialogs/TabletFileDialog.qml b/interface/resources/qml/dialogs/TabletFileDialog.qml index 3be6e30dd0..6848c230e3 100644 --- a/interface/resources/qml/dialogs/TabletFileDialog.qml +++ b/interface/resources/qml/dialogs/TabletFileDialog.qml @@ -16,8 +16,8 @@ import QtQuick.Controls 1.4 as QQC1 import QtQuick.Controls 2.3 import ".." -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" import "../windows" import "fileDialog" diff --git a/interface/resources/qml/dialogs/TabletLoginDialog.qml b/interface/resources/qml/dialogs/TabletLoginDialog.qml index 6314921286..c85b2b2ba0 100644 --- a/interface/resources/qml/dialogs/TabletLoginDialog.qml +++ b/interface/resources/qml/dialogs/TabletLoginDialog.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.5 -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" import "../windows" import "../LoginDialog" diff --git a/interface/resources/qml/dialogs/TabletMessageBox.qml b/interface/resources/qml/dialogs/TabletMessageBox.qml index 1e6f0734ad..fabe0dd247 100644 --- a/interface/resources/qml/dialogs/TabletMessageBox.qml +++ b/interface/resources/qml/dialogs/TabletMessageBox.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Dialogs 1.2 as OriginalDialogs -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" import "../windows" import "messageDialog" diff --git a/interface/resources/qml/dialogs/TabletQueryDialog.qml b/interface/resources/qml/dialogs/TabletQueryDialog.qml index 8f63730b8e..5746a3d67c 100644 --- a/interface/resources/qml/dialogs/TabletQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletQueryDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Dialogs 1.2 as OriginalDialogs import QtQuick.Controls 2.3 -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" import "../windows" TabletModalWindow { diff --git a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml index da976ef3e1..c3e842bc2f 100644 --- a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml +++ b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 import QtQuick.Controls 1.5 as QQC1 -import controlsUit 1.0 -import stylesUit 1.0 +import "../../controls-uit" +import "../../styles-uit" import "../fileDialog" diff --git a/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml b/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml index 6c042b5598..50a10974b5 100644 --- a/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml +++ b/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import controlsUit 1.0 +import "../../controls-uit" ComboBox { id: root diff --git a/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml b/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml index f5715fa2c2..8411980db7 100644 --- a/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml +++ b/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtQuick.Dialogs 1.2 -import controlsUit 1.0 +import "../../controls-uit" Button { property var dialog; diff --git a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml index 9505e70530..0efc3776b3 100644 --- a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml +++ b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import controlsUit 1.0 +import "../../controls-uit" import "../../hifi/tablet/tabletWindows/preferences" Preference { diff --git a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml index 6059f8ff1c..2cf50891c9 100644 --- a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../dialogs" -import controlsUit 1.0 +import "../../controls-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml index 09c5b4329d..454a9124ae 100644 --- a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import TabletScriptingInterface 1.0 -import controlsUit 1.0 +import "../../controls-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml index f6f840bbe8..e2172d8eda 100644 --- a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import TabletScriptingInterface 1.0 -import controlsUit 1.0 +import "../../controls-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml index 98cb397976..3b3efaf520 100644 --- a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import controlsUit 1.0 as HiFiControls -import stylesUit 1.0 +import "../../controls-uit" as HiFiControls +import "../../styles-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/EditablePreference.qml b/interface/resources/qml/dialogs/preferences/EditablePreference.qml index e0c79ebba0..8acf8e1f76 100644 --- a/interface/resources/qml/dialogs/preferences/EditablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/EditablePreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../dialogs" -import controlsUit 1.0 +import "../../controls-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/PrimaryHandPreference.qml b/interface/resources/qml/dialogs/preferences/PrimaryHandPreference.qml index f963003c59..cfc2e94ed9 100644 --- a/interface/resources/qml/dialogs/preferences/PrimaryHandPreference.qml +++ b/interface/resources/qml/dialogs/preferences/PrimaryHandPreference.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import controlsUit 1.0 +import "../../controls-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml b/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml index 0a09d8d609..103904a666 100644 --- a/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml +++ b/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import controlsUit 1.0 -import stylesUit 1.0 +import "../../controls-uit" +import "../../styles-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index a9b755ad83..c2c6583b7e 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import Hifi 1.0 -import controlsUit 1.0 as HiFiControls -import stylesUit 1.0 +import "../../controls-uit" as HiFiControls +import "../../styles-uit" import "." Preference { diff --git a/interface/resources/qml/dialogs/preferences/SliderPreference.qml b/interface/resources/qml/dialogs/preferences/SliderPreference.qml index c8a2aae158..2bdda09fc3 100644 --- a/interface/resources/qml/dialogs/preferences/SliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SliderPreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../dialogs" -import controlsUit 1.0 +import "../../controls-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml index 1b080c2759..b2c334b674 100644 --- a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import controlsUit 1.0 +import "../../controls-uit" Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml b/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml index cbc804d9d7..126e62fc30 100644 --- a/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../dialogs" -import controlsUit 1.0 +import "../../controls-uit" Preference { id: root diff --git a/interface/resources/qml/hifi/+android/ActionBar.qml b/interface/resources/qml/hifi/+android/ActionBar.qml index 3c58156f30..d487901d6f 100644 --- a/interface/resources/qml/hifi/+android/ActionBar.qml +++ b/interface/resources/qml/hifi/+android/ActionBar.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/+android/AudioBar.qml b/interface/resources/qml/hifi/+android/AudioBar.qml index 912572fdf8..6cc17fccf7 100644 --- a/interface/resources/qml/hifi/+android/AudioBar.qml +++ b/interface/resources/qml/hifi/+android/AudioBar.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/+android/AvatarOption.qml b/interface/resources/qml/hifi/+android/AvatarOption.qml index 7eba3c2a67..85d7e52eb2 100644 --- a/interface/resources/qml/hifi/+android/AvatarOption.qml +++ b/interface/resources/qml/hifi/+android/AvatarOption.qml @@ -11,7 +11,7 @@ import QtQuick.Layouts 1.3 import QtQuick 2.5 -import controlsUit 1.0 as HifiControlsUit +import "../controls-uit" as HifiControlsUit ColumnLayout { id: itemRoot diff --git a/interface/resources/qml/hifi/+android/StatsBar.qml b/interface/resources/qml/hifi/+android/StatsBar.qml index 64e93b4a08..aee438b44f 100644 --- a/interface/resources/qml/hifi/+android/StatsBar.qml +++ b/interface/resources/qml/hifi/+android/StatsBar.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/+android/WindowHeader.qml b/interface/resources/qml/hifi/+android/WindowHeader.qml index 5316fc4786..4ec0a0c6e6 100644 --- a/interface/resources/qml/hifi/+android/WindowHeader.qml +++ b/interface/resources/qml/hifi/+android/WindowHeader.qml @@ -16,8 +16,8 @@ import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import "." import "../styles" as HifiStyles -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../styles-uit" +import "../controls-uit" as HifiControlsUit import "../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/+android/bottomHudOptions.qml b/interface/resources/qml/hifi/+android/bottomHudOptions.qml index 6b830d94c2..22beccf531 100644 --- a/interface/resources/qml/hifi/+android/bottomHudOptions.qml +++ b/interface/resources/qml/hifi/+android/bottomHudOptions.qml @@ -16,8 +16,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import "../../styles" as HifiStyles -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls import ".." import "." diff --git a/interface/resources/qml/hifi/+android/modesbar.qml b/interface/resources/qml/hifi/+android/modesbar.qml index 1bf04fb8d9..994bf1efe4 100644 --- a/interface/resources/qml/hifi/+android/modesbar.qml +++ b/interface/resources/qml/hifi/+android/modesbar.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index ad337a6361..1a7f5bac40 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -14,8 +14,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls import "../windows" as Windows import "../dialogs" diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index 39590748cf..aea5931627 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQml.Models 2.1 import QtGraphicalEffects 1.0 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 +import "../controls-uit" as HifiControls +import "../styles-uit" import "avatarapp" Rectangle { diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 7f29324416..83bf1e2c54 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -17,7 +17,7 @@ import QtGraphicalEffects 1.0 import TabletScriptingInterface 1.0 import "toolbars" -import stylesUit 1.0 +import "../styles-uit" Item { id: root; diff --git a/interface/resources/qml/hifi/ComboDialog.qml b/interface/resources/qml/hifi/ComboDialog.qml index 74d9c1019b..e5dc8a9c1a 100644 --- a/interface/resources/qml/hifi/ComboDialog.qml +++ b/interface/resources/qml/hifi/ComboDialog.qml @@ -10,8 +10,8 @@ // import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 +import "../styles-uit" +import "../controls-uit" Item { property var dialogTitleText : ""; diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 511d9377e5..4d342fe775 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -8,7 +8,7 @@ import "../desktop" as OriginalDesktop import ".." import "." import "./toolbars" -import controlsUit 1.0 +import "../controls-uit" OriginalDesktop.Desktop { id: desktop diff --git a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml index 048add24e5..9e9dcc75b2 100644 --- a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml +++ b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import stylesUit 1.0 +import "../styles-uit" Item { property alias text: popupText.text diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index 4cfd4804b3..346481fe1f 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -15,7 +15,7 @@ import Hifi 1.0 import QtQuick 2.5 import QtGraphicalEffects 1.0 import "toolbars" -import stylesUit 1.0 +import "../styles-uit" import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. Column { diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index 68bebdd041..8a18d88842 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import stylesUit 1.0 +import "../styles-uit" Item { property alias text: popupText.text diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 242ca5ab57..dfa6555150 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -13,8 +13,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls import "toolbars" // references Users, UserActivityLogger, MyAvatar, Vec3, Quat, AddressManager, Account from root context diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 368beaab47..1384cb8711 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -15,8 +15,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../styles-uit" +import "../controls-uit" as HifiControlsUit import "../controls" as HifiControls import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. diff --git a/interface/resources/qml/hifi/SkyboxChanger.qml b/interface/resources/qml/hifi/SkyboxChanger.qml index a66fc38415..f0c97a11a3 100644 --- a/interface/resources/qml/hifi/SkyboxChanger.qml +++ b/interface/resources/qml/hifi/SkyboxChanger.qml @@ -10,8 +10,8 @@ // import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls import QtQuick.Controls 2.2 Item { diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 09b722b906..4bf80e410b 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.7 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../styles-uit" +import "../controls-uit" as HifiControlsUit import "../controls" as HifiControls // references HMD, XXX from root context diff --git a/interface/resources/qml/hifi/TabletTextButton.qml b/interface/resources/qml/hifi/TabletTextButton.qml index 6c9e0331df..e5ff1d381d 100644 --- a/interface/resources/qml/hifi/TabletTextButton.qml +++ b/interface/resources/qml/hifi/TabletTextButton.qml @@ -10,7 +10,7 @@ import Hifi 1.0 import QtQuick 2.4 -import stylesUit 1.0 +import "../styles-uit" Rectangle { property alias text: label.text diff --git a/interface/resources/qml/hifi/TextButton.qml b/interface/resources/qml/hifi/TextButton.qml index 61588a9603..02e49d86e4 100644 --- a/interface/resources/qml/hifi/TextButton.qml +++ b/interface/resources/qml/hifi/TextButton.qml @@ -9,7 +9,7 @@ // import Hifi 1.0 import QtQuick 2.4 -import stylesUit 1.0 +import "../styles-uit" Rectangle { property alias text: label.text; diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index c05de26471..ab93752d92 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -18,8 +18,8 @@ import QtGraphicalEffects 1.0 import QtWebEngine 1.5 import QtWebChannel 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../styles-uit" +import "../controls-uit" as HifiControls import "../windows" import "../controls" diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index c8dd83cd62..f4a708567a 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -15,8 +15,8 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls import "../../windows" import "./" as AudioControls diff --git a/interface/resources/qml/hifi/audio/AudioTabButton.qml b/interface/resources/qml/hifi/audio/AudioTabButton.qml index 32331ccb6e..3a3ed90f5e 100644 --- a/interface/resources/qml/hifi/audio/AudioTabButton.qml +++ b/interface/resources/qml/hifi/audio/AudioTabButton.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 +import "../../controls-uit" as HifiControls +import "../../styles-uit" TabButton { id: control diff --git a/interface/resources/qml/hifi/audio/CheckBox.qml b/interface/resources/qml/hifi/audio/CheckBox.qml index 5ab62a5091..3a954d4004 100644 --- a/interface/resources/qml/hifi/audio/CheckBox.qml +++ b/interface/resources/qml/hifi/audio/CheckBox.qml @@ -11,7 +11,7 @@ import QtQuick 2.7 -import controlsUit 1.0 as HifiControls +import "../../controls-uit" as HifiControls HifiControls.CheckBoxQQC2 { color: "white" diff --git a/interface/resources/qml/hifi/audio/PlaySampleSound.qml b/interface/resources/qml/hifi/audio/PlaySampleSound.qml index cfe55af9c4..2b9599a3cc 100644 --- a/interface/resources/qml/hifi/audio/PlaySampleSound.qml +++ b/interface/resources/qml/hifi/audio/PlaySampleSound.qml @@ -13,8 +13,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls RowLayout { property var sound: null; diff --git a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml index 0740914440..5fff14e4a1 100644 --- a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml +++ b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml @@ -1,8 +1,9 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit +import "../../controls" as HifiControls Rectangle { id: root; diff --git a/interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml b/interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml index d3c9cd1d5f..9d9db010fb 100644 --- a/interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml +++ b/interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml @@ -1,6 +1,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 +import "../../styles-uit" ShadowRectangle { id: header diff --git a/interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml b/interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml index 36cb4b1080..f66c7121cb 100644 --- a/interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml +++ b/interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 import QtQuick.Window 2.2 -import stylesUit 1.0 +import "../../styles-uit" QtObject { readonly property QtObject colors: QtObject { diff --git a/interface/resources/qml/hifi/avatarapp/AvatarWearablesIndicator.qml b/interface/resources/qml/hifi/avatarapp/AvatarWearablesIndicator.qml index 8b28d4c66b..cb73e9fe71 100644 --- a/interface/resources/qml/hifi/avatarapp/AvatarWearablesIndicator.qml +++ b/interface/resources/qml/hifi/avatarapp/AvatarWearablesIndicator.qml @@ -1,6 +1,6 @@ import QtQuick 2.9 -import controlsUit 1.0 -import stylesUit 1.0 +import "../../controls-uit" +import "../../styles-uit" ShadowRectangle { property int wearablesCount: 0 diff --git a/interface/resources/qml/hifi/avatarapp/BlueButton.qml b/interface/resources/qml/hifi/avatarapp/BlueButton.qml index 0cc84d5ba0..e668951517 100644 --- a/interface/resources/qml/hifi/avatarapp/BlueButton.qml +++ b/interface/resources/qml/hifi/avatarapp/BlueButton.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit HifiControlsUit.Button { HifiConstants { diff --git a/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml b/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml index 780981a5a3..1387c0791a 100644 --- a/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml +++ b/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml @@ -1,7 +1,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls Rectangle { diff --git a/interface/resources/qml/hifi/avatarapp/InputField.qml b/interface/resources/qml/hifi/avatarapp/InputField.qml index 2020d56c96..905518ef0f 100644 --- a/interface/resources/qml/hifi/avatarapp/InputField.qml +++ b/interface/resources/qml/hifi/avatarapp/InputField.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit TextField { id: textField diff --git a/interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml b/interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml index 6c2101498c..4b868b47ce 100644 --- a/interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml +++ b/interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml @@ -1,5 +1,5 @@ -import controlsUit 1.0 as HifiControlsUit -import stylesUit 1.0 +import "../../controls-uit" as HifiControlsUit +import "../../styles-uit" import QtQuick 2.0 import QtQuick.Controls 2.2 diff --git a/interface/resources/qml/hifi/avatarapp/MessageBox.qml b/interface/resources/qml/hifi/avatarapp/MessageBox.qml index eb28745b1a..f111303214 100644 --- a/interface/resources/qml/hifi/avatarapp/MessageBox.qml +++ b/interface/resources/qml/hifi/avatarapp/MessageBox.qml @@ -1,7 +1,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls Rectangle { diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index 38acce2b2c..71bfbb084d 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -2,8 +2,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls Rectangle { diff --git a/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml b/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml index a2c84fad47..c2d84bb371 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml @@ -1,4 +1,4 @@ -import stylesUit 1.0 +import "../../styles-uit" import QtQuick 2.9 import QtGraphicalEffects 1.0 diff --git a/interface/resources/qml/hifi/avatarapp/ShadowImage.qml b/interface/resources/qml/hifi/avatarapp/ShadowImage.qml index 51e1043702..3995446e49 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowImage.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowImage.qml @@ -1,4 +1,4 @@ -import stylesUit 1.0 +import "../../styles-uit" import QtQuick 2.9 import QtGraphicalEffects 1.0 diff --git a/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml b/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml index 3968fcb1ff..741fce3d8d 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml @@ -1,4 +1,4 @@ -import stylesUit 1.0 +import "../../styles-uit" import QtQuick 2.9 import QtGraphicalEffects 1.0 diff --git a/interface/resources/qml/hifi/avatarapp/SquareLabel.qml b/interface/resources/qml/hifi/avatarapp/SquareLabel.qml index 69aff47373..e2c456ec04 100644 --- a/interface/resources/qml/hifi/avatarapp/SquareLabel.qml +++ b/interface/resources/qml/hifi/avatarapp/SquareLabel.qml @@ -1,5 +1,5 @@ -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import QtQuick 2.9 import QtGraphicalEffects 1.0 diff --git a/interface/resources/qml/hifi/avatarapp/Vector3.qml b/interface/resources/qml/hifi/avatarapp/Vector3.qml index 698123104f..d77665f992 100644 --- a/interface/resources/qml/hifi/avatarapp/Vector3.qml +++ b/interface/resources/qml/hifi/avatarapp/Vector3.qml @@ -1,7 +1,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit import "../../controls" as HifiControls Row { diff --git a/interface/resources/qml/hifi/avatarapp/WhiteButton.qml b/interface/resources/qml/hifi/avatarapp/WhiteButton.qml index d0a4a152db..dc729ae097 100644 --- a/interface/resources/qml/hifi/avatarapp/WhiteButton.qml +++ b/interface/resources/qml/hifi/avatarapp/WhiteButton.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../styles-uit" +import "../../controls-uit" as HifiControlsUit HifiControlsUit.Button { HifiConstants { diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index ac6aa3d56c..b13f23f17d 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls import "../wallet" as HifiWallet import "../common" as HifiCommerceCommon diff --git a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml index 8cfea0bcd9..9d9216c461 100644 --- a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml +++ b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml index 429f993817..1b77dcd3e9 100644 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.7 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml index 6002747596..5f874d3f04 100644 --- a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml +++ b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml index 1eb8af31e6..41eacd68d5 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml @@ -16,8 +16,8 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../../styles-uit" +import "../../../../controls-uit" as HifiControlsUit import "../../../../controls" as HifiControls import "../../wallet" as HifiWallet diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml index 9e1a967d50..9293dc83ab 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml @@ -15,8 +15,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.6 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../../styles-uit" +import "../../../../controls-uit" as HifiControlsUit import "../../../../controls" as HifiControls import "../" as HifiCommerceCommon diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml index f204d943fe..0a5c3e8053 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml @@ -15,8 +15,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.6 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../../styles-uit" +import "../../../../controls-uit" as HifiControlsUit import "../../../../controls" as HifiControls import "../" as HifiCommerceCommon import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index 7721dc3142..d24344b40a 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls import "../wallet" as HifiWallet diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index ee9858103c..c3d87ca2f5 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -17,8 +17,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.0 import QtQuick.Layouts 1.1 import Hifi 1.0 as Hifi -import stylesUit 1.0 as HifiStylesUit -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" as HifiStylesUit +import "../../../controls-uit" as HifiControlsUit diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index 9d2df1a865..eeb9ac3c54 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -15,8 +15,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls import "../wallet" as HifiWallet import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 8b7ebcf768..015ec3a172 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. import "../wallet" as HifiWallet diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml index 24ca5407b2..6d8fc3c33f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.7 import QtQuick.Controls 2.2 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml index b1fbb91c80..eadf1ca8a2 100644 --- a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml +++ b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml index 6ddfe0da1c..8451c90836 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index 86d50e87ec..c4abd40d2a 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls import "../common" as HifiCommerceCommon diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index 179ffcf707..e052b78876 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index f0b1ecd4e0..14ac696ef7 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index da0d0d59d5..01df18352b 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml index 82933eebcb..599c6a1851 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 0cca581c4f..cbb77883df 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls import "../common" as HifiCommerceCommon import "../common/sendAsset" diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml b/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml index e7163a3641..19065ee542 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import "../common" as HifiCommerceCommon -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit Item { diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 1e78027f91..627da1d43f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -15,8 +15,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 import QtQuick.Controls 2.2 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml index b793075843..dc6ce45a74 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControlsUit +import "../../../styles-uit" +import "../../../controls-uit" as HifiControlsUit import "../../../controls" as HifiControls import "../common" as HifiCommerceCommon diff --git a/interface/resources/qml/hifi/dialogs/AboutDialog.qml b/interface/resources/qml/hifi/dialogs/AboutDialog.qml index 3d5d1a94a3..b8e6e89aec 100644 --- a/interface/resources/qml/hifi/dialogs/AboutDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AboutDialog.qml @@ -10,7 +10,7 @@ import QtQuick 2.8 -import stylesUit 1.0 +import "../../styles-uit" import "../../windows" ScrollingWindow { diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index be17e65ab3..9a180a66f6 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls import "../../windows" import "../" diff --git a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml index d26bf81e57..579aa1cb1e 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import stylesUit 1.0 +import "../../styles-uit" Rectangle { width: 480 diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index f665032b01..0eeb252049 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -14,8 +14,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls import "../../windows" import ".." diff --git a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml index 763f56b92b..afe06897df 100644 --- a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml +++ b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls import "../../windows" Rectangle { diff --git a/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml b/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml index 213dca8b48..50df4dedbc 100644 --- a/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml +++ b/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import Hifi 1.0 as Hifi -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls Rectangle { id: root diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml index 4cfc99e0eb..24798af21a 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls import "../../windows" Rectangle { diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml index e86dfd7554..d5c5a5ee02 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls Column { id: root diff --git a/interface/resources/qml/hifi/dialogs/TabletLODTools.qml b/interface/resources/qml/hifi/dialogs/TabletLODTools.qml index bb3d668850..ab53f03477 100644 --- a/interface/resources/qml/hifi/dialogs/TabletLODTools.qml +++ b/interface/resources/qml/hifi/dialogs/TabletLODTools.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls import "../../windows" Rectangle { diff --git a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml index 6cd220307d..018c8f5737 100644 --- a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls import "../../windows" import "../" diff --git a/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml b/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml index b1aa8e5c45..ce1abc6154 100644 --- a/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml +++ b/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml @@ -1,7 +1,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 -import controlsUit 1.0 as HifiControls +import "../../../controls-uit" as HifiControls Column { width: pane.contentWidth diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml index 6b2aa331e8..e3115a5738 100644 --- a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -10,9 +10,9 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import stylesUit 1.0 +import "../../styles-uit" import "../../controls" -import controlsUit 1.0 as HifiControls +import "../../controls-uit" as HifiControls Rectangle { diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index b8bbd71f33..6706830537 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -11,9 +11,9 @@ import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import Qt.labs.settings 1.0 -import stylesUit 1.0 +import "../../styles-uit" import "../../controls" -import controlsUit 1.0 as HifiControls +import "../../controls-uit" as HifiControls import "../../dialogs" import "../../dialogs/preferences" import "tabletWindows" diff --git a/interface/resources/qml/hifi/tablet/EditEntityList.qml b/interface/resources/qml/hifi/tablet/EditEntityList.qml index d2fb99ea0a..d484885103 100644 --- a/interface/resources/qml/hifi/tablet/EditEntityList.qml +++ b/interface/resources/qml/hifi/tablet/EditEntityList.qml @@ -4,8 +4,8 @@ import QtWebChannel 1.0 import "../../controls" import "../toolbars" import QtGraphicalEffects 1.0 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 +import "../../controls-uit" as HifiControls +import "../../styles-uit" WebView { diff --git a/interface/resources/qml/hifi/tablet/EditTabButton.qml b/interface/resources/qml/hifi/tablet/EditTabButton.qml index 5fc4341eb8..13894f4d15 100644 --- a/interface/resources/qml/hifi/tablet/EditTabButton.qml +++ b/interface/resources/qml/hifi/tablet/EditTabButton.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 +import "../../controls-uit" as HifiControls +import "../../styles-uit" TabButton { id: control diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index 332fab6112..4ac8755570 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -4,8 +4,8 @@ import QtWebChannel 1.0 import "../../controls" import "../toolbars" import QtGraphicalEffects 1.0 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 +import "../../controls-uit" as HifiControls +import "../../styles-uit" TabBar { id: editTabView diff --git a/interface/resources/qml/hifi/tablet/EditToolsTabView.qml b/interface/resources/qml/hifi/tablet/EditToolsTabView.qml index 76078b4afd..00084b8ca9 100644 --- a/interface/resources/qml/hifi/tablet/EditToolsTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditToolsTabView.qml @@ -4,8 +4,8 @@ import QtWebChannel 1.0 import "../../controls" import "../toolbars" import QtGraphicalEffects 1.0 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 +import "../../controls-uit" as HifiControls +import "../../styles-uit" TabBar { id: editTabView diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index 9b63a612a8..527a6cacb4 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -9,8 +9,8 @@ import QtQuick 2.5 import Hifi 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../styles-uit" +import "../../controls-uit" as HifiControls import "../../windows" import "../../dialogs" diff --git a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml index dde372648b..526a42f8e2 100644 --- a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml @@ -13,8 +13,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Dialogs 1.2 as OriginalDialogs -import stylesUit 1.0 -import controlsUit 1.0 +import "../../styles-uit" +import "../../controls-uit" import "../dialogs" Rectangle { diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index 9540979479..553a4fd59f 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import QtQuick.Dialogs 1.2 as OriginalDialogs -import stylesUit 1.0 -import controlsUit 1.0 +import "../../styles-uit" +import "../../controls-uit" import "../dialogs" Rectangle { diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 684d12c9b4..c2aff08e35 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -9,9 +9,9 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import stylesUit 1.0 +import "../../styles-uit" import "../../controls" -import controlsUit 1.0 as HifiControls +import "../../controls-uit" as HifiControls import "." diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 0f26ba20aa..3d518289fb 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -18,8 +18,8 @@ import "../../styles" import "../../windows" import "../" import "../toolbars" -import stylesUit 1.0 as HifiStyles -import controlsUit 1.0 as HifiControls +import "../../styles-uit" as HifiStyles +import "../../controls-uit" as HifiControls import QtQuick.Controls 2.2 as QQC2 import QtQuick.Templates 2.2 as T diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 934ed91995..1922b02f93 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -6,7 +6,7 @@ import QtQuick.Layouts 1.3 import TabletScriptingInterface 1.0 import "." -import stylesUit 1.0 +import "../../styles-uit" import "../audio" as HifiAudio Item { diff --git a/interface/resources/qml/hifi/tablet/TabletMenu.qml b/interface/resources/qml/hifi/tablet/TabletMenu.qml index 267fb9f0cf..6540d53fca 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenu.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenu.qml @@ -7,7 +7,7 @@ import QtWebEngine 1.1 import "." -import stylesUit 1.0 +import "../../styles-uit" import "../../controls" FocusScope { diff --git a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml index 25db90c771..74f175e049 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import controlsUit 1.0 -import stylesUit 1.0 +import "../../controls-uit" +import "../../styles-uit" Item { id: root diff --git a/interface/resources/qml/hifi/tablet/TabletMenuView.qml b/interface/resources/qml/hifi/tablet/TabletMenuView.qml index 73b0405984..b632a17e57 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuView.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuView.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import TabletScriptingInterface 1.0 -import stylesUit 1.0 +import "../../styles-uit" import "." FocusScope { diff --git a/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml b/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml index ce4e641476..d69d760b95 100644 --- a/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import controlsUit 1.0 as HifiControls -import stylesUit 1.0 +import "../../controls-uit" as HifiControls +import "../../styles-uit" import "../dialogs/content" Item { diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml index 8e91655dda..871d1c92a9 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml @@ -16,8 +16,8 @@ import QtQuick.Controls 1.4 as QQC1 import QtQuick.Controls 2.3 import ".." -import controlsUit 1.0 -import stylesUit 1.0 +import "../../../controls-uit" +import "../../../styles-uit" import "../../../windows" import "../../../dialogs/fileDialog" diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index 57ca705352..3708f75114 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import "." import "./preferences" -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "../../../styles-uit" +import "../../../controls-uit" as HifiControls Item { id: dialog diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml index 57fdeb482b..6ac3f706e4 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import Hifi 1.0 import "../../../../dialogs/preferences" -import controlsUit 1.0 as HiFiControls -import stylesUit 1.0 +import "../../../../controls-uit" as HiFiControls +import "../../../../styles-uit" import "." Preference { diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletBrowsablePreference.qml b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletBrowsablePreference.qml index 36b927f5f9..8c0e934971 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletBrowsablePreference.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletBrowsablePreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../../../dialogs" -import controlsUit 1.0 +import "../../../../controls-uit" import "../" Preference { diff --git a/interface/resources/qml/stylesUit/+android/HifiConstants.qml b/interface/resources/qml/styles-uit/+android/HifiConstants.qml similarity index 100% rename from interface/resources/qml/stylesUit/+android/HifiConstants.qml rename to interface/resources/qml/styles-uit/+android/HifiConstants.qml diff --git a/interface/resources/qml/stylesUit/AnonymousProRegular.qml b/interface/resources/qml/styles-uit/AnonymousProRegular.qml similarity index 100% rename from interface/resources/qml/stylesUit/AnonymousProRegular.qml rename to interface/resources/qml/styles-uit/AnonymousProRegular.qml diff --git a/interface/resources/qml/stylesUit/ButtonLabel.qml b/interface/resources/qml/styles-uit/ButtonLabel.qml similarity index 100% rename from interface/resources/qml/stylesUit/ButtonLabel.qml rename to interface/resources/qml/styles-uit/ButtonLabel.qml diff --git a/interface/resources/qml/stylesUit/FiraSansRegular.qml b/interface/resources/qml/styles-uit/FiraSansRegular.qml similarity index 100% rename from interface/resources/qml/stylesUit/FiraSansRegular.qml rename to interface/resources/qml/styles-uit/FiraSansRegular.qml diff --git a/interface/resources/qml/stylesUit/FiraSansSemiBold.qml b/interface/resources/qml/styles-uit/FiraSansSemiBold.qml similarity index 100% rename from interface/resources/qml/stylesUit/FiraSansSemiBold.qml rename to interface/resources/qml/styles-uit/FiraSansSemiBold.qml diff --git a/interface/resources/qml/stylesUit/HiFiGlyphs.qml b/interface/resources/qml/styles-uit/HiFiGlyphs.qml similarity index 100% rename from interface/resources/qml/stylesUit/HiFiGlyphs.qml rename to interface/resources/qml/styles-uit/HiFiGlyphs.qml diff --git a/interface/resources/qml/stylesUit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml similarity index 100% rename from interface/resources/qml/stylesUit/HifiConstants.qml rename to interface/resources/qml/styles-uit/HifiConstants.qml diff --git a/interface/resources/qml/stylesUit/IconButton.qml b/interface/resources/qml/styles-uit/IconButton.qml similarity index 100% rename from interface/resources/qml/stylesUit/IconButton.qml rename to interface/resources/qml/styles-uit/IconButton.qml diff --git a/interface/resources/qml/stylesUit/InfoItem.qml b/interface/resources/qml/styles-uit/InfoItem.qml similarity index 100% rename from interface/resources/qml/stylesUit/InfoItem.qml rename to interface/resources/qml/styles-uit/InfoItem.qml diff --git a/interface/resources/qml/stylesUit/InputLabel.qml b/interface/resources/qml/styles-uit/InputLabel.qml similarity index 100% rename from interface/resources/qml/stylesUit/InputLabel.qml rename to interface/resources/qml/styles-uit/InputLabel.qml diff --git a/interface/resources/qml/stylesUit/ListItem.qml b/interface/resources/qml/styles-uit/ListItem.qml similarity index 100% rename from interface/resources/qml/stylesUit/ListItem.qml rename to interface/resources/qml/styles-uit/ListItem.qml diff --git a/interface/resources/qml/stylesUit/Logs.qml b/interface/resources/qml/styles-uit/Logs.qml similarity index 100% rename from interface/resources/qml/stylesUit/Logs.qml rename to interface/resources/qml/styles-uit/Logs.qml diff --git a/interface/resources/qml/stylesUit/OverlayTitle.qml b/interface/resources/qml/styles-uit/OverlayTitle.qml similarity index 100% rename from interface/resources/qml/stylesUit/OverlayTitle.qml rename to interface/resources/qml/styles-uit/OverlayTitle.qml diff --git a/interface/resources/qml/stylesUit/RalewayBold.qml b/interface/resources/qml/styles-uit/RalewayBold.qml similarity index 100% rename from interface/resources/qml/stylesUit/RalewayBold.qml rename to interface/resources/qml/styles-uit/RalewayBold.qml diff --git a/interface/resources/qml/stylesUit/RalewayLight.qml b/interface/resources/qml/styles-uit/RalewayLight.qml similarity index 100% rename from interface/resources/qml/stylesUit/RalewayLight.qml rename to interface/resources/qml/styles-uit/RalewayLight.qml diff --git a/interface/resources/qml/stylesUit/RalewayRegular.qml b/interface/resources/qml/styles-uit/RalewayRegular.qml similarity index 100% rename from interface/resources/qml/stylesUit/RalewayRegular.qml rename to interface/resources/qml/styles-uit/RalewayRegular.qml diff --git a/interface/resources/qml/stylesUit/RalewaySemiBold.qml b/interface/resources/qml/styles-uit/RalewaySemiBold.qml similarity index 100% rename from interface/resources/qml/stylesUit/RalewaySemiBold.qml rename to interface/resources/qml/styles-uit/RalewaySemiBold.qml diff --git a/interface/resources/qml/stylesUit/SectionName.qml b/interface/resources/qml/styles-uit/SectionName.qml similarity index 100% rename from interface/resources/qml/stylesUit/SectionName.qml rename to interface/resources/qml/styles-uit/SectionName.qml diff --git a/interface/resources/qml/stylesUit/Separator.qml b/interface/resources/qml/styles-uit/Separator.qml similarity index 97% rename from interface/resources/qml/stylesUit/Separator.qml rename to interface/resources/qml/styles-uit/Separator.qml index d9f11e192c..4134b928a7 100644 --- a/interface/resources/qml/stylesUit/Separator.qml +++ b/interface/resources/qml/styles-uit/Separator.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "." +import "../styles-uit" Item { // Size diff --git a/interface/resources/qml/stylesUit/ShortcutText.qml b/interface/resources/qml/styles-uit/ShortcutText.qml similarity index 100% rename from interface/resources/qml/stylesUit/ShortcutText.qml rename to interface/resources/qml/styles-uit/ShortcutText.qml diff --git a/interface/resources/qml/stylesUit/TabName.qml b/interface/resources/qml/styles-uit/TabName.qml similarity index 100% rename from interface/resources/qml/stylesUit/TabName.qml rename to interface/resources/qml/styles-uit/TabName.qml diff --git a/interface/resources/qml/stylesUit/TextFieldInput.qml b/interface/resources/qml/styles-uit/TextFieldInput.qml similarity index 100% rename from interface/resources/qml/stylesUit/TextFieldInput.qml rename to interface/resources/qml/styles-uit/TextFieldInput.qml diff --git a/interface/resources/qml/stylesUit/qmldir b/interface/resources/qml/styles-uit/qmldir similarity index 100% rename from interface/resources/qml/stylesUit/qmldir rename to interface/resources/qml/styles-uit/qmldir diff --git a/interface/resources/qml/windows/Decoration.qml b/interface/resources/qml/windows/Decoration.qml index efaea6be8a..f8fd9f4e6c 100644 --- a/interface/resources/qml/windows/Decoration.qml +++ b/interface/resources/qml/windows/Decoration.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import stylesUit 1.0 +import "../styles-uit" Rectangle { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/DefaultFrame.qml b/interface/resources/qml/windows/DefaultFrame.qml index 5a366e367b..60e744bec3 100644 --- a/interface/resources/qml/windows/DefaultFrame.qml +++ b/interface/resources/qml/windows/DefaultFrame.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "." -import stylesUit 1.0 +import "../styles-uit" Frame { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/DefaultFrameDecoration.qml b/interface/resources/qml/windows/DefaultFrameDecoration.qml index fb0dd55985..1ddd83976e 100644 --- a/interface/resources/qml/windows/DefaultFrameDecoration.qml +++ b/interface/resources/qml/windows/DefaultFrameDecoration.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import stylesUit 1.0 +import "../styles-uit" Decoration { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/Fadable.qml b/interface/resources/qml/windows/Fadable.qml index 6d88fb067a..406c6be556 100644 --- a/interface/resources/qml/windows/Fadable.qml +++ b/interface/resources/qml/windows/Fadable.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import stylesUit 1.0 +import "../styles-uit" // Enable window visibility transitions FocusScope { diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml index 7b0fbf8d8c..271d4f2e07 100644 --- a/interface/resources/qml/windows/Frame.qml +++ b/interface/resources/qml/windows/Frame.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import stylesUit 1.0 +import "../styles-uit" import "../js/Utils.js" as Utils Item { diff --git a/interface/resources/qml/windows/ModalFrame.qml b/interface/resources/qml/windows/ModalFrame.qml index ae149224e3..cb23ccd5ad 100644 --- a/interface/resources/qml/windows/ModalFrame.qml +++ b/interface/resources/qml/windows/ModalFrame.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import "." -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" Frame { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/ScrollingWindow.qml b/interface/resources/qml/windows/ScrollingWindow.qml index 4cab96701e..c156b80388 100644 --- a/interface/resources/qml/windows/ScrollingWindow.qml +++ b/interface/resources/qml/windows/ScrollingWindow.qml @@ -14,8 +14,8 @@ import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import "." -import stylesUit 1.0 -import controlsUit 1.0 as HiFiControls +import "../styles-uit" +import "../controls-uit" as HiFiControls // FIXME how do I set the initial position of a window without // overriding places where the a individual client of the window diff --git a/interface/resources/qml/windows/TabletModalFrame.qml b/interface/resources/qml/windows/TabletModalFrame.qml index 1e9310eb5a..550eec8357 100644 --- a/interface/resources/qml/windows/TabletModalFrame.qml +++ b/interface/resources/qml/windows/TabletModalFrame.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import "." -import controlsUit 1.0 -import stylesUit 1.0 +import "../controls-uit" +import "../styles-uit" Rectangle { diff --git a/interface/resources/qml/windows/ToolFrame.qml b/interface/resources/qml/windows/ToolFrame.qml index bb2bada498..20c86afb5e 100644 --- a/interface/resources/qml/windows/ToolFrame.qml +++ b/interface/resources/qml/windows/ToolFrame.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import stylesUit 1.0 +import "../styles-uit" Frame { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/ToolFrameDecoration.qml b/interface/resources/qml/windows/ToolFrameDecoration.qml index 4f149037b3..ba36a2a38c 100644 --- a/interface/resources/qml/windows/ToolFrameDecoration.qml +++ b/interface/resources/qml/windows/ToolFrameDecoration.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import stylesUit 1.0 +import "../styles-uit" Decoration { id: root diff --git a/interface/resources/qml/windows/Window.qml b/interface/resources/qml/windows/Window.qml index 9f180af55d..835967c628 100644 --- a/interface/resources/qml/windows/Window.qml +++ b/interface/resources/qml/windows/Window.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import stylesUit 1.0 +import "../styles-uit" // FIXME how do I set the initial position of a window without // overriding places where the a individual client of the window diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index f67a356078..74098f69c7 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -250,7 +250,6 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) { engine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory); auto importList = engine->importPathList(); - importList.insert(importList.begin(), PathUtils::resourcesPath() + "qml/"); importList.insert(importList.begin(), PathUtils::resourcesPath()); engine->setImportPathList(importList); for (const auto& path : importList) { diff --git a/scripts/developer/tests/ControlsGallery.qml b/scripts/developer/tests/ControlsGallery.qml index 9685fa6fe8..ceb8a26dc9 100644 --- a/scripts/developer/tests/ControlsGallery.qml +++ b/scripts/developer/tests/ControlsGallery.qml @@ -2,9 +2,16 @@ import QtQuick 2.10 import QtQuick.Window 2.10 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 +import "qrc:////qml//styles-uit" as HifiStylesUit +import "qrc:////qml//controls-uit" as HifiControlsUit -import stylesUit 1.0 as HifiStylesUit -import controlsUit 1.0 as HifiControlsUit +//uncomment to use from qmlscratch tool +//import '../../../interface/resources/qml/controls-uit' as HifiControlsUit +//import '../../../interface/resources/qml/styles-uit' + +//uncomment to use with HIFI_USE_SOURCE_TREE_RESOURCES=1 +//import '../../../resources/qml/controls-uit' as HifiControlsUit +//import '../../../resources/qml/styles-uit' Item { visible: true diff --git a/scripts/developer/utilities/audio/Stats.qml b/scripts/developer/utilities/audio/Stats.qml index e2291e485d..f359e9b04c 100644 --- a/scripts/developer/utilities/audio/Stats.qml +++ b/scripts/developer/utilities/audio/Stats.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import controlsUit 1.0 as HifiControls +import "qrc:////qml//controls-uit" as HifiControls Column { id: stats diff --git a/scripts/developer/utilities/audio/TabletStats.qml b/scripts/developer/utilities/audio/TabletStats.qml index b50acabec4..2f8d212a2a 100644 --- a/scripts/developer/utilities/audio/TabletStats.qml +++ b/scripts/developer/utilities/audio/TabletStats.qml @@ -11,7 +11,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import stylesUit 1.0 + +import "qrc:////qml//styles-uit" Item { id: dialog diff --git a/scripts/developer/utilities/lib/jet/qml/TaskList.qml b/scripts/developer/utilities/lib/jet/qml/TaskList.qml index 166f604666..5b1aa0afb5 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskList.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskList.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "../jet.js" as Jet diff --git a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml index 0f083aa72c..2c75865698 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "../jet.js" as Jet diff --git a/scripts/developer/utilities/lib/plotperf/Color.qml b/scripts/developer/utilities/lib/plotperf/Color.qml index 1ad72fe2e6..15d7f9fcc9 100644 --- a/scripts/developer/utilities/lib/plotperf/Color.qml +++ b/scripts/developer/utilities/lib/plotperf/Color.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls Item { diff --git a/scripts/developer/utilities/render/antialiasing.qml b/scripts/developer/utilities/render/antialiasing.qml index 5abfd30935..1a8f9dac2d 100644 --- a/scripts/developer/utilities/render/antialiasing.qml +++ b/scripts/developer/utilities/render/antialiasing.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "configSlider" import "../lib/plotperf" diff --git a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml index bf9089d82c..41de77fb09 100644 --- a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml +++ b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls Item { diff --git a/scripts/developer/utilities/render/configSlider/RichSlider.qml b/scripts/developer/utilities/render/configSlider/RichSlider.qml index ff16cb32ad..01b14f3d48 100644 --- a/scripts/developer/utilities/render/configSlider/RichSlider.qml +++ b/scripts/developer/utilities/render/configSlider/RichSlider.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls Item { diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 64e00acdac..a9479b2935 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "configSlider" import "../lib/jet/qml" as Jet diff --git a/scripts/developer/utilities/render/engineInspector.qml b/scripts/developer/utilities/render/engineInspector.qml index 16dd8eb985..1b9941e64e 100644 --- a/scripts/developer/utilities/render/engineInspector.qml +++ b/scripts/developer/utilities/render/engineInspector.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "../lib/jet/qml" as Jet diff --git a/scripts/developer/utilities/render/highlight.qml b/scripts/developer/utilities/render/highlight.qml index d8af2a828e..88d6a807ae 100644 --- a/scripts/developer/utilities/render/highlight.qml +++ b/scripts/developer/utilities/render/highlight.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "configSlider" import "../lib/plotperf" import "highlight" diff --git a/scripts/developer/utilities/render/highlight/HighlightStyle.qml b/scripts/developer/utilities/render/highlight/HighlightStyle.qml index 475aadfdce..371b7e81f7 100644 --- a/scripts/developer/utilities/render/highlight/HighlightStyle.qml +++ b/scripts/developer/utilities/render/highlight/HighlightStyle.qml @@ -12,8 +12,8 @@ import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import "../configSlider" import "../../lib/plotperf" -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls Item { id: root diff --git a/scripts/developer/utilities/render/lod.qml b/scripts/developer/utilities/render/lod.qml index 892b43d8be..889d8db836 100644 --- a/scripts/developer/utilities/render/lod.qml +++ b/scripts/developer/utilities/render/lod.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "../lib/plotperf" import "configSlider" diff --git a/scripts/developer/utilities/render/shadow.qml b/scripts/developer/utilities/render/shadow.qml index a1d6777a68..464fe00eb9 100644 --- a/scripts/developer/utilities/render/shadow.qml +++ b/scripts/developer/utilities/render/shadow.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "configSlider" diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index c150c523f9..f74468a273 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtQuick.Dialogs 1.0 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "configSlider" import "../lib/plotperf" diff --git a/scripts/developer/utilities/workload/workloadInspector.qml b/scripts/developer/utilities/workload/workloadInspector.qml index 746a572f29..2eaa9d8133 100644 --- a/scripts/developer/utilities/workload/workloadInspector.qml +++ b/scripts/developer/utilities/workload/workloadInspector.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import stylesUit 1.0 -import controlsUit 1.0 as HifiControls +import "qrc:///qml/styles-uit" +import "qrc:///qml/controls-uit" as HifiControls import "../render/configSlider" import "../lib/jet/qml" as Jet import "../lib/plotperf" diff --git a/tests-manual/ui/qml/ControlsGalleryWindow.qml b/tests-manual/ui/qml/ControlsGalleryWindow.qml deleted file mode 100644 index 32fd62da36..0000000000 --- a/tests-manual/ui/qml/ControlsGalleryWindow.qml +++ /dev/null @@ -1,14 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Window 2.3 -import QtQuick.Controls 1.4 -import '../../../scripts/developer/tests' as Tests - -ApplicationWindow { - width: 640 - height: 480 - visible: true - - Tests.ControlsGallery { - anchors.fill: parent - } -} diff --git a/tests-manual/ui/qml/Palettes.qml b/tests-manual/ui/qml/Palettes.qml new file mode 100644 index 0000000000..2bdf6eba8b --- /dev/null +++ b/tests-manual/ui/qml/Palettes.qml @@ -0,0 +1,150 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +Rectangle { + color: "teal" + height: 512 + width: 192 + SystemPalette { id: sp; colorGroup: SystemPalette.Active } + SystemPalette { id: spi; colorGroup: SystemPalette.Inactive } + SystemPalette { id: spd; colorGroup: SystemPalette.Disabled } + + Column { + anchors.margins: 8 + anchors.fill: parent + spacing: 8 + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "base" } + Rectangle { height: parent.height; width: 16; color: sp.base } + Rectangle { height: parent.height; width: 16; color: spi.base } + Rectangle { height: parent.height; width: 16; color: spd.base } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "alternateBase" } + Rectangle { height: parent.height; width: 16; color: sp.alternateBase } + Rectangle { height: parent.height; width: 16; color: spi.alternateBase } + Rectangle { height: parent.height; width: 16; color: spd.alternateBase } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "dark" } + Rectangle { height: parent.height; width: 16; color: sp.dark } + Rectangle { height: parent.height; width: 16; color: spi.dark } + Rectangle { height: parent.height; width: 16; color: spd.dark } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "mid" } + Rectangle { height: parent.height; width: 16; color: sp.mid } + Rectangle { height: parent.height; width: 16; color: spi.mid } + Rectangle { height: parent.height; width: 16; color: spd.mid } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "mid light" } + Rectangle { height: parent.height; width: 16; color: sp.midlight } + Rectangle { height: parent.height; width: 16; color: spi.midlight } + Rectangle { height: parent.height; width: 16; color: spd.midlight } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "light" } + Rectangle { height: parent.height; width: 16; color: sp.light} + Rectangle { height: parent.height; width: 16; color: spi.light} + Rectangle { height: parent.height; width: 16; color: spd.light} + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "shadow" } + Rectangle { height: parent.height; width: 16; color: sp.shadow} + Rectangle { height: parent.height; width: 16; color: spi.shadow} + Rectangle { height: parent.height; width: 16; color: spd.shadow} + } + Item { + height: 16 + width:parent.width + } + + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "text" } + Rectangle { height: parent.height; width: 16; color: sp.text } + Rectangle { height: parent.height; width: 16; color: spi.text } + Rectangle { height: parent.height; width: 16; color: spd.text } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "window" } + Rectangle { height: parent.height; width: 16; color: sp.window } + Rectangle { height: parent.height; width: 16; color: spi.window } + Rectangle { height: parent.height; width: 16; color: spd.window } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "window text" } + Rectangle { height: parent.height; width: 16; color: sp.windowText } + Rectangle { height: parent.height; width: 16; color: spi.windowText } + Rectangle { height: parent.height; width: 16; color: spd.windowText } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "button" } + Rectangle { height: parent.height; width: 16; color: sp.button } + Rectangle { height: parent.height; width: 16; color: spi.button } + Rectangle { height: parent.height; width: 16; color: spd.button } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "buttonText" } + Rectangle { height: parent.height; width: 16; color: sp.buttonText } + Rectangle { height: parent.height; width: 16; color: spi.buttonText } + Rectangle { height: parent.height; width: 16; color: spd.buttonText } + } + Item { + height: 16 + width:parent.width + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "highlight" } + Rectangle { height: parent.height; width: 16; color: sp.highlight } + Rectangle { height: parent.height; width: 16; color: spi.highlight } + Rectangle { height: parent.height; width: 16; color: spd.highlight } + } + Row { + width: parent.width + height: 16 + Text { height: parent.height; width: 128; text: "highlighted text" } + Rectangle { height: parent.height; width: 16; color: sp.highlightedText} + Rectangle { height: parent.height; width: 16; color: spi.highlightedText} + Rectangle { height: parent.height; width: 16; color: spd.highlightedText} + } + } +} diff --git a/tests-manual/ui/qml/ScrollingGraph.qml b/tests-manual/ui/qml/ScrollingGraph.qml new file mode 100644 index 0000000000..55523a23f4 --- /dev/null +++ b/tests-manual/ui/qml/ScrollingGraph.qml @@ -0,0 +1,111 @@ +import QtQuick 2.1 +import QtQuick.Controls 1.0 +import QtQuick.Layouts 1.0 +import QtQuick.Dialogs 1.0 + +Rectangle { + id: root + property int size: 64 + width: size + height: size + color: 'black' + property int controlId: 0 + property real value: 0.5 + property int scrollWidth: 1 + property real min: 0.0 + property real max: 1.0 + property bool log: false + property real range: max - min + property color lineColor: 'yellow' + property bool bar: false + property real lastHeight: -1 + property string label: "" + + function update() { + value = Controller.getValue(controlId); + if (log) { + var log = Math.log(10) / Math.log(Math.abs(value)); + var sign = Math.sign(value); + value = log * sign; + } + canvas.requestPaint(); + } + + function drawHeight() { + if (value < min) { + return 0; + } + if (value > max) { + return height; + } + return ((value - min) / range) * height; + } + + Timer { + interval: 50; running: true; repeat: true + onTriggered: root.update() + } + + Canvas { + id: canvas + anchors.fill: parent + antialiasing: false + + Text { + anchors.top: parent.top + text: root.label + color: 'white' + } + + Text { + anchors.right: parent.right + anchors.top: parent.top + text: root.max + color: 'white' + } + + Text { + anchors.right: parent.right + anchors.bottom: parent.bottom + text: root.min + color: 'white' + } + + function scroll() { + var ctx = canvas.getContext('2d'); + var image = ctx.getImageData(0, 0, canvas.width, canvas.height); + ctx.beginPath(); + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.drawImage(image, -root.scrollWidth, 0, canvas.width, canvas.height) + ctx.restore() + } + + onPaint: { + scroll(); + var ctx = canvas.getContext('2d'); + ctx.save(); + var currentHeight = root.drawHeight(); + if (root.lastHeight == -1) { + root.lastHeight = currentHeight + } + +// var x = canvas.width - root.drawWidth; +// var y = canvas.height - drawHeight; +// ctx.fillStyle = root.color +// ctx.fillRect(x, y, root.drawWidth, root.bar ? drawHeight : 1) +// ctx.fill(); +// ctx.restore() + + + ctx.beginPath(); + ctx.lineWidth = 1 + ctx.strokeStyle = root.lineColor + ctx.moveTo(canvas.width - root.scrollWidth, root.lastHeight).lineTo(canvas.width, currentHeight) + ctx.stroke() + ctx.restore() + root.lastHeight = currentHeight + } + } +} + + diff --git a/tests-manual/ui/qml/StubMenu.qml b/tests-manual/ui/qml/StubMenu.qml new file mode 100644 index 0000000000..fd0298988a --- /dev/null +++ b/tests-manual/ui/qml/StubMenu.qml @@ -0,0 +1,730 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +import "../../../interface/resources/qml/hifi" + +Menu { + property var menuOption: MenuOption {} + Item { + Action { + id: login; + text: menuOption.login + } + Action { + id: update; + text: "Update"; + enabled: false + } + Action { + id: crashReporter; + text: "Crash Reporter..."; + enabled: false + } + Action { + id: help; + text: menuOption.help + onTriggered: Application.showHelp() + } + Action { + id: aboutApp; + text: menuOption.aboutApp + } + Action { + id: quit; + text: menuOption.quit + } + + ExclusiveGroup { id: renderResolutionGroup } + Action { + id: renderResolutionOne; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionOne; + checkable: true; + checked: true + } + Action { + id: renderResolutionTwoThird; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionTwoThird; + checkable: true + } + Action { + id: renderResolutionHalf; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionHalf; + checkable: true + } + Action { + id: renderResolutionThird; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionThird; + checkable: true + } + Action { + id: renderResolutionQuarter; + exclusiveGroup: renderResolutionGroup; + text: menuOption.renderResolutionQuarter; + checkable: true + } + + ExclusiveGroup { id: ambientLightGroup } + Action { + id: renderAmbientLightGlobal; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLightGlobal; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight0; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight0; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight1; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight1; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight2; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight2; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight3; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight3; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight4; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight4; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight5; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight5; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight6; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight6; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight7; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight7; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight8; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight8; + checkable: true; + checked: true + } + Action { + id: renderAmbientLight9; + exclusiveGroup: ambientLightGroup; + text: menuOption.renderAmbientLight9; + checkable: true; + checked: true + } + Action { + id: preferences + shortcut: StandardKey.Preferences + text: menuOption.preferences + onTriggered: dialogsManager.editPreferences() + } + + } + + Menu { + title: "File" + MenuItem { + action: login + } + MenuItem { + action: update + } + MenuItem { + action: help + } + MenuItem { + action: crashReporter + } + MenuItem { + action: aboutApp + } + MenuItem { + action: quit + } + } + + Menu { + title: "Edit" + MenuItem { + text: "Undo" } + MenuItem { + text: "Redo" } + MenuItem { + text: menuOption.runningScripts + } + MenuItem { + text: menuOption.loadScript + } + MenuItem { + text: menuOption.loadScriptURL + } + MenuItem { + text: menuOption.stopAllScripts + } + MenuItem { + text: menuOption.reloadAllScripts + } + MenuItem { + text: menuOption.scriptEditor + } + MenuItem { + text: menuOption.console_ + } + MenuItem { + text: menuOption.reloadContent + } + MenuItem { + text: menuOption.packageModel + } + } + + Menu { + title: "Audio" + MenuItem { + text: menuOption.muteAudio; + checkable: true + } + MenuItem { + text: menuOption.audioTools; + checkable: true + } + } + Menu { + title: "Avatar" + // Avatar > Attachments... + MenuItem { + text: menuOption.attachments + } + Menu { + title: "Size" + // Avatar > Size > Increase + MenuItem { + text: menuOption.increaseAvatarSize + } + // Avatar > Size > Decrease + MenuItem { + text: menuOption.decreaseAvatarSize + } + // Avatar > Size > Reset + MenuItem { + text: menuOption.resetAvatarSize + } + } + // Avatar > Reset Sensors + MenuItem { + text: menuOption.resetSensors + } + } + Menu { + title: "Display" + } + Menu { + title: "View" + ExclusiveGroup { + id: cameraModeGroup + } + + MenuItem { + text: menuOption.firstPerson; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuItem { + text: menuOption.thirdPerson; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuItem { + text: menuOption.fullscreenMirror; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuItem { + text: menuOption.independentMode; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuItem { + text: menuOption.cameraEntityMode; + checkable: true; + exclusiveGroup: cameraModeGroup + } + MenuSeparator{} + MenuItem { + text: menuOption.miniMirror; + checkable: true + } + } + Menu { + title: "Navigate" + MenuItem { + text: "Home" } + MenuItem { + text: menuOption.addressBar + } + MenuItem { + text: "Directory" } + MenuItem { + text: menuOption.copyAddress + } + MenuItem { + text: menuOption.copyPath + } + } + Menu { + title: "Settings" + MenuItem { + text: "Advanced Menus" } + MenuItem { + text: "Developer Menus" } + MenuItem { + text: menuOption.preferences + } + MenuItem { + text: "Avatar..." } + MenuItem { + text: "Audio..." } + MenuItem { + text: "LOD..." } + MenuItem { + text: menuOption.inputMenu + } + } + Menu { + title: "Developer" + Menu { + title: "Render" + MenuItem { + text: menuOption.atmosphere; + checkable: true + } + MenuItem { + text: menuOption.worldAxes; + checkable: true + } + MenuItem { + text: menuOption.debugAmbientOcclusion; + checkable: true + } + MenuItem { + text: menuOption.antialiasing; + checkable: true + } + MenuItem { + text: menuOption.stars; + checkable: true + } + Menu { + title: menuOption.renderAmbientLight + MenuItem { + action: renderAmbientLightGlobal; } + MenuItem { + action: renderAmbientLight0; } + MenuItem { + action: renderAmbientLight1; } + MenuItem { + action: renderAmbientLight2; } + MenuItem { + action: renderAmbientLight3; } + MenuItem { + action: renderAmbientLight4; } + MenuItem { + action: renderAmbientLight5; } + MenuItem { + action: renderAmbientLight6; } + MenuItem { + action: renderAmbientLight7; } + MenuItem { + action: renderAmbientLight8; } + MenuItem { + action: renderAmbientLight9; } + } + MenuItem { + text: menuOption.throttleFPSIfNotFocus; + checkable: true + } + Menu { + title: menuOption.renderResolution + MenuItem { + action: renderResolutionOne + } + MenuItem { + action: renderResolutionTwoThird + } + MenuItem { + action: renderResolutionHalf + } + MenuItem { + action: renderResolutionThird + } + MenuItem { + action: renderResolutionQuarter + } + } + MenuItem { + text: menuOption.lodTools + } + } + Menu { + title: "Assets" + MenuItem { + text: menuOption.uploadAsset + } + MenuItem { + text: menuOption.assetMigration + } + } + Menu { + title: "Avatar" + Menu { + title: "Face Tracking" + MenuItem { + text: menuOption.noFaceTracking; + checkable: true + } + MenuItem { + text: menuOption.faceshift; + checkable: true + } + MenuItem { + text: menuOption.useCamera; + checkable: true + } + MenuSeparator{} + MenuItem { + text: menuOption.binaryEyelidControl; + checkable: true + } + MenuItem { + text: menuOption.coupleEyelids; + checkable: true + } + MenuItem { + text: menuOption.useAudioForMouth; + checkable: true + } + MenuItem { + text: menuOption.velocityFilter; + checkable: true + } + MenuItem { + text: menuOption.calibrateCamera + } + MenuSeparator{} + MenuItem { + text: menuOption.muteFaceTracking; + checkable: true + } + MenuItem { + text: menuOption.autoMuteAudio; + checkable: true + } + } + Menu { + title: "Eye Tracking" + MenuItem { + text: menuOption.sMIEyeTracking; + checkable: true + } + Menu { + title: "Calibrate" + MenuItem { + text: menuOption.onePointCalibration + } + MenuItem { + text: menuOption.threePointCalibration + } + MenuItem { + text: menuOption.fivePointCalibration + } + } + MenuItem { + text: menuOption.simulateEyeTracking; + checkable: true + } + } + MenuItem { + text: menuOption.avatarReceiveStats; + checkable: true + } + MenuItem { + text: menuOption.renderBoundingCollisionShapes; + checkable: true + } + MenuItem { + text: menuOption.renderLookAtVectors; + checkable: true + } + MenuItem { + text: menuOption.renderLookAtTargets; + checkable: true + } + MenuItem { + text: menuOption.renderFocusIndicator; + checkable: true + } + MenuItem { + text: menuOption.showWhosLookingAtMe; + checkable: true + } + MenuItem { + text: menuOption.fixGaze; + checkable: true + } + MenuItem { + text: menuOption.animDebugDrawDefaultPose; + checkable: true + } + MenuItem { + text: menuOption.animDebugDrawAnimPose; + checkable: true + } + MenuItem { + text: menuOption.animDebugDrawPosition; + checkable: true + } + MenuItem { + text: menuOption.meshVisible; + checkable: true + } + MenuItem { + text: menuOption.disableEyelidAdjustment; + checkable: true + } + MenuItem { + text: menuOption.turnWithHead; + checkable: true + } + MenuItem { + text: menuOption.keyboardMotorControl; + checkable: true + } + MenuItem { + text: menuOption.scriptedMotorControl; + checkable: true + } + MenuItem { + text: menuOption.enableCharacterController; + checkable: true + } + } + Menu { + title: "Hands" + MenuItem { + text: menuOption.displayHandTargets; + checkable: true + } + MenuItem { + text: menuOption.lowVelocityFilter; + checkable: true + } + Menu { + title: "Leap Motion" + MenuItem { + text: menuOption.leapMotionOnHMD; + checkable: true + } + } + } + Menu { + title: "Entities" + MenuItem { + text: menuOption.octreeStats + } + MenuItem { + text: menuOption.showRealtimeEntityStats; + checkable: true + } + } + Menu { + title: "Network" + MenuItem { + text: menuOption.reloadContent + } + MenuItem { + text: menuOption.disableNackPackets; + checkable: true + } + MenuItem { + text: menuOption.disableActivityLogger; + checkable: true + } + MenuItem { + text: menuOption.cachesSize + } + MenuItem { + text: menuOption.diskCacheEditor + } + MenuItem { + text: menuOption.showDSConnectTable + } + MenuItem { + text: menuOption.bandwidthDetails + } + } + Menu { + title: "Timing" + Menu { + title: "Performance Timer" + MenuItem { + text: menuOption.displayDebugTimingDetails; + checkable: true + } + MenuItem { + text: menuOption.onlyDisplayTopTen; + checkable: true + } + MenuItem { + text: menuOption.expandUpdateTiming; + checkable: true + } + MenuItem { + text: menuOption.expandMyAvatarTiming; + checkable: true + } + MenuItem { + text: menuOption.expandMyAvatarSimulateTiming; + checkable: true + } + MenuItem { + text: menuOption.expandOtherAvatarTiming; + checkable: true + } + MenuItem { + text: menuOption.expandPaintGLTiming; + checkable: true + } + } + MenuItem { + text: menuOption.frameTimer; + checkable: true + } + MenuItem { + text: menuOption.runTimingTests + } + MenuItem { + text: menuOption.pipelineWarnings; + checkable: true + } + MenuItem { + text: menuOption.logExtraTimings; + checkable: true + } + MenuItem { + text: menuOption.suppressShortTimings; + checkable: true + } + } + Menu { + title: "Audio" + MenuItem { + text: menuOption.audioNoiseReduction; + checkable: true + } + MenuItem { + text: menuOption.echoServerAudio; + checkable: true + } + MenuItem { + text: menuOption.echoLocalAudio; + checkable: true + } + MenuItem { + text: menuOption.muteEnvironment + } + Menu { + title: "Audio" + MenuItem { + text: menuOption.audioScope; + checkable: true + } + MenuItem { + text: menuOption.audioScopePause; + checkable: true + } + Menu { + title: "Display Frames" + ExclusiveGroup { + id: audioScopeFramesGroup + } + MenuItem { + exclusiveGroup: audioScopeFramesGroup; + text: menuOption.audioScopeFiveFrames; + checkable: true + } + MenuItem { + exclusiveGroup: audioScopeFramesGroup; + text: menuOption.audioScopeTwentyFrames; + checkable: true + } + MenuItem { + exclusiveGroup: audioScopeFramesGroup; + text: menuOption.audioScopeFiftyFrames; + checkable: true + } + } + MenuItem { + text: menuOption.audioNetworkStats + } + } + } + Menu { + title: "Physics" + MenuItem { + text: menuOption.physicsShowOwned; + checkable: true + } + MenuItem { + text: menuOption.physicsShowHulls; + checkable: true + } + } + MenuItem { + text: menuOption.displayCrashOptions; + checkable: true + } + MenuItem { + text: menuOption.crashInterface + } + MenuItem { + text: menuOption.log + } + MenuItem { + text: menuOption.stats; + checkable: true + } + } +} diff --git a/tests-manual/ui/qml/Stubs.qml b/tests-manual/ui/qml/Stubs.qml new file mode 100644 index 0000000000..8c1465d54c --- /dev/null +++ b/tests-manual/ui/qml/Stubs.qml @@ -0,0 +1,346 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 + +// Stubs for the global service objects set by Interface.cpp when creating the UI +// This is useful for testing inside Qt creator where these services don't actually exist. +Item { + + Item { + objectName: "offscreenFlags" + property bool navigationFocused: false + } + + Item { + objectName: "urlHandler" + function fixupUrl(url) { return url; } + function canHandleUrl(url) { return false; } + function handleUrl(url) { return true; } + } + + Item { + objectName: "Account" + function isLoggedIn() { return true; } + function getUsername() { return "Jherico"; } + } + + Item { + objectName: "GL" + property string vendor: "" + } + + Item { + objectName: "ApplicationCompositor" + property bool reticleOverDesktop: true + } + + Item { + objectName: "Controller" + function getRecommendedOverlayRect() { + return Qt.rect(0, 0, 1920, 1080); + } + } + + Item { + objectName: "Preferences" + // List of categories obtained by logging categories as they are added in Interface in Preferences::addPreference(). + property var categories: [ + "Avatar Basics", "Snapshots", "Scripts", "Privacy", "Level of Detail Tuning", "Avatar Tuning", "Avatar Camera", + "Audio", "Octree", "HMD", "Sixense Controllers", "Graphics" + ] + } + + Item { + objectName: "ScriptDiscoveryService" + //property var scriptsModelFilter: scriptsModel + signal scriptCountChanged() + property var _runningScripts:[ + { name: "wireFrameTest.js", url: "foo/wireframetest.js", path: "foo/wireframetest.js", local: true }, + { name: "edit.js", url: "foo/edit.js", path: "foo/edit.js", local: false }, + { name: "listAllScripts.js", url: "foo/listAllScripts.js", path: "foo/listAllScripts.js", local: false }, + { name: "users.js", url: "foo/users.js", path: "foo/users.js", local: false }, + ] + + function getRunning() { + return _runningScripts; + } + } + + Item { + objectName: "HMD" + property bool active: false + } + + Item { + id: menuHelper + objectName: "MenuHelper" + + Component { + id: modelMaker + ListModel { } + } + + function toModel(menu, parent) { + if (!parent) { parent = menuHelper } + var result = modelMaker.createObject(parent); + if (menu.type !== MenuItemType.Menu) { + console.warn("Not a menu: " + menu); + return result; + } + + var items = menu.items; + for (var i = 0; i < items.length; ++i) { + var item = items[i]; + switch (item.type) { + case 2: + result.append({"name": item.title, "item": item}) + break; + case 1: + result.append({"name": item.text, "item": item}) + break; + case 0: + result.append({"name": "", "item": item}) + break; + } + } + return result; + } + + } + + Item { + objectName: "Desktop" + + property string _OFFSCREEN_ROOT_OBJECT_NAME: "desktopRoot"; + property string _OFFSCREEN_DIALOG_OBJECT_NAME: "topLevelWindow"; + + + function findChild(item, name) { + for (var i = 0; i < item.children.length; ++i) { + if (item.children[i].objectName === name) { + return item.children[i]; + } + } + return null; + } + + function findParent(item, name) { + while (item) { + if (item.objectName === name) { + return item; + } + item = item.parent; + } + return null; + } + + function findDialog(item) { + item = findParent(item, _OFFSCREEN_DIALOG_OBJECT_NAME); + return item; + } + + function closeDialog(item) { + item = findDialog(item); + if (item) { + item.visible = false + } else { + console.warn("Could not find top level dialog") + } + } + + function getDesktop(item) { + while (item) { + if (item.desktopRoot) { + break; + } + item = item.parent; + } + return item + } + + function raise(item) { + var desktop = getDesktop(item); + if (desktop) { + desktop.raise(item); + } + } + } + + Menu { + id: root + objectName: "rootMenu" + + Menu { + title: "Audio" + } + + Menu { + title: "Avatar" + } + + Menu { + title: "Display" + ExclusiveGroup { id: displayMode } + Menu { + title: "More Stuff" + + Menu { title: "Empty" } + + MenuItem { + text: "Do Nothing" + onTriggered: console.log("Nothing") + } + } + MenuItem { + text: "Oculus" + exclusiveGroup: displayMode + checkable: true + } + MenuItem { + text: "OpenVR" + exclusiveGroup: displayMode + checkable: true + } + MenuItem { + text: "OSVR" + exclusiveGroup: displayMode + checkable: true + } + MenuItem { + text: "2D Screen" + exclusiveGroup: displayMode + checkable: true + checked: true + } + MenuItem { + text: "3D Screen (Active)" + exclusiveGroup: displayMode + checkable: true + } + MenuItem { + text: "3D Screen (Passive)" + exclusiveGroup: displayMode + checkable: true + } + } + + Menu { + title: "View" + Menu { + title: "Camera Mode" + ExclusiveGroup { id: cameraMode } + MenuItem { + exclusiveGroup: cameraMode + text: "First Person"; + onTriggered: console.log(text + " checked " + checked) + checkable: true + checked: true + } + MenuItem { + exclusiveGroup: cameraMode + text: "Third Person"; + onTriggered: console.log(text) + checkable: true + } + MenuItem { + exclusiveGroup: cameraMode + text: "Independent Mode"; + onTriggered: console.log(text) + checkable: true + } + MenuItem { + exclusiveGroup: cameraMode + text: "Entity Mode"; + onTriggered: console.log(text) + enabled: false + checkable: true + } + MenuItem { + exclusiveGroup: cameraMode + text: "Fullscreen Mirror"; + onTriggered: console.log(text) + checkable: true + } + } + } + + Menu { + title: "Edit" + + MenuItem { + text: "Undo" + shortcut: "Ctrl+Z" + enabled: false + onTriggered: console.log(text) + } + + MenuItem { + text: "Redo" + shortcut: "Ctrl+Shift+Z" + enabled: false + onTriggered: console.log(text) + } + + MenuSeparator { } + + MenuItem { + text: "Cut" + shortcut: "Ctrl+X" + onTriggered: console.log(text) + } + + MenuItem { + text: "Copy" + shortcut: "Ctrl+C" + onTriggered: console.log(text) + } + + MenuItem { + text: "Paste" + shortcut: "Ctrl+V" + visible: false + onTriggered: console.log("Paste") + } + } + + Menu { + title: "Navigate" + } + + Menu { + title: "Market" + } + + Menu { + title: "Settings" + } + + Menu { + title: "Developer" + } + + Menu { + title: "Quit" + } + + Menu { + title: "File" + + Action { + id: login + text: "Login" + } + + Action { + id: quit + text: "Quit" + shortcut: "Ctrl+Q" + onTriggered: Qt.quit(); + } + + MenuItem { action: quit } + MenuItem { action: login } + } + } + +} + diff --git a/tests-manual/ui/qml/TestControllers.qml b/tests-manual/ui/qml/TestControllers.qml new file mode 100644 index 0000000000..e9a7fb49e5 --- /dev/null +++ b/tests-manual/ui/qml/TestControllers.qml @@ -0,0 +1,160 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Layouts 1.0 +import QtQuick.Dialogs 1.0 + +import "controller" +import "controls" as HifiControls +import "styles" + +HifiControls.VrDialog { + id: root + HifiConstants { id: hifi } + title: "Controller Test" + resizable: true + contentImplicitWidth: clientArea.implicitWidth + contentImplicitHeight: clientArea.implicitHeight + backgroundColor: "beige" + + property var actions: Controller.Actions + property var standard: Controller.Standard + property var hydra: null + property var testMapping: null + property bool testMappingEnabled: false + property var xbox: null + + function buildMapping() { + testMapping = Controller.newMapping(); + testMapping.fromQml(standard.RY).invert().toQml(actions.Pitch); + testMapping.fromQml(function(){ + return Math.sin(Date.now() / 250); + }).toQml(actions.Yaw); + //testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw); + // Step yaw takes a number of degrees + testMapping.fromQml(standard.LB).pulse(0.10).invert().scale(40.0).toQml(actions.StepYaw); + testMapping.fromQml(standard.RB).pulse(0.10).scale(15.0).toQml(actions.StepYaw); + testMapping.fromQml(standard.RX).scale(15.0).toQml(actions.StepYaw); + } + + function toggleMapping() { + testMapping.enable(!testMappingEnabled); + testMappingEnabled = !testMappingEnabled; + } + + Component.onCompleted: { + var xboxRegex = /^GamePad/; + var hydraRegex = /^Hydra/; + for (var prop in Controller.Hardware) { + if(xboxRegex.test(prop)) { + root.xbox = Controller.Hardware[prop] + print("found xbox") + continue + } + if (hydraRegex.test(prop)) { + root.hydra = Controller.Hardware[prop] + print("found hydra") + continue + } + } + } + + Column { + id: clientArea + spacing: 12 + x: root.clientX + y: root.clientY + + Row { + spacing: 8 + + Button { + text: !root.testMapping ? "Build Mapping" : (root.testMappingEnabled ? "Disable Mapping" : "Enable Mapping") + onClicked: { + + if (!root.testMapping) { + root.buildMapping() + } else { + root.toggleMapping(); + } + } + } + } + + Row { + Standard { device: root.standard; label: "Standard"; width: 180 } + } + + Row { + spacing: 8 + Xbox { device: root.xbox; label: "XBox"; width: 180 } + Hydra { device: root.hydra; width: 180 } + } + + Row { + spacing: 4 + ScrollingGraph { + controlId: Controller.Actions.Yaw + label: "Yaw" + min: -2.0 + max: 2.0 + size: 64 + } + + ScrollingGraph { + controlId: Controller.Actions.YawLeft + label: "Yaw Left" + min: -2.0 + max: 2.0 + size: 64 + } + + ScrollingGraph { + controlId: Controller.Actions.YawRight + label: "Yaw Right" + min: -2.0 + max: 2.0 + size: 64 + } + + ScrollingGraph { + controlId: Controller.Actions.StepYaw + label: "StepYaw" + min: -20.0 + max: 20.0 + size: 64 + } + } + + Row { + ScrollingGraph { + controlId: Controller.Actions.TranslateZ + label: "TranslateZ" + min: -2.0 + max: 2.0 + size: 64 + } + + ScrollingGraph { + controlId: Controller.Actions.Forward + label: "Forward" + min: -2.0 + max: 2.0 + size: 64 + } + + ScrollingGraph { + controlId: Controller.Actions.Backward + label: "Backward" + min: -2.0 + max: 2.0 + size: 64 + } + + } + } +} // dialog + + + + + diff --git a/tests-manual/ui/qml/TestDialog.qml b/tests-manual/ui/qml/TestDialog.qml new file mode 100644 index 0000000000..e6675b7282 --- /dev/null +++ b/tests-manual/ui/qml/TestDialog.qml @@ -0,0 +1,94 @@ +import QtQuick 2.3 +import QtQuick.Controls 1.2 +import QtQuick.Controls.Styles 1.3 +import "controls" + +VrDialog { + title: "Test Dialog" + id: testDialog + objectName: "TestDialog" + width: 512 + height: 512 + animationDuration: 200 + + onEnabledChanged: { + if (enabled) { + edit.forceActiveFocus(); + } + } + + Item { + id: clientArea + // The client area + anchors.fill: parent + anchors.margins: parent.margins + anchors.topMargin: parent.topMargin + + Rectangle { + property int d: 100 + id: square + objectName: "testRect" + width: d + height: d + anchors.centerIn: parent + color: "red" + NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } + } + + + TextEdit { + id: edit + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + clip: true + text: "test edit" + anchors.top: parent.top + anchors.topMargin: 12 + } + + Button { + x: 128 + y: 192 + text: "Test" + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + onClicked: { + console.log("Click"); + + if (square.visible) { + square.visible = false + } else { + square.visible = true + } + } + } + + Button { + id: customButton2 + y: 192 + text: "Move" + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + onClicked: { + onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0 + } + } + + Keys.onPressed: { + console.log("Key " + event.key); + switch (event.key) { + case Qt.Key_Q: + if (Qt.ControlModifier == event.modifiers) { + event.accepted = true; + break; + } + } + } + } +} diff --git a/tests-manual/ui/qml/TestMenu.qml b/tests-manual/ui/qml/TestMenu.qml new file mode 100644 index 0000000000..fe8a26e234 --- /dev/null +++ b/tests-manual/ui/qml/TestMenu.qml @@ -0,0 +1,10 @@ +import QtQuick 2.4 +import QtQuick.Controls 1.3 +import Hifi 1.0 + +// Currently for testing a pure QML replacement menu +Item { + Menu { + objectName: "rootMenu"; + } +} diff --git a/tests-manual/ui/qml/TestRoot.qml b/tests-manual/ui/qml/TestRoot.qml new file mode 100644 index 0000000000..bd38c696bf --- /dev/null +++ b/tests-manual/ui/qml/TestRoot.qml @@ -0,0 +1,43 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.3 +// Import local folder last so that our own control customizations override +// the built in ones +import "controls" + +Root { + id: root + anchors.fill: parent + onParentChanged: { + forceActiveFocus(); + } + Button { + id: messageBox + anchors.right: createDialog.left + anchors.rightMargin: 24 + anchors.bottom: parent.bottom + anchors.bottomMargin: 24 + text: "Message" + onClicked: { + console.log("Foo") + root.information("a") + console.log("Bar") + } + } + Button { + id: createDialog + anchors.right: parent.right + anchors.rightMargin: 24 + anchors.bottom: parent.bottom + anchors.bottomMargin: 24 + text: "Create" + onClicked: { + root.loadChild("MenuTest.qml"); + } + } + + Keys.onPressed: { + console.log("Key press root") + } +} + diff --git a/tests-manual/ui/qml/controlDemo/ButtonPage.qml b/tests-manual/ui/qml/controlDemo/ButtonPage.qml new file mode 100644 index 0000000000..0ed7e2d6ad --- /dev/null +++ b/tests-manual/ui/qml/controlDemo/ButtonPage.qml @@ -0,0 +1,128 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, grid.implicitWidth + 2 * grid.rowSpacing) + height: Math.max(page.viewport.height, grid.implicitHeight + 2 * grid.columnSpacing) + + GridLayout { + id: grid + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.leftMargin: grid.rowSpacing + anchors.rightMargin: grid.rowSpacing + anchors.topMargin: grid.columnSpacing + + columns: page.width < page.height ? 1 : 2 + + GroupBox { + title: "Button" + Layout.fillWidth: true + Layout.columnSpan: grid.columns + RowLayout { + anchors.fill: parent + Button { text: "OK"; isDefault: true } + Button { text: "Cancel" } + Item { Layout.fillWidth: true } + Button { + text: "Attach" + menu: Menu { + MenuItem { text: "Image" } + MenuItem { text: "Document" } + } + } + } + } + + GroupBox { + title: "CheckBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + CheckBox { text: "E-mail"; checked: true } + CheckBox { text: "Calendar"; checked: true } + CheckBox { text: "Contacts" } + } + } + + GroupBox { + title: "RadioButton" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ExclusiveGroup { id: radioGroup } + RadioButton { text: "Portrait"; exclusiveGroup: radioGroup } + RadioButton { text: "Landscape"; exclusiveGroup: radioGroup } + RadioButton { text: "Automatic"; exclusiveGroup: radioGroup; checked: true } + } + } + + GroupBox { + title: "Switch" + Layout.fillWidth: true + Layout.columnSpan: grid.columns + ColumnLayout { + anchors.fill: parent + RowLayout { + Label { text: "Wi-Fi"; Layout.fillWidth: true } + Switch { checked: true } + } + RowLayout { + Label { text: "Bluetooth"; Layout.fillWidth: true } + Switch { checked: false } + } + } + } + } + } +} diff --git a/tests-manual/ui/qml/controlDemo/InputPage.qml b/tests-manual/ui/qml/controlDemo/InputPage.qml new file mode 100644 index 0000000000..cb1878d023 --- /dev/null +++ b/tests-manual/ui/qml/controlDemo/InputPage.qml @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, column.implicitWidth + 2 * column.spacing) + height: Math.max(page.viewport.height, column.implicitHeight + 2 * column.spacing) + + ColumnLayout { + id: column + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: column.spacing + + GroupBox { + title: "TextField" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + TextField { placeholderText: "..."; Layout.fillWidth: true; z: 1 } + TextField { placeholderText: "Password"; echoMode: TextInput.Password; Layout.fillWidth: true } + } + } + + GroupBox { + title: "ComboBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ComboBox { + model: Qt.fontFamilies() + Layout.fillWidth: true + } + ComboBox { + editable: true + model: ListModel { + id: listModel + ListElement { text: "Apple" } + ListElement { text: "Banana" } + ListElement { text: "Coconut" } + ListElement { text: "Orange" } + } + onAccepted: { + if (find(currentText) === -1) { + listModel.append({text: editText}) + currentIndex = find(editText) + } + } + Layout.fillWidth: true + } + } + } + + GroupBox { + title: "SpinBox" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + SpinBox { value: 99; Layout.fillWidth: true; z: 1 } + SpinBox { decimals: 2; Layout.fillWidth: true } + } + } + } + } +} diff --git a/tests-manual/ui/qml/controlDemo/ProgressPage.qml b/tests-manual/ui/qml/controlDemo/ProgressPage.qml new file mode 100644 index 0000000000..a1fa596f79 --- /dev/null +++ b/tests-manual/ui/qml/controlDemo/ProgressPage.qml @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.2 + +ScrollView { + id: page + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + + Item { + id: content + + width: Math.max(page.viewport.width, column.implicitWidth + 2 * column.spacing) + height: Math.max(page.viewport.height, column.implicitHeight + 2 * column.spacing) + + ColumnLayout { + id: column + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: column.spacing + + GroupBox { + title: "ProgressBar" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + ProgressBar { indeterminate: true; Layout.fillWidth: true } + ProgressBar { value: slider.value; Layout.fillWidth: true } + } + } + + GroupBox { + title: "Slider" + Layout.fillWidth: true + ColumnLayout { + anchors.fill: parent + Slider { id: slider; value: 0.5; Layout.fillWidth: true } + } + } + + GroupBox { + title: "BusyIndicator" + Layout.fillWidth: true + BusyIndicator { running: true } + } + } + } +} diff --git a/tests-manual/ui/qml/controlDemo/main.qml b/tests-manual/ui/qml/controlDemo/main.qml new file mode 100644 index 0000000000..168b9fb291 --- /dev/null +++ b/tests-manual/ui/qml/controlDemo/main.qml @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Layouts 1.1 +import QtQuick.Dialogs 1.1 +import QtQuick.Controls 1.2 +import "qml/UI.js" as UI +import "qml" +//import "/Users/bdavis/Git/hifi/interface/resources/qml" + +Item { + anchors.fill: parent + visible: true + //title: "Qt Quick Controls Gallery" + + MessageDialog { + id: aboutDialog + icon: StandardIcon.Information + title: "About" + text: "Qt Quick Controls Gallery" + informativeText: "This example demonstrates most of the available Qt Quick Controls." + } + + Action { + id: copyAction + text: "&Copy" + shortcut: StandardKey.Copy + iconName: "edit-copy" + enabled: (!!activeFocusItem && !!activeFocusItem["copy"]) + onTriggered: activeFocusItem.copy() + } + + Action { + id: cutAction + text: "Cu&t" + shortcut: StandardKey.Cut + iconName: "edit-cut" + enabled: (!!activeFocusItem && !!activeFocusItem["cut"]) + onTriggered: activeFocusItem.cut() + } + + Action { + id: pasteAction + text: "&Paste" + shortcut: StandardKey.Paste + iconName: "edit-paste" + enabled: (!!activeFocusItem && !!activeFocusItem["paste"]) + onTriggered: activeFocusItem.paste() + } + +// toolBar: ToolBar { +// RowLayout { +// anchors.fill: parent +// anchors.margins: spacing +// Label { +// text: UI.label +// } +// Item { Layout.fillWidth: true } +// CheckBox { +// id: enabler +// text: "Enabled" +// checked: true +// } +// } +// } + +// menuBar: MenuBar { +// Menu { +// title: "&File" +// MenuItem { +// text: "E&xit" +// shortcut: StandardKey.Quit +// onTriggered: Qt.quit() +// } +// } +// Menu { +// title: "&Edit" +// visible: tabView.currentIndex == 2 +// MenuItem { action: cutAction } +// MenuItem { action: copyAction } +// MenuItem { action: pasteAction } +// } +// Menu { +// title: "&Help" +// MenuItem { +// text: "About..." +// onTriggered: aboutDialog.open() +// } +// } +// } + + TabView { + id: tabView + + anchors.fill: parent + anchors.margins: UI.margin + tabPosition: UI.tabPosition + + Layout.minimumWidth: 360 + Layout.minimumHeight: 360 + Layout.preferredWidth: 480 + Layout.preferredHeight: 640 + + Tab { + title: "Buttons" + ButtonPage { + enabled: enabler.checked + } + } + Tab { + title: "Progress" + ProgressPage { + enabled: enabler.checked + } + } + Tab { + title: "Input" + InputPage { + enabled: enabler.checked + } + } + } +} diff --git a/tests-manual/ui/qml/main.qml b/tests-manual/ui/qml/main.qml new file mode 100644 index 0000000000..607bd624a1 --- /dev/null +++ b/tests-manual/ui/qml/main.qml @@ -0,0 +1,461 @@ +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import QtQuick.Dialogs 1.2 as OriginalDialogs +import Qt.labs.settings 1.0 + +import "../../../interface/resources/qml" +//import "../../../interface/resources/qml/windows" +import "../../../interface/resources/qml/windows" +import "../../../interface/resources/qml/dialogs" +import "../../../interface/resources/qml/hifi" +import "../../../interface/resources/qml/hifi/dialogs" +import "../../../interface/resources/qml/styles-uit" + +ApplicationWindow { + id: appWindow + objectName: "MainWindow" + visible: true + width: 1280 + height: 800 + title: qsTr("Scratch App") + toolBar: Row { + id: testButtons + anchors { margins: 8; left: parent.left; top: parent.top } + spacing: 8 + property int count: 0 + + property var tabs: []; + property var urls: []; + property var toolbar; + property var lastButton; + + Button { + text: HMD.active ? "Disable HMD" : "Enable HMD" + onClicked: HMD.active = !HMD.active + } + + Button { + text: desktop.hmdHandMouseActive ? "Disable HMD HandMouse" : "Enable HMD HandMouse" + onClicked: desktop.hmdHandMouseActive = !desktop.hmdHandMouseActive + } + + // Window visibility + Button { + text: "toggle desktop" + onClicked: desktop.togglePinned() + } + + Button { + text: "Create Toolbar" + onClicked: testButtons.toolbar = desktop.getToolbar("com.highfidelity.interface.toolbar.system"); + } + + Button { + text: "Toggle Toolbar Direction" + onClicked: testButtons.toolbar.horizontal = !testButtons.toolbar.horizontal + } + + Button { + readonly property var icons: [ + "edit-01.svg", + "model-01.svg", + "cube-01.svg", + "sphere-01.svg", + "light-01.svg", + "text-01.svg", + "web-01.svg", + "zone-01.svg", + "particle-01.svg", + ] + property int iconIndex: 0 + readonly property string toolIconUrl: "../../../../../scripts/system/assets/images/tools/" + text: "Create Button" + onClicked: { + var name = icons[iconIndex]; + var url = toolIconUrl + name; + iconIndex = (iconIndex + 1) % icons.length; + var button = testButtons.lastButton = testButtons.toolbar.addButton({ + imageURL: url, + objectName: name, + subImage: { + y: 50, + }, + alpha: 0.9 + }); + + button.clicked.connect(function(){ + console.log("Clicked on button " + button.imageURL + " alpha " + button.alpha) + }); + } + } + + Button { + text: "Toggle Button Visible" + onClicked: testButtons.lastButton.visible = !testButtons.lastButton.visible + } + + // Error alerts + /* + Button { + // Message without title. + text: "Show Error" + onClicked: { + var messageBox = desktop.messageBox({ + text: "Diagnostic cycle will be complete in 30 seconds", + icon: hifi.icons.critical, + }); + messageBox.selected.connect(function(button) { + console.log("You clicked " + button) + }) + } + } + Button { + // detailedText is not currently used anywhere in Interface but it is easier to leave in and style good enough. + text: "Show Long Error" + onClicked: { + desktop.messageBox({ + informativeText: "Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds ", + text: "Baloney", + icon: hifi.icons.warning, + detailedText: "sakjd;laskj dksa;dl jka;lsd j;lkjas ;dlkaj s;dlakjd ;alkjda; slkjda; lkjda;lksjd ;alksjd; alksjd ;alksjd; alksjd; alksdjas;ldkjas;lkdja ;kj ;lkasjd; lkj as;dlka jsd;lka jsd;laksjd a" + }); + } + } + */ + + // query + /* + // There is no such desktop.queryBox() function; may need to update test to cover QueryDialog.qml? + Button { + text: "Show Query" + onClicked: { + var queryBox = desktop.queryBox({ + text: "Have you stopped beating your wife?", + placeholderText: "Are you sure?", + // icon: hifi.icons.critical, + }); + queryBox.selected.connect(function(result) { + console.log("User responded with " + result); + }); + + queryBox.canceled.connect(function() { + console.log("User cancelled query box "); + }) + } + } + */ + + // Browser + /* + Button { + text: "Open Browser" + onClicked: builder.createObject(desktop); + property var builder: Component { + Browser {} + } + } + */ + + + // file dialog + /* + + Button { + text: "Open Directory" + property var builder: Component { + FileDialog { selectDirectory: true } + } + + onClicked: { + var fileDialog = builder.createObject(desktop); + fileDialog.canceled.connect(function(){ + console.log("Cancelled") + }) + fileDialog.selectedFile.connect(function(file){ + console.log("Selected " + file) + }) + } + } + Button { + text: "Open File" + property var builder: Component { + FileDialog { + title: "Open File" + filter: "All Files (*.*)" + //filter: "HTML files (*.html);;Other(*.png)" + } + } + + onClicked: { + var fileDialog = builder.createObject(desktop); + fileDialog.canceled.connect(function(){ + console.log("Cancelled") + }) + fileDialog.selectedFile.connect(function(file){ + console.log("Selected " + file) + }) + } + } + */ + + // tabs + /* + Button { + text: "Add Tab" + onClicked: { + console.log(desktop.toolWindow); + desktop.toolWindow.addWebTab({ source: "Foo" }); + desktop.toolWindow.showTabForUrl("Foo", true); + } + } + + Button { + text: "Add Tab 2" + onClicked: { + console.log(desktop.toolWindow); + desktop.toolWindow.addWebTab({ source: "Foo 2" }); + desktop.toolWindow.showTabForUrl("Foo 2", true); + } + } + + Button { + text: "Add Tab 3" + onClicked: { + console.log(desktop.toolWindow); + desktop.toolWindow.addWebTab({ source: "Foo 3" }); + desktop.toolWindow.showTabForUrl("Foo 3", true); + } + } + + Button { + text: "Destroy Tab" + onClicked: { + console.log(desktop.toolWindow); + desktop.toolWindow.removeTabForUrl("Foo"); + } + } + */ + + // Hifi specific stuff + /* + Button { + // Shows the dialog with preferences sections but not each section's preference items + // because Preferences.preferencesByCategory() method is not stubbed out. + text: "Settings > General..." + property var builder: Component { + GeneralPreferencesDialog { } + } + onClicked: { + var runningScripts = builder.createObject(desktop); + } + } + + Button { + text: "Running Scripts" + property var builder: Component { + RunningScripts { } + } + onClicked: { + var runningScripts = builder.createObject(desktop); + } + } + + Button { + text: "Attachments" + property var builder: Component { + AttachmentsDialog { } + } + onClicked: { + var attachmentsDialog = builder.createObject(desktop); + } + } + Button { + // Replicates message box that pops up after selecting new avatar. Includes title. + text: "Confirm Avatar" + onClicked: { + var messageBox = desktop.messageBox({ + title: "Set Avatar", + text: "Would you like to use 'Albert' for your avatar?", + icon: hifi.icons.question, // Test question icon + //icon: hifi.icons.information, // Test informaton icon + //icon: hifi.icons.warning, // Test warning icon + //icon: hifi.icons.critical, // Test critical icon + //icon: hifi.icons.none, // Test no icon + buttons: OriginalDialogs.StandardButton.Ok + OriginalDialogs.StandardButton.Cancel, + defaultButton: OriginalDialogs.StandardButton.Ok + }); + messageBox.selected.connect(function(button) { + console.log("You clicked " + button) + }) + } + } + */ + // bookmarks + /* + Button { + text: "Bookmark Location" + onClicked: { + desktop.inputDialog({ + title: "Bookmark Location", + icon: hifi.icons.placemark, + label: "Name" + }); + } + } + Button { + text: "Delete Bookmark" + onClicked: { + desktop.inputDialog({ + title: "Delete Bookmark", + icon: hifi.icons.placemark, + label: "Select the bookmark to delete", + items: ["Bookmark A", "Bookmark B", "Bookmark C"] + }); + } + } + Button { + text: "Duplicate Bookmark" + onClicked: { + desktop.messageBox({ + title: "Duplicate Bookmark", + icon: hifi.icons.warning, + text: "The bookmark name you entered alread exists in yoru list.", + informativeText: "Would you like to overwrite it?", + buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No, + defaultButton: OriginalDialogs.StandardButton.Yes + }); + } + } + */ + + } + + + HifiConstants { id: hifi } + + Desktop { + id: desktop + anchors.fill: parent + + //rootMenu: StubMenu { id: rootMenu } + //Component.onCompleted: offscreenWindow = appWindow + + /* + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: desktop.popupMenu(Qt.vector2d(mouseX, mouseY)); + } + */ + + Browser { + url: "http://s3.amazonaws.com/DreamingContent/testUiDelegates.html" + } + + + Window { + id: blue + closable: true + visible: true + resizable: true + destroyOnHidden: false + title: "Blue" + + width: 100; height: 100 + x: 1280 / 2; y: 720 / 2 + Settings { + category: "TestWindow.Blue" + property alias x: blue.x + property alias y: blue.y + property alias width: blue.width + property alias height: blue.height + } + + Rectangle { + anchors.fill: parent + visible: true + color: "blue" + Component.onDestruction: console.log("Blue destroyed") + } + } + + Window { + id: green + closable: true + visible: true + resizable: true + title: "Green" + destroyOnHidden: false + + width: 100; height: 100 + x: 1280 / 2; y: 720 / 2 + Settings { + category: "TestWindow.Green" + property alias x: green.x + property alias y: green.y + property alias width: green.width + property alias height: green.height + } + + Rectangle { + anchors.fill: parent + visible: true + color: "green" + Component.onDestruction: console.log("Green destroyed") + } + } + +/* + Rectangle { width: 100; height: 100; x: 100; y: 100; color: "#00f" } + + Window { + id: green + alwaysOnTop: true + frame: HiddenFrame{} + hideBackground: true + closable: true + visible: true + resizable: false + x: 1280 / 2; y: 720 / 2 + width: 100; height: 100 + Rectangle { + color: "#0f0" + width: green.width; + height: green.height; + } + } + */ + +/* + Window { + id: yellow + closable: true + visible: true + resizable: true + x: 100; y: 100 + width: 100; height: 100 + Rectangle { + anchors.fill: parent + visible: true + color: "yellow" + } + } +*/ + } + + Action { + id: openBrowserAction + text: "Open Browser" + shortcut: "Ctrl+Shift+X" + onTriggered: { + builder.createObject(desktop); + } + property var builder: Component { + ModelBrowserDialog{} + } + } +} + + + + diff --git a/tests-manual/ui/qmlscratch.pro b/tests-manual/ui/qmlscratch.pro index 3287180d26..5c9b91ee52 100644 --- a/tests-manual/ui/qmlscratch.pro +++ b/tests-manual/ui/qmlscratch.pro @@ -4,10 +4,34 @@ QT += gui qml quick xml webengine widgets CONFIG += c++11 -SOURCES += src/main.cpp +SOURCES += src/main.cpp \ + ../../libraries/ui/src/FileDialogHelper.cpp + +HEADERS += \ + ../../libraries/ui/src/FileDialogHelper.h # Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = ../../interface/resources/qml + DISTFILES += \ - qml/*.qml + qml/*.qml \ + ../../interface/resources/QtWebEngine/UIDelegates/original/*.qml \ + ../../interface/resources/QtWebEngine/UIDelegates/*.qml \ + ../../interface/resources/qml/*.qml \ + ../../interface/resources/qml/controls/*.qml \ + ../../interface/resources/qml/controls-uit/*.qml \ + ../../interface/resources/qml/dialogs/*.qml \ + ../../interface/resources/qml/dialogs/fileDialog/*.qml \ + ../../interface/resources/qml/dialogs/preferences/*.qml \ + ../../interface/resources/qml/dialogs/messageDialog/*.qml \ + ../../interface/resources/qml/desktop/*.qml \ + ../../interface/resources/qml/menus/*.qml \ + ../../interface/resources/qml/styles/*.qml \ + ../../interface/resources/qml/styles-uit/*.qml \ + ../../interface/resources/qml/windows/*.qml \ + ../../interface/resources/qml/hifi/*.qml \ + ../../interface/resources/qml/hifi/toolbars/*.qml \ + ../../interface/resources/qml/hifi/dialogs/*.qml \ + ../../interface/resources/qml/hifi/dialogs/preferences/*.qml \ + ../../interface/resources/qml/hifi/overlays/*.qml diff --git a/tests-manual/ui/src/main.cpp b/tests-manual/ui/src/main.cpp index a5061f4d01..312b5f3823 100644 --- a/tests-manual/ui/src/main.cpp +++ b/tests-manual/ui/src/main.cpp @@ -3,31 +3,88 @@ #include #include +#include "../../../libraries/ui/src/FileDialogHelper.h" + + +class Preference : public QObject { + Q_OBJECT + Q_PROPERTY(QString category READ getCategory() CONSTANT) + Q_PROPERTY(QString name READ getName() CONSTANT) + Q_PROPERTY(Type type READ getType() CONSTANT) + Q_ENUMS(Type) +public: + enum Type { + Editable, + Browsable, + Spinner, + Checkbox, + }; + + Preference(QObject* parent = nullptr) : QObject(parent) {} + + Preference(const QString& category, const QString& name, QObject* parent = nullptr) + : QObject(parent), _category(category), _name(name) { } + const QString& getCategory() const { return _category; } + const QString& getName() const { return _name; } + virtual Type getType() { return Editable; } + +protected: + const QString _category; + const QString _name; +}; + +class Reticle : public QObject { + Q_OBJECT + Q_PROPERTY(QPoint position READ getPosition CONSTANT) +public: + + Reticle(QObject* parent) : QObject(parent) { + } + + QPoint getPosition() { + if (!_window) { + return QPoint(0, 0); + } + return _window->mapFromGlobal(QCursor::pos()); + } + + void setWindow(QWindow* window) { + _window = window; + } + +private: + QWindow* _window{nullptr}; +}; + QString getRelativeDir(const QString& relativePath = ".") { - QDir path(__FILE__); - path.cdUp(); - path.cdUp(); + QDir path(__FILE__); path.cdUp(); auto result = path.absoluteFilePath(relativePath); result = path.cleanPath(result) + "/"; return result; } -QString getResourcesDir() { - return getRelativeDir("../../interface/resources"); +QString getTestQmlDir() { + return getRelativeDir("../qml"); } -QString getQmlDir() { - return getRelativeDir("../../interface/resources/qml"); +QString getInterfaceQmlDir() { + return getRelativeDir("/"); } -QString getScriptsDir() { - return getRelativeDir("../../scripts"); + +void setChild(QQmlApplicationEngine& engine, const char* name) { + for (auto obj : engine.rootObjects()) { + auto child = obj->findChild(QString(name)); + if (child) { + engine.rootContext()->setContextProperty(name, child); + return; + } + } + qWarning() << "Could not find object named " << name; } void addImportPath(QQmlApplicationEngine& engine, const QString& relativePath, bool insert = false) { QString resolvedPath = getRelativeDir(relativePath); - - qDebug() << "adding import path: " << QDir::toNativeSeparators(resolvedPath); engine.addImportPath(resolvedPath); } @@ -36,24 +93,44 @@ int main(int argc, char *argv[]) { app.setOrganizationName("Some Company"); app.setOrganizationDomain("somecompany.com"); app.setApplicationName("Amazing Application"); + QDir::setCurrent(getRelativeDir("..")); - auto scriptsDir = getScriptsDir(); - auto resourcesDir = getResourcesDir(); + QtWebEngine::initialize(); + qmlRegisterType("Hifi", 1, 0, "Preference"); QQmlApplicationEngine engine; - addImportPath(engine, "."); addImportPath(engine, "qml"); - addImportPath(engine, resourcesDir); - addImportPath(engine, resourcesDir + "/qml"); - addImportPath(engine, scriptsDir); - addImportPath(engine, scriptsDir + "/developer/tests"); + addImportPath(engine, "../../interface/resources/qml"); + addImportPath(engine, "../../interface/resources"); + engine.load(QUrl(QStringLiteral("qml/Stubs.qml"))); - QFontDatabase::addApplicationFont(resourcesDir + "/fonts/FiraSans-Regular.ttf"); - QFontDatabase::addApplicationFont(resourcesDir + "/fonts/FiraSans-SemiBold.ttf"); - QFontDatabase::addApplicationFont(resourcesDir + "/fonts/hifi-glyphs.ttf"); + setChild(engine, "offscreenFlags"); + setChild(engine, "Account"); + setChild(engine, "ApplicationCompositor"); + setChild(engine, "Controller"); + setChild(engine, "Desktop"); + setChild(engine, "ScriptDiscoveryService"); + setChild(engine, "HMD"); + setChild(engine, "GL"); + setChild(engine, "MenuHelper"); + setChild(engine, "Preferences"); + setChild(engine, "urlHandler"); + engine.rootContext()->setContextProperty("DebugQML", true); + engine.rootContext()->setContextProperty("fileDialogHelper", new FileDialogHelper()); - auto url = getRelativeDir(".") + "qml/ControlsGalleryWindow.qml"; - - engine.load(url); + //engine.load(QUrl(QStringLiteral("qrc:/qml/gallery/main.qml"))); + engine.load(QUrl(QStringLiteral("qml/main.qml"))); + for (QObject* rootObject : engine.rootObjects()) { + if (rootObject->objectName() == "MainWindow") { + Reticle* reticle = new Reticle(rootObject); + reticle->setWindow((QWindow*)rootObject); + engine.rootContext()->setContextProperty("Reticle", reticle); + engine.rootContext()->setContextProperty("Window", rootObject); + break; + } + } return app.exec(); } + +#include "main.moc" + diff --git a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml index 753771987a..033039b87d 100644 --- a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml +++ b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml @@ -16,8 +16,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 -import stylesUit 1.0 as HifiStylesUit -import controlsUit 1.0 as HifiControlsUit +import "qrc:////qml//styles-uit" as HifiStylesUit +import "qrc:////qml//controls-uit" as HifiControlsUit import "qrc:////qml//controls" as HifiControls import "qrc:////qml//hifi" as Hifi From 0d39343be4fee9954ef870c091ea6b6270d0191e Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 11:19:47 -0700 Subject: [PATCH 110/114] changed if statement to switch in preferencesDialog.cpp, also removed print statement --- interface/src/ui/PreferencesDialog.cpp | 35 +++++++++++++++----------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 92628c23b7..2b8f991174 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -260,20 +260,27 @@ void setupPreferences() { preferences->addPreference(preference); } { - auto getter = [myAvatar]()->int { if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::Auto) { - return 0; - } else if (myAvatar->getUserRecenterModel() == MyAvatar::SitStandModelType::ForceSit) { - return 1; - } else { - return 2; - }}; - auto setter = [myAvatar](int value) { if (value == 0) { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); - } else if (value == 1) { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); - } else { - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); - }}; + auto getter = [myAvatar]()->int { switch (myAvatar->getUserRecenterModel()) { + case MyAvatar::SitStandModelType::Auto: + default: + return 0; + case MyAvatar::SitStandModelType::ForceSit: + return 1; + case MyAvatar::SitStandModelType::DisableHMDLean: + return 2; + }}; + auto setter = [myAvatar](int value) { switch (value) { + case 0: + default: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); + break; + case 1: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); + break; + case 2: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); + break; + }}; auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); QStringList items; items << "Auto - turns on avatar leaning when standing in real world" << "Seated - disables all avatar leaning while sitting in real world" << "Disabled - allows avatar sitting on the floor [Experimental]"; From 78f0afd39ff85a1467c460b4d5d0d9c78bf1dfe3 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 23 Oct 2018 12:13:41 -0700 Subject: [PATCH 111/114] fix crash on shutdown --- libraries/networking/src/ResourceCache.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 076db44ea6..220e487d3a 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -252,7 +252,9 @@ ResourceCache::ResourceCache(QObject* parent) : QObject(parent) { } } -ResourceCache::~ResourceCache() {} +ResourceCache::~ResourceCache() { + clearUnusedResources(); +} void ResourceCache::clearATPAssets() { { From 9bc92cb2a33cf982ff894057a0a65454d6cb7840 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 12:29:04 -0700 Subject: [PATCH 112/114] removed leftover triggers --- interface/src/avatar/MyAvatar.cpp | 4 +--- interface/src/avatar/MyAvatar.h | 23 ----------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index dd40a748af..78cfed9b30 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3961,6 +3961,7 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { setIsSitStandStateLocked(true); break; case MyAvatar::SitStandModelType::Auto: + default: setHMDLeanRecenterEnabled(true); setIsInSittingState(false); setIsSitStandStateLocked(false); @@ -3970,10 +3971,7 @@ void MyAvatar::setUserRecenterModel(MyAvatar::SitStandModelType modelName) { setIsInSittingState(false); setIsSitStandStateLocked(false); break; - default: - break; } - emit userRecenterModelChanged((int)modelName); } void MyAvatar::setIsSitStandStateLocked(bool isLocked) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 0f6f9d9411..8bbf163bd8 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1555,29 +1555,6 @@ signals: */ void disableHandTouchForIDChanged(const QUuid& entityID, bool disable); - /**jsdoc - * Triggered when the sit state is enabled or disabled - * @function MyAvatar.sittingEnabledChanged - * @param {boolean} enabled - * @returns {Signal} - */ - void sittingEnabledChanged(bool enabled); - - /**jsdoc - * Triggered when the recenter model is changed - * @function MyAvatar.userRecenterModelChanged - * @param {int} userRecenteringModeltype - * @returns {Signal} - */ - void userRecenterModelChanged(int modelName); - - /**jsdoc - * Triggered when the sit state is enabled or disabled - * @function MyAvatar.sitStandStateLockEnabledChanged - * @param {boolean} enabled - * @returns {Signal} - */ - void sitStandStateLockEnabledChanged(bool enabled); private slots: void leaveDomain(); From 5cbddfe0c47c9c96d1c739726c72ab9b0427c7ae Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 22 Oct 2018 14:08:22 -0700 Subject: [PATCH 113/114] consider all sockets in findNodeWithAddr --- libraries/networking/src/LimitedNodeList.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 7cae5d8a71..37b914143e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -1188,7 +1188,9 @@ void LimitedNodeList::sendPeerQueryToIceServer(const HifiSockAddr& iceServerSock SharedNodePointer LimitedNodeList::findNodeWithAddr(const HifiSockAddr& addr) { QReadLocker locker(&_nodeMutex); auto it = std::find_if(std::begin(_nodeHash), std::end(_nodeHash), [&addr](const UUIDNodePair& pair) { - return pair.second->getActiveSocket() ? (*pair.second->getActiveSocket() == addr) : false; + return pair.second->getPublicSocket() == addr + || pair.second->getLocalSocket() == addr + || pair.second->getSymmetricSocket() == addr; }); return (it != std::end(_nodeHash)) ? it->second : SharedNodePointer(); } @@ -1197,8 +1199,8 @@ bool LimitedNodeList::sockAddrBelongsToNode(const HifiSockAddr& sockAddr) { QReadLocker locker(&_nodeMutex); auto it = std::find_if(std::begin(_nodeHash), std::end(_nodeHash), [&sockAddr](const UUIDNodePair& pair) { return pair.second->getPublicSocket() == sockAddr - || pair.second->getLocalSocket() == sockAddr - || pair.second->getSymmetricSocket() == sockAddr; + || pair.second->getLocalSocket() == sockAddr + || pair.second->getSymmetricSocket() == sockAddr; }); return it != std::end(_nodeHash); } From 2df9d6c5e9065fbe9b83eb975dccec98a6273f2c Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 23 Oct 2018 13:37:56 -0700 Subject: [PATCH 114/114] addressed missing changes for luis --- interface/src/avatar/MyAvatar.cpp | 32 +++++++++--------- interface/src/ui/PreferencesDialog.cpp | 46 ++++++++++++++------------ 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 78cfed9b30..71c3ba4fc6 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -530,6 +530,7 @@ void MyAvatar::update(float deltaTime) { const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders const float COSINE_THIRTY_DEGREES = 0.866f; const float SQUATTY_TIMEOUT = 30.0f; // 30 seconds + const float HEIGHT_FILTER_COEFFICIENT = 0.01f; float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); @@ -559,7 +560,7 @@ void MyAvatar::update(float deltaTime) { controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD); if (newHeightReading.isValid()) { int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER); - _averageUserHeightSensorSpace = lerp(_averageUserHeightSensorSpace, newHeightReading.getTranslation().y, 0.01f); + _averageUserHeightSensorSpace = lerp(_averageUserHeightSensorSpace, newHeightReading.getTranslation().y, HEIGHT_FILTER_COEFFICIENT); _recentModeReadings.insert(newHeightReadingInCentimeters); setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); @@ -4232,21 +4233,22 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, co if (myAvatar.getSitStandStateChange()) { returnValue = true; - } - if (myAvatar.getIsInSittingState()) { - if (myAvatar.getIsSitStandStateLocked()) { - returnValue = (offset.y > CYLINDER_TOP); - } - if (offset.y < SITTING_BOTTOM) { - // we recenter more easily when in sitting state. - returnValue = true; - } } else { - // in the standing state - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); - // finally check for squats in standing - if (_squatDetected) { - returnValue = true; + if (myAvatar.getIsInSittingState()) { + if (myAvatar.getIsSitStandStateLocked()) { + returnValue = (offset.y > CYLINDER_TOP); + } + if (offset.y < SITTING_BOTTOM) { + // we recenter more easily when in sitting state. + returnValue = true; + } + } else { + // in the standing state + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // finally check for squats in standing + if (_squatDetected) { + returnValue = true; + } } } return returnValue; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 2b8f991174..34d80f50cf 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -260,27 +260,31 @@ void setupPreferences() { preferences->addPreference(preference); } { - auto getter = [myAvatar]()->int { switch (myAvatar->getUserRecenterModel()) { - case MyAvatar::SitStandModelType::Auto: - default: - return 0; - case MyAvatar::SitStandModelType::ForceSit: - return 1; - case MyAvatar::SitStandModelType::DisableHMDLean: - return 2; - }}; - auto setter = [myAvatar](int value) { switch (value) { - case 0: - default: - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); - break; - case 1: - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); - break; - case 2: - myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); - break; - }}; + auto getter = [myAvatar]()->int { + switch (myAvatar->getUserRecenterModel()) { + case MyAvatar::SitStandModelType::Auto: + default: + return 0; + case MyAvatar::SitStandModelType::ForceSit: + return 1; + case MyAvatar::SitStandModelType::DisableHMDLean: + return 2; + } + }; + auto setter = [myAvatar](int value) { + switch (value) { + case 0: + default: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::Auto); + break; + case 1: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::ForceSit); + break; + case 2: + myAvatar->setUserRecenterModel(MyAvatar::SitStandModelType::DisableHMDLean); + break; + } + }; auto preference = new RadioButtonsPreference(VR_MOVEMENT, "Auto / Force Sit / Disable Recenter", getter, setter); QStringList items; items << "Auto - turns on avatar leaning when standing in real world" << "Seated - disables all avatar leaning while sitting in real world" << "Disabled - allows avatar sitting on the floor [Experimental]";

Qd%Ka2Apmb~P_L>@7Kk>gbHUQ;C^H}3_k<9&MH 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 (TOTAL_LOADING_PROGRESS * 0.4)) { + if (currentProgress >= ((TOTAL_LOADING_PROGRESS * 0.4) - TEXTURE_EPSILON)) { var textureResourceGPUMemSize = renderStats.textureResourceGPUMemSize; var texturePopulatedGPUMemSize = renderStats.textureResourcePopulatedGPUMemSize; @@ -472,10 +474,9 @@ textureMemSizeAtLastCheck = textureResourceGPUMemSize; - if (textureMemSizeStabilityCount >= 20) { + if (textureMemSizeStabilityCount >= 30) { if (textureResourceGPUMemSize > 0) { - // print((texturePopulatedGPUMemSize / textureResourceGPUMemSize)); var gpuPercantage = (TOTAL_LOADING_PROGRESS * 0.6) * (texturePopulatedGPUMemSize / textureResourceGPUMemSize); var totalProgress = progress + gpuPercantage; if (totalProgress >= target) { @@ -489,7 +490,11 @@ target = TOTAL_LOADING_PROGRESS; } - currentProgress = lerp(currentProgress, target, 0.2); + if (deltaTime > 1.0) { + deltaTimeMS = 0.02; + } + + currentProgress = lerp(currentProgress, target, (deltaTimeMS * 2.0)); var properties = { localPosition: { x: (1.85 - (currentProgress / 2) - (-0.029 * (currentProgress / TOTAL_LOADING_PROGRESS))), y: -0.935, z: 0.0 }, dimensions: { From fa6b3019f6768ec3901e1e74dd5ea2972a3ff2e8 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Fri, 12 Oct 2018 12:07:39 -0700 Subject: [PATCH 045/114] fix js memory leak --- .../controllers/controllerModules/webSurfaceLaserInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js index 898164dc99..229f1c411f 100644 --- a/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js +++ b/scripts/system/controllers/controllerModules/webSurfaceLaserInput.js @@ -109,7 +109,7 @@ Script.include("/~/system/libraries/controllers.js"); Messages.sendMessage('Hifi-Hand-RayPick-Blacklist', JSON.stringify(data)); } - this.ignoredOverlays = []; + this.ignoredObjects = []; }; this.isPointingAtTriggerable = function(controllerData, triggerPressed, checkEntitiesOnly) { From 7dd156ccdd790bbc750d05465ad4ad3de6698067 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 12 Oct 2018 15:00:15 -0700 Subject: [PATCH 046/114] made the threshold for the spine angle larger to make auto transitions more robust --- interface/src/avatar/MyAvatar.cpp | 57 +++++++++++++++--------- interface/src/avatar/MyAvatar.h | 2 +- interface/src/avatar/MySkeletonModel.cpp | 2 +- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 745705f7b8..e130f78dc4 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -471,6 +471,7 @@ void MyAvatar::update(float deltaTime) { const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; const float COSINE_TEN_DEGREES = 0.98f; + const float COSINE_THIRTY_DEGREES = 0.866f; const int SITTING_COUNT_THRESHOLD = 300; const int SQUATTY_COUNT_THRESHOLD = 600; @@ -518,7 +519,7 @@ void MyAvatar::update(float deltaTime) { upSpine2 = glm::normalize(upSpine2); } float angleSpine2 = glm::dot(upSpine2, glm::vec3(0.0f, 1.0f, 0.0f)); - if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_TEN_DEGREES)) { + if (getControllerPoseInAvatarFrame(controller::Action::HEAD).getTranslation().y < (headDefaultPositionAvatarSpace.y - SQUAT_THRESHOLD) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { _squatCount++; } else { _squatCount = 0; @@ -531,7 +532,7 @@ void MyAvatar::update(float deltaTime) { glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); // put update sit stand state counts here - if (getIsSitStandStateLocked()) { + if (!getIsSitStandStateLocked() && (_follow._velocityCount > 60)) { if (getIsInSittingState()) { if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we recenter upwards then no longer in sitting state @@ -544,10 +545,10 @@ void MyAvatar::update(float deltaTime) { _tippingPoint = newHeightReading.getTranslation().y; } _averageUserHeightCount = 1; - setResetMode(true); + // setResetMode(true); setIsInSittingState(false); - setCenterOfGravityModelEnabled(true); - setSitStandStateChange(true); + // setCenterOfGravityModelEnabled(true); + // setSitStandStateChange(true); } qCDebug(interfaceapp) << "going to stand state"; } else { @@ -557,7 +558,7 @@ void MyAvatar::update(float deltaTime) { } } else { // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint))) {// && (angleSpine2 > COSINE_TEN_DEGREES) && !(sensorHips.y > (0.4f * averageSensorSpaceHeight))) { + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { _sitStandStateCount++; if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { _sitStandStateCount = 0; @@ -567,11 +568,10 @@ void MyAvatar::update(float deltaTime) { _tippingPoint = newHeightReading.getTranslation().y; } _averageUserHeightCount = 1; - setResetMode(true); + // setResetMode(true); setIsInSittingState(true); - setCenterOfGravityModelEnabled(false); - - setSitStandStateChange(true); + // setCenterOfGravityModelEnabled(false); + // setSitStandStateChange(true); } qCDebug(interfaceapp) << "going to sit state"; } else { @@ -3898,6 +3898,13 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { void MyAvatar::setIsInSittingState(bool isSitting) { _isInSittingState.set(isSitting); + setResetMode(true); + if (isSitting) { + setCenterOfGravityModelEnabled(false); + } else { + setCenterOfGravityModelEnabled(true); + } + setSitStandStateChange(true); emit sittingEnabledChanged(isSitting); } @@ -4146,32 +4153,34 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const float CYLINDER_TOP = 0.1f; const float CYLINDER_BOTTOM = -1.5f; const float SITTING_BOTTOM = -0.02f; - const int SQUATTY_COUNT_THRESHOLD = 600; + const int SQUATTY_COUNT_THRESHOLD = 1800; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); bool returnValue = false; - returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); if (myAvatar.getSitStandStateChange()) { - qCDebug(interfaceapp) << "sit state change"; + // qCDebug(interfaceapp) << "sit state change"; returnValue = true; + } if (myAvatar.getIsInSittingState()) { + if (myAvatar.getIsSitStandStateLocked()) { + returnValue = (offset.y > CYLINDER_TOP); + } if (offset.y < SITTING_BOTTOM) { // we recenter when sitting. - qCDebug(interfaceapp) << "lean back sitting "; + // qCDebug(interfaceapp) << "lean back sitting "; returnValue = true; } } else { // in the standing state - if (myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) { + returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); + // finally check for squats in standing + if ((myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) && !myAvatar.getIsSitStandStateLocked()) { myAvatar._squatCount = 0; - qCDebug(interfaceapp) << "squatting "; - // returnValue = true; - } - if (returnValue == true) { - qCDebug(interfaceapp) << "above or below capsule in standing"; + // qCDebug(interfaceapp) << "squatting "; + returnValue = true; } } return returnValue; @@ -4185,6 +4194,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); + qCDebug(interfaceapp) << "should activate rotation true "; myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { @@ -4199,7 +4209,8 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat // center of gravity model is not enabled if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Horizontal); - if (myAvatar.getEnableStepResetRotation()) { + if (myAvatar.getEnableStepResetRotation() && !myAvatar.getIsInSittingState()) { + qCDebug(interfaceapp) << "step recenter rotation true "; activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } @@ -4214,6 +4225,10 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) { _velocityCount++; } + if (_velocityCount > 60) { + qCDebug(interfaceapp) << "reached velocity count "; + } + } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 674d4b8b70..10b5510e4d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1835,7 +1835,7 @@ private: float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; int _averageUserHeightCount{ 1 }; bool _sitStandStateChange{ false }; - ThreadSafeValueCache _lockSitStandState { true }; + ThreadSafeValueCache _lockSitStandState { false }; // max unscaled forward movement speed ThreadSafeValueCache _walkSpeed { DEFAULT_AVATAR_MAX_WALKING_SPEED }; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 78c5c03cc9..e5b9df7dd1 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { } glm::mat4 hipsMat; - if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState())) { + if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && !(myAvatar->getIsInSittingState()) && myAvatar->getHMDLeanRecenterEnabled()) { // then we use center of gravity model hipsMat = myAvatar->deriveBodyUsingCgModel(); } else { From ee830cdcb0ef19f7f731d6032eccefe957a7fec3 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 12 Oct 2018 16:05:31 -0700 Subject: [PATCH 047/114] cleaned white space --- interface/src/avatar/MyAvatar.cpp | 40 +++++++++---------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e130f78dc4..5e4db283a3 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -470,7 +470,6 @@ void MyAvatar::update(float deltaTime) { const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; - const float COSINE_TEN_DEGREES = 0.98f; const float COSINE_THIRTY_DEGREES = 0.866f; const int SITTING_COUNT_THRESHOLD = 300; const int SQUATTY_COUNT_THRESHOLD = 600; @@ -545,12 +544,8 @@ void MyAvatar::update(float deltaTime) { _tippingPoint = newHeightReading.getTranslation().y; } _averageUserHeightCount = 1; - // setResetMode(true); setIsInSittingState(false); - // setCenterOfGravityModelEnabled(true); - // setSitStandStateChange(true); } - qCDebug(interfaceapp) << "going to stand state"; } else { _sitStandStateCount = 0; // tipping point is average height when sitting. @@ -568,19 +563,13 @@ void MyAvatar::update(float deltaTime) { _tippingPoint = newHeightReading.getTranslation().y; } _averageUserHeightCount = 1; - // setResetMode(true); setIsInSittingState(true); - // setCenterOfGravityModelEnabled(false); - // setSitStandStateChange(true); } - qCDebug(interfaceapp) << "going to sit state"; } else { - // returnValue = (offset.y > CYLINDER_TOP) || (offset.y < CYLINDER_BOTTOM); // use the mode height for the tipping point when we are standing. _tippingPoint = getCurrentStandingHeight(); _sitStandStateCount = 0; } - } } @@ -594,7 +583,7 @@ void MyAvatar::update(float deltaTime) { // draw hand azimuth vector glm::vec3 handAzimuthMidpoint = transformPoint(getTransform().getMatrix(), glm::vec3(_hipToHandController.x, 0.0f, _hipToHandController.y)); - DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); + DebugDraw::getInstance().drawRay(getWorldPosition(), handAzimuthMidpoint, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)); } if (_goToPending) { @@ -3909,7 +3898,12 @@ void MyAvatar::setIsInSittingState(bool isSitting) { } void MyAvatar::setIsSitStandStateLocked(bool isLocked) { + const float DEFAULT_FLOOR_HEIGHT = 0.0f; _lockSitStandState.set(isLocked); + _sitStandStateCount = 0; + _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; + _tippingPoint = DEFAULT_FLOOR_HEIGHT; + _averageUserHeightCount = 1; emit sitStandStateLockEnabledChanged(isLocked); } @@ -4156,21 +4150,17 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl const int SQUATTY_COUNT_THRESHOLD = 1800; glm::vec3 offset = extractTranslation(desiredBodyMatrix) - extractTranslation(currentBodyMatrix); - bool returnValue = false; if (myAvatar.getSitStandStateChange()) { - // qCDebug(interfaceapp) << "sit state change"; returnValue = true; - } if (myAvatar.getIsInSittingState()) { if (myAvatar.getIsSitStandStateLocked()) { returnValue = (offset.y > CYLINDER_TOP); } if (offset.y < SITTING_BOTTOM) { - // we recenter when sitting. - // qCDebug(interfaceapp) << "lean back sitting "; + // we recenter more easily when in sitting state. returnValue = true; } } else { @@ -4179,7 +4169,6 @@ bool MyAvatar::FollowHelper::shouldActivateVertical(MyAvatar& myAvatar, const gl // finally check for squats in standing if ((myAvatar._squatCount > SQUATTY_COUNT_THRESHOLD) && !myAvatar.getIsSitStandStateLocked()) { myAvatar._squatCount = 0; - // qCDebug(interfaceapp) << "squatting "; returnValue = true; } } @@ -4194,7 +4183,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); - qCDebug(interfaceapp) << "should activate rotation true "; myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } if (myAvatar.getCenterOfGravityModelEnabled()) { @@ -4210,28 +4198,22 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (!isActive(Horizontal) && (shouldActivateHorizontal(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Horizontal); if (myAvatar.getEnableStepResetRotation() && !myAvatar.getIsInSittingState()) { - qCDebug(interfaceapp) << "step recenter rotation true "; activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); } } } - - if (_velocityCount > 60) { + const int VELOCITY_COUNT_THRESHOLD = 60; + const float MINIMUM_HMD_VELOCITY = 0.1f; + if (_velocityCount > VELOCITY_COUNT_THRESHOLD) { if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Vertical); } } else { - if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > 0.1f)) { + if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > MINIMUM_HMD_VELOCITY)) { _velocityCount++; } - if (_velocityCount > 60) { - qCDebug(interfaceapp) << "reached velocity count "; - } - } - - } else { if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); From 90c9e578c845df4661adeda1f8d3809d2fb9fe53 Mon Sep 17 00:00:00 2001 From: amantley Date: Fri, 12 Oct 2018 16:47:53 -0700 Subject: [PATCH 048/114] when you unlock the transitions you now start in stand state --- interface/src/avatar/MyAvatar.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 5e4db283a3..172fdac96c 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -3904,6 +3904,10 @@ void MyAvatar::setIsSitStandStateLocked(bool isLocked) { _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; _tippingPoint = DEFAULT_FLOOR_HEIGHT; _averageUserHeightCount = 1; + if (!isLocked) { + // always start the auto transition mode in standing state. + setIsInSittingState(false); + } emit sitStandStateLockEnabledChanged(isLocked); } From 8e272d6dd27c95a9a2a73dc14c6e7755a97d9887 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 08:43:25 -0700 Subject: [PATCH 049/114] added the correction code for when you are misslabeled as sitting while you are standing. It will now handle a sit down correctly. Also made the first approximation of state based on the average user height. This should use the user input of their height associated with their account --- interface/src/avatar/MyAvatar.cpp | 12 ++++++++++++ interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 172fdac96c..458c3ee422 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -546,6 +546,18 @@ void MyAvatar::update(float deltaTime) { _averageUserHeightCount = 1; setIsInSittingState(false); } + } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(true); + } } else { _sitStandStateCount = 0; // tipping point is average height when sitting. diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 10b5510e4d..61eed672ef 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1846,7 +1846,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; - float _tippingPoint { DEFAULT_FLOOR_HEIGHT }; + float _tippingPoint { DEFAULT_AVATAR_HEIGHT }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From ae3ae9ce9a081e7b41d544f038655adda975b367 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 09:52:34 -0700 Subject: [PATCH 050/114] put in condition for away mode so that when you take the hmd off and put it back on the initial guess to your state is made again. --- interface/src/avatar/MyAvatar.cpp | 102 +++++++++++++++++------------- 1 file changed, 57 insertions(+), 45 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 458c3ee422..4e347eebbb 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -530,58 +530,70 @@ void MyAvatar::update(float deltaTime) { glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); + const int VELOCITY_COUNT_THRESHOLD = 60; // put update sit stand state counts here - if (!getIsSitStandStateLocked() && (_follow._velocityCount > 60)) { - if (getIsInSittingState()) { - if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + if (!getIsSitStandStateLocked() && (_follow._velocityCount > VELOCITY_COUNT_THRESHOLD)) { + if (!getIsAway()) { + if (getIsInSittingState()) { + if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(false); } - _averageUserHeightCount = 1; - setIsInSittingState(false); - } - } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(true); } - _averageUserHeightCount = 1; - setIsInSittingState(true); + } else { + _sitStandStateCount = 0; + // tipping point is average height when sitting. + _tippingPoint = averageSensorSpaceHeight; } } else { - _sitStandStateCount = 0; - // tipping point is average height when sitting. - _tippingPoint = averageSensorSpaceHeight; + // in the standing state + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(true); + } + } else { + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; + } } } else { - // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - setIsInSittingState(true); - } - } else { - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; - } + // if you are away then reset the average and set state to standing. + _squatCount = 0; + _sitStandStateCount = 0; + _follow._velocityCount = 0; + _averageUserHeightCount = 1; + _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; + _tippingPoint = DEFAULT_AVATAR_HEIGHT; + setIsInSittingState(false); } } From 9ec999e15e84b7eda15462efbe5ffb109955f9c4 Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 16:43:03 -0700 Subject: [PATCH 051/114] added condition for start up in oculus that gets the correct starting height --- interface/src/avatar/MyAvatar.cpp | 104 +++++++++++++++++------------- 1 file changed, 59 insertions(+), 45 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4e347eebbb..c809a2d614 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -471,7 +471,9 @@ void MyAvatar::update(float deltaTime) { const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; const float COSINE_THIRTY_DEGREES = 0.866f; - const int SITTING_COUNT_THRESHOLD = 300; + const float COSINE_TEN_DEGREES = 0.9848f; + const int SITTING_COUNT_THRESHOLD = 100; + const int STANDING_COUNT_THRESHOLD = 10; const int SQUATTY_COUNT_THRESHOLD = 600; float tau = deltaTime / HMD_FACING_TIMESCALE; @@ -530,59 +532,70 @@ void MyAvatar::update(float deltaTime) { glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); + glm::vec3 headUp = newHeightReading.getRotation() * glm::vec3(0.0f, 1.0f, 0.0f); + if (glm::length(headUp) > 0.0f) { + headUp = glm::normalize(headUp); + } + float angleHeadUp = glm::dot(headUp, glm::vec3(0.0f, 1.0f, 0.0f)); + const int VELOCITY_COUNT_THRESHOLD = 60; // put update sit stand state counts here - if (!getIsSitStandStateLocked() && (_follow._velocityCount > VELOCITY_COUNT_THRESHOLD)) { + if (!getIsSitStandStateLocked()) { if (!getIsAway()) { - if (getIsInSittingState()) { - if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + if ((_follow._velocityCount > VELOCITY_COUNT_THRESHOLD) || (qApp->isHMDMode() && (qApp->getActiveDisplayPlugin()->getName() == "Oculus Rift"))) { + if (getIsInSittingState()) { + if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(false); } - _averageUserHeightCount = 1; - setIsInSittingState(false); - } - } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleHeadUp > COSINE_THIRTY_DEGREES)) { + // if we are mis labelled as sitting but we are standing in the real world this will + // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + // here we stay in sit state but reset the average height + setIsInSittingState(true); } - _averageUserHeightCount = 1; - setIsInSittingState(true); + } else { + _sitStandStateCount = 0; + // tipping point is average height when sitting. + _tippingPoint = averageSensorSpaceHeight; } } else { - _sitStandStateCount = 0; - // tipping point is average height when sitting. - _tippingPoint = averageSensorSpaceHeight; - } - } else { - // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleSpine2 > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; + // in the standing state + if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleHeadUp > COSINE_THIRTY_DEGREES)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sitStandStateCount = 0; + _squatCount = 0; + if (newHeightReading.isValid()) { + _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; + _tippingPoint = newHeightReading.getTranslation().y; + } + _averageUserHeightCount = 1; + setIsInSittingState(true); } - _averageUserHeightCount = 1; - setIsInSittingState(true); + } else { + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; } - } else { - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; } } } else { @@ -4240,6 +4253,7 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } else { if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > MINIMUM_HMD_VELOCITY)) { _velocityCount++; + qCDebug(interfaceapp) << "velocity count is " << _velocityCount << " is away " << myAvatar.getIsAway() << " hmd mode "<< qApp->isHMDMode() << " " << qApp->getActiveDisplayPlugin()->getName(); } } } else { From 49b869c5e31c7d0b45ff51eaa54af28850cd26bf Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 18:02:50 -0700 Subject: [PATCH 052/114] got rid of velocity count, now use 'away' to trigger when to start computing the sit stand state --- interface/src/avatar/MyAvatar.cpp | 15 +-------------- interface/src/avatar/MyAvatar.h | 1 - 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c809a2d614..66e8570743 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -542,7 +542,7 @@ void MyAvatar::update(float deltaTime) { // put update sit stand state counts here if (!getIsSitStandStateLocked()) { if (!getIsAway()) { - if ((_follow._velocityCount > VELOCITY_COUNT_THRESHOLD) || (qApp->isHMDMode() && (qApp->getActiveDisplayPlugin()->getName() == "Oculus Rift"))) { + if (qApp->isHMDMode()) { if (getIsInSittingState()) { if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { // if we recenter upwards then no longer in sitting state @@ -602,7 +602,6 @@ void MyAvatar::update(float deltaTime) { // if you are away then reset the average and set state to standing. _squatCount = 0; _sitStandStateCount = 0; - _follow._velocityCount = 0; _averageUserHeightCount = 1; _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; _tippingPoint = DEFAULT_AVATAR_HEIGHT; @@ -4244,18 +4243,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } - const int VELOCITY_COUNT_THRESHOLD = 60; - const float MINIMUM_HMD_VELOCITY = 0.1f; - if (_velocityCount > VELOCITY_COUNT_THRESHOLD) { - if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { - activate(Vertical); - } - } else { - if ((glm::length(myAvatar.getControllerPoseInSensorFrame(controller::Action::HEAD).getVelocity()) > MINIMUM_HMD_VELOCITY)) { - _velocityCount++; - qCDebug(interfaceapp) << "velocity count is " << _velocityCount << " is away " << myAvatar.getIsAway() << " hmd mode "<< qApp->isHMDMode() << " " << qApp->getActiveDisplayPlugin()->getName(); - } - } } else { if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 61eed672ef..e8d9090e03 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1760,7 +1760,6 @@ private: std::atomic _forceActivateVertical { false }; std::atomic _forceActivateHorizontal { false }; std::atomic _toggleHipsFollowing { true }; - int _velocityCount { 0 }; }; FollowHelper _follow; From 7d7fe8c08913de6fc852881df268984934c2c80a Mon Sep 17 00:00:00 2001 From: amantley Date: Mon, 15 Oct 2018 18:12:27 -0700 Subject: [PATCH 053/114] removed some cruft --- interface/src/avatar/MyAvatar.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 66e8570743..00a8e0f30e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -510,6 +510,7 @@ void MyAvatar::update(float deltaTime) { setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); } + float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. const float SQUAT_THRESHOLD = 0.05f; @@ -526,12 +527,6 @@ void MyAvatar::update(float deltaTime) { _squatCount = 0; } - float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; - - glm::vec3 avatarHips = getAbsoluteJointTranslationInObjectFrame(getJointIndex("Hips")); - glm::vec3 worldHips = transformPoint(getTransform().getMatrix(), avatarHips); - glm::vec3 sensorHips = transformPoint(glm::inverse(getSensorToWorldMatrix()), worldHips); - glm::vec3 headUp = newHeightReading.getRotation() * glm::vec3(0.0f, 1.0f, 0.0f); if (glm::length(headUp) > 0.0f) { headUp = glm::normalize(headUp); From 952b1122713192f70bb5b1df4fb8ae987da16522 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 16 Oct 2018 15:10:26 -0700 Subject: [PATCH 054/114] changed the transition times to make them shorter sit == 3sec stand == 1sec, also added failsafe for when the average height is above 5ft. this can recover from a missed transition to standing. --- interface/src/avatar/MyAvatar.cpp | 153 ++++++++++++++---------------- interface/src/avatar/MyAvatar.h | 10 +- 2 files changed, 76 insertions(+), 87 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 00a8e0f30e..b59ff675e1 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -464,17 +464,72 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { } } +void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { + const float STANDING_HEIGHT_MULTIPLE = 1.2f; + const float SITTING_HEIGHT_MULTIPLE = 0.833f; + const int SITTING_COUNT_THRESHOLD = 180; + const int STANDING_COUNT_THRESHOLD = 60; + const int SQUATTY_COUNT_THRESHOLD = 600; + + // qCDebug(interfaceapp) << "locked " << getIsSitStandStateLocked() << " away " << getIsAway() << " hmd " << qApp->isHMDMode() << " user height " << _userHeight.get(); + if (!getIsSitStandStateLocked() && !getIsAway() && qApp->isHMDMode()) { + if (getIsInSittingState()) { + if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we recenter upwards then no longer in sitting state + _sitStandStateCount++; + if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { + _sumUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + setIsInSittingState(false); + } + } else if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { + // if we are mis labelled as sitting but we are standing in the real world this will + // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sumUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + // here we stay in sit state but reset the average height + setIsInSittingState(true); + } + } else { + // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) + if (_sumUserHeightSensorSpace > 1.52f) { + setIsInSittingState(true); + } else { + // tipping point is average height when sitting. + _tippingPoint = _sumUserHeightSensorSpace; + _sitStandStateCount = 0; + } + } + } else { + // in the standing state + if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { + _sitStandStateCount++; + if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { + _sumUserHeightSensorSpace = newHeightReading; + _tippingPoint = newHeightReading; + setIsInSittingState(true); + } + } else { + // use the mode height for the tipping point when we are standing. + _tippingPoint = getCurrentStandingHeight(); + _sitStandStateCount = 0; + } + } + } else { + // if you are away then reset the average and set state to standing. + _sumUserHeightSensorSpace = _userHeight.get(); + _tippingPoint = _userHeight.get(); + setIsInSittingState(false); + } +} + void MyAvatar::update(float deltaTime) { // update moving average of HMD facing in xz plane. const float HMD_FACING_TIMESCALE = getRotationRecenterFilterLength(); const float PERCENTAGE_WEIGHT_HEAD_VS_SHOULDERS_AZIMUTH = 0.0f; // 100 percent shoulders - const float STANDING_HEIGHT_MULTIPLE = 1.2f; - const float SITTING_HEIGHT_MULTIPLE = 0.833f; const float COSINE_THIRTY_DEGREES = 0.866f; - const float COSINE_TEN_DEGREES = 0.9848f; - const int SITTING_COUNT_THRESHOLD = 100; - const int STANDING_COUNT_THRESHOLD = 10; - const int SQUATTY_COUNT_THRESHOLD = 600; float tau = deltaTime / HMD_FACING_TIMESCALE; setHipToHandController(computeHandAzimuth()); @@ -504,13 +559,11 @@ void MyAvatar::update(float deltaTime) { controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD); if (newHeightReading.isValid()) { int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER); - _sumUserHeightSensorSpace += newHeightReading.getTranslation().y; - _averageUserHeightCount++; + _sumUserHeightSensorSpace = lerp(_sumUserHeightSensorSpace, newHeightReading.getTranslation().y, 0.01f); _recentModeReadings.insert(newHeightReadingInCentimeters); setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); } - float averageSensorSpaceHeight = _sumUserHeightSensorSpace / _averageUserHeightCount; // if the spine is straight and the head is below the default position by 5 cm then increment squatty count. const float SQUAT_THRESHOLD = 0.05f; @@ -533,76 +586,8 @@ void MyAvatar::update(float deltaTime) { } float angleHeadUp = glm::dot(headUp, glm::vec3(0.0f, 1.0f, 0.0f)); - const int VELOCITY_COUNT_THRESHOLD = 60; // put update sit stand state counts here - if (!getIsSitStandStateLocked()) { - if (!getIsAway()) { - if (qApp->isHMDMode()) { - if (getIsInSittingState()) { - if (newHeightReading.getTranslation().y > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { - // if we recenter upwards then no longer in sitting state - _sitStandStateCount++; - if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - setIsInSittingState(false); - } - } else if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleHeadUp > COSINE_THIRTY_DEGREES)) { - // if we are mis labelled as sitting but we are standing in the real world this will - // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - // here we stay in sit state but reset the average height - setIsInSittingState(true); - } - } else { - _sitStandStateCount = 0; - // tipping point is average height when sitting. - _tippingPoint = averageSensorSpaceHeight; - } - } else { - // in the standing state - if ((newHeightReading.getTranslation().y < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) && (angleHeadUp > COSINE_THIRTY_DEGREES)) { - _sitStandStateCount++; - if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sitStandStateCount = 0; - _squatCount = 0; - if (newHeightReading.isValid()) { - _sumUserHeightSensorSpace = newHeightReading.getTranslation().y; - _tippingPoint = newHeightReading.getTranslation().y; - } - _averageUserHeightCount = 1; - setIsInSittingState(true); - } - } else { - // use the mode height for the tipping point when we are standing. - _tippingPoint = getCurrentStandingHeight(); - _sitStandStateCount = 0; - } - } - } - } else { - // if you are away then reset the average and set state to standing. - _squatCount = 0; - _sitStandStateCount = 0; - _averageUserHeightCount = 1; - _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; - _tippingPoint = DEFAULT_AVATAR_HEIGHT; - setIsInSittingState(false); - } - } + updateSitStandState(newHeightReading.getTranslation().y, angleHeadUp); if (_drawAverageFacingEnabled) { auto sensorHeadPose = getControllerPoseInSensorFrame(controller::Action::HEAD); @@ -3917,6 +3902,9 @@ void MyAvatar::setIsInWalkingState(bool isWalking) { } void MyAvatar::setIsInSittingState(bool isSitting) { + _sitStandStateCount = 0; + _squatCount = 0; + // on reset height we need the count to be more than one in case the user sits and stands up quickly. _isInSittingState.set(isSitting); setResetMode(true); if (isSitting) { @@ -3929,12 +3917,10 @@ void MyAvatar::setIsInSittingState(bool isSitting) { } void MyAvatar::setIsSitStandStateLocked(bool isLocked) { - const float DEFAULT_FLOOR_HEIGHT = 0.0f; _lockSitStandState.set(isLocked); _sitStandStateCount = 0; - _sumUserHeightSensorSpace = DEFAULT_AVATAR_HEIGHT; - _tippingPoint = DEFAULT_FLOOR_HEIGHT; - _averageUserHeightCount = 1; + _sumUserHeightSensorSpace = _userHeight.get(); + _tippingPoint = _userHeight.get(); if (!isLocked) { // always start the auto transition mode in standing state. setIsInSittingState(false); @@ -4238,6 +4224,9 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat } } } + if (!isActive(Vertical) && (shouldActivateVertical(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { + activate(Vertical); + } } else { if (!isActive(Rotation) && getForceActivateRotation()) { activate(Rotation); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index e8d9090e03..59f9145404 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1116,6 +1116,7 @@ public: float getSprintSpeed() const; void setSitStandStateChange(bool stateChanged); float getSitStandStateChange() const; + void updateSitStandState(float newHeightReading, float angleHeadUp); QVector getScriptUrls(); @@ -1830,10 +1831,9 @@ private: const float DEFAULT_FLOOR_HEIGHT = 0.0f; // height of user in sensor space, when standing erect. - ThreadSafeValueCache _userHeight{ DEFAULT_AVATAR_HEIGHT }; - float _sumUserHeightSensorSpace{ DEFAULT_AVATAR_HEIGHT }; - int _averageUserHeightCount{ 1 }; - bool _sitStandStateChange{ false }; + ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; + float _sumUserHeightSensorSpace { _userHeight.get() }; + bool _sitStandStateChange { false }; ThreadSafeValueCache _lockSitStandState { false }; // max unscaled forward movement speed @@ -1845,7 +1845,7 @@ private: ThreadSafeValueCache _isInSittingState { false }; int _sitStandStateCount { 0 }; int _squatCount { 0 }; - float _tippingPoint { DEFAULT_AVATAR_HEIGHT }; + float _tippingPoint { _userHeight.get() }; // load avatar scripts once when rig is ready bool _shouldLoadScripts { false }; From cf7dc49499814f286b0e19c7ad75482b9557e367 Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 16 Oct 2018 16:04:31 -0700 Subject: [PATCH 055/114] removed a commment and changed the sanity check to be a const instead of a magic number --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b59ff675e1..742dda72b2 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -470,8 +470,8 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { const int SITTING_COUNT_THRESHOLD = 180; const int STANDING_COUNT_THRESHOLD = 60; const int SQUATTY_COUNT_THRESHOLD = 600; + const float SITTING_UPPER_BOUND = 1.52f; - // qCDebug(interfaceapp) << "locked " << getIsSitStandStateLocked() << " away " << getIsAway() << " hmd " << qApp->isHMDMode() << " user height " << _userHeight.get(); if (!getIsSitStandStateLocked() && !getIsAway() && qApp->isHMDMode()) { if (getIsInSittingState()) { if (newHeightReading > (STANDING_HEIGHT_MULTIPLE * _tippingPoint)) { @@ -494,7 +494,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } } else { // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) - if (_sumUserHeightSensorSpace > 1.52f) { + if (_sumUserHeightSensorSpace > SITTING_UPPER_BOUND) { setIsInSittingState(true); } else { // tipping point is average height when sitting. From 1764531822f86b160a2e509c6e46820d9a088f1c Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 16 Oct 2018 16:31:55 -0700 Subject: [PATCH 056/114] removed hand azimuth changes, that fixed azimuth when hands go behind origin of MyAvatar, these changes will be in a separate pr --- interface/src/avatar/MyAvatar.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 742dda72b2..7a35b0ee56 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -941,13 +941,6 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { // Find the vector halfway between the hip to hand azimuth vectors // This midpoint hand azimuth is in Avatar space glm::vec2 MyAvatar::computeHandAzimuth() const { - int spine2Index = _skeletonModel->getRig().indexOfJoint("Spine2"); - glm::vec3 azimuthOrigin(0.0f,0.0f,0.0f); - if (!(spine2Index < 0)) { - // use the spine for the azimuth origin. - azimuthOrigin = getAbsoluteJointTranslationInObjectFrame(spine2Index); - } - controller::Pose leftHandPoseAvatarSpace = getLeftHandPose(); controller::Pose rightHandPoseAvatarSpace = getRightHandPose(); controller::Pose headPoseAvatarSpace = getControllerPoseInAvatarFrame(controller::Action::HEAD); @@ -955,13 +948,11 @@ glm::vec2 MyAvatar::computeHandAzimuth() const { glm::vec2 latestHipToHandController = _hipToHandController; if (leftHandPoseAvatarSpace.isValid() && rightHandPoseAvatarSpace.isValid() && headPoseAvatarSpace.isValid()) { - glm::vec3 rightHandOffset = rightHandPoseAvatarSpace.translation - azimuthOrigin; - glm::vec3 leftHandOffset = leftHandPoseAvatarSpace.translation - azimuthOrigin; // we need the old azimuth reading to prevent flipping the facing direction 180 // in the case where the hands go from being slightly less than 180 apart to slightly more than 180 apart. glm::vec2 oldAzimuthReading = _hipToHandController; - if ((glm::length(glm::vec2(rightHandOffset.x, rightHandOffset.z)) > 0.0f) && (glm::length(glm::vec2(leftHandOffset.x, leftHandOffset.z)) > 0.0f)) { - latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandOffset.x, rightHandOffset.z)), glm::normalize(glm::vec2(leftHandOffset.x, leftHandOffset.z)), HALFWAY); + if ((glm::length(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)) > 0.0f) && (glm::length(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)) > 0.0f)) { + latestHipToHandController = lerp(glm::normalize(glm::vec2(rightHandPoseAvatarSpace.translation.x, rightHandPoseAvatarSpace.translation.z)), glm::normalize(glm::vec2(leftHandPoseAvatarSpace.translation.x, leftHandPoseAvatarSpace.translation.z)), HALFWAY); } else { latestHipToHandController = glm::vec2(0.0f, -1.0f); } From baeccebfb9e3349f238adc7d4175dbcf7e1c0adb Mon Sep 17 00:00:00 2001 From: amantley Date: Tue, 16 Oct 2018 17:45:55 -0700 Subject: [PATCH 057/114] changed the transition times to make the sit longer and the stand shorter --- interface/src/avatar/MyAvatar.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7a35b0ee56..b85f19a06d 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -467,8 +467,8 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { const float STANDING_HEIGHT_MULTIPLE = 1.2f; const float SITTING_HEIGHT_MULTIPLE = 0.833f; - const int SITTING_COUNT_THRESHOLD = 180; - const int STANDING_COUNT_THRESHOLD = 60; + const int SITTING_COUNT_THRESHOLD = 240; + const int STANDING_COUNT_THRESHOLD = 20; const int SQUATTY_COUNT_THRESHOLD = 600; const float SITTING_UPPER_BOUND = 1.52f; @@ -495,7 +495,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } else { // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) if (_sumUserHeightSensorSpace > SITTING_UPPER_BOUND) { - setIsInSittingState(true); + setIsInSittingState(false); } else { // tipping point is average height when sitting. _tippingPoint = _sumUserHeightSensorSpace; @@ -4192,7 +4192,6 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat if (myAvatar.getHMDLeanRecenterEnabled() && qApp->getCamera().getMode() != CAMERA_MODE_MIRROR) { - if (!isActive(Rotation) && (shouldActivateRotation(myAvatar, desiredBodyMatrix, currentBodyMatrix) || hasDriveInput)) { activate(Rotation); myAvatar.setHeadControllerFacingMovingAverage(myAvatar.getHeadControllerFacing()); From cd7af8b6052c887276e552b99be6a341530a459b Mon Sep 17 00:00:00 2001 From: amantley Date: Wed, 17 Oct 2018 08:51:40 -0700 Subject: [PATCH 058/114] changed the name of sumuserheightsensorspace to averageuserheightSensorSpace --- interface/src/avatar/MyAvatar.cpp | 16 ++++++++-------- interface/src/avatar/MyAvatar.h | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index b85f19a06d..9fe91e44b9 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -478,7 +478,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { // if we recenter upwards then no longer in sitting state _sitStandStateCount++; if (_sitStandStateCount > STANDING_COUNT_THRESHOLD) { - _sumUserHeightSensorSpace = newHeightReading; + _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; setIsInSittingState(false); } @@ -487,18 +487,18 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { // make sure that a real sit is still recognized so we won't be stuck in sitting unable to change state _sitStandStateCount++; if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sumUserHeightSensorSpace = newHeightReading; + _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; // here we stay in sit state but reset the average height setIsInSittingState(true); } } else { // sanity check if average height greater than 5ft they are not sitting(or get off your dangerous barstool please) - if (_sumUserHeightSensorSpace > SITTING_UPPER_BOUND) { + if (_averageUserHeightSensorSpace > SITTING_UPPER_BOUND) { setIsInSittingState(false); } else { // tipping point is average height when sitting. - _tippingPoint = _sumUserHeightSensorSpace; + _tippingPoint = _averageUserHeightSensorSpace; _sitStandStateCount = 0; } } @@ -507,7 +507,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { if (newHeightReading < (SITTING_HEIGHT_MULTIPLE * _tippingPoint)) { _sitStandStateCount++; if (_sitStandStateCount > SITTING_COUNT_THRESHOLD) { - _sumUserHeightSensorSpace = newHeightReading; + _averageUserHeightSensorSpace = newHeightReading; _tippingPoint = newHeightReading; setIsInSittingState(true); } @@ -519,7 +519,7 @@ void MyAvatar::updateSitStandState(float newHeightReading, float angleHeadUp) { } } else { // if you are away then reset the average and set state to standing. - _sumUserHeightSensorSpace = _userHeight.get(); + _averageUserHeightSensorSpace = _userHeight.get(); _tippingPoint = _userHeight.get(); setIsInSittingState(false); } @@ -559,7 +559,7 @@ void MyAvatar::update(float deltaTime) { controller::Pose newHeightReading = getControllerPoseInSensorFrame(controller::Action::HEAD); if (newHeightReading.isValid()) { int newHeightReadingInCentimeters = glm::floor(newHeightReading.getTranslation().y * CENTIMETERS_PER_METER); - _sumUserHeightSensorSpace = lerp(_sumUserHeightSensorSpace, newHeightReading.getTranslation().y, 0.01f); + _averageUserHeightSensorSpace = lerp(_averageUserHeightSensorSpace, newHeightReading.getTranslation().y, 0.01f); _recentModeReadings.insert(newHeightReadingInCentimeters); setCurrentStandingHeight(computeStandingHeightMode(newHeightReading)); setAverageHeadRotation(computeAverageHeadRotation(getControllerPoseInAvatarFrame(controller::Action::HEAD))); @@ -3910,7 +3910,7 @@ void MyAvatar::setIsInSittingState(bool isSitting) { void MyAvatar::setIsSitStandStateLocked(bool isLocked) { _lockSitStandState.set(isLocked); _sitStandStateCount = 0; - _sumUserHeightSensorSpace = _userHeight.get(); + _averageUserHeightSensorSpace = _userHeight.get(); _tippingPoint = _userHeight.get(); if (!isLocked) { // always start the auto transition mode in standing state. diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 59f9145404..d1ba0fd9cf 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1832,7 +1832,7 @@ private: // height of user in sensor space, when standing erect. ThreadSafeValueCache _userHeight { DEFAULT_AVATAR_HEIGHT }; - float _sumUserHeightSensorSpace { _userHeight.get() }; + float _averageUserHeightSensorSpace { _userHeight.get() }; bool _sitStandStateChange { false }; ThreadSafeValueCache _lockSitStandState { false }; From 3b15548ea3dec0e62cbb9e6ad7acf0f90c8cc536 Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Wed, 26 Sep 2018 14:32:25 -0700 Subject: [PATCH 059/114] Display resource-access events in marketplace item tester Includes refactoring marketplace item tester into a single-page app. --- assignment-client/src/Agent.cpp | 5 +- .../MarketplaceItemTester.qml | 364 ++++++++++++------ interface/src/Application.cpp | 16 +- interface/src/Application.h | 2 +- interface/src/assets/ATPAssetMigrator.cpp | 17 +- interface/src/commerce/QmlCommerce.cpp | 3 +- .../scripting/ClipboardScriptingInterface.cpp | 10 +- .../scripting/ClipboardScriptingInterface.h | 6 +- interface/src/ui/overlays/Web3DOverlay.cpp | 7 +- libraries/avatars/src/AvatarData.cpp | 27 +- libraries/entities/src/EntityEditFilters.cpp | 37 +- libraries/entities/src/EntityTree.cpp | 16 +- libraries/entities/src/EntityTree.h | 10 +- libraries/fbx/src/GLTFReader.cpp | 193 +++++----- libraries/fbx/src/OBJReader.cpp | 29 +- .../src/model-networking/TextureCache.cpp | 6 +- .../networking/src/AssetResourceRequest.cpp | 12 +- .../networking/src/AssetResourceRequest.h | 6 +- libraries/networking/src/AtpReply.cpp | 3 +- .../networking/src/FileResourceRequest.h | 11 +- .../networking/src/HTTPResourceRequest.h | 10 +- .../networking/src/NetworkAccessManager.cpp | 2 +- libraries/networking/src/ResourceCache.cpp | 70 ++-- libraries/networking/src/ResourceManager.cpp | 19 +- libraries/networking/src/ResourceManager.h | 7 +- libraries/networking/src/ResourceRequest.cpp | 7 +- libraries/networking/src/ResourceRequest.h | 23 +- libraries/octree/src/Octree.cpp | 39 +- libraries/octree/src/Octree.h | 11 +- libraries/qml/src/qml/OffscreenSurface.cpp | 5 + .../src/FileScriptingInterface.cpp | 7 +- libraries/script-engine/src/ScriptCache.cpp | 6 +- .../script-engine/src/XMLHttpRequestClass.cpp | 7 +- .../EntityItemWeakPointerWithUrlAncestry.h | 31 ++ libraries/shared/src/QUrlAncestry.cpp | 35 ++ libraries/shared/src/QUrlAncestry.h | 32 ++ .../shared/src/ResourceRequestObserver.cpp | 38 ++ .../shared/src/ResourceRequestObserver.h | 31 ++ scripts/system/marketplaces/marketplaces.js | 59 ++- 39 files changed, 841 insertions(+), 378 deletions(-) create mode 100644 libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h create mode 100644 libraries/shared/src/QUrlAncestry.cpp create mode 100644 libraries/shared/src/QUrlAncestry.h create mode 100644 libraries/shared/src/ResourceRequestObserver.cpp create mode 100644 libraries/shared/src/ResourceRequestObserver.h diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 639e9f924b..5f1e1ca74a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -222,7 +222,8 @@ void Agent::requestScript() { return; } - auto request = DependencyManager::get()->createResourceRequest(this, scriptURL); + auto request = DependencyManager::get()->createResourceRequest( + this, scriptURL, true, -1, "Agent::requestScript"); if (!request) { qWarning() << "Could not create ResourceRequest for Agent script at" << scriptURL.toString(); @@ -896,7 +897,7 @@ void Agent::aboutToFinish() { { DependencyManager::get()->shutdownScripting(); } - + DependencyManager::destroy(); DependencyManager::destroy(); diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index c3d87ca2f5..98b0355e81 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -4,7 +4,7 @@ // // Load items not in the marketplace for testing purposes // -// Created by Zach Fox on 2018-09-05 +// Created by Kerry Ivan Kurian on 2018-09-05 // Copyright 2018 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. @@ -26,7 +26,9 @@ Rectangle { id: root property string installedApps + property string resourceAccessEventText property var nextResourceObjectId: 0 + property var startDate signal sendToScript(var message) HifiStylesUit.HifiConstants { id: hifi } @@ -51,9 +53,28 @@ Rectangle { spinner.visible = false; break; case "nextObjectIdInTest": + print("!!!! message from script! " + JSON.stringify(message)); nextResourceObjectId = message.id; spinner.visible = false; break; + case "resourceRequestEvent": + try { + var date = new Date(JSON.parse(message.data.date)); + } catch(err) { + print("!!!!! Date conversion failed: " + JSON.stringify(message.data)); + } + // XXX Eventually this date check goes away b/c we will + // be able to match up resouce access events to resource + // object ids, ignoring those that have -1 resource + // object ids. + if (date >= startDate) { + resourceAccessEventText += ( + message.data.callerId + " " + message.data.extra + + " " + message.data.url + + " [" + date.toISOString() + "]\n" + ); + } + break; } } @@ -64,7 +85,7 @@ Rectangle { resource.match(/\.json\.gz$/) ? "content set" : resource.match(/\.json$/) ? "entity or wearable" : "unknown"); - return { "id": nextResourceObjectId++, + return { "resourceObjectId": nextResourceObjectId++, "resource": resource, "assetType": assetType }; } @@ -89,153 +110,240 @@ Rectangle { return httpPattern.test(resource) ? resource : "file:///" + resource; } - function rezEntity(resource, entityType) { + function rezEntity(resource, entityType, resourceObjectId) { + print("!!!! tester_rezClicked"); sendToScript({ method: 'tester_rezClicked', itemHref: toUrl(resource), - itemType: entityType}); + itemType: entityType, + itemId: resourceObjectId }); } - ListView { - anchors.fill: parent - anchors.leftMargin: 12 - anchors.bottomMargin: 40 - anchors.rightMargin: 12 - model: resourceListModel - spacing: 5 - interactive: false + Component.onCompleted: startDate = new Date() - delegate: RowLayout { + ColumnLayout { + id: rootColumn + spacing: 30 + + HifiStylesUit.RalewayRegular { + id: rootHeader + text: "Marketplace Item Tester" + height: 40 + width: paintedWidth + size: 22 + color: hifi.colors.black + anchors.top: parent.top + anchors.topMargin: 20 anchors.left: parent.left - width: parent.width - spacing: 5 + anchors.leftMargin: 12 + } - property var actions: { - "forward": function(resource, assetType){ - switch(assetType) { - case "application": - Commerce.openApp(resource); - break; - case "avatar": - MyAvatar.useFullAvatarURL(resource); - break; - case "content set": - urlHandler.handleUrl("hifi://localhost/0,0,0"); - Commerce.replaceContentSet(toUrl(resource), ""); - break; - case "entity": - case "wearable": - rezEntity(resource, assetType); - break; - default: - print("Marketplace item tester unsupported assetType " + assetType); - } - }, - "trash": function(resource, assetType){ - if ("application" === assetType) { - Commerce.uninstallApp(resource); - } - sendToScript({ - method: "tester_deleteResourceObject", - objectId: resourceListModel.get(index).id}); - resourceListModel.remove(index); - } - } + Rectangle { + height: root.height - 100 + width: root.width + anchors.left: parent.left - Column { - Layout.preferredWidth: root.width * .6 - spacing: 5 - Text { - text: { - var match = resource.match(/\/([^/]*)$/); - return match ? match[1] : resource; - } - font.pointSize: 12 - horizontalAlignment: Text.AlignBottom - } - Text { - text: resource - font.pointSize: 8 - width: root.width * .6 - horizontalAlignment: Text.AlignBottom - wrapMode: Text.WrapAnywhere - } - } + ScrollView { + id: scrollView + anchors.fill: parent + anchors.rightMargin: 12 + anchors.bottom: parent.top + anchors.bottomMargin: 20 + anchors.leftMargin: 12 + verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn - ComboBox { - id: comboBox + frameVisible: false - Layout.preferredWidth: root.width * .2 + contentItem: ListView { + spacing: 20 + height: 200 + model: resourceListModel + interactive: false - model: [ - "application", - "avatar", - "content set", - "entity", - "wearable", - "unknown" - ] + delegate: Column { + spacing: 8 - currentIndex: (("entity or wearable" === assetType) ? - model.indexOf("unknown") : model.indexOf(assetType)) + RowLayout { + id: listRow + width: scrollView.width - 20 + anchors.rightMargin: scrollView.rightMargin + spacing: 5 - Component.onCompleted: { - onCurrentIndexChanged.connect(function() { - assetType = model[currentIndex]; - sendToScript({ - method: "tester_updateResourceObjectAssetType", - objectId: resourceListModel.get(index)["id"], - assetType: assetType }); - }); - } - } + property var actions: { + "forward": function(resource, assetType, resourceObjectId){ + switch(assetType) { + case "application": + Commerce.openApp(resource); + break; + case "avatar": + MyAvatar.useFullAvatarURL(resource); + break; + case "content set": + urlHandler.handleUrl("hifi://localhost/0,0,0"); + Commerce.replaceContentSet(toUrl(resource), ""); + break; + case "entity": + case "wearable": + rezEntity(resource, assetType, resourceObjectId); + break; + default: + print("Marketplace item tester unsupported assetType " + assetType); + } + }, + "trash": function(resource, assetType){ + if ("application" === assetType) { + Commerce.uninstallApp(resource); + } + sendToScript({ + method: "tester_deleteResourceObject", + objectId: resourceListModel.get(index).id}); + resourceListModel.remove(index); + } + } - Repeater { - model: [ "forward", "trash" ] + Column { + Layout.preferredWidth: scrollView.width * .6 + spacing: 5 + Text { + width: listRow.width * .6 + text: { + var match = resource.match(/\/([^/]*)$/); + return match ? match[1] : resource; + } + font.pointSize: 12 + horizontalAlignment: Text.AlignBottom + wrapMode: Text.WrapAnywhere + } + Text { + width: listRow.width * .6 + text: resource + font.pointSize: 8 + horizontalAlignment: Text.AlignBottom + wrapMode: Text.WrapAnywhere + } + } - HifiStylesUit.HiFiGlyphs { - property var glyphs: { - "application": hifi.glyphs.install, - "avatar": hifi.glyphs.avatar, - "content set": hifi.glyphs.globe, - "entity": hifi.glyphs.wand, - "trash": hifi.glyphs.trash, - "unknown": hifi.glyphs.circleSlash, - "wearable": hifi.glyphs.hat, - } - text: (("trash" === modelData) ? - glyphs.trash : - glyphs[comboBox.model[comboBox.currentIndex]]) - size: ("trash" === modelData) ? 22 : 30 - color: hifi.colors.black - horizontalAlignment: Text.AlignHCenter - MouseArea { - anchors.fill: parent - onClicked: { - actions[modelData](resource, comboBox.currentText); + ComboBox { + id: comboBox + + Layout.preferredWidth: listRow.width * .2 + + model: [ + "application", + "avatar", + "content set", + "entity", + "wearable", + "unknown" + ] + + currentIndex: (("entity or wearable" === assetType) ? + model.indexOf("unknown") : model.indexOf(assetType)) + + Component.onCompleted: { + onCurrentIndexChanged.connect(function() { + assetType = model[currentIndex]; + sendToScript({ + method: "tester_updateResourceObjectAssetType", + objectId: resourceListModel.get(index)["resourceObjectId"], + assetType: assetType }); + }); + } + } + + Repeater { + model: [ "forward", "trash" ] + + HifiStylesUit.HiFiGlyphs { + property var glyphs: { + "application": hifi.glyphs.install, + "avatar": hifi.glyphs.avatar, + "content set": hifi.glyphs.globe, + "entity": hifi.glyphs.wand, + "trash": hifi.glyphs.trash, + "unknown": hifi.glyphs.circleSlash, + "wearable": hifi.glyphs.hat, + } + text: (("trash" === modelData) ? + glyphs.trash : + glyphs[comboBox.model[comboBox.currentIndex]]) + size: ("trash" === modelData) ? 22 : 30 + color: hifi.colors.black + horizontalAlignment: Text.AlignHCenter + MouseArea { + anchors.fill: parent + onClicked: { + listRow.actions[modelData](resource, comboBox.currentText, resourceObjectId); + } + } + } + } + } + + Rectangle { + id: detailsContainer + + width: scrollView.width - 20 + height: resourceDetails.isOpen ? 300 : 20 + anchors.left: parent.left + + HifiStylesUit.HiFiGlyphs { + id: detailsToggle + anchors.top: parent.top + text: resourceDetails.isOpen ? hifi.glyphs.minimize : hifi.glyphs.maximize + color: hifi.colors.black + size: 22 + verticalAlignment: Text.AlignBottom + MouseArea { + anchors.fill: parent + onClicked: resourceDetails.isOpen = !resourceDetails.isOpen + } + } + + TextArea { + id: resourceDetails + + property var isOpen: false + + width: detailsContainer.width - 20 + height: detailsContainer.height + anchors.top: parent.top + anchors.left: detailsToggle.left + anchors.leftMargin: 20 + verticalScrollBarPolicy: isOpen ? Qt.ScrollBarAsNeeded : Qt.ScrollBarAlwaysOff + frameVisible: isOpen + readOnly: true + + text: { + if (isOpen) { + return resourceAccessEventText + } else { + return (resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..." + } + } + font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) + wrapMode: TextEdit.NoWrap + } + } + + Rectangle { + width: listRow.width + height: 1 + color: hifi.colors.black } } } } } - headerPositioning: ListView.OverlayHeader - header: HifiStylesUit.RalewayRegular { - id: rootHeader - text: "Marketplace Item Tester" - height: 80 - width: paintedWidth - size: 22 - color: hifi.colors.black - anchors.left: parent.left - anchors.leftMargin: 12 - } - - footerPositioning: ListView.OverlayFooter - footer: Row { + Row { id: rootActions spacing: 20 - anchors.horizontalCenter: parent.horizontalCenter + + anchors.left: parent.left + anchors.leftMargin: root.width / 6 - 10 + anchors.bottomMargin: 40 + anchors.bottom: parent.bottom property string currentAction property var actions: { @@ -257,6 +365,7 @@ Rectangle { // Alas, there is nothing we can do about that so charge // ahead as though we are sure the present signal is one // we expect. + print("!!!! resource selected"); switch(currentAction) { case "load file": Window.browseChanged.disconnect(onResourceSelected); @@ -266,8 +375,11 @@ Rectangle { break; } if (resource) { + print("!!!! building resource object"); var resourceObj = buildResourceObj(resource); + print("!!!! installing resource object"); installResourceObj(resourceObj); + print("!!!! notifying script of resource object"); sendToScript({ method: 'tester_newResourceObject', resourceObject: resourceObj }); @@ -282,7 +394,7 @@ Rectangle { text: modelData width: root.width / 3 height: 40 - onClicked: actions[text]() + onClicked: rootActions.actions[text]() } } } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2dc3645be0..4c580d7de7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -170,6 +170,7 @@ #include "ModelPackager.h" #include "scripting/Audio.h" #include "networking/CloseEventSender.h" +#include "QUrlAncestry.h" #include "scripting/TestScriptingInterface.h" #include "scripting/AssetMappingsScriptingInterface.h" #include "scripting/ClipboardScriptingInterface.h" @@ -226,6 +227,7 @@ #include "commerce/Ledger.h" #include "commerce/Wallet.h" #include "commerce/QmlCommerce.h" +#include "ResourceRequestObserver.h" #include "webbrowser/WebBrowserSuggestionsEngine.h" #include @@ -945,8 +947,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); + DependencyManager::set(); return previousSessionCrashed; } @@ -1781,7 +1783,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo updateHeartbeat(); QTimer* settingsTimer = new QTimer(); moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{ - // This needs to run on the settings thread, so we need to pass the `settingsTimer` as the + // This needs to run on the settings thread, so we need to pass the `settingsTimer` as the // receiver object, otherwise it will run on the application thread and trigger a warning // about trying to kill the timer on the main thread. connect(qApp, &Application::beforeAboutToQuit, settingsTimer, [this, settingsTimer]{ @@ -3129,6 +3131,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get().data()); surfaceContext->setContextProperty("Wallet", DependencyManager::get().data()); surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance()); + surfaceContext->setContextProperty("ResourceRequestObserver", DependencyManager::get().data()); if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); @@ -5021,12 +5024,11 @@ void Application::saveSettings() const { PluginManager::getInstance()->saveSettings(); } -bool Application::importEntities(const QString& urlOrFilename) { +bool Application::importEntities(const QString& urlOrFilename, const bool isObservable, const qint64 callerId) { bool success = false; _entityClipboard->withWriteLock([&] { _entityClipboard->eraseAllOctreeElements(); - - success = _entityClipboard->readFromURL(urlOrFilename); + success = _entityClipboard->readFromURL(urlOrFilename, isObservable, callerId, QUrlAncestry()); if (success) { _entityClipboard->reaverageOctreeElements(); } @@ -6810,6 +6812,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("Wallet", DependencyManager::get().data()); scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get().data()); scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance()); + scriptEngine->registerGlobalObject("ResourceRequestObserver", DependencyManager::get().data()); qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); @@ -7196,7 +7199,8 @@ void Application::addAssetToWorldFromURL(QString url) { addAssetToWorldInfo(filename, "Downloading model file " + filename + "."); - auto request = DependencyManager::get()->createResourceRequest(nullptr, QUrl(url)); + auto request = DependencyManager::get()->createResourceRequest( + nullptr, QUrl(url), true, -1, "Application::addAssetToWorldFromURL"); connect(request, &ResourceRequest::finished, this, &Application::addAssetToWorldFromURLRequestFinished); request->send(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 75260b910f..d9f9591086 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -340,7 +340,7 @@ public slots: QVector pasteEntities(float x, float y, float z); bool exportEntities(const QString& filename, const QVector& entityIDs, const glm::vec3* givenOffset = nullptr); bool exportEntities(const QString& filename, float x, float y, float z, float scale); - bool importEntities(const QString& url); + bool importEntities(const QString& url, const bool isObservable = true, const qint64 callerId = -1); void updateThreadPoolCount() const; void updateSystemTabletMode(); void goToErrorDomainURL(QUrl errorDomainURL); diff --git a/interface/src/assets/ATPAssetMigrator.cpp b/interface/src/assets/ATPAssetMigrator.cpp index 45ac80b054..6912c69db8 100644 --- a/interface/src/assets/ATPAssetMigrator.cpp +++ b/interface/src/assets/ATPAssetMigrator.cpp @@ -53,7 +53,8 @@ void ATPAssetMigrator::loadEntityServerFile() { auto migrateResources = [=](QUrl migrationURL, QJsonValueRef jsonValue, bool isModelURL) { auto request = - DependencyManager::get()->createResourceRequest(this, migrationURL); + DependencyManager::get()->createResourceRequest( + this, migrationURL, true, -1, "ATPAssetMigrator::loadEntityServerFile"); if (request) { qCDebug(asset_migrator) << "Requesting" << migrationURL << "for ATP asset migration"; @@ -202,7 +203,7 @@ void ATPAssetMigrator::loadEntityServerFile() { void ATPAssetMigrator::migrateResource(ResourceRequest* request) { // use an asset client to upload the asset auto assetClient = DependencyManager::get(); - + auto upload = assetClient->createUpload(request->getData()); // add this URL to our hash of AssetUpload to original URL @@ -242,7 +243,7 @@ void ATPAssetMigrator::assetUploadFinished(AssetUpload *upload, const QString& h } checkIfFinished(); - + upload->deleteLater(); } @@ -298,24 +299,24 @@ void ATPAssetMigrator::checkIfFinished() { bool ATPAssetMigrator::wantsToMigrateResource(const QUrl& url) { static bool hasAskedForCompleteMigration { false }; static bool wantsCompleteMigration { false }; - + if (!hasAskedForCompleteMigration) { // this is the first resource migration - ask the user if they just want to migrate everything static const QString COMPLETE_MIGRATION_TEXT { "Do you want to migrate all assets found in this entity-server file?\n"\ "Select \"Yes\" to upload all discovered assets to the current asset-server immediately.\n"\ "Select \"No\" to be prompted for each discovered asset." }; - + auto button = OffscreenUi::question(_dialogParent, MESSAGE_BOX_TITLE, COMPLETE_MIGRATION_TEXT, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); - + if (button == QMessageBox::Yes) { wantsCompleteMigration = true; } - + hasAskedForCompleteMigration = true; } - + if (wantsCompleteMigration) { return true; } else { diff --git a/interface/src/commerce/QmlCommerce.cpp b/interface/src/commerce/QmlCommerce.cpp index aa39fdc1b9..83907df103 100644 --- a/interface/src/commerce/QmlCommerce.cpp +++ b/interface/src/commerce/QmlCommerce.cpp @@ -325,7 +325,8 @@ bool QmlCommerce::installApp(const QString& itemHref) { QUrl appHref(itemHref); - auto request = DependencyManager::get()->createResourceRequest(this, appHref); + auto request = DependencyManager::get()->createResourceRequest( + this, appHref, true, -1, "QmlCommerce::installApp"); if (!request) { qCDebug(commerce) << "Couldn't create resource request for app."; diff --git a/interface/src/scripting/ClipboardScriptingInterface.cpp b/interface/src/scripting/ClipboardScriptingInterface.cpp index c2d2b69883..c14f4ea895 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.cpp +++ b/interface/src/scripting/ClipboardScriptingInterface.cpp @@ -46,11 +46,17 @@ bool ClipboardScriptingInterface::exportEntities(const QString& filename, float return retVal; } -bool ClipboardScriptingInterface::importEntities(const QString& filename) { +bool ClipboardScriptingInterface::importEntities( + const QString& filename, + const bool isObservable, + const qint64 callerId +) { bool retVal; BLOCKING_INVOKE_METHOD(qApp, "importEntities", Q_RETURN_ARG(bool, retVal), - Q_ARG(const QString&, filename)); + Q_ARG(const QString&, filename), + Q_ARG(const bool, isObservable), + Q_ARG(const qint64, callerId)); return retVal; } diff --git a/interface/src/scripting/ClipboardScriptingInterface.h b/interface/src/scripting/ClipboardScriptingInterface.h index 32b8c64a7d..535ccfd5ab 100644 --- a/interface/src/scripting/ClipboardScriptingInterface.h +++ b/interface/src/scripting/ClipboardScriptingInterface.h @@ -50,9 +50,11 @@ public: * You can generate a JSON file using {@link Clipboard.exportEntities}. * @function Clipboard.importEntities * @param {string} filename Path and name of file to import. + * @param {boolean} does the ResourceRequestObserver observe this request? + * @param {number} optional internal id of object causing this import. * @returns {boolean} true if the import was successful, otherwise false. */ - Q_INVOKABLE bool importEntities(const QString& filename); + Q_INVOKABLE bool importEntities(const QString& filename, const bool isObservable = true, const qint64 callerId = -1); /**jsdoc * Export the entities specified to a JSON file. @@ -62,7 +64,7 @@ public: * @returns {boolean} true if the export was successful, otherwise false. */ Q_INVOKABLE bool exportEntities(const QString& filename, const QVector& entityIDs); - + /**jsdoc * Export the entities with centers within a cube to a JSON file. * @function Clipboard.exportEntities diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 9d55c91ef3..53505c2013 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -59,6 +59,8 @@ #include "raypick/PointerScriptingInterface.h" #include #include "AboutUtil.h" +#include "ResourceRequestObserver.h" + static int MAX_WINDOW_SIZE = 4096; static const float METERS_TO_INCHES = 39.3701f; @@ -269,6 +271,7 @@ void Web3DOverlay::setupQmlSurface(bool isTablet) { _webSurface->getSurfaceContext()->setContextProperty("Window", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("Reticle", qApp->getApplicationCompositor().getReticleInterface()); _webSurface->getSurfaceContext()->setContextProperty("HiFiAbout", AboutUtil::getInstance()); + _webSurface->getSurfaceContext()->setContextProperty("ResourceRequestObserver", DependencyManager::get().data()); // Override min fps for tablet UI, for silky smooth scrolling setMaxFPS(90); @@ -536,7 +539,7 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) { * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. * * @property {string} name="" - A friendly name for the overlay. - * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and + * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and * start. * @property {Vec3} localPosition - The local position of the overlay relative to its parent if the overlay has a * parentID set, otherwise the same value as position. @@ -561,7 +564,7 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) { * @property {string} url - The URL of the Web page to display. * @property {string} scriptURL="" - The URL of a JavaScript file to inject into the Web page. * @property {number} dpi=30 - The dots per inch to display the Web page at, on the overlay. - * @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms: + * @property {Vec2} dimensions=1,1 - The size of the overlay to display the Web page on, in meters. Synonyms: * scale, size. * @property {number} maxFPS=10 - The maximum update rate for the Web overlay content, in frames/second. * @property {boolean} showKeyboardFocusHighlight=true - If true, the Web overlay is highlighted when it has diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index a7cd5ccb5e..aae4c3bbe8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -44,6 +44,7 @@ #include "AvatarLogging.h" #include "AvatarTraits.h" #include "ClientTraitsHandler.h" +#include "ResourceRequestObserver.h" //#define WANT_DEBUG @@ -379,7 +380,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent } else { AVATAR_MEMCPY(_globalPosition); } - + int numBytes = destinationBuffer - startSection; @@ -647,7 +648,7 @@ QByteArray AvatarData::toByteArray(AvatarDataDetail dataDetail, quint64 lastSent if (!data.translationIsDefaultPose) { if (sendAll || last.translationIsDefaultPose || (!cullSmallChanges && last.translation != data.translation) || (cullSmallChanges && glm::distance(data.translation, lastSentJointData[i].translation) > minTranslation)) { - + validity |= (1 << validityBit); #ifdef WANT_DEBUG translationSentCount++; @@ -1054,7 +1055,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { auto newHasProceduralEyeFaceMovement = oneAtBit16(bitItems, PROCEDURAL_EYE_FACE_MOVEMENT); auto newHasProceduralBlinkFaceMovement = oneAtBit16(bitItems, PROCEDURAL_BLINK_FACE_MOVEMENT); - + bool keyStateChanged = (_keyState != newKeyState); bool handStateChanged = (_handState != newHandState); bool faceStateChanged = (_headData->_isFaceTrackerConnected != newFaceTrackerConnected); @@ -1526,7 +1527,7 @@ glm::vec3 AvatarData::getJointTranslation(int index) const { } glm::vec3 AvatarData::getJointTranslation(const QString& name) const { - // Can't do this, because the lock needs to cover the entire set of logic. In theory, the joints could change + // Can't do this, because the lock needs to cover the entire set of logic. In theory, the joints could change // on another thread in between the call to getJointIndex and getJointTranslation // return getJointTranslation(getJointIndex(name)); return readLockWithNamedJointIndex(name, [this](int index) { @@ -1607,7 +1608,7 @@ bool AvatarData::isJointDataValid(const QString& name) const { // return isJointDataValid(getJointIndex(name)); return readLockWithNamedJointIndex(name, false, [&](int index) { - // This is technically superfluous.... the lambda is only called if index is a valid + // This is technically superfluous.... the lambda is only called if index is a valid // offset for _jointData. Nevertheless, it would be confusing to leave the lamdba as // `return true` return index < _jointData.size(); @@ -1826,7 +1827,7 @@ qint64 AvatarData::packTrait(AvatarTraits::TraitType traitType, ExtendedIODevice if (traitVersion > AvatarTraits::DEFAULT_TRAIT_VERSION) { bytesWritten += destination.writePrimitive(traitVersion); } - + AvatarTraits::TraitWireSize encodedURLSize = encodedSkeletonURL.size(); bytesWritten += destination.writePrimitive(encodedURLSize); @@ -1935,7 +1936,7 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) { if (expanded == _skeletonModelURL) { return; } - + _skeletonModelURL = expanded; qCDebug(avatars) << "Changing skeleton model for avatar" << getSessionUUID() << "to" << _skeletonModelURL.toString(); @@ -2161,11 +2162,21 @@ void AvatarData::updateJointMappings() { } if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) { + //// + // TODO: Should we rely upon HTTPResourceRequest instead? + // HTTPResourceRequest::doSend() covers all of the following and + // then some. It doesn't cover the connect() call, so we may + // want to add a HTTPResourceRequest::doSend() method that does + // connects. QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); QNetworkRequest networkRequest = QNetworkRequest(_skeletonModelURL); networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); + DependencyManager::get()->update( + _skeletonModelURL, -1, "AvatarData::updateJointMappings"); QNetworkReply* networkReply = networkAccessManager.get(networkRequest); + // + //// connect(networkReply, &QNetworkReply::finished, this, &AvatarData::setJointMappingsFromNetworkReply); } } @@ -2391,7 +2402,7 @@ QJsonObject AvatarData::toJson() const { for (auto entityID : _avatarEntityData.keys()) { QVariantMap entityData; QUuid newId = _avatarEntityForRecording.size() == _avatarEntityData.size() ? _avatarEntityForRecording.values()[entityCount++] : entityID; - entityData.insert("id", newId); + entityData.insert("id", newId); entityData.insert("properties", _avatarEntityData.value(entityID).toBase64()); avatarEntityJson.push_back(QVariant(entityData).toJsonObject()); } diff --git a/libraries/entities/src/EntityEditFilters.cpp b/libraries/entities/src/EntityEditFilters.cpp index 94df7eb465..83e105c0ad 100644 --- a/libraries/entities/src/EntityEditFilters.cpp +++ b/libraries/entities/src/EntityEditFilters.cpp @@ -24,7 +24,7 @@ QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { for (auto id : zoneIDs) { if (!id.isInvalidID()) { // for now, look it up in the tree (soon we need to cache or similar?) - EntityItemPointer itemPtr = _tree->findEntityByEntityItemID(id); + EntityItemPointer itemPtr = _tree->findEntityByEntityItemID(id); auto zone = std::dynamic_pointer_cast(itemPtr); if (!zone) { // TODO: maybe remove later? @@ -33,7 +33,7 @@ QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { zones.append(id); } } else { - // the null id is the global filter we put in the domain server's + // the null id is the global filter we put in the domain server's // advanced entity server settings zones.append(id); } @@ -43,7 +43,7 @@ QList EntityEditFilters::getZonesByPosition(glm::vec3& position) { bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& propertiesIn, EntityItemProperties& propertiesOut, bool& wasChanged, EntityTree::FilterType filterType, EntityItemID& itemID, EntityItemPointer& existingEntity) { - + // get the ids of all the zones (plus the global entity edit filter) that the position // lies within auto zoneIDs = getZonesByPosition(position); @@ -51,12 +51,12 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper if (!itemID.isInvalidID() && id == itemID) { continue; } - - // get the filter pair, etc... + + // get the filter pair, etc... _lock.lockForRead(); FilterData filterData = _filterDataMap.value(id); _lock.unlock(); - + if (filterData.valid()) { if (filterData.rejectAll) { return false; @@ -153,13 +153,13 @@ bool EntityEditFilters::filter(glm::vec3& position, EntityItemProperties& proper // otherwise, assume it wants to pass all properties propertiesOut = propertiesIn; wasChanged = false; - + } else { return false; } } } - // if we made it here, + // if we made it here, return true; } @@ -175,23 +175,23 @@ void EntityEditFilters::removeFilter(EntityItemID entityID) { void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) { QUrl scriptURL(filterURL); - - // setting it to an empty string is same as removing + + // setting it to an empty string is same as removing if (filterURL.size() == 0) { removeFilter(entityID); return; } - + // The following should be abstracted out for use in Agent.cpp (and maybe later AvatarMixer.cpp) if (scriptURL.scheme().isEmpty() || (scriptURL.scheme() == URL_SCHEME_FILE)) { qWarning() << "Cannot load script from local filesystem, because assignment may be on a different computer."; scriptRequestFinished(entityID); return; } - + // first remove any existing info for this entity removeFilter(entityID); - + // reject all edits until we load the script FilterData filterData; filterData.rejectAll = true; @@ -199,8 +199,9 @@ void EntityEditFilters::addFilter(EntityItemID entityID, QString filterURL) { _lock.lockForWrite(); _filterDataMap.insert(entityID, filterData); _lock.unlock(); - - auto scriptRequest = DependencyManager::get()->createResourceRequest(this, scriptURL); + + auto scriptRequest = DependencyManager::get()->createResourceRequest( + this, scriptURL, true, -1, "EntityEditFilters::addFilter"); if (!scriptRequest) { qWarning() << "Could not create ResourceRequest for Entity Edit filter script at" << scriptURL.toString(); scriptRequestFinished(entityID); @@ -264,7 +265,7 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { FilterData filterData; filterData.engine = engine; filterData.rejectAll = false; - + // define the uncaughtException function QScriptEngine& engineRef = *engine; filterData.uncaughtExceptions = [&engineRef, urlString]() { return hadUncaughtExceptions(engineRef, urlString); }; @@ -368,11 +369,11 @@ void EntityEditFilters::scriptRequestFinished(EntityItemID entityID) { _lock.unlock(); qDebug() << "script request filter processed for entity id " << entityID; - + emit filterAdded(entityID, true); return; } - } + } } else if (scriptRequest) { const QString urlString = scriptRequest->getUrl().toString(); qCritical() << "Failed to download script at" << urlString; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 0b3b8abba2..8992157681 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -38,6 +38,8 @@ #include "LogHandler.h" #include "EntityEditFilters.h" #include "EntityDynamicFactoryInterface.h" +#include "QUrlAncestry.h" + static const quint64 DELETED_ENTITIES_EXTRA_USECS_TO_CONSIDER = USECS_PER_MSEC * 50; const float EntityTree::DEFAULT_MAX_TMP_ENTITY_LIFETIME = 60 * 60; // 1 hour @@ -98,7 +100,7 @@ EntityTree::~EntityTree() { eraseAllOctreeElements(false); } -void EntityTree::setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist) { +void EntityTree::setEntityScriptSourceWhitelist(const QString& entityScriptSourceWhitelist) { _entityScriptSourceWhitelist = entityScriptSourceWhitelist.split(',', QString::SkipEmptyParts); } @@ -860,7 +862,7 @@ float findRayIntersectionSortingOp(const OctreeElementPointer& element, void* ex EntityItemID EntityTree::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, QVector entityIdsToInclude, QVector entityIdsToDiscard, - bool visibleOnly, bool collidableOnly, bool precisionPicking, + bool visibleOnly, bool collidableOnly, bool precisionPicking, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, Octree::lockType lockType, bool* accurateResult) { @@ -1351,7 +1353,7 @@ bool EntityTree::verifyNonce(const QString& certID, const QString& nonce, Entity key = sent.second; } - QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; + QString annotatedKey = "-----BEGIN PUBLIC KEY-----\n" + key.insert(64, "\n") + "\n-----END PUBLIC KEY-----\n"; QByteArray hashedActualNonce = QCryptographicHash::hash(QByteArray(actualNonce.toUtf8()), QCryptographicHash::Sha256); bool verificationSuccess = EntityItemProperties::verifySignature(annotatedKey.toUtf8(), hashedActualNonce, QByteArray::fromBase64(nonce.toUtf8())); @@ -1795,7 +1797,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c if (newEntity) { newEntity->markAsChangedOnServer(); notifyNewlyCreatedEntity(*newEntity, senderNode); - + startLogging = usecTimestampNow(); if (wantEditLogging()) { qCDebug(entities) << "User [" << senderNode->getUUID() << "] added entity. ID:" @@ -1820,7 +1822,7 @@ int EntityTree::processEditPacketData(ReceivedMessage& message, const unsigned c } } else { HIFI_FCDEBUG(entities(), "Edit failed. [" << message.getType() <<"] " << - "entity id:" << entityItemID << + "entity id:" << entityItemID << "existingEntity pointer:" << existingEntity.get()); } } @@ -2041,7 +2043,7 @@ bool EntityTree::hasEntitiesDeletedSince(quint64 sinceTime) { if (hasSomethingNewer) { int elapsed = usecTimestampNow() - considerEntitiesSince; int difference = considerEntitiesSince - sinceTime; - qCDebug(entities) << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime + qCDebug(entities) << "EntityTree::hasEntitiesDeletedSince() sinceTime:" << sinceTime << "considerEntitiesSince:" << considerEntitiesSince << "elapsed:" << elapsed << "difference:" << difference; } #endif @@ -2493,7 +2495,7 @@ bool EntityTree::writeToMap(QVariantMap& entityDescription, OctreeElementPointer return true; } -bool EntityTree::readFromMap(QVariantMap& map) { +bool EntityTree::readFromMap(QVariantMap& map, const QUrlAncestry& ancestry) { // These are needed to deal with older content (before adding inheritance modes) int contentVersion = map["Version"].toInt(); bool needsConversion = (contentVersion < (int)EntityVersion::ZoneLightInheritModes); diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 2f971b8566..8c787f8eb8 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -22,6 +22,8 @@ #include "EntityTreeElement.h" #include "DeleteEntityOperator.h" #include "MovingEntitiesOperator.h" +#include "QUrlAncestry.h" + class EntityTree; using EntityTreePointer = std::shared_ptr; @@ -94,7 +96,7 @@ public: virtual EntityItemID findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, QVector entityIdsToInclude, QVector entityIdsToDiscard, - bool visibleOnly, bool collidableOnly, bool precisionPicking, + bool visibleOnly, bool collidableOnly, bool precisionPicking, OctreeElementPointer& element, float& distance, BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, Octree::lockType lockType = Octree::TryLock, bool* accurateResult = NULL); @@ -170,7 +172,7 @@ public: void addNewlyCreatedHook(NewlyCreatedEntityHook* hook); void removeNewlyCreatedHook(NewlyCreatedEntityHook* hook); - bool hasAnyDeletedEntities() const { + bool hasAnyDeletedEntities() const { QReadLocker locker(&_recentlyDeletedEntitiesLock); return _recentlyDeletedEntityItemIDs.size() > 0; } @@ -178,7 +180,7 @@ public: bool hasEntitiesDeletedSince(quint64 sinceTime); static quint64 getAdjustedConsiderSince(quint64 sinceTime); - QMultiMap getRecentlyDeletedEntityIDs() const { + QMultiMap getRecentlyDeletedEntityIDs() const { QReadLocker locker(&_recentlyDeletedEntitiesLock); return _recentlyDeletedEntityItemIDs; } @@ -223,7 +225,7 @@ public: virtual bool writeToMap(QVariantMap& entityDescription, OctreeElementPointer element, bool skipDefaultValues, bool skipThoseWithBadParents) override; - virtual bool readFromMap(QVariantMap& entityDescription) override; + virtual bool readFromMap(QVariantMap& entityDescription, const QUrlAncestry& ancestry = {}) override; glm::vec3 getContentsDimensions(); float getContentsLargestDimension(); diff --git a/libraries/fbx/src/GLTFReader.cpp b/libraries/fbx/src/GLTFReader.cpp index 317342b886..89592c399c 100644 --- a/libraries/fbx/src/GLTFReader.cpp +++ b/libraries/fbx/src/GLTFReader.cpp @@ -40,7 +40,7 @@ GLTFReader::GLTFReader() { } -bool GLTFReader::getStringVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getStringVal(const QJsonObject& object, const QString& fieldname, QString& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isString()); if (_defined) { @@ -60,7 +60,7 @@ bool GLTFReader::getBoolVal(const QJsonObject& object, const QString& fieldname, return _defined; } -bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname, int& value, QMap& defined) { bool _defined = (object.contains(fieldname) && !object[fieldname].isNull()); if (_defined) { @@ -70,7 +70,7 @@ bool GLTFReader::getIntVal(const QJsonObject& object, const QString& fieldname, return _defined; } -bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldname, double& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isDouble()); if (_defined) { @@ -79,7 +79,7 @@ bool GLTFReader::getDoubleVal(const QJsonObject& object, const QString& fieldnam defined.insert(fieldname, _defined); return _defined; } -bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldname, QJsonObject& value, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isObject()); if (_defined) { @@ -89,7 +89,7 @@ bool GLTFReader::getObjectVal(const QJsonObject& object, const QString& fieldnam return _defined; } -bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldname, QVector& values, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -104,7 +104,7 @@ bool GLTFReader::getIntArrayVal(const QJsonObject& object, const QString& fieldn return _defined; } -bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fieldname, QVector& values, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -119,7 +119,7 @@ bool GLTFReader::getDoubleArrayVal(const QJsonObject& object, const QString& fie return _defined; } -bool GLTFReader::getObjectArrayVal(const QJsonObject& object, const QString& fieldname, +bool GLTFReader::getObjectArrayVal(const QJsonObject& object, const QString& fieldname, QJsonArray& objects, QMap& defined) { bool _defined = (object.contains(fieldname) && object[fieldname].isArray()); if (_defined) { @@ -229,7 +229,7 @@ bool GLTFReader::setAsset(const QJsonObject& object) { QJsonObject jsAsset; bool isAssetDefined = getObjectVal(object, "asset", jsAsset, _file.defined); if (isAssetDefined) { - if (!getStringVal(jsAsset, "version", _file.asset.version, + if (!getStringVal(jsAsset, "version", _file.asset.version, _file.asset.defined) || _file.asset.version != "2.0") { return false; } @@ -241,7 +241,7 @@ bool GLTFReader::setAsset(const QJsonObject& object) { bool GLTFReader::addAccessor(const QJsonObject& object) { GLTFAccessor accessor; - + getIntVal(object, "bufferView", accessor.bufferView, accessor.defined); getIntVal(object, "byteOffset", accessor.byteOffset, accessor.defined); getIntVal(object, "componentType", accessor.componentType, accessor.defined); @@ -261,7 +261,7 @@ bool GLTFReader::addAccessor(const QJsonObject& object) { bool GLTFReader::addAnimation(const QJsonObject& object) { GLTFAnimation animation; - + QJsonArray channels; if (getObjectArrayVal(object, "channels", channels, animation.defined)) { foreach(const QJsonValue & v, channels) { @@ -272,7 +272,7 @@ bool GLTFReader::addAnimation(const QJsonObject& object) { if (getObjectVal(v.toObject(), "target", jsChannel, channel.defined)) { getIntVal(jsChannel, "node", channel.target.node, channel.target.defined); getIntVal(jsChannel, "path", channel.target.path, channel.target.defined); - } + } } } } @@ -291,7 +291,7 @@ bool GLTFReader::addAnimation(const QJsonObject& object) { } } } - + _file.animations.push_back(animation); return true; @@ -299,20 +299,20 @@ bool GLTFReader::addAnimation(const QJsonObject& object) { bool GLTFReader::addBufferView(const QJsonObject& object) { GLTFBufferView bufferview; - + getIntVal(object, "buffer", bufferview.buffer, bufferview.defined); getIntVal(object, "byteLength", bufferview.byteLength, bufferview.defined); getIntVal(object, "byteOffset", bufferview.byteOffset, bufferview.defined); getIntVal(object, "target", bufferview.target, bufferview.defined); - + _file.bufferviews.push_back(bufferview); - + return true; } bool GLTFReader::addBuffer(const QJsonObject& object) { GLTFBuffer buffer; - + getIntVal(object, "byteLength", buffer.byteLength, buffer.defined); if (getStringVal(object, "uri", buffer.uri, buffer.defined)) { if (!readBinary(buffer.uri, buffer.blob)) { @@ -320,13 +320,13 @@ bool GLTFReader::addBuffer(const QJsonObject& object) { } } _file.buffers.push_back(buffer); - + return true; } bool GLTFReader::addCamera(const QJsonObject& object) { GLTFCamera camera; - + QJsonObject jsPerspective; QJsonObject jsOrthographic; QString type; @@ -346,28 +346,28 @@ bool GLTFReader::addCamera(const QJsonObject& object) { } else if (getStringVal(object, "type", type, camera.defined)) { camera.type = getCameraType(type); } - + _file.cameras.push_back(camera); - + return true; } bool GLTFReader::addImage(const QJsonObject& object) { GLTFImage image; - + QString mime; getStringVal(object, "uri", image.uri, image.defined); if (getStringVal(object, "mimeType", mime, image.defined)) { image.mimeType = getImageMimeType(mime); } getIntVal(object, "bufferView", image.bufferView, image.defined); - + _file.images.push_back(image); return true; } -bool GLTFReader::getIndexFromObject(const QJsonObject& object, const QString& field, +bool GLTFReader::getIndexFromObject(const QJsonObject& object, const QString& field, int& outidx, QMap& defined) { QJsonObject subobject; if (getObjectVal(object, field, subobject, defined)) { @@ -393,20 +393,20 @@ bool GLTFReader::addMaterial(const QJsonObject& object) { getDoubleVal(object, "alphaCutoff", material.alphaCutoff, material.defined); QJsonObject jsMetallicRoughness; if (getObjectVal(object, "pbrMetallicRoughness", jsMetallicRoughness, material.defined)) { - getDoubleArrayVal(jsMetallicRoughness, "baseColorFactor", - material.pbrMetallicRoughness.baseColorFactor, + getDoubleArrayVal(jsMetallicRoughness, "baseColorFactor", + material.pbrMetallicRoughness.baseColorFactor, material.pbrMetallicRoughness.defined); - getIndexFromObject(jsMetallicRoughness, "baseColorTexture", - material.pbrMetallicRoughness.baseColorTexture, + getIndexFromObject(jsMetallicRoughness, "baseColorTexture", + material.pbrMetallicRoughness.baseColorTexture, material.pbrMetallicRoughness.defined); - getDoubleVal(jsMetallicRoughness, "metallicFactor", - material.pbrMetallicRoughness.metallicFactor, + getDoubleVal(jsMetallicRoughness, "metallicFactor", + material.pbrMetallicRoughness.metallicFactor, material.pbrMetallicRoughness.defined); - getDoubleVal(jsMetallicRoughness, "roughnessFactor", - material.pbrMetallicRoughness.roughnessFactor, + getDoubleVal(jsMetallicRoughness, "roughnessFactor", + material.pbrMetallicRoughness.roughnessFactor, material.pbrMetallicRoughness.defined); - getIndexFromObject(jsMetallicRoughness, "metallicRoughnessTexture", - material.pbrMetallicRoughness.metallicRoughnessTexture, + getIndexFromObject(jsMetallicRoughness, "metallicRoughnessTexture", + material.pbrMetallicRoughness.metallicRoughnessTexture, material.pbrMetallicRoughness.defined); } _file.materials.push_back(material); @@ -428,7 +428,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) { getIntVal(jsPrimitive, "mode", primitive.mode, primitive.defined); getIntVal(jsPrimitive, "indices", primitive.indices, primitive.defined); getIntVal(jsPrimitive, "material", primitive.material, primitive.defined); - + QJsonObject jsAttributes; if (getObjectVal(jsPrimitive, "attributes", jsAttributes, primitive.defined)) { QStringList attrKeys = jsAttributes.keys(); @@ -455,7 +455,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) { primitive.targets.push_back(target); } } - } + } mesh.primitives.push_back(primitive); } } @@ -469,7 +469,7 @@ bool GLTFReader::addMesh(const QJsonObject& object) { bool GLTFReader::addNode(const QJsonObject& object) { GLTFNode node; - + getStringVal(object, "name", node.name, node.defined); getIntVal(object, "camera", node.camera, node.defined); getIntVal(object, "mesh", node.mesh, node.defined); @@ -524,10 +524,10 @@ bool GLTFReader::addSkin(const QJsonObject& object) { } bool GLTFReader::addTexture(const QJsonObject& object) { - GLTFTexture texture; + GLTFTexture texture; getIntVal(object, "sampler", texture.sampler, texture.defined); getIntVal(object, "source", texture.source, texture.defined); - + _file.textures.push_back(texture); return true; @@ -535,7 +535,7 @@ bool GLTFReader::addTexture(const QJsonObject& object) { bool GLTFReader::parseGLTF(const QByteArray& model) { PROFILE_RANGE_EX(resource_parse, __FUNCTION__, 0xffff0000, nullptr); - + QJsonDocument d = QJsonDocument::fromJson(model); QJsonObject jsFile = d.object(); @@ -707,25 +707,25 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { foreach(int child, node.children) nodeDependencies[child].push_back(nodecount); nodecount++; } - + nodecount = 0; foreach(auto &node, _file.nodes) { // collect node transform - _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); + _file.nodes[nodecount].transforms.push_back(getModelTransform(node)); if (nodeDependencies[nodecount].size() == 1) { int parentidx = nodeDependencies[nodecount][0]; while (true) { // iterate parents // collect parents transforms - _file.nodes[nodecount].transforms.push_back(getModelTransform(_file.nodes[parentidx])); + _file.nodes[nodecount].transforms.push_back(getModelTransform(_file.nodes[parentidx])); if (nodeDependencies[parentidx].size() == 1) { parentidx = nodeDependencies[parentidx][0]; } else break; } } - + nodecount++; } - + //Build default joints geometry.joints.resize(1); geometry.joints[0].isFree = false; @@ -756,7 +756,7 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { setFBXMaterial(fbxMaterial, _file.materials[i]); } - + nodecount = 0; // Build meshes @@ -789,11 +789,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { QVector raw_vertices; QVector raw_normals; - bool success = addArrayOfType(indicesBuffer.blob, - indicesBufferview.byteOffset + indicesAccBoffset, - indicesAccessor.count, - part.triangleIndices, - indicesAccessor.type, + bool success = addArrayOfType(indicesBuffer.blob, + indicesBufferview.byteOffset + indicesAccBoffset, + indicesAccessor.count, + part.triangleIndices, + indicesAccessor.type, indicesAccessor.componentType); if (!success) { @@ -813,10 +813,10 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { int accBoffset = accessor.defined["byteOffset"] ? accessor.byteOffset : 0; if (key == "POSITION") { QVector vertices; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, vertices, - accessor.type, + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, vertices, + accessor.type, accessor.componentType); if (!success) { qWarning(modelformat) << "There was a problem reading glTF POSITION data for model " << _url; @@ -827,11 +827,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { } } else if (key == "NORMAL") { QVector normals; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - normals, - accessor.type, + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, + normals, + accessor.type, accessor.componentType); if (!success) { qWarning(modelformat) << "There was a problem reading glTF NORMAL data for model " << _url; @@ -842,11 +842,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { } } else if (key == "TEXCOORD_0") { QVector texcoords; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - texcoords, - accessor.type, + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, + texcoords, + accessor.type, accessor.componentType); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_0 data for model " << _url; @@ -857,11 +857,11 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { } } else if (key == "TEXCOORD_1") { QVector texcoords; - success = addArrayOfType(buffer.blob, - bufferview.byteOffset + accBoffset, - accessor.count, - texcoords, - accessor.type, + success = addArrayOfType(buffer.blob, + bufferview.byteOffset + accBoffset, + accessor.count, + texcoords, + accessor.type, accessor.componentType); if (!success) { qWarning(modelformat) << "There was a problem reading glTF TEXCOORD_1 data for model " << _url; @@ -888,8 +888,8 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { mesh.meshExtents.addPoint(vertex); geometry.meshExtents.addPoint(vertex); } - - // since mesh.modelTransform seems to not have any effect I apply the transformation the model + + // since mesh.modelTransform seems to not have any effect I apply the transformation the model for (int h = 0; h < mesh.vertices.size(); h++) { glm::vec4 ver = glm::vec4(mesh.vertices[h], 1); if (node.transforms.size() > 0) { @@ -901,18 +901,18 @@ bool GLTFReader::buildGeometry(FBXGeometry& geometry, const QUrl& url) { mesh.meshIndex = geometry.meshes.size(); FBXReader::buildModelMesh(mesh, url.toString()); } - + } nodecount++; } - + return true; } -FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping, +FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping, const QUrl& url, bool loadLightmaps, float lightmapLevel) { - + _url = url; // Normalize url for local files @@ -928,10 +928,10 @@ FBXGeometry* GLTFReader::readGLTF(QByteArray& model, const QVariantHash& mapping FBXGeometry& geometry = *geometryPtr; buildGeometry(geometry, url); - + //fbxDebugDump(geometry); return geometryPtr; - + } bool GLTFReader::readBinary(const QString& url, QByteArray& outdata) { @@ -940,7 +940,7 @@ bool GLTFReader::readBinary(const QString& url, QByteArray& outdata) { qCDebug(modelformat) << "binaryUrl: " << binaryUrl << " OriginalUrl: " << _url; bool success; std::tie(success, outdata) = requestData(binaryUrl); - + return success; } @@ -953,7 +953,8 @@ bool GLTFReader::doesResourceExist(const QString& url) { } std::tuple GLTFReader::requestData(QUrl& url) { - auto request = DependencyManager::get()->createResourceRequest(nullptr, url); + auto request = DependencyManager::get()->createResourceRequest( + nullptr, url, true, -1, "GLTFReader::requestData"); if (!request) { return std::make_tuple(false, QByteArray()); @@ -999,7 +1000,7 @@ QNetworkReply* GLTFReader::request(QUrl& url, bool isTest) { FBXTexture GLTFReader::getFBXTexture(const GLTFTexture& texture) { FBXTexture fbxtex = FBXTexture(); fbxtex.texcoordSet = 0; - + if (texture.defined["source"]) { QString url = _file.images[texture.source].uri; QString fname = QUrl(url).fileName(); @@ -1019,10 +1020,10 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia if (material.defined["name"]) { fbxmat.name = fbxmat.materialID = material.name; } - + if (material.defined["emissiveFactor"] && material.emissiveFactor.size() == 3) { - glm::vec3 emissive = glm::vec3(material.emissiveFactor[0], - material.emissiveFactor[1], + glm::vec3 emissive = glm::vec3(material.emissiveFactor[0], + material.emissiveFactor[1], material.emissiveFactor[2]); fbxmat._material->setEmissive(emissive); } @@ -1031,12 +1032,12 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia fbxmat.emissiveTexture = getFBXTexture(_file.textures[material.emissiveTexture]); fbxmat.useEmissiveMap = true; } - + if (material.defined["normalTexture"]) { fbxmat.normalTexture = getFBXTexture(_file.textures[material.normalTexture]); fbxmat.useNormalMap = true; } - + if (material.defined["occlusionTexture"]) { fbxmat.occlusionTexture = getFBXTexture(_file.textures[material.occlusionTexture]); fbxmat.useOcclusionMap = true; @@ -1044,7 +1045,7 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia if (material.defined["pbrMetallicRoughness"]) { fbxmat.isPBSMaterial = true; - + if (material.pbrMetallicRoughness.defined["metallicFactor"]) { fbxmat.metallic = material.pbrMetallicRoughness.metallicFactor; } @@ -1062,23 +1063,23 @@ void GLTFReader::setFBXMaterial(FBXMaterial& fbxmat, const GLTFMaterial& materia if (material.pbrMetallicRoughness.defined["roughnessFactor"]) { fbxmat._material->setRoughness(material.pbrMetallicRoughness.roughnessFactor); } - if (material.pbrMetallicRoughness.defined["baseColorFactor"] && + if (material.pbrMetallicRoughness.defined["baseColorFactor"] && material.pbrMetallicRoughness.baseColorFactor.size() == 4) { - glm::vec3 dcolor = glm::vec3(material.pbrMetallicRoughness.baseColorFactor[0], - material.pbrMetallicRoughness.baseColorFactor[1], + glm::vec3 dcolor = glm::vec3(material.pbrMetallicRoughness.baseColorFactor[0], + material.pbrMetallicRoughness.baseColorFactor[1], material.pbrMetallicRoughness.baseColorFactor[2]); fbxmat.diffuseColor = dcolor; fbxmat._material->setAlbedo(dcolor); fbxmat._material->setOpacity(material.pbrMetallicRoughness.baseColorFactor[3]); - } + } } } template -bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count, +bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count, QVector& outarray, int accessorType) { - + QDataStream blobstream(bin); blobstream.setByteOrder(QDataStream::LittleEndian); blobstream.setVersion(QDataStream::Qt_5_9); @@ -1133,9 +1134,9 @@ bool GLTFReader::readArray(const QByteArray& bin, int byteOffset, int count, return true; } template -bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count, +bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count, QVector& outarray, int accessorType, int componentType) { - + switch (componentType) { case GLTFAccessorComponentType::BYTE: {} case GLTFAccessorComponentType::UNSIGNED_BYTE: { @@ -1157,8 +1158,8 @@ bool GLTFReader::addArrayOfType(const QByteArray& bin, int byteOffset, int count return false; } -void GLTFReader::retriangulate(const QVector& inIndices, const QVector& in_vertices, - const QVector& in_normals, QVector& outIndices, +void GLTFReader::retriangulate(const QVector& inIndices, const QVector& in_vertices, + const QVector& in_normals, QVector& outIndices, QVector& out_vertices, QVector& out_normals) { for (int i = 0; i < inIndices.size(); i = i + 3) { diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index c46a1e234c..00109e9030 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -15,7 +15,7 @@ #include "OBJReader.h" #include // .obj files are not locale-specific. The C/ASCII charset applies. -#include +#include #include #include @@ -263,16 +263,16 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { default: materials[matName] = currentMaterial; #ifdef WANT_DEBUG - qCDebug(modelformat) << + qCDebug(modelformat) << "OBJ Reader Last material illumination model:" << currentMaterial.illuminationModel << - " shininess:" << currentMaterial.shininess << + " shininess:" << currentMaterial.shininess << " opacity:" << currentMaterial.opacity << - " diffuse color:" << currentMaterial.diffuseColor << - " specular color:" << currentMaterial.specularColor << - " emissive color:" << currentMaterial.emissiveColor << - " diffuse texture:" << currentMaterial.diffuseTextureFilename << - " specular texture:" << currentMaterial.specularTextureFilename << - " emissive texture:" << currentMaterial.emissiveTextureFilename << + " diffuse color:" << currentMaterial.diffuseColor << + " specular color:" << currentMaterial.specularColor << + " emissive color:" << currentMaterial.emissiveColor << + " diffuse texture:" << currentMaterial.diffuseTextureFilename << + " specular texture:" << currentMaterial.specularTextureFilename << + " emissive texture:" << currentMaterial.emissiveTextureFilename << " bump texture:" << currentMaterial.bumpTextureFilename << " opacity texture:" << currentMaterial.opacityTextureFilename; #endif @@ -352,7 +352,7 @@ void OBJReader::parseMaterialLibrary(QIODevice* device) { } } } -} +} void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& filename, OBJMaterialTextureOptions& textureOptions) { // Texture options reference http://paulbourke.net/dataformats/mtl/ @@ -443,7 +443,8 @@ void OBJReader::parseTextureLine(const QByteArray& textureLine, QByteArray& file } std::tuple requestData(QUrl& url) { - auto request = DependencyManager::get()->createResourceRequest(nullptr, url); + auto request = DependencyManager::get()->createResourceRequest( + nullptr, url, true, -1, "(OBJReader) requestData"); if (!request) { return std::make_tuple(false, QByteArray()); @@ -793,7 +794,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m n0 = checked_at(normals, face.normalIndices[0]); n1 = checked_at(normals, face.normalIndices[1]); n2 = checked_at(normals, face.normalIndices[2]); - } else { + } else { // generate normals from triangle plane if not provided n0 = n1 = n2 = glm::cross(v1 - v0, v2 - v0); } @@ -923,7 +924,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m bool applyNonMetallic = false; bool fresnelOn = false; - // Illumination model reference http://paulbourke.net/dataformats/mtl/ + // Illumination model reference http://paulbourke.net/dataformats/mtl/ switch (objMaterial.illuminationModel) { case 0: // Color on and Ambient off // We don't support ambient = do nothing? @@ -967,7 +968,7 @@ FBXGeometry::Pointer OBJReader::readOBJ(QByteArray& model, const QVariantHash& m case 10: // Casts shadows onto invisible surfaces // Do nothing? break; - } + } if (applyTransparency) { fbxMaterial.opacity = std::max(fbxMaterial.opacity, ILLUMINATION_MODEL_MIN_OPACITY); diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index e8aec5e60e..740af44591 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -456,7 +456,8 @@ void NetworkTexture::makeRequest() { // Add a fragment to the base url so we can identify the section of the ktx being requested when debugging // The actual requested url is _activeUrl and will not contain the fragment _url.setFragment("head"); - _ktxHeaderRequest = DependencyManager::get()->createResourceRequest(this, _activeUrl); + _ktxHeaderRequest = DependencyManager::get()->createResourceRequest( + this, _activeUrl, true, -1, "NetworkTexture::makeRequest"); if (!_ktxHeaderRequest) { qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString(); @@ -617,7 +618,8 @@ void NetworkTexture::startMipRangeRequest(uint16_t low, uint16_t high) { bool isHighMipRequest = low == NULL_MIP_LEVEL && high == NULL_MIP_LEVEL; - _ktxMipRequest = DependencyManager::get()->createResourceRequest(this, _activeUrl); + _ktxMipRequest = DependencyManager::get()->createResourceRequest( + this, _activeUrl, true, -1, "NetworkTexture::startMipRangeRequest"); if (!_ktxMipRequest) { qCWarning(networking).noquote() << "Failed to get request for" << _url.toDisplayString(); diff --git a/libraries/networking/src/AssetResourceRequest.cpp b/libraries/networking/src/AssetResourceRequest.cpp index 6d5bbb3ac5..23ab1548a0 100644 --- a/libraries/networking/src/AssetResourceRequest.cpp +++ b/libraries/networking/src/AssetResourceRequest.cpp @@ -24,8 +24,12 @@ static const int DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS = 5; -AssetResourceRequest::AssetResourceRequest(const QUrl& url) : - ResourceRequest(url) +AssetResourceRequest::AssetResourceRequest( + const QUrl& url, + const bool isObservable, + const qint64 callerId, + const QString& extra) : + ResourceRequest(url, isObservable, callerId, extra) { _lastProgressDebug = p_high_resolution_clock::now() - std::chrono::seconds(DOWNLOAD_PROGRESS_LOG_INTERVAL_SECONDS); } @@ -35,7 +39,7 @@ AssetResourceRequest::~AssetResourceRequest() { if (_assetMappingRequest) { _assetMappingRequest->deleteLater(); } - + if (_assetRequest) { _assetRequest->deleteLater(); } @@ -78,7 +82,7 @@ void AssetResourceRequest::requestMappingForPath(const AssetUtils::AssetPath& pa // make sure we'll hear about the result of the get mapping request connect(_assetMappingRequest, &GetMappingRequest::finished, this, [this, path](GetMappingRequest* request){ auto statTracker = DependencyManager::get(); - + Q_ASSERT(_state == InProgress); Q_ASSERT(request == _assetMappingRequest); diff --git a/libraries/networking/src/AssetResourceRequest.h b/libraries/networking/src/AssetResourceRequest.h index 2fe79040ca..07baca5416 100644 --- a/libraries/networking/src/AssetResourceRequest.h +++ b/libraries/networking/src/AssetResourceRequest.h @@ -22,7 +22,11 @@ class AssetResourceRequest : public ResourceRequest { Q_OBJECT public: - AssetResourceRequest(const QUrl& url); + AssetResourceRequest( + const QUrl& url, + const bool isObservable = true, + const qint64 callerId = -1, + const QString& extra = ""); virtual ~AssetResourceRequest() override; protected: diff --git a/libraries/networking/src/AtpReply.cpp b/libraries/networking/src/AtpReply.cpp index b2b7e8bee7..3ec9b23f5f 100644 --- a/libraries/networking/src/AtpReply.cpp +++ b/libraries/networking/src/AtpReply.cpp @@ -14,7 +14,8 @@ #include "ResourceManager.h" AtpReply::AtpReply(const QUrl& url, QObject* parent) : - _resourceRequest(DependencyManager::get()->createResourceRequest(parent, url)) { + _resourceRequest(DependencyManager::get()->createResourceRequest( + parent, url, true, -1, "AtpReply::AtpReply")) { setOperation(QNetworkAccessManager::GetOperation); connect(_resourceRequest, &AssetResourceRequest::progress, this, &AtpReply::downloadProgress); diff --git a/libraries/networking/src/FileResourceRequest.h b/libraries/networking/src/FileResourceRequest.h index 547b754cb5..12b5b7d72e 100644 --- a/libraries/networking/src/FileResourceRequest.h +++ b/libraries/networking/src/FileResourceRequest.h @@ -12,14 +12,19 @@ #ifndef hifi_FileResourceRequest_h #define hifi_FileResourceRequest_h -#include - #include "ResourceRequest.h" +#include "QUrlAncestry.h" + class FileResourceRequest : public ResourceRequest { Q_OBJECT public: - FileResourceRequest(const QUrl& url) : ResourceRequest(url) { } + FileResourceRequest( + const QUrlAncestry& urlAncestry, + const bool isObservable = true, + const qint64 callerId = -1, + const QString& extra = "" + ) : ResourceRequest(urlAncestry, isObservable, callerId, extra) { } protected: virtual void doSend() override; diff --git a/libraries/networking/src/HTTPResourceRequest.h b/libraries/networking/src/HTTPResourceRequest.h index cc628d8855..41f605e856 100644 --- a/libraries/networking/src/HTTPResourceRequest.h +++ b/libraries/networking/src/HTTPResourceRequest.h @@ -13,15 +13,21 @@ #define hifi_HTTPResourceRequest_h #include -#include #include #include "ResourceRequest.h" +#include "QUrlAncestry.h" + class HTTPResourceRequest : public ResourceRequest { Q_OBJECT public: - HTTPResourceRequest(const QUrl& url) : ResourceRequest(url) { } + HTTPResourceRequest( + const QUrlAncestry& urlAncestry, + const bool isObservable = true, + const qint64 callerId = -1, + const QString& = "" + ) : ResourceRequest(urlAncestry, isObservable, callerId) { } ~HTTPResourceRequest(); protected: diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index f73243e675..c5229d65ac 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -22,7 +22,7 @@ QNetworkAccessManager& NetworkAccessManager::getInstance() { if (!networkAccessManagers.hasLocalData()) { networkAccessManagers.setLocalData(new QNetworkAccessManager()); } - + return *networkAccessManagers.localData(); } diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 076db44ea6..3cf12cb824 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -10,6 +10,7 @@ // #include "ResourceCache.h" +#include "ResourceRequestObserver.h" #include #include @@ -319,7 +320,7 @@ QVariantList ResourceCache::getResourceList() { return list; } - + void ResourceCache::setRequestLimit(uint32_t limit) { auto sharedItems = DependencyManager::get(); sharedItems->setRequestLimit(limit); @@ -336,30 +337,33 @@ QSharedPointer ResourceCache::getResource(const QUrl& url, const QUrl& QReadLocker locker(&_resourcesLock); resource = _resources.value(url).lock(); } + if (resource) { removeUnusedResource(resource); - return resource; } - if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { - return getResource(fallback, QUrl()); + if (!resource && !url.isValid() && !url.isEmpty() && fallback.isValid()) { + resource = getResource(fallback, QUrl()); } - resource = createResource( - url, - fallback.isValid() ? getResource(fallback, QUrl()) : QSharedPointer(), - extra); - resource->setSelf(resource); - resource->setCache(this); - resource->moveToThread(qApp->thread()); - connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); - { - QWriteLocker locker(&_resourcesLock); - _resources.insert(url, resource); + if (!resource) { + resource = createResource( + url, + fallback.isValid() ? getResource(fallback, QUrl()) : QSharedPointer(), + extra); resource->setSelf(resource); + resource->setCache(this); + resource->moveToThread(qApp->thread()); + connect(resource.data(), &Resource::updateSize, this, &ResourceCache::updateTotalSize); + { + QWriteLocker locker(&_resourcesLock); + _resources.insert(url, resource); + } + removeUnusedResource(resource); + resource->ensureLoading(); } - removeUnusedResource(resource); - resource->ensureLoading(); + DependencyManager::get()->update( + resource->getURL(), -1, "ResourceCache::getResource"); return resource; } @@ -378,7 +382,7 @@ void ResourceCache::addUnusedResource(const QSharedPointer& resource) return; } reserveUnusedResource(resource->getBytes()); - + resource->setLRUKey(++_lastLRUKey); { @@ -407,7 +411,7 @@ void ResourceCache::reserveUnusedResource(qint64 resourceSize) { _unusedResourcesSize + resourceSize > _unusedResourcesMaxSize) { // unload the oldest resource QMap >::iterator it = _unusedResources.begin(); - + it.value()->setCache(nullptr); auto size = it.value()->getBytes(); @@ -473,7 +477,7 @@ void ResourceCache::updateTotalSize(const qint64& deltaSize) { emit dirty(); } - + QList> ResourceCache::getLoadingRequests() { return DependencyManager::get()->getLoadingRequests(); } @@ -494,7 +498,15 @@ bool ResourceCache::attemptRequest(QSharedPointer resource) { resource->makeRequest(); return true; } +<<<<<<< HEAD return false; +======= + + ++_requestsActive; + sharedItems->appendActiveRequest(resource); + resource->makeRequest(); + return true; +>>>>>>> ac26e68e78... Display resource-access events in marketplace item tester } void ResourceCache::requestCompleted(QWeakPointer resource) { @@ -588,7 +600,7 @@ void Resource::refresh() { _request = nullptr; ResourceCache::requestCompleted(_self); } - + _activeUrl = _url; init(); ensureLoading(); @@ -602,8 +614,13 @@ void Resource::allReferencesCleared() { } if (_cache && isCacheable()) { - // create and reinsert new shared pointer +<<<<<<< HEAD + // create and reinsert new shared pointer QSharedPointer self(this, &Resource::deleter); +======= + // create and reinsert new shared pointer + QSharedPointer self(this, &Resource::allReferencesCleared); +>>>>>>> ac26e68e78... Display resource-access events in marketplace item tester setSelf(self); reinsert(); @@ -627,10 +644,10 @@ void Resource::init(bool resetLoaded) { _loaded = false; } _attempts = 0; - + if (_url.isEmpty()) { _startedLoading = _loaded = true; - + } else if (!(_url.isValid())) { _startedLoading = _failedToLoad = true; } @@ -682,7 +699,8 @@ void Resource::makeRequest() { PROFILE_ASYNC_BEGIN(resource, "Resource:" + getType(), QString::number(_requestID), { { "url", _url.toString() }, { "activeURL", _activeUrl.toString() } }); - _request = DependencyManager::get()->createResourceRequest(this, _activeUrl); + _request = DependencyManager::get()->createResourceRequest( + this, _activeUrl, true, -1, "Resource::makeRequest"); if (!_request) { qCDebug(networking).noquote() << "Failed to get request for" << _url.toDisplayString(); @@ -751,7 +769,7 @@ void Resource::handleReplyFinished() { } else { handleFailedRequest(result); } - + _request->disconnect(this); _request->deleteLater(); _request = nullptr; diff --git a/libraries/networking/src/ResourceManager.cpp b/libraries/networking/src/ResourceManager.cpp index 553f0d0a61..d9774e3437 100644 --- a/libraries/networking/src/ResourceManager.cpp +++ b/libraries/networking/src/ResourceManager.cpp @@ -26,6 +26,7 @@ #include "NetworkAccessManager.h" #include "NetworkLogging.h" + ResourceManager::ResourceManager(bool atpSupportEnabled) : _atpSupportEnabled(atpSupportEnabled) { _thread.setObjectName("Resource Manager Thread"); @@ -112,22 +113,29 @@ void ResourceManager::cleanup() { _thread.wait(); } -ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const QUrl& url) { +ResourceRequest* ResourceManager::createResourceRequest( + QObject* parent, + const QUrl& url, + const bool isObservable, + const qint64 callerId, + const QString& extra +) { auto normalizedURL = normalizeURL(url); auto scheme = normalizedURL.scheme(); ResourceRequest* request = nullptr; + qDebug() << "!!!! in createResourceRequest " << callerId; if (scheme == URL_SCHEME_FILE || scheme == URL_SCHEME_QRC) { - request = new FileResourceRequest(normalizedURL); + request = new FileResourceRequest(normalizedURL, isObservable, callerId, extra); } else if (scheme == URL_SCHEME_HTTP || scheme == URL_SCHEME_HTTPS || scheme == URL_SCHEME_FTP) { - request = new HTTPResourceRequest(normalizedURL); + request = new HTTPResourceRequest(normalizedURL, isObservable, callerId, extra); } else if (scheme == URL_SCHEME_ATP) { if (!_atpSupportEnabled) { qCDebug(networking) << "ATP support not enabled, unable to create request for URL: " << url.url(); return nullptr; } - request = new AssetResourceRequest(normalizedURL); + request = new AssetResourceRequest(normalizedURL, isObservable, callerId, extra); } else { qCDebug(networking) << "Unknown scheme (" << scheme << ") for URL: " << url.url(); return nullptr; @@ -138,6 +146,7 @@ ResourceRequest* ResourceManager::createResourceRequest(QObject* parent, const Q QObject::connect(parent, &QObject::destroyed, request, &QObject::deleteLater); } request->moveToThread(&_thread); + return request; } @@ -163,7 +172,7 @@ bool ResourceManager::resourceExists(const QUrl& url) { return reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 200; } else if (scheme == URL_SCHEME_ATP && _atpSupportEnabled) { - auto request = new AssetResourceRequest(url); + auto request = new AssetResourceRequest(url, ResourceRequest::IS_NOT_OBSERVABLE); ByteRange range; range.fromInclusive = 1; range.toExclusive = 1; diff --git a/libraries/networking/src/ResourceManager.h b/libraries/networking/src/ResourceManager.h index a79222d2d8..adaa1cf886 100644 --- a/libraries/networking/src/ResourceManager.h +++ b/libraries/networking/src/ResourceManager.h @@ -34,7 +34,12 @@ public: QString normalizeURL(const QString& urlString); QUrl normalizeURL(const QUrl& url); - ResourceRequest* createResourceRequest(QObject* parent, const QUrl& url); + ResourceRequest* createResourceRequest( + QObject* parent, + const QUrl& url, + const bool isObservable = true, + const qint64 callerId = -1, + const QString& extra = ""); void init(); void cleanup(); diff --git a/libraries/networking/src/ResourceRequest.cpp b/libraries/networking/src/ResourceRequest.cpp index 115e665b77..a651e9a2b6 100644 --- a/libraries/networking/src/ResourceRequest.cpp +++ b/libraries/networking/src/ResourceRequest.cpp @@ -10,15 +10,20 @@ // #include "ResourceRequest.h" +#include "ResourceRequestObserver.h" #include #include #include -ResourceRequest::ResourceRequest(const QUrl& url) : _url(url) { } void ResourceRequest::send() { + if (_isObservable) { + DependencyManager::get()->update( + _urlAncestry, _callerId, _extra + " => ResourceRequest::send" ); + } + if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "send", Qt::QueuedConnection); return; diff --git a/libraries/networking/src/ResourceRequest.h b/libraries/networking/src/ResourceRequest.h index 8dd09ccc49..3ce1a9da2b 100644 --- a/libraries/networking/src/ResourceRequest.h +++ b/libraries/networking/src/ResourceRequest.h @@ -18,6 +18,8 @@ #include #include "ByteRange.h" +#include "QUrlAncestry.h" + const QString STAT_ATP_REQUEST_STARTED = "StartedATPRequest"; const QString STAT_HTTP_REQUEST_STARTED = "StartedHTTPRequest"; @@ -40,7 +42,21 @@ const QString STAT_FILE_RESOURCE_TOTAL_BYTES = "FILEBytesDownloaded"; class ResourceRequest : public QObject { Q_OBJECT public: - ResourceRequest(const QUrl& url); + static const bool IS_OBSERVABLE = true; + static const bool IS_NOT_OBSERVABLE = false; + + ResourceRequest( + const QUrlAncestry& urlAncestry, + const bool isObservable = IS_OBSERVABLE, + const qint64 callerId = -1, + const QString& extra = "" + ) : _urlAncestry(urlAncestry), + _isObservable(isObservable), + _callerId(callerId), + _extra(extra), + _url(urlAncestry.last()) + { } + virtual ~ResourceRequest() = default; enum State { @@ -87,6 +103,7 @@ protected: virtual void doSend() = 0; void recordBytesDownloadedInStats(const QString& statName, int64_t bytesReceived); + QUrl _url; QUrl _relativePathURL; State _state { NotStarted }; @@ -99,6 +116,10 @@ protected: bool _rangeRequestSuccessful { false }; uint64_t _totalSizeOfResource { 0 }; int64_t _lastRecordedBytesDownloaded { 0 }; + bool _isObservable; + qint64 _callerId; + QString _extra; + QUrlAncestry _urlAncestry; }; #endif diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index 3d387e0956..a50438dd54 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -669,7 +669,7 @@ OctreeElementPointer Octree::getElementEnclosingPoint(const glm::vec3& point, Oc return args.element; } -bool Octree::readFromFile(const char* fileName) { +bool Octree::readFromFile(const char* fileName, const QUrlAncestry& urlAncestry) { QString qFileName = findMostRecentFileExtension(fileName, PERSIST_EXTENSIONS); if (qFileName.endsWith(".json.gz")) { @@ -689,7 +689,7 @@ bool Octree::readFromFile(const char* fileName) { qCDebug(octree) << "Loading file" << qFileName << "..."; - bool success = readFromStream(fileLength, fileInputStream); + bool success = readFromStream(fileLength, fileInputStream, "", urlAncestry); file.close(); @@ -734,11 +734,18 @@ QString getMarketplaceID(const QString& urlString) { return QString(); } -bool Octree::readFromURL(const QString& urlString) { +bool Octree::readFromURL( + const QString& urlString, + const bool isObservable, + const qint64 callerId, + const QUrlAncestry& urlAncestry +) { QString trimmedUrl = urlString.trimmed(); QString marketplaceID = getMarketplaceID(trimmedUrl); - auto request = - std::unique_ptr(DependencyManager::get()->createResourceRequest(this, trimmedUrl)); + qDebug() << "!!!!! going to createResourceRequest " << callerId; + auto request = std::unique_ptr( + DependencyManager::get()->createResourceRequest( + this, trimmedUrl, isObservable, callerId, "Octree::readFromURL")); if (!request) { return false; @@ -760,15 +767,20 @@ bool Octree::readFromURL(const QString& urlString) { if (wasCompressed) { QDataStream inputStream(uncompressedJsonData); - return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID); + return readFromStream(uncompressedJsonData.size(), inputStream, marketplaceID, urlAncestry); } QDataStream inputStream(data); - return readFromStream(data.size(), inputStream, marketplaceID); + return readFromStream(data.size(), inputStream, marketplaceID, urlAncestry); } -bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID) { +bool Octree::readFromStream( + uint64_t streamLength, + QDataStream& inputStream, + const QString& marketplaceID, + const QUrlAncestry& urlAncestry +) { // decide if this is binary SVO or JSON-formatted SVO QIODevice *device = inputStream.device(); char firstChar; @@ -780,7 +792,7 @@ bool Octree::readFromStream(uint64_t streamLength, QDataStream& inputStream, con return false; } else { qCDebug(octree) << "Reading from JSON SVO Stream length:" << streamLength; - return readJSONFromStream(streamLength, inputStream, marketplaceID); + return readJSONFromStream(streamLength, inputStream, marketplaceID, urlAncestry); } } @@ -809,7 +821,12 @@ QJsonDocument addMarketplaceIDToDocumentEntities(QJsonDocument& doc, const QStri const int READ_JSON_BUFFER_SIZE = 2048; -bool Octree::readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID /*=""*/) { +bool Octree::readJSONFromStream( + uint64_t streamLength, + QDataStream& inputStream, + const QString& marketplaceID, /*=""*/ + const QUrlAncestry& urlAncestry +) { // if the data is gzipped we may not have a useful bytesAvailable() result, so just keep reading until // we get an eof. Leave streamLength parameter for consistency. @@ -834,7 +851,7 @@ bool Octree::readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, } QVariant asVariant = asDocument.toVariant(); QVariantMap asMap = asVariant.toMap(); - bool success = readFromMap(asMap); + bool success = readFromMap(asMap, urlAncestry); delete[] rawData; return success; } diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index a2b2f227cb..53acbc5a60 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -29,6 +29,7 @@ #include "OctreePacketData.h" #include "OctreeSceneStats.h" #include "OctreeUtils.h" +#include "QUrlAncestry.h" class ReadBitstreamToTreeParams; class Octree; @@ -209,13 +210,13 @@ public: bool skipThoseWithBadParents) = 0; // Octree importers - bool readFromFile(const char* filename); - bool readFromURL(const QString& url); // will support file urls as well... - bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); + bool readFromFile(const char* filename, const QUrlAncestry& urlAncestry = {}); + bool readFromURL(const QString& url, const bool isObservable = true, const qint64 callerId = -1, const QUrlAncestry& urlAncestry = {}); // will support file urls as well... + bool readFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const QUrlAncestry& urlAncestry = {}); bool readSVOFromStream(uint64_t streamLength, QDataStream& inputStream); - bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID=""); + bool readJSONFromStream(uint64_t streamLength, QDataStream& inputStream, const QString& marketplaceID="", const QUrlAncestry& urlAncestry = {}); bool readJSONFromGzippedFile(QString qFileName); - virtual bool readFromMap(QVariantMap& entityDescription) = 0; + virtual bool readFromMap(QVariantMap& entityDescription, const QUrlAncestry& urlAncestry = {}) = 0; uint64_t getOctreeElementsCount(); diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index cbcafe9c7d..eccb812f09 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -258,24 +258,29 @@ void OffscreenSurface::setMaxFps(uint8_t maxFps) { } void OffscreenSurface::load(const QUrl& qmlSource, QQuickItem* parent, const QJSValue& callback) { + qDebug() << "Here 1"; loadInternal(qmlSource, false, parent, [callback](QQmlContext* context, QQuickItem* newItem) { QJSValue(callback).call(QJSValueList() << context->engine()->newQObject(newItem)); }); } void OffscreenSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextObjectCallback& callback) { + qDebug() << "Here 2"; loadInternal(qmlSource, createNewContext, nullptr, callback); } void OffscreenSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextObjectCallback& callback, const QmlContextCallback& contextCallback) { + qDebug() << "Here 3"; loadInternal(qmlSource, true, nullptr, callback, contextCallback); } void OffscreenSurface::load(const QUrl& qmlSource, const QmlContextObjectCallback& callback) { + qDebug() << "Here 4"; load(qmlSource, false, callback); } void OffscreenSurface::load(const QString& qmlSourceFile, const QmlContextObjectCallback& callback) { + qDebug() << "Here 5"; return load(QUrl(qmlSourceFile), callback); } diff --git a/libraries/script-engine/src/FileScriptingInterface.cpp b/libraries/script-engine/src/FileScriptingInterface.cpp index 3bf044fd8b..103ed6d232 100644 --- a/libraries/script-engine/src/FileScriptingInterface.cpp +++ b/libraries/script-engine/src/FileScriptingInterface.cpp @@ -50,7 +50,7 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool tempDir = zipTemp.path(); path.remove("file:///"); } - + qCDebug(scriptengine) << "Temporary directory at: " + tempDir; if (!isTempDir(tempDir)) { qCDebug(scriptengine) << "Temporary directory mismatch; risk of losing files"; @@ -58,7 +58,7 @@ void FileScriptingInterface::runUnzip(QString path, QUrl url, bool autoAdd, bool } QStringList fileList = unzipFile(path, tempDir); - + if (!fileList.isEmpty()) { qCDebug(scriptengine) << "First file to upload: " + fileList.first(); } else { @@ -138,7 +138,8 @@ QString FileScriptingInterface::convertUrlToPath(QUrl url) { // this function is not in use void FileScriptingInterface::downloadZip(QString path, const QString link) { QUrl url = QUrl(link); - auto request = DependencyManager::get()->createResourceRequest(nullptr, url); + auto request = DependencyManager::get()->createResourceRequest( + nullptr, url, true, -1, "FileScriptingInterface::downloadZip"); connect(request, &ResourceRequest::finished, this, [this, path]{ unzipFile(path, ""); // so intellisense isn't mad }); diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index dba2db0458..8acf88a7ce 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -109,7 +109,8 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "about to call: ResourceManager::createResourceRequest(this, url); on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif - auto request = DependencyManager::get()->createResourceRequest(nullptr, url); + auto request = DependencyManager::get()->createResourceRequest( + nullptr, url, true, -1, "ScriptCache::getScriptContents"); Q_ASSERT(request); request->setCacheEnabled(!forceDownload); connect(request, &ResourceRequest::finished, this, [=]{ scriptContentAvailable(maxRetries); }); @@ -166,7 +167,8 @@ void ScriptCache::scriptContentAvailable(int maxRetries) { qCDebug(scriptengine) << QString("Retrying script request [%1 / %2]: %3") .arg(attempt).arg(maxRetries).arg(url.toString()); - auto request = DependencyManager::get()->createResourceRequest(nullptr, url); + auto request = DependencyManager::get()->createResourceRequest( + nullptr, url, true, -1, "ScriptCache::scriptContentAvailable"); Q_ASSERT(request); // We've already made a request, so the cache must be disabled or it wasn't there, so enabling diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index ebc459b2d1..297d3bb924 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -21,6 +21,7 @@ #include #include +#include "ResourceRequestObserver.h" #include "ScriptEngine.h" const QString METAVERSE_API_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/"; @@ -62,7 +63,7 @@ QScriptValue XMLHttpRequestClass::constructor(QScriptContext* context, QScriptEn QScriptValue XMLHttpRequestClass::getStatus() const { if (_reply) { return QScriptValue(_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()); - } + } return QScriptValue(0); } @@ -143,7 +144,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) { auto accountManager = DependencyManager::get(); - + if (accountManager->hasValidAccessToken()) { static const QString HTTP_AUTHORIZATION_HEADER = "Authorization"; QString bearerString = "Bearer " + accountManager->getAccountInfo().getAccessToken().token; @@ -189,7 +190,7 @@ void XMLHttpRequestClass::send(const QScriptValue& data) { } void XMLHttpRequestClass::doSend() { - + DependencyManager::get()->update(_url, -1, "XMLHttpRequestClass::doSend"); _reply = NetworkAccessManager::getInstance().sendCustomRequest(_request, _method.toLatin1(), _sendData); connectToReply(_reply); diff --git a/libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h b/libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h new file mode 100644 index 0000000000..fd3647b19e --- /dev/null +++ b/libraries/shared/src/EntityItemWeakPointerWithUrlAncestry.h @@ -0,0 +1,31 @@ +// +// EntityItemWeakPointerWithUrlAncestry.h +// libraries/shared/src/ +// +// Created by Kerry Ivan Kurian 10/15/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_EntityItemWeakPointerWithUrlAncestry_h +#define hifi_EntityItemWeakPointerWithUrlAncestry_h + +#include "EntityTypes.h" +#include "QUrlAncestry.h" + + +struct EntityItemWeakPointerWithUrlAncestry { + EntityItemWeakPointerWithUrlAncestry( + const EntityItemWeakPointer& a, + const QUrlAncestry& b + ) : entityItemWeakPointer(a), urlAncestry(b) {} + + EntityItemWeakPointer entityItemWeakPointer; + QUrlAncestry urlAncestry; +}; + + +#endif // hifi_EntityItemWeakPointerWithUrlAncestry_h + diff --git a/libraries/shared/src/QUrlAncestry.cpp b/libraries/shared/src/QUrlAncestry.cpp new file mode 100644 index 0000000000..f38c663803 --- /dev/null +++ b/libraries/shared/src/QUrlAncestry.cpp @@ -0,0 +1,35 @@ +// +// QUrlAncestry.cpp +// libraries/shared/src/ +// +// Created by Kerry Ivan Kurian on 10/12/18. +// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "QUrlAncestry.h" + + +QUrlAncestry::QUrlAncestry(const QUrl& resource, const QUrl& referrer) { + this->append(referrer); + this->append(resource); +} + +QUrlAncestry::QUrlAncestry( + const QUrl& resource, + const QUrlAncestry& ancestors) : QVector(ancestors) +{ + this->append(resource); +} + +void QUrlAncestry::toJson(QJsonArray& array) const { + for (auto const& qurl : *this) { + array.append(qurl.toDisplayString()); + } +} + +const QUrl QUrlAncestry::url() const { + return this->last(); +} diff --git a/libraries/shared/src/QUrlAncestry.h b/libraries/shared/src/QUrlAncestry.h new file mode 100644 index 0000000000..84c32ff7c1 --- /dev/null +++ b/libraries/shared/src/QUrlAncestry.h @@ -0,0 +1,32 @@ +// +// QUrlAncestry.h +// libraries/shared/src/ +// +// Created by Kerry Ivan Kurian on 10/12/18. +// Copyright (c) 2018 High Fidelity, Inc. All rights reserved. +// +// 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_QUrlAncestry_H +#define hifi_QUrlAncestry_H + +#include +#include +#include + + +class QUrlAncestry : public QVector { +public: + QUrlAncestry() {} + QUrlAncestry(const QUrl& resource, const QUrl& referrer = QUrl("__NONE__")); + QUrlAncestry(const QUrl& resource, const QUrlAncestry& ancestors); + + void toJson(QJsonArray& array) const; + const QUrl url() const; +}; + + +#endif // hifi_QUrlVector_H diff --git a/libraries/shared/src/ResourceRequestObserver.cpp b/libraries/shared/src/ResourceRequestObserver.cpp new file mode 100644 index 0000000000..6c52fcdc79 --- /dev/null +++ b/libraries/shared/src/ResourceRequestObserver.cpp @@ -0,0 +1,38 @@ +// +// ResourceAccessMonitor.h +// libraries/networking/src +// +// Created by Kerry Ivan Kurian on 9/27/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 +#include +#include +#include +#include "ResourceRequestObserver.h" +#include "QUrlAncestry.h" + + +// void ResourceRequestObserver::update(const QNetworkRequest& request, const qint64 callerId, const QString& extra) { +// update(QUrlAncestry(request.url()), callerId, extra); +// } + +void ResourceRequestObserver::update( + const QUrlAncestry& urlAncestry, + const qint64 callerId, + const QString& extra +) { + QJsonArray array; + urlAncestry.toJson(array); + QJsonObject data { + { "url", array }, + { "callerId", callerId }, + { "extra", extra } + }; + emit resourceRequestEvent(data.toVariantMap()); +} diff --git a/libraries/shared/src/ResourceRequestObserver.h b/libraries/shared/src/ResourceRequestObserver.h new file mode 100644 index 0000000000..edccdb5e48 --- /dev/null +++ b/libraries/shared/src/ResourceRequestObserver.h @@ -0,0 +1,31 @@ +// +// ResourceRequestObserver.h +// libraries/commerce/src +// +// Created by Kerry Ivan Kurian on 9/27/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 +#include +#include + +#include "DependencyManager.h" +#include "QUrlAncestry.h" + + +class ResourceRequestObserver : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public: + // void update(const QNetworkRequest& request, const qint64 callerId = -1, const QString& extra = ""); + void update(const QUrlAncestry& urlAncestry, const qint64 callerId = -1, const QString& extra = ""); + +signals: + void resourceRequestEvent(QVariantMap result); +}; diff --git a/scripts/system/marketplaces/marketplaces.js b/scripts/system/marketplaces/marketplaces.js index cca535a064..d59a6b89d5 100644 --- a/scripts/system/marketplaces/marketplaces.js +++ b/scripts/system/marketplaces/marketplaces.js @@ -49,6 +49,33 @@ var NO_BUTTON = 0; // QMessageBox::NoButton var NO_PERMISSIONS_ERROR_MESSAGE = "Cannot download model because you can't write to \nthe domain's Asset Server."; + +var resourceRequestEvents = []; +function signalResourceRequestEvent(data) { + ui.tablet.sendToQml({ + method: "resourceRequestEvent", + data: data }); +} + +function onResourceRequestEvent(data) { + var resourceRequestEvent = { + "date": JSON.stringify(new Date()), + "url": data.url, + "callerId": data.callerId, + "extra": data.extra }; + resourceRequestEvents.push(resourceRequestEvent); + signalResourceRequestEvent(resourceRequestEvent); +} + +function pushResourceRequestEvents() { + var length = resourceRequestEvents.length + for (var i = 0; i < length; i++) { + if (i in resourceRequestEvents) { + signalResourceRequestEvent(resourceRequestEvents[i]); + } + } +} + function onMessageBoxClosed(id, button) { if (id === messageBox && button === CANCEL_BUTTON) { isDownloadBeingCancelled = true; @@ -522,13 +549,19 @@ function getPositionToCreateEntity(extra) { return position; } -function rezEntity(itemHref, itemType) { +function defaultFor(arg, val) { + return typeof arg !== 'undefined' ? arg : val; +} + +function rezEntity(itemHref, itemType, marketplaceItemTesterId) { var isWearable = itemType === "wearable"; - var success = Clipboard.importEntities(itemHref); + print("!!!!! Clipboard.importEntities " + marketplaceItemTesterId); + var success = Clipboard.importEntities(itemHref, true, marketplaceItemTesterId); var wearableLocalPosition = null; var wearableLocalRotation = null; var wearableLocalDimensions = null; var wearableDimensions = null; + marketplaceItemTesterId = defaultFor(marketplaceItemTesterId, -1); if (itemType === "contentSet") { console.log("Item is a content set; codepath shouldn't go here."); @@ -877,11 +910,12 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { case 'checkout_rezClicked': case 'purchases_rezClicked': case 'tester_rezClicked': - rezEntity(message.itemHref, message.itemType); + print("!!!!! marketplaces tester_rezClicked"); + rezEntity(message.itemHref, message.itemType, message.itemId); break; case 'tester_newResourceObject': var resourceObject = message.resourceObject; - resourceObjectsInTest[resourceObject.id] = resourceObject; + resourceObjectsInTest[resourceObject.resourceObjectId] = resourceObject; signalNewResourceObjectInTest(resourceObject); break; case 'tester_updateResourceObjectAssetType': @@ -1029,16 +1063,20 @@ var onQmlMessageReceived = function onQmlMessageReceived(message) { }; function pushResourceObjectsInTest() { - var maxObjectId = -1; - for (var objectId in resourceObjectsInTest) { - signalNewResourceObjectInTest(resourceObjectsInTest[objectId]); - maxObjectId = (maxObjectId < objectId) ? parseInt(objectId) : maxObjectId; + var maxResourceObjectId = -1; + var length = resourceObjectsInTest.length; + for (var i = 0; i < length; i++) { + if (i in resourceObjectsInTest) { + signalNewResourceObjectInTest(resourceObjectsInTest[i]); + var resourceObjectId = resourceObjectsInTest[i].resourceObjectId; + maxResourceObjectId = (maxResourceObjectId < resourceObjectId) ? parseInt(resourceObjectId) : maxResourceObjectId; + } } // N.B. Thinking about removing the following sendToQml? Be sure // that the marketplace item tester QML has heard from us, at least // so that it can indicate to the user that all of the resoruce // objects in test have been transmitted to it. - ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxObjectId + 1 }); + ui.tablet.sendToQml({ method: "nextObjectIdInTest", id: maxResourceObjectId + 1 }); } // Function Name: onTabletScreenChanged() @@ -1127,6 +1165,7 @@ var onTabletScreenChanged = function onTabletScreenChanged(type, url) { // variable amount of time to come up, in practice less than // 750ms. Script.setTimeout(pushResourceObjectsInTest, 750); + Script.setTimeout(pushResourceRequestEvents, 750); } console.debug(ui.buttonName + " app reports: Tablet screen changed.\nNew screen type: " + type + @@ -1193,6 +1232,7 @@ function startup() { ui.tablet.webEventReceived.connect(onWebEventReceived); Wallet.walletStatusChanged.connect(sendCommerceSettings); Window.messageBoxClosed.connect(onMessageBoxClosed); + ResourceRequestObserver.resourceRequestEvent.connect(onResourceRequestEvent); Wallet.refreshWalletStatus(); } @@ -1226,6 +1266,7 @@ function shutdown() { GlobalServices.myUsernameChanged.disconnect(onUsernameChanged); Entities.canWriteAssetsChanged.disconnect(onCanWriteAssetsChanged); ContextOverlay.contextOverlayClicked.disconnect(openInspectionCertificateQML); + ResourceRequestObserver.resourceRequestEvent.disconnect(onResourceRequestEvent); off(); } From 89a5da80e0049de7bbf1670d5b021574d8a96a83 Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Thu, 18 Oct 2018 00:54:15 -0700 Subject: [PATCH 060/114] Do not display incomplete metadata --- .../marketplaceItemTester/MarketplaceItemTester.qml | 5 ++--- libraries/networking/src/ResourceCache.cpp | 13 ------------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index 98b0355e81..f06612d035 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -69,9 +69,8 @@ Rectangle { // object ids. if (date >= startDate) { resourceAccessEventText += ( - message.data.callerId + " " + message.data.extra + - " " + message.data.url + - " [" + date.toISOString() + "]\n" + "[" + date.toISOString() + "] " + + message.data.url.toString().replace("__NONE__,", "") + "\n" ); } break; diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 3cf12cb824..186addbd86 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -498,15 +498,7 @@ bool ResourceCache::attemptRequest(QSharedPointer resource) { resource->makeRequest(); return true; } -<<<<<<< HEAD return false; -======= - - ++_requestsActive; - sharedItems->appendActiveRequest(resource); - resource->makeRequest(); - return true; ->>>>>>> ac26e68e78... Display resource-access events in marketplace item tester } void ResourceCache::requestCompleted(QWeakPointer resource) { @@ -614,13 +606,8 @@ void Resource::allReferencesCleared() { } if (_cache && isCacheable()) { -<<<<<<< HEAD // create and reinsert new shared pointer QSharedPointer self(this, &Resource::deleter); -======= - // create and reinsert new shared pointer - QSharedPointer self(this, &Resource::allReferencesCleared); ->>>>>>> ac26e68e78... Display resource-access events in marketplace item tester setSelf(self); reinsert(); From 8b922ad7ccb857188f2c5a74bf881d551d7d8434 Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Thu, 18 Oct 2018 11:07:45 -0700 Subject: [PATCH 061/114] Add missing dependency --- assignment-client/src/Agent.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 5f1e1ca74a..0b590a6d27 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -57,6 +57,7 @@ #include "RecordingScriptingInterface.h" #include "AbstractAudioInterface.h" #include "AgentScriptingInterface.h" +#include "ResourceRequestObserver.h" static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; @@ -99,6 +100,8 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); + // Needed to ensure the creation of the DebugDraw instance on the main thread DebugDraw::getInstance(); From 77b6389671b8cdb22a4bf62c54e620bde83b9da4 Mon Sep 17 00:00:00 2001 From: Kerry Ivan Kurian Date: Thu, 18 Oct 2018 12:38:18 -0700 Subject: [PATCH 062/114] Correct location of dependency --- assignment-client/src/Agent.cpp | 3 --- assignment-client/src/AssignmentClient.cpp | 13 ++++++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 0b590a6d27..5f1e1ca74a 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -57,7 +57,6 @@ #include "RecordingScriptingInterface.h" #include "AbstractAudioInterface.h" #include "AgentScriptingInterface.h" -#include "ResourceRequestObserver.h" static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; @@ -100,8 +99,6 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); - // Needed to ensure the creation of the DebugDraw instance on the main thread DebugDraw::getInstance(); diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 426f3ce6fc..06b3f4da86 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -35,6 +35,8 @@ #include "AssignmentClientLogging.h" #include "AssignmentFactory.h" +#include "ResourceRequestObserver.h" + const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client"; const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000; @@ -49,6 +51,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); auto addressManager = DependencyManager::set(); @@ -159,7 +162,7 @@ void AssignmentClient::setUpStatusToMonitor() { void AssignmentClient::sendStatusPacketToACM() { // tell the assignment client monitor what this assignment client is doing (if anything) auto nodeList = DependencyManager::get(); - + quint8 assignmentType = Assignment::Type::AllTypes; if (_currentAssignment) { @@ -170,7 +173,7 @@ void AssignmentClient::sendStatusPacketToACM() { statusPacket->write(_childAssignmentUUID.toRfc4122()); statusPacket->writePrimitive(assignmentType); - + nodeList->sendPacket(std::move(statusPacket), _assignmentClientMonitorSocket); } @@ -256,10 +259,10 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer message) { const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); - + if (senderSockAddr.getAddress() == QHostAddress::LocalHost || senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { - + qCDebug(assignment_client) << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketType::StopNode."; QCoreApplication::quit(); } else { @@ -312,6 +315,6 @@ void AssignmentClient::assignmentCompleted() { nodeList->setOwnerType(NodeType::Unassigned); nodeList->reset(); nodeList->resetNodeInterestSet(); - + _isAssigned = false; } From 9f91238945ed9f5e27116a7be8a334285b724f39 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 18 Oct 2018 15:19:29 -0700 Subject: [PATCH 063/114] UX/UI improvements --- .../marketplaceItemTester/ItemUnderTest.qml | 352 ++++++++++++ .../MarketplaceItemTester.qml | 499 +++++++----------- .../marketplaceItemTester/spinner.gif | Bin 46135 -> 59412 bytes 3 files changed, 555 insertions(+), 296 deletions(-) create mode 100644 interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml new file mode 100644 index 0000000000..4852158df9 --- /dev/null +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/ItemUnderTest.qml @@ -0,0 +1,352 @@ +// +// ItemUnderTest +// qml/hifi/commerce/marketplaceItemTester +// +// Load items not in the marketplace for testing purposes +// +// Created by Kerry Ivan Kurian on 2018-10-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 +// + +import QtQuick 2.10 +import QtQuick.Controls 2.3 +import Hifi 1.0 as Hifi +import "qrc:////qml//styles-uit" as HifiStylesUit +import "qrc:////qml//controls-uit" as HifiControlsUit + +Rectangle { + id: root; + color: hifi.colors.baseGray + width: parent.width - 16 + height: childrenRect.height + itemHeaderContainer.anchors.topMargin + detailsContainer.anchors.topMargin + + property var detailsExpanded: false + + property var actions: { + "forward": function(resource, assetType, resourceObjectId){ + switch(assetType) { + case "application": + Commerce.openApp(resource); + break; + case "avatar": + MyAvatar.useFullAvatarURL(resource); + break; + case "content set": + urlHandler.handleUrl("hifi://localhost/0,0,0"); + Commerce.replaceContentSet(toUrl(resource), ""); + break; + case "entity": + case "wearable": + rezEntity(resource, assetType, resourceObjectId); + break; + default: + print("Marketplace item tester unsupported assetType " + assetType); + } + }, + "trash": function(resource, assetType){ + if ("application" === assetType) { + Commerce.uninstallApp(resource); + } + sendToScript({ + method: "tester_deleteResourceObject", + objectId: resourceListModel.get(index).id}); + resourceListModel.remove(index); + } + } + + Item { + id: itemHeaderContainer + anchors.top: parent.top + anchors.topMargin: 8 + anchors.left: parent.left + anchors.leftMargin: 8 + width: parent.width - 16 + height: childrenRect.height + + Item { + id: itemNameContainer + width: parent.width * 0.5 + height: childrenRect.height + + HifiStylesUit.RalewaySemiBold { + id: resourceName + height: paintedHeight + width: parent.width + text: { + var match = resource.match(/\/([^/]*)$/); + return match ? match[1] : resource; + } + size: 14 + color: hifi.colors.white + wrapMode: Text.WrapAnywhere + } + + HifiStylesUit.RalewayRegular { + id: resourceUrl + anchors.top: resourceName.bottom; + anchors.topMargin: 4; + height: paintedHeight + width: parent.width + text: resource + size: 12 + color: hifi.colors.faintGray; + wrapMode: Text.WrapAnywhere + } + } + + HifiControlsUit.ComboBox { + id: comboBox + anchors.left: itemNameContainer.right + anchors.leftMargin: 4 + anchors.verticalCenter: itemNameContainer.verticalCenter + height: 30 + width: parent.width * 0.3 - anchors.leftMargin + + model: [ + "application", + "avatar", + "content set", + "entity", + "wearable", + "unknown" + ] + + currentIndex: (("entity or wearable" === assetType) ? + model.indexOf("unknown") : model.indexOf(assetType)) + + Component.onCompleted: { + onCurrentIndexChanged.connect(function() { + assetType = model[currentIndex]; + sendToScript({ + method: "tester_updateResourceObjectAssetType", + objectId: resourceListModel.get(index)["resourceObjectId"], + assetType: assetType }); + }); + } + } + + Button { + id: actionButton + property var glyphs: { + "application": hifi.glyphs.install, + "avatar": hifi.glyphs.avatar, + "content set": hifi.glyphs.globe, + "entity": hifi.glyphs.wand, + "trash": hifi.glyphs.trash, + "unknown": hifi.glyphs.circleSlash, + "wearable": hifi.glyphs.hat, + } + property int color: hifi.buttons.blue; + property int colorScheme: hifi.colorSchemes.dark; + anchors.left: comboBox.right + anchors.leftMargin: 4 + anchors.verticalCenter: itemNameContainer.verticalCenter + width: parent.width * 0.10 - anchors.leftMargin + height: width + enabled: comboBox.model[comboBox.currentIndex] !== "unknown" + + onClicked: { + root.actions["forward"](resource, comboBox.currentText, resourceObjectId); + } + + background: Rectangle { + radius: 4; + gradient: Gradient { + GradientStop { + position: 0.2 + color: { + if (!actionButton.enabled) { + hifi.buttons.disabledColorStart[actionButton.colorScheme] + } else if (actionButton.pressed) { + hifi.buttons.pressedColor[actionButton.color] + } else if (actionButton.hovered) { + hifi.buttons.hoveredColor[actionButton.color] + } else { + hifi.buttons.colorStart[actionButton.color] + } + } + } + GradientStop { + position: 1.0 + color: { + if (!actionButton.enabled) { + hifi.buttons.disabledColorFinish[actionButton.colorScheme] + } else if (actionButton.pressed) { + hifi.buttons.pressedColor[actionButton.color] + } else if (actionButton.hovered) { + hifi.buttons.hoveredColor[actionButton.color] + } else { + hifi.buttons.colorFinish[actionButton.color] + } + } + } + } + } + + contentItem: Item { + HifiStylesUit.HiFiGlyphs { + id: rezIcon; + text: actionButton.glyphs[comboBox.model[comboBox.currentIndex]]; + anchors.fill: parent + size: 30; + horizontalAlignment: Text.AlignHCenter; + verticalAlignment: Text.AlignVCenter; + color: enabled ? hifi.buttons.textColor[actionButton.color] + : hifi.buttons.disabledTextColor[actionButton.colorScheme] + } + } + } + + Button { + id: trashButton + property int color: hifi.buttons.red; + property int colorScheme: hifi.colorSchemes.dark; + anchors.left: actionButton.right + anchors.verticalCenter: itemNameContainer.verticalCenter + anchors.leftMargin: 4 + width: parent.width * 0.10 - anchors.leftMargin + height: width + + onClicked: { + root.actions["trash"](resource, comboBox.currentText, resourceObjectId); + } + + background: Rectangle { + radius: 4; + gradient: Gradient { + GradientStop { + position: 0.2 + color: { + if (!trashButton.enabled) { + hifi.buttons.disabledColorStart[trashButton.colorScheme] + } else if (trashButton.pressed) { + hifi.buttons.pressedColor[trashButton.color] + } else if (trashButton.hovered) { + hifi.buttons.hoveredColor[trashButton.color] + } else { + hifi.buttons.colorStart[trashButton.color] + } + } + } + GradientStop { + position: 1.0 + color: { + if (!trashButton.enabled) { + hifi.buttons.disabledColorFinish[trashButton.colorScheme] + } else if (trashButton.pressed) { + hifi.buttons.pressedColor[trashButton.color] + } else if (trashButton.hovered) { + hifi.buttons.hoveredColor[trashButton.color] + } else { + hifi.buttons.colorFinish[trashButton.color] + } + } + } + } + } + + contentItem: Item { + HifiStylesUit.HiFiGlyphs { + id: trashIcon; + text: hifi.glyphs.trash + anchors.fill: parent + size: 22; + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + color: enabled ? hifi.buttons.textColor[trashButton.color] + : hifi.buttons.disabledTextColor[trashButton.colorScheme] + } + } + } + } + + Item { + id: detailsContainer + + width: parent.width - 16 + height: root.detailsExpanded ? 300 : 26 + anchors.top: itemHeaderContainer.bottom + anchors.topMargin: 12 + anchors.left: parent.left + anchors.leftMargin: 8 + + HifiStylesUit.HiFiGlyphs { + id: detailsToggle + anchors.left: parent.left + anchors.leftMargin: -4 + anchors.top: parent.top + anchors.topMargin: -2 + width: 22 + text: root.detailsExpanded ? hifi.glyphs.minimize : hifi.glyphs.maximize + color: hifi.colors.white + size: 22 + MouseArea { + anchors.fill: parent + onClicked: root.detailsExpanded = !root.detailsExpanded + } + } + + ScrollView { + id: detailsTextContainer + anchors.top: parent.top + anchors.left: detailsToggle.right + anchors.leftMargin: 4 + anchors.right: parent.right + height: detailsContainer.height - (root.detailsExpanded ? (copyToClipboardButton.height + copyToClipboardButton.anchors.topMargin) : 0) + clip: true + + TextArea { + id: detailsText + readOnly: true + color: hifi.colors.white + text: { + if (root.detailsExpanded) { + return resourceAccessEventText + } else { + return (resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..." + } + } + font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) + wrapMode: TextEdit.NoWrap + + background: Rectangle { + anchors.fill: parent; + color: hifi.colors.baseGrayShadow; + border.width: 0; + } + } + + MouseArea { + anchors.fill: parent + onClicked: { + if (root.detailsExpanded) { + detailsText.selectAll(); + } else { + root.detailsExpanded = true; + } + } + } + } + + HifiControlsUit.Button { + id: copyToClipboardButton; + visible: root.detailsExpanded + color: hifi.buttons.noneBorderlessWhite + colorScheme: hifi.colorSchemes.dark + + anchors.top: detailsTextContainer.bottom + anchors.topMargin: 8 + anchors.right: parent.right + width: 150 + height: 30 + text: "Copy to Clipboard" + + onClicked: { + Window.copyToClipboard(detailsText.text); + } + } + } +} diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index f06612d035..89b1dd3915 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -11,14 +11,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Controls.Styles 1.4 -import QtQuick.Dialogs 1.0 +import QtQuick 2.10 import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.3 import Hifi 1.0 as Hifi -import "../../../styles-uit" as HifiStylesUit -import "../../../controls-uit" as HifiControlsUit +import "qrc:////qml//styles-uit" as HifiStylesUit +import "qrc:////qml//controls-uit" as HifiControlsUit @@ -29,20 +27,208 @@ Rectangle { property string resourceAccessEventText property var nextResourceObjectId: 0 property var startDate - signal sendToScript(var message) HifiStylesUit.HifiConstants { id: hifi } ListModel { id: resourceListModel } - color: hifi.colors.white + color: hifi.colors.darkGray - AnimatedImage { - id: spinner; - source: "spinner.gif" - width: 74; - height: width; - anchors.verticalCenter: parent.verticalCenter; - anchors.horizontalCenter: parent.horizontalCenter; + Component.onCompleted: startDate = new Date() + + // + // TITLE BAR START + // + Item { + id: titleBarContainer + // Size + width: root.width + height: 50 + // Anchors + anchors.left: parent.left + anchors.top: parent.top + + // Title bar text + HifiStylesUit.RalewaySemiBold { + id: titleBarText + text: "Marketplace Item Tester" + // Text size + size: 24 + // Anchors + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.leftMargin: 16 + width: paintedWidth + // Style + color: hifi.colors.lightGrayText + // Alignment + horizontalAlignment: Text.AlignHLeft + verticalAlignment: Text.AlignVCenter + } + + // Separator + HifiControlsUit.Separator { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 1 + } + } + // + // TITLE BAR END + // + + Rectangle { + id: spinner + z: 999 + anchors.top: titleBarContainer.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: buttonContainer.top + color: hifi.colors.darkGray + + AnimatedImage { + source: "spinner.gif" + width: 74 + height: width + anchors.centerIn: parent + } + } + + Rectangle { + id: instructionsContainer + z: 998 + color: hifi.colors.darkGray + visible: resourceListModel.count === 0 && !spinner.visible + anchors.top: titleBarContainer.bottom + anchors.topMargin: 20 + anchors.left: parent.left + anchors.leftMargin: 20 + anchors.right: parent.right + anchors.rightMargin: 20 + anchors.bottom: buttonContainer.top + anchors.bottomMargin: 20 + + HifiStylesUit.RalewayRegular { + text: "Use Marketplace Item Tester to test out your items before submitting them to the Marketplace." + + "\n\nUse one of the buttons below to load your item." + // Text size + size: 20 + // Anchors + anchors.fill: parent + // Style + color: hifi.colors.lightGrayText + wrapMode: Text.Wrap + // Alignment + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + + ListView { + id: itemList + visible: !instructionsContainer.visible + anchors.top: titleBarContainer.bottom + anchors.topMargin: 20 + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: buttonContainer.top + anchors.bottomMargin: 20 + ScrollBar.vertical: ScrollBar { + visible: !instructionsContainer.visible + policy: ScrollBar.AlwaysOn + parent: itemList.parent + anchors.top: itemList.top + anchors.right: itemList.right + anchors.bottom: itemList.bottom + width: 16 + } + clip: true + model: resourceListModel + spacing: 8 + + delegate: ItemUnderTest { + } + } + + Item { + id: buttonContainer + + anchors.left: parent.left + anchors.leftMargin: 12 + anchors.right: parent.right + anchors.rightMargin: 12 + anchors.bottom: parent.bottom + anchors.bottomMargin: 12 + height: 40 + + property string currentAction + property var actions: { + "Load File": function() { + buttonContainer.currentAction = "load file"; + Window.browseChanged.connect(onResourceSelected); + Window.browseAsync("Please select a file (*.app.json *.json *.fst *.json.gz)", "", "Assets (*.app.json *.json *.fst *.json.gz)"); + }, + "Load URL": function() { + buttonContainer.currentAction = "load url"; + Window.promptTextChanged.connect(onResourceSelected); + Window.promptAsync("Please enter a URL", ""); + } + } + + function onResourceSelected(resource) { + // It is possible that we received the present signal + // from something other than our browserAsync window. + // Alas, there is nothing we can do about that so charge + // ahead as though we are sure the present signal is one + // we expect. + print("!!!! resource selected"); + switch(currentAction) { + case "load file": + Window.browseChanged.disconnect(onResourceSelected); + break + case "load url": + Window.promptTextChanged.disconnect(onResourceSelected); + break; + } + if (resource) { + print("!!!! building resource object"); + var resourceObj = buildResourceObj(resource); + print("!!!! installing resource object"); + installResourceObj(resourceObj); + print("!!!! notifying script of resource object"); + sendToScript({ + method: 'tester_newResourceObject', + resourceObject: resourceObj + }); + } + } + + HifiControlsUit.Button { + enabled: !spinner.visible + anchors.right: parent.horizontalCenter + anchors.rightMargin: width/4 + anchors.verticalCenter: parent.verticalCenter + color: hifi.buttons.blue + fontSize: 20 + text: "Load File" + width: parent.width / 3 + height: parent.height + onClicked: buttonContainer.actions[text]() + } + + HifiControlsUit.Button { + enabled: !spinner.visible + anchors.left: parent.horizontalCenter + anchors.leftMargin: width/4 + anchors.verticalCenter: parent.verticalCenter + color: hifi.buttons.blue + fontSize: 20 + text: "Load URL" + width: parent.width / 3 + height: parent.height + onClicked: buttonContainer.actions[text]() + } } function fromScript(message) { @@ -117,285 +303,6 @@ Rectangle { itemType: entityType, itemId: resourceObjectId }); } - - Component.onCompleted: startDate = new Date() - - ColumnLayout { - id: rootColumn - spacing: 30 - - HifiStylesUit.RalewayRegular { - id: rootHeader - text: "Marketplace Item Tester" - height: 40 - width: paintedWidth - size: 22 - color: hifi.colors.black - anchors.top: parent.top - anchors.topMargin: 20 - anchors.left: parent.left - anchors.leftMargin: 12 - } - - Rectangle { - height: root.height - 100 - width: root.width - anchors.left: parent.left - - ScrollView { - id: scrollView - anchors.fill: parent - anchors.rightMargin: 12 - anchors.bottom: parent.top - anchors.bottomMargin: 20 - anchors.leftMargin: 12 - verticalScrollBarPolicy: Qt.ScrollBarAlwaysOn - - frameVisible: false - - contentItem: ListView { - spacing: 20 - height: 200 - model: resourceListModel - interactive: false - - delegate: Column { - spacing: 8 - - RowLayout { - id: listRow - width: scrollView.width - 20 - anchors.rightMargin: scrollView.rightMargin - spacing: 5 - - property var actions: { - "forward": function(resource, assetType, resourceObjectId){ - switch(assetType) { - case "application": - Commerce.openApp(resource); - break; - case "avatar": - MyAvatar.useFullAvatarURL(resource); - break; - case "content set": - urlHandler.handleUrl("hifi://localhost/0,0,0"); - Commerce.replaceContentSet(toUrl(resource), ""); - break; - case "entity": - case "wearable": - rezEntity(resource, assetType, resourceObjectId); - break; - default: - print("Marketplace item tester unsupported assetType " + assetType); - } - }, - "trash": function(resource, assetType){ - if ("application" === assetType) { - Commerce.uninstallApp(resource); - } - sendToScript({ - method: "tester_deleteResourceObject", - objectId: resourceListModel.get(index).id}); - resourceListModel.remove(index); - } - } - - Column { - Layout.preferredWidth: scrollView.width * .6 - spacing: 5 - Text { - width: listRow.width * .6 - text: { - var match = resource.match(/\/([^/]*)$/); - return match ? match[1] : resource; - } - font.pointSize: 12 - horizontalAlignment: Text.AlignBottom - wrapMode: Text.WrapAnywhere - } - Text { - width: listRow.width * .6 - text: resource - font.pointSize: 8 - horizontalAlignment: Text.AlignBottom - wrapMode: Text.WrapAnywhere - } - } - - ComboBox { - id: comboBox - - Layout.preferredWidth: listRow.width * .2 - - model: [ - "application", - "avatar", - "content set", - "entity", - "wearable", - "unknown" - ] - - currentIndex: (("entity or wearable" === assetType) ? - model.indexOf("unknown") : model.indexOf(assetType)) - - Component.onCompleted: { - onCurrentIndexChanged.connect(function() { - assetType = model[currentIndex]; - sendToScript({ - method: "tester_updateResourceObjectAssetType", - objectId: resourceListModel.get(index)["resourceObjectId"], - assetType: assetType }); - }); - } - } - - Repeater { - model: [ "forward", "trash" ] - - HifiStylesUit.HiFiGlyphs { - property var glyphs: { - "application": hifi.glyphs.install, - "avatar": hifi.glyphs.avatar, - "content set": hifi.glyphs.globe, - "entity": hifi.glyphs.wand, - "trash": hifi.glyphs.trash, - "unknown": hifi.glyphs.circleSlash, - "wearable": hifi.glyphs.hat, - } - text: (("trash" === modelData) ? - glyphs.trash : - glyphs[comboBox.model[comboBox.currentIndex]]) - size: ("trash" === modelData) ? 22 : 30 - color: hifi.colors.black - horizontalAlignment: Text.AlignHCenter - MouseArea { - anchors.fill: parent - onClicked: { - listRow.actions[modelData](resource, comboBox.currentText, resourceObjectId); - } - } - } - } - } - - Rectangle { - id: detailsContainer - - width: scrollView.width - 20 - height: resourceDetails.isOpen ? 300 : 20 - anchors.left: parent.left - - HifiStylesUit.HiFiGlyphs { - id: detailsToggle - anchors.top: parent.top - text: resourceDetails.isOpen ? hifi.glyphs.minimize : hifi.glyphs.maximize - color: hifi.colors.black - size: 22 - verticalAlignment: Text.AlignBottom - MouseArea { - anchors.fill: parent - onClicked: resourceDetails.isOpen = !resourceDetails.isOpen - } - } - - TextArea { - id: resourceDetails - - property var isOpen: false - - width: detailsContainer.width - 20 - height: detailsContainer.height - anchors.top: parent.top - anchors.left: detailsToggle.left - anchors.leftMargin: 20 - verticalScrollBarPolicy: isOpen ? Qt.ScrollBarAsNeeded : Qt.ScrollBarAlwaysOff - frameVisible: isOpen - readOnly: true - - text: { - if (isOpen) { - return resourceAccessEventText - } else { - return (resourceAccessEventText.split("\n").length - 1).toString() + " resources loaded..." - } - } - font: Qt.font({ family: "Courier", pointSize: 8, weight: Font.Normal }) - wrapMode: TextEdit.NoWrap - } - } - - Rectangle { - width: listRow.width - height: 1 - color: hifi.colors.black - } - } - } - } - } - - Row { - id: rootActions - spacing: 20 - - anchors.left: parent.left - anchors.leftMargin: root.width / 6 - 10 - anchors.bottomMargin: 40 - anchors.bottom: parent.bottom - - property string currentAction - property var actions: { - "Load File": function(){ - rootActions.currentAction = "load file"; - Window.browseChanged.connect(onResourceSelected); - Window.browseAsync("Please select a file (*.app.json *.json *.fst *.json.gz)", "", "Assets (*.app.json *.json *.fst *.json.gz)"); - }, - "Load URL": function(){ - rootActions.currentAction = "load url"; - Window.promptTextChanged.connect(onResourceSelected); - Window.promptAsync("Please enter a URL", ""); - } - } - - function onResourceSelected(resource) { - // It is possible that we received the present signal - // from something other than our browserAsync window. - // Alas, there is nothing we can do about that so charge - // ahead as though we are sure the present signal is one - // we expect. - print("!!!! resource selected"); - switch(currentAction) { - case "load file": - Window.browseChanged.disconnect(onResourceSelected); - break - case "load url": - Window.promptTextChanged.disconnect(onResourceSelected); - break; - } - if (resource) { - print("!!!! building resource object"); - var resourceObj = buildResourceObj(resource); - print("!!!! installing resource object"); - installResourceObj(resourceObj); - print("!!!! notifying script of resource object"); - sendToScript({ - method: 'tester_newResourceObject', - resourceObject: resourceObj }); - } - } - - Repeater { - model: [ "Load File", "Load URL" ] - HifiControlsUit.Button { - color: hifi.buttons.blue - fontSize: 20 - text: modelData - width: root.width / 3 - height: 40 - onClicked: rootActions.actions[text]() - } - } - } - } + + signal sendToScript(var message) } diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/spinner.gif b/interface/resources/qml/hifi/commerce/marketplaceItemTester/spinner.gif index 00f75ae62fa59b28a7813ca00c4185390e3e51da..0536bd1884f1cb4a814b729803b1996c8347d182 100644 GIT binary patch literal 59412 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�)#8TsS*rVAU%J0tpt=B2=IG*djp3b$!Y|O z3<@sDTgX5K42VJTg%@3a1B{Z;;a@Yi57(3+-ikELpdy1ONl0%WY3V~b2Ane(A47^V zq)#?5fS)pdVvoVd7|iWMVuK*yGa$|8=YNF72*yWZ{9KLw8Yb(C%F(a8Jy^Z%QL?b6 zp5N}^In5PgKS+Cv>hx`rnOP&=c_Vc=Gap;(MP^u`jZ-sk;~N!FBzDhU_uyJZw! zImkVHnk;6|uCtV9r4x^m?6c4Er4U(A#q_IUQD=@~OQ=1Uj7oAhEK*Dkhizs4)O&_! zZi(KGhtWPuA*)s>}Im!gAgG2^c3|t&R76Wz}bjg4}h8!y2zWtFEBcLrH!{+8z z!(spB2I=RtwH|&AoyBW$S~d)mdNb+J?-Y=yyG$)vQ;PN-P^r+6`=HTTjLn#lOQ=Eh zU(wq>El*2cKA78FKO`SS;UaD3RawGtwvf7_e4zKS{g)bMHX1V3PTZ2j`_VdE&J*6w zGLC~qBb6HRO7*zP)Tl6@9+p{+Ypo(xGHz0}c}I#b8dl}u5llSODaj1 zddin~6{RIav%Rn-UJvbh27QxpNcg%MjUI2Y#DT=*yTi(DMXe&3{dXU}E3Ya(C4`Z? zJE>wM=l%F;>2eXrNO9u(`0w`@+0PG1Pe0A{AH@b6kO-8Nc$xTM`1>(uN#%mG_P>!# zjU&mXP`wyT?)mcZJ{mixI9J^bFLRYHB}v;UEweotir9E|TVJFQ*^AzNqOpEMu0qB} zw&({rUAZy)>42rBr2#3H znfVXyBF^wb0PZSU0r5>aOqC&H8OU@jjK(%KHQm0wdXofJ01qEN1mRbBdjuv*{I${F zK-y&xz&AslmBX9z^_+hgxmZ|O_>W2c^#WwShQw&JI5ci$O|mSz8guNDrwb+F!CxS$ zaB}Jjh=vw>psF3eF>vEJDr{=ElEsU+4(j4KK^Iz(`Zsw7I*-3~o0*yGlJ zJicLfbXB`qf0Ot(CAQZd)3#Sdl_k7S#Ja2OdYSV*l37#OK0+)~IFNbMjBGQ#vVCCW ziOIp@Q~YXY&B_YTcQN0(>Nq%9TKgxH(ZPzQW5;evvU*cdT$@{Z7sHv;E>bF=EqvZT zbE~20%=A*MOV*u@Xwo;O4zbmlvHJWY`NxX|a)T28{62l^%VK6-|EB}bWRpT=y+_ri zDQelZCS^k`)ca_{485Ot)2s4t2n;hk`#E?MtNMX*F-y%$6b_t56y7frLwV#d>Aw7O z_IYQ7_tlI?u(Ug&yg$=dXUA;e^&1b9-$|_;KGe5^$I(;)-5x8?RoW+{$T)G%$<&n2 zK{2+=r%+MsQ|fspbM^^ko=`F7qC3z7IBxW@N5R)7PjFUx0MFF;hvnO=@Ay&^WS5}&-sdx$`sLTMX01%gj z+W=smA+;C*z`RL(tJK-~4}k`P7)W&nPQn4e*(8){1QCq&QWyY8)%Nk@$IqWX|6k%{ zzlPPiG>Xh>8zvt-p(x?xmZxjK*SfO0Omm2g_p*t`yZ*YW-bcc9%vziu(Q_S%wzca~ zV(YIhqRBP$y?#BY_e{K?yHChlpTa4IiYf9W-5q!0WGlQ6x1affscgAp+F0w&yzwpi zc*L%qvR}OhY*MmvXuq(EZ5AsDwQ4`(99z@6<6@?saVeRzW29P6ne+9ADm7))k!GR0;UCGhscA!URZV*9hP9f`zBC};lZ<&9YNXI>7a-P;MMZq}E8@=D({PwV5^gdnvZYEEw`zr?H(+^ z4OHv-de#o|und?4*Xc-BI&9B1v8k3U9b|khF6~0|u9Kef(rDWLVI^LPlrb{h(2wmm zmL)FQhnr_9s`l4UJ}JHEmRN^!%@2guLFUN$bZ~3>#keQytOUo4vsHK1uzC-pH+z&3iGY)ZZ0i_MKO6 zTPd<=Q`W zVXdglI?Kmt!md8dUr%eV=UEgV+E}GxE&sT0%2xi5ER`J8km*7yYP!}d7d_aj5pQ(B zeVdUJM%HWCk(DtGMR!?2G9rOojMOL=CBWkl)NiEONtsw%GN}|SKR-!)EdIBBh9|X@ z4IBRF=?t(G02~H0vjn^a0P8K*EH#7j3^{#*H71-s39iF|1_Nm_=##-H89}@s4xr$~ z5?Rp$L>fUq5AhiK^JE!;W`l?0u(^zY%m@I5*_wcRPN>%6kH9}nY7po&2;_nQMmE5<6NLPMqc$`&G%`YHrxB<%f;}g(P6Mn4@0B32 zt+(V{lfBl&uc0&p&2+=N6QoH;9`tka%F}i5^|_Vw6whhh*O2Rs5H7)H4=u-I(EV5R zsiwcu(3hL$-YpvX+C^U`V;y#}Bxy_~R?rjM=vjE5(OE*4i#{@rj-qTdZQqa_!#IhS8j>XvVd1B4trt`5l{9kLJ1JqZwd&oDlO=nT z9w{Un`i5D)Oh7)&XX(=AEME96*bnuJ7=d7-32~N_j=Ki@|`~?H25hx zgf?U>QAYIg#5gLQMVwKNU01lZzP6J9ZxbK9wmvHMTB0`vzMc!T_ zWf%YuW3UGU?mLk*N6d5pu#u6t&Ijbpkn2p4-v9+aYvwm#8%97tKwuy~B?}Lkh^Y<9 zVlZPC6B82~8;gvY0eJ=oOJt)@cJ@Cuok-{Z(xpqVkrA9TA+0kA0<{LBw)OS(ppg+C zY65lxQ|R5hcj4I*@<0G)HVCK8G8=sO-Rb71ilO%uRXDBSYGu-5TaC?lBTvFG&vD^{7c2_d8M- zo7>*cHSGJtQnvDrlD5`-MZc3HW2`8h?rZ6rV(KI@S|!3QG{NNief*_nt~XGhyJ*gG z+z?}LwP&j$qj$G9b25#7VimKqQ?hAx7Fsu6t5;vxO_{eqY#-(!|3SqVsloB^er3-q z!TTjXsL7&kRrG$Vk!dff(OzaJdvJKP_y+nx;4Xo?+zZ9GFyEKo#>?GY;Af)Ra=EKX zEXm+t?7i%STk3!9iC>}*V7|^2bK;Hn1p6tzijNq7w#>VkT2IG%EY)9((XneO{*l@h zh;lHYJ@!eaIG(wsDsfD@-#}vH@lSlk2`6_hF*2Op;}A|2OXE$_7b29)IO3Am98MK4 z=)XH7oYH7(5>Av<=Ber(g%F)60X8Oz3p7TW!#avK{9PpXbZ~vC7VEoe(=W5nY!!Hw z6Fm1DE(0hiRztPOvjE6&Nc{#G4whi-+4H06hj=LpyDvmUMBq9US$_e5q&m1j0B287 z%Yje_P;N-shK$o9gB&2jVP$0nDl%Y@1F#+JnRRz}M^pD1|g8tbx+sz0z2555KIH5iv;yQ@ZbsF3J^4A zfE58GwyCKpP)YXsHDP#TmBEMr=h1})ysP$;iVP&yV>O6hBHIS5f)kbMg8Ep@_F@I( zRQ+}fbw`x+6ff3!=jD3Y(3qpD54@EKITE2{)^fnRpgI^;_&y8ML)gJDnK zA2IwP9=MU@M8|kH(}PKqd*pQUk2&c1lyDb`NBOI?VGN}AF-faQ<@GV03QLE{6Eo5?K4o+K8ejNlKlYxU z!@0)1p^$v&uh+IM2mQ1#cocQRdo!cKRN;b+Kf5qi{~TWcC!2botWkz$J4NAEb-I3W zO6{98wU4}*_)Y%YBc%G0{upz-bnofsXOj)iC^x5Ocs?`51Vw#l!rYVDTDN4SAaS$R z&P9b1YoyGW9{wV6TNm}X16D3^M0}S|8nsA^Jint7Z>s+qy|ODygH?J<{0-U-383TF zwAKiKlywjULn|`O2E`rn$`cg+fDUfrZZm=bR$d;j?7%SrSez0c6A+6#DC>}OtAm4s zi;D}OH7_qbry)Ze@Vp7wYy|R+U=#&FDmch>u$=K&e_Y48e)_<&$_C|zlng>et$WJ+)m1*r~D97w7CUseVX zzl7YTXQOg;Ytsi=Ivyl)3d_?iodKPUZJIOjUN%%{RJF6@Bu^=4g-z|w?&)BYfohb$ zckQ$aE7mylX8GH(3k+CKmm_tL1RhZv6^0f#v|V~4+^Z?X9vGq}Q#4rIbW_8tThQ%c zo8C#@tb2KLJyjx^hx%OOLu`u2zhABSB5|~BFUqv`%?1XEc1@H~aqC;mkXlc+=}va% z{oIZx$Bpj0YG6LBOJwgqt-l!?}Rb)@*?5+?uPD^$Fg>bKs-0KPQa{r4;jU?n5cStAByD*(t@ zphuRV4+t7<0Kjeom5c;o4+x}I1Nk(l*udccY%zm?YXbNt0Bpgwvcg{z*xTE~&N5;_ zMxe=nxrUrTk#*Q>^4CvTjJTB%t~|kl0O~fl=0t{W3HmjV(OXz63vShkuRD=7*+8Yi zz6>DL2nvAUEhlWv0Q*j47dA3e3mJ+4P?Lc%6UZ{8{Q3zXN&PE+4U5s-XR)ZCAg$fn zi?3un8hv%8lJNoG$RRm=B_q~ScT$t|(vwU5xZ~iq=oPsTOPmas+v$3 zEpnwlwp(Sqzf`)4?C8VUt;R=nZklY6RAoXbRfUhb?(n9 z9xm_Vc(o+u+me${Bez-(V9tr|_BL~t6rdkOGferR%ri4zRUec9jnQx28rO`B@(F0pd_&z8xhLHQl`1|nHH&I`s z50rZ-_COmIT+ zNTFlacBR-??_*rD_L<9WaaLzUg=K73kVsbVQO>@TKfFkPUR_?lshH*;8ovqeB{Iab$f$FM%@DtPn zqe*I?JN~aw9!h7q?UW-FLWUx?$Ma!Ag&2EtP=f7#aa50*oLgoXQ4Zykp6#f64t_Y+V!S%p;>jET@mjn>7 z3=QxcY!X_tMH|eUP_iL6q3{J0f_w)7u|W__osjV0wNzvz;SLl$5&(Ayuv#0w292YnZFMdtd3^G8w1dGb=jl~3SL3}n;&V{djw6L3M z#}>=CC%Hkk-#^lAa=N2Tyy%P^i^EY9c1tni(#)E>qXn3%xf5mqFOKKlz$gV|ihV>c zzCWlG@_ymP!l(X6PJ@5Ve%(K2q%dK9V#9$YdY>&)y_qO)o_i>=s3vsQxowL}lp)(0 zKI-}H;A$nsxO!vbPQT~i<5G;Q@a0krbi0;!NLWtwd8D<&qHZ`_k!V<`l4(CD&4F6l zkMRN>yBaZ7y)VenWvcK&Rih=^qVBo+LG&jQc zm_W!DjFM}5{_qJpAc;AO05EX|BDL^EI#}C?9!gvfV7n}61_FtWf30v_lgdIvS6gS{kpX-b0KUxx4hujdT0sFm zj|N|%gVjOMI)kPead{(>zK8(`jo{J~924~S_k$-)h@W9XdSz=Kbt2Un02n<%kYj0S z>A!RZ5eqS5{2CIQjVQ9X-q6L8uHBorN1kqqns?4E9`+jL@rfoU(^T15!%JE)LJ``S4glT+txx;$+cospwvmG%@T z(aF4hKSNu$u)==U{Zy9BU-&;nb781zFB*P+6YH1BrO)3{r~X>tY^g%w zjqQQHpNl)ol;}4Y9cW!%V(Iruzm@BM;??4{xMQuPB`6=|5yu?Gg_vs`N zUFzLUzq5cY|@IV~^CNy9#wuuR0+bpoiKuCkQYQxR# zA88Hb6bT3moTI~Q0sJtze%C+fX+#1kxnOPMg$ox5?l)mhgZKan-aY-~=m{8Q#3?kG zqy&4F21Tk9? z;FplsVAtjpRUKYAnJM7XOmT^RYnw^N@A zO-sgKsR?nVy{bsf%h^fCIvXlhl4v!0+roc5=CQKorB*Er>$6DXoJi-ijH-5JltcDc zEeSK1sNFX2t@so9m}758_?Vk+o|%o>oii$>S>&%^$!^`Kpxe}a+2Z`Mte`8)l^;77 z->?{`u>Zx`yG;51h4rhORyE(gmTt>YnxBo7Bj`{gCM&3bc&95#&h z3>UPS-C=Epnm%?|?^`Y}W!P-Mj%1mb4XIBOjVS%@2^Ld0M2m#o%QcNy*C?a-4O$E| zHqz12F|2@~HV6hFT2-=x5Yt(5&76V64#OLU1zAFbFm4jgo zsKW5C%B{Qx01UF?;#J4LtZel?6XeSP$Y~Nj1PlXbNcSJ|8e9Y1zmM;zMOtQXw+S!R zA+J4u{v2pAg5=qH8%qKJIkvcnzf}J()JDKx1o$O%HeIE`Y1wdNkcCV_k0y)MMJG}U z{}j`xO5Y*5O0`SH*lMjw&AhnIa+_?uZqo_uK(+pP-CENL!G5d5<*bsZ7OhMxo2EyZ zxHdQRaqoVvH_rGY0m-kF6)JaZOo(!WXaS28huMm|tP*x8vmSm| zR9!0KHCc0gDfG{bYYofqIwO0mCRnU?rQaOuSt5VdqL2OZ{%i15M&7N{m2o|@UzvkV z(2ZL(s7bFfYs8(_)y#i>i06}J$GMGS1HDJ*C!h2NQ>lHT4}IGwYKl&hA4onzmLN)M zJat9`?Y*UsI?Qef6WWVwXf7t?$svK;g{MW-ax;{Uqthi1DQ z!mG<`nBe{7jO0?cHs_$hdi}FSzh{LB0s1wNaWjI4GLaGuvK)92bImuZGqs>D2v}lB zeFkl?H34Z20IAR5SpYoZgeU8O(6Y1fei*W@5uTkRlVwQyLiWK7IQ1U%dV`LBLvT;@41_rxq9b)+7#>nNlxm&5b-R$5YGvzQ??Z0w{&`1A zE*Qs~cb5Y&BfYbI6UnB-g5|pYb6q&wQ8fy`kyMNs5TmL64~) zILwft54GL&*#9wj^i}~&?{~~s#n*ZnY0?@NODBT-GPj=29xi?Tacels-J={KSBvK> zo(!NHD#EhR@0wmdLl4pOS&_wU2+KA_Z8^8gQ)#-8j`%kKILfN$lbM{43_{81A_%sp9dzJY3`sF+&K0{(u>$TAN}RAF?UtJoW}*zZM#O2bP1cO!;0+l7(%L*<#80Hn*{C&y6hO{Yn#hO%>dy z1V*2e&rOmZJD;NP?e?&8X(Q8)2c>zRx8A1e3%V8EtOhqvv|!5=;|EuZ*a*#vbuk?l`Y$AN(;Be2?kB+?vC>3^+`J(hP!kFp*nG zP?Zg0|FA0v8Mr7cTpcFit$F1NVAKLWcmkLVI{aXs1ey#AGUOPE%=|-H27NN{R5^I~ z7nC;wdkj8~35|U?OcG3w0JF2ROH02d{`$+VmuNIOu}x)tmrN>5u4rla?QS)k0oO}{ zA*$22+3?p(WG>tOWJs!u95K^;8EJpGM@_eGd^c^bxx-|$Vc#Dk@>g2}wat3cja@v3 z1cDFiy&g>$OjnRJ(GYE62&pkXE+p=$aQqaf9Y1-JupK&$`yGnBFQG3?L+0S(i3ZMu zl1j7v(d4z4T|)#hPsF`5I9W@co!DzZBU$5d&Oe(`E=!aOWBQQB?(DMQa`UwQCDVgD zyiY2Qqnc{zS`XBueL6ew+UVfX+n;+DUtXZHe0)>p>2qhYFg4{X--Ux?B+r1#O8%4TW9iOwb0MZ+tAK-%?V)) z#w42$vsZ>Y#6*gj7WKzI3dUaG-CyJoabD^zhjpCt{qY<_Y-(Nxb}H4*)GWc54np_5nOixb_d3J7OM0mVpZEbC5XXohXh{NHK@AwkKGV-~bcZp^bdC z96X0fFjK;3{zG`M<0o*Q+o4Iev{2o9)Q8xIRi6a6~APl~5J;=gx_0bB#%Y}yy`2Jx-QLm@S$OSsaP2m`Z-&}4)K;+-CZZ$Q`>NtyC~?S zlcJYxB0H3XYpwkDEVwr7JsQ^2NS=2OjtRN598kGnI==O|jH!5P!0 zF>*e;5RtT3SdlOb&J&=wAhPwM`~*w)(;&~EW9U8wY8(8qpPbcaj_Zn@L`!5a*RYSDgSjtNxYX>AATU^h zqb1;sfmlCsm;`N&tL_*A$P*#YdfYxhf!i$uJn`)f(1JqtGX=T$JO!K=%spjY% zP5TQc(Lyh&Hl+Q5nfsY-JBIPXUK9;u7voh5Z;CS__o>Hx=mk`s*-T#N;lOm&c;+11 zhdGw3K>2uq(^$=@*@)r5{bMF!6AnK8rZ=NW=D87sq z#4F(ICCI(wdZrfyB&jt4mFZg^MXvhYWN^GdJkcZ)5-3X2-VU`tHx`-59KR51?`0r0GA@OsywH|&AdC`#Nnp_zs zt=L*aOP@vdf}XCUhQG%y=@f^g#=TOb;_L!FhSc#glcFR;S4q*C*H0|X;)6V;1u0YW zx8|IQ5P#qzS+CKyTSu{E$Vl`s(_F2Yu$xUV>Z{a9;YZOs^fxXVA1fCPu`3GYX9^zo zN}LKd%5ePtaPey6{en^{;p8EkCq;hd+shwF#JUD~rax{_@DT19x$#1(g3%(UXMAhy zwwDhR{XCv2ot=ODt?|?4qF}2a+{IbRo&mmqYHG9efWuC?cd=Q%CNYhw4|EMKEsWL3 zw=cd^%NE+s!hO6bt5)Ti$2--DbGXkuu+`_KIWL3MJ)$;ZhRVI(k-bRvV1}Bv59T)lN_b%U0yc2XFkT+ZJ zzy}kaGm7IA%Di_!`RQQN6%FnSRr48BBzu;J44@h6ENoEj8GJ^mwHi?O?k(ng`q_=|y4=O3GHqIiW7sy9WKn4~(W&&RS zMZT0t@MsCJ!T$BlO9JXbCM!U#4?IHx;R=H5BVdeyyGmrs4?$NM?7)B{B|Jbv2KJ%! z0?s~s{TGJD@B?K_3n*a(MPBv&hfv1u<>K$1WxmzqddPl1j`QvsA_0^O$xfg_LNDj1@ zJyA3#rJSAdPU)}Q`YJfWnS(rC5mVvQ5+pT7tvylpxFSQejibryGZ*=Vlv1&}Ac`W< zetOsObIN3U6~5GSBo{Rb?E3mZqH^jif1*h3!gUU|qCd5w+-6KAg^FU0Se~=iB)Xop zOY|)M5dnNm6wKGK7_4kfs?t6IIUD4M6RFlM#=Ccd3^+h&K zhF&N+R@_tWyWOLGyY}zTGl9eyY?dW>&z!&{8yp-Q9{zEN1ja~w+TsPi>4MlN1Auf!z-55Q zK(p*mX3O8eWz4h@P1#E)77gt~_Ne4&oK7#ZO|D z#a!A^c1Y3JmBK5n1Ff;?xQg4}s%O%W{hS}h9HAI`g);{F-ImGugdF`{K>%Wb`XlQ64 zO(AQ?SXo(j?ZSujVYU^|S^WG^Q2_wf0+a>h6twV>Auy<)6cm2M^WlU@JRYtI0?N|W z{jr+FV(~BfLdgZ+j6-fAaX1|EfnN}N1=c<=@_`hCt%`7d{0WdWMGP1b1NpGHxHypC z2RD*{rjU+405VvCOuNDh%BmG0?J&5h#4jmp@ujkW&>9*DADcr;wANPqH6`FNVs{LV zpFoyD;sV=Aq$Y!`g#ab=;pTllL=2#_CGc*nwwGYMx9h1dC=wC;ebk;36<03t(ssz@%y zr{zS8QBOs%wbi8RgtD~BWL-C}3IB^-Dq_9ck^)7H!g?)K#Yp=0kzOufHa3&>VlwUt zzL#K))kKFzZn{6liJ8zLp|i!c+1;b{8riKbgzNJ|liVwG;4yB!P0|ygF6F;NU(9KM z2a_jLe}O8moT-3sx^^;zGmjcQAkj*FI6S7RaGi5-q2G|*r=VCpMFOdPf{_w{V5-DF zT+YVE&i>=kOoEazB+)^-gMn9I`Xjjxf>@YAZ3f!L2ws*0{6@U41a*s`?gDgOfLNKm zJ^nRdWW)k_O$i@2LFzOp%-}uvdK*h(uOG^=@bI-`7$EZstNoF6i_r0h6DH7Oppgue z$gYT|<=+3^!9kW24$2cXD z+BuXT6V)&={8nVK(>0Op2FnwTM}_-@x`f!P%Z*8O1>VGlriG%@80_CC-rDc(*pYEu zeNZQ?wvO%pwRh#;Q1AcW?W!oUjw~f>mXs`GubU8!vCW1-VMey-lFD+mSjv`=v0as9 zERmw96gOf>sW6CAS;oDTZi_+P+r6LT`|^3+cQZ}5^F4j~smCAjIM3y=L{0mZ1)8nS zn82{YihE4!8cM8Hb1O=98keaJNc)WbCU;)q1fx2W`Qy-M!G zxMsRVuNxBWC%^7&%{Dz<%FbR(<`{+$cqfWGqx` znN3#GBow;LWa77B*EEIODmg3oG@$}iLYJn@VD-*mjb1JsP4^boD?E~{m`F`F9pWoE z?#jyWw#UW%Mm44jy(Nf8Uh!5ra#baxB_o#?r~M@Lb+Te1z#9{)_+b+;(8?mKGXc1% z4aSl28s;GWHJS_(9E>C52#`gNamW~1@V&(0aG(qrOmFV)?w+2WR4NtpW+Lxo+zzCu zs1Hm?KtuM4K@EUoM1zc$lr(R#M22I-A0{}P0X-Q;33Fq4iOJxq`8jD9Nc^t{wObc`8=Z0@ zXY*$#A8&B7JG@bga!EspE^Lhs($vym##xofzTd$<+bEe(H^owgx_FT!6oV4sfRHIk|5v44T;KBhj8?GJRjx znDuknHM6?Bf!R^N5_vT_RDM@K^X`i8@We7UC22q-B#IfGVQBqCwWj!Gc+^=;ot@XN z%pgKudv^-nVI>{M-q5>ZpI!8sjH{hDWel%5OeW#9Cyw^ss?x$nTwzpnIw$SQ+j@o_ z^%Nhl>R9I=8z$DWYOm#H3pso>|!hZA(rie4$3Qi(#x^ahtxQ${nh zB$ne=%A8sAc9Lnadc`7*4mqb~JZAh(ExKHzn2_y8H~Pw z%6{bij3Z(UuAZOhSV98HT*wqy4sk#HSYj~qv9F-U97xBYztY?LpYBW`aYb4w0gzJ| z67XgQ#bn4H&Cii!Kyb5LLc%}PmX?+V)Uq7zOXyVMPF+M^(SV1%ynIe%2Ie(n#v=0D ziJaHqwTz6^ZY;IorB75hpizW9`l?b2ST~fUt)Kh2(AY$fPj=N|oumup85bH{ z<)f@f#(`nh_X_Z`BLOYSPtFG7Q&B@=>z!#7^RcYxKSqKxF9!a-(e-k`v()n^l$3@0 zlmlpCSEgUPm{ehu8x0342Ygg1B}sa(%&8+*Mo?k#VX_Ewg; zu0DXdR+v&u%vFBk6(IZ|O`!bTOqZL-AUh3}7EVNA?Go`bK2VTzX4><^+)Lq2_(?#zMIUSTa9hR^kA#iNnI* zckkZ)D}iyd7ZP8L$xfjo_-LiW4|Gr#tL&?NwaLeegzDG(3`}Y;<2s9Rs3j8qTeMl1 z227V+ysuNfJVHgnbX-;BY=rJvfpXfK+m2)(pPfnu1luz5QhzO#-rFAMSl7Mt%X@xr z4<^t2_~;CJ0MkH5-9{x(k9L(^G<%m+5jw>*kk@cv6UpU6sRwhb?Qiu{o)>Gj#4zpL zo&`VApkJL%$o0S4i{HNc`UW|=e{qKC*{pM+b@gL%zWzZ!R~z9wk^`H|B{!nqd7kT9 z<}kUap>RnXer5UfAcr5fG?7h9m?u{$N55TDPe(;bz2bX9*jqK#PiR#U5EE%l@Hu6x zS%EGH6+wq6;BU1xfA2vyANJg=`Si%PsI}@aq<()g%~ZCCTn-S*QgZ+pAA>f!XRxEMu8&2Xm#ZK=@T zZp-U$qw@^$S0j7{tt_~riHnO%O3tmCAEh(yX$?8BfmjSE{RdnIOPD}NKN^iTF!)F_ z2>_D0z}bvr$+Wbz1b+jtWO5wOpwOQ{AP|W}5{U$hN3w5M{cpcEFZSejxux%(?u~wKh-cZ|{GkW#;2?;fUeglO=cd^gmdU z-DjVhb7`XbG`{lg-H=N?OpVs&3YsnL;Tu}(xrU)Dk@B}ONw=K!MQYiY!Ct|KL2qS^ z8LWz{lF~l6PFt-CURR@b^e17NkOCsTh8m+A81ns~#j;BDO6=+)YuVUEx%VHN<=(RF zBRgNMN)rrzMCvtK*c7Ie^yW&;ViZAu%8xpHWwUak4nu$Fm}OU~P=ZdQ^JvCl1&wau z_iJ5A+WX#9t+eF-GO|}Se@C@at)B{gXjGr+ZR2af^NKb-?rZ*ac#Rt(A|j%qqCi^< zNDbc1V67b3Jc0WXnNCjc_v8i0e^ILrV@fzB6b67?HNmzCodC$uEH;*BqCdxm2}unk`f~`;;P?iT6+vq`$5Q}`G?0%@ zuw){28Xpy(f#)VH&Ey!?z;hEC0AOVaa9_eh8ql9X113~x@OlSulNww#r>3Sp)7A7j zj0W)K=Cw^;N*ZF4N*O`dl1$7@c0E?5FU>VLp|+ZmD65-n7xYeOq_b%K(x4N|m))|` zdzdE`nMmE)pS+8a7j)Hj9Yc%KSh@4so*;%TrK*zOtmYZR*UhR5Yswb3uEJjyvrF9f zjCxeHDX61RJhabvE zL282^P0+E#L1dq}pK)^;xR$}u44LHv0GCkcGw0R#i~I{fk^p7Ab<7s^&vgvux4rg889@rb%Ii*Pb)THGVEtYk$paSA@SviOkRVvU`e`V<-Xsq ziv}fF%609#YokScFr|UBz>5w17{DIPuUNEI;Ms)mQkU55x+TXWvkHW(4Gbbfq%N~M zOCG2BUHWdRe_57Iop(n<{F<&h&F+my8B)rEyGVamhV7sUSzC~5&I#?T3E3j;nt%+SY3ZLW4h~N zU{v#a!d}dP!!LVPCY@Dh_7$79djE2^>#ga%REzU*`FYAR<()3o`_BqTTZv!OuKMXA zd1T+?wH-5=K~lNCgZn*td^<@VI+wc+G#SmNxp<5(?he1fo_6#K=)c@W5tJPsGFSO? zCO__Al`lr+7j7t-by=Y2C$#f@_;T{wE-**r&~ z-U>FOe<(7I(N}TgUbp_44fFt=Tt18;pi) z+x?350=CN@Wx1C!CVOv@>c(R|Xnh}ulUzw9hmg=oKWKBn^; z&5v?PtJiPR@r;moVBy@UDj_^_kmx{Orm8w@B-lW(OpwXQ5fwhdJhEc9USeZmLc^W( zh3-~V9cwqWU?T}(=_J3=blV7&M)noNzcC9zU0$0S{}C-#k6%ihn_Nc0fP?U^Zl&8Hmq-R!(Sr z;^pH+QW?nahao_)&U}u=j?ZnJaOnhZO-N`!y#ee_Ac+wg%sIv~Kv~e@1m`nAS@5|D z^JAgQ3FI+?{8+$Xpp%5d;smuCVAq6;CMYL?)^cv?83f=lAVUL%<=`78A{`@$_Q;{CGm9=4ug1nqp6w!#MMBwi6{)Eg z7VQbE$EYtHh`mv{=*`>Sr})ywN4;xvMkjRZqXc8>+V$6)uXNUySr;xiVR$21xWY~o zU428#S#cNEX_2Hy=Dy=GlP-(=yG%6k=I8F{gqb;Ns%f(mTs79yoPSU{ob>Zd>m!Xr zQIh*#PxKEpI4z1L=TIh#ZWETJPIR*UGWQg0ds3Pg+5YR+V~jwoc{oeAwA8TfFGh70 zj+(coIIY8k75uyO;2PBV*S$UWP={vnY@^K=Vt*2)d(v=xm7`>{#kkDP?&U3E@`N`1 znfoq|J}A8SlW;4+n8oy$o@P&8&WI;$^Rh@xS~$L`Ed~?at$@{vM2Tp|xp>8IGI22% z&@?Fwr(jKHokugMD~-Dov5~~>_FJ*bS;WgmiTEXZ+}lQV<8C}4$iy8CP0nsC+MIAW zi|4qu?kh{vP^h`A?9XR52uN`X3JS`~%1CB|KyIYq{R#OE+}n))4|BVz@dvL^?r#E& z-9Rp=a61L@8jg;RBofKP!^6wV%g4vZ-`^i(Yd}#g+&>}UkcMP7Uf%&EAin`8dP+(P z@Ny#cXW)1Soait{gCj8mHvOJEHy^?X<1&!`02l^z{rcSTtf8R+<^dte4Q`1SM8_?GAC{&LsP)WwPj#G|9J=;%MGI1(IjTL*u$rs#eZ1+iN!JQKxq{N_w7>4NYGEtlQUp zTvp$b?dn#~AJrVce4VyuOiiu)I`#N~`z`#6gYTF2-*~D=Tbz0tBcr>$q*PbLk{y=n zcc|{<{#QAL$)~Mr^vj9{ZjNM^wCwodeNJHj=I*NKGd~p%P(+5*@TMMvuWGxCG`5psSmuviC@~5hqZk;tZZ?Q@T{f)BnPMSOvm>H+gTKjx6|72dk z{BHf$Iz7DL>S#XxZrWle@{67^@dE-&W*wK@bzFGTmf=_bzaLa4GGjbZq+y@sq_oKA>cjD4*h6e!+!&i}{||6WIUrTR+BoDbjr${j+&0&*pA)6Q-V#H@4-y(bJ&jpfT0)Ni z0N|;A#r&TDGw&vVCBQKA42)~rx6gNG!otiQJLa<-krEG3l?i4z5Z=gLm5F3DBp|y% zfOQniaNyVmz3Xs*16nj#{|hJ&@Eu6ofR#)iB|8Xi`R$b}bFTHex;kWvBP2eKbrd@E@lNYP&&JF_+ve^eDW|~~ z8XlNSrJI+Z%fb)`nB(Sl_=}_(6VbT)75K}cY#rg}^{x@MJBP^kt-H#`h7Wp1i8i~H zC60A%nB7xmyedk}n^t$n>S^q{r?MM&u0Kn-k+L*cP_F-}dfC_%Nj`jLTYd+BG`2^` zB%SG6Ah_&!o*Mf`k8NL_fuq6n&hPQNMzY?CS-!}up|y`0MU3mxF2qM^Rfb82_R7Dp z*>f`V0*<-TcZjG#*7Q$lSXF;sUyc2SVU**#ZQHG!EATHA`J19~b`naq z8`GSJo&6{~ywP0_1DIf?vb4|92}piZ0kOy`K~8@}NizTq3b;Tyi; L8@}NiK8F7Q4CAa& literal 46135 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