From 51246a2e45ece2e60e11b97f388101de55a38800 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 17 Feb 2017 10:24:01 -0700 Subject: [PATCH 01/35] first cut, pretty ugly --- interface/resources/qml/hifi/NameCard.qml | 5 +- interface/resources/qml/hifi/Pal.qml | 42 +++++++++++---- scripts/system/pal.js | 66 +++++++++++++---------- 3 files changed, 73 insertions(+), 40 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index b55b9c517d..5eb6e6b8b1 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -31,6 +31,7 @@ Item { property real displayNameTextPixelSize: 18 property int usernameTextHeight: 12 property real audioLevel: 0.0 + property real avgAudioLevel: 0.0 property bool isMyCard: false property bool selected: false property bool isAdmin: false @@ -335,7 +336,7 @@ Item { } } - // Per-Avatar Gain Slider + // Per-Avatar Gain Slider Slider { id: gainSlider // Size @@ -369,7 +370,7 @@ Item { mouse.accepted = false } onReleased: { - // the above mouse.accepted seems to make this + // the above mouse.accepted seems to make this // never get called, nonetheless... mouse.accepted = false } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index c1fea7c09b..0d1da1eed5 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -2,7 +2,7 @@ // Pal.qml // qml/hifi // -// People Action List +// People Action List // // Created by Howard Stearns on 12/12/2016 // Copyright 2016 High Fidelity, Inc. @@ -29,8 +29,8 @@ Rectangle { property int myCardHeight: 90 property int rowHeight: 70 property int actionButtonWidth: 55 - property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4 : 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth - property var myData: ({displayName: "", userName: "", audioLevel: 0.0, admin: true}) // valid dummy until set + property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 5 : 3) - 4 - hifi.dimensions.scrollbarBackgroundWidth + property var myData: ({displayName: "", userName: "", audioLevel: 0.0, avgAudioLevel: 0.0, admin: true}) // valid dummy until set property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities. property bool iAmAdmin: false @@ -86,6 +86,7 @@ Rectangle { displayName: myData.displayName userName: myData.userName audioLevel: myData.audioLevel + avgAudioLevel: myData.avgAudioLevel isMyCard: true // Size width: nameCardWidth @@ -184,6 +185,13 @@ Rectangle { movable: false resizable: false } + TableViewColumn { + role: "avgAudioLevel" + title: "VOL" + width: actionButtonWidth + movable: false + resizable: false + } TableViewColumn { visible: iAmAdmin role: "mute" @@ -218,6 +226,7 @@ Rectangle { id: itemCell property bool isCheckBox: styleData.role === "personalMute" || styleData.role === "ignore" property bool isButton: styleData.role === "mute" || styleData.role === "kick" + property bool isText: styleData.role == "avgAudioLevel" // This NameCard refers to the cell that contains an avatar's // DisplayName and UserName NameCard { @@ -226,7 +235,8 @@ Rectangle { displayName: styleData.value userName: model ? model.userName : "" audioLevel: model ? model.audioLevel : 0.0 - visible: !isCheckBox && !isButton + avgAudioLevel: model ? model.avgAudioLevel : 0.0 + visible: !isCheckBox && !isButton && !isText uuid: model ? model.sessionId : "" selected: styleData.selected isAdmin: model && model.admin @@ -236,7 +246,16 @@ Rectangle { // Anchors anchors.left: parent.left } - + Text { + id: avgAudioVolume + text: model ? model.avgAudioLevel : 0.0 + visible: isText + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + width: parent.width + height: parent.height + } + // This CheckBox belongs in the columns that contain the stateful action buttons ("Mute" & "Ignore" for now) // KNOWN BUG with the Checkboxes: When clicking in the center of the sorting header, the checkbox // will appear in the "hovered" state. Hovering over the checkbox will fix it. @@ -272,7 +291,7 @@ Rectangle { checked = Qt.binding(function() { return (model[styleData.role])}) } } - + // This Button belongs in the columns that contain the stateless action buttons ("Silence" & "Ban" for now) HifiControls.Button { id: actionButton @@ -542,23 +561,28 @@ Rectangle { } } break; - case 'updateAudioLevel': + case 'updateAudioLevel': for (var userId in message.params) { - var audioLevel = message.params[userId]; + var audioLevel = message.params[userId][0]; + var avgAudioLevel = message.params[userId][1]; // If the userId is 0, we're updating "myData". if (userId == 0) { myData.audioLevel = audioLevel; myCard.audioLevel = audioLevel; // Defensive programming + myData.avgAudioLevel = avgAudioLevel; + myCard.avgAudioLevel = avgAudioLevel; } else { var userIndex = findSessionIndex(userId); if (userIndex != -1) { userModel.setProperty(userIndex, "audioLevel", audioLevel); userModelData[userIndex].audioLevel = audioLevel; // Defensive programming + userModel.setProperty(userIndex, "avgAudioLevel", avgAudioLevel); + userModelData[userIndex].avgAudioLevel = avgAudioLevel; } } } break; - case 'clearLocalQMLData': + case 'clearLocalQMLData': ignored = {}; gainSliderValueDB = {}; break; diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 57648da79a..b5d7c3885d 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -13,7 +13,7 @@ (function() { // BEGIN LOCAL_SCOPE -// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed +// hardcoding these as it appears we cannot traverse the originalTextures in overlays??? Maybe I've missed // something, will revisit as this is sorta horrible. const UNSELECTED_TEXTURES = {"idle-D": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png"), "idle-E": Script.resolvePath("./assets/models/Avatar-Overlay-v1.fbx/Avatar-Overlay-v1.fbm/avatar-overlay-idle.png") @@ -87,7 +87,7 @@ ExtendedOverlay.prototype.hover = function (hovering) { } else { lastHoveringId = 0; } - } + } this.editOverlay({color: color(this.selected, hovering, this.audioLevel)}); if (this.model) { this.model.editOverlay({textures: textures(this.selected, hovering)}); @@ -104,7 +104,7 @@ ExtendedOverlay.prototype.select = function (selected) { if (this.selected === selected) { return; } - + UserActivityLogger.palAction(selected ? "avatar_selected" : "avatar_deselected", this.key); this.editOverlay({color: color(selected, this.hovering, this.audioLevel)}); @@ -273,7 +273,7 @@ function sendToQml(message) { // function addAvatarNode(id) { var selected = ExtendedOverlay.isSelected(id); - return new ExtendedOverlay(id, "sphere", { + return new ExtendedOverlay(id, "sphere", { drawInFront: true, solid: true, alpha: 0.8, @@ -290,6 +290,7 @@ function populateUserList(selectData) { userName: '', sessionId: id || '', audioLevel: 0.0, + avgAudioLevel: 0.0, admin: false, personalMute: !!id && Users.getPersonalMuteStatus(id), // expects proper boolean, not null ignore: !!id && Users.getIgnoreStatus(id) // ditto @@ -341,7 +342,7 @@ function updateOverlays() { var target = avatar.position; var distance = Vec3.distance(target, eye); var offset = 0.2; - + // base offset on 1/2 distance from hips to head if we can var headIndex = avatar.getJointIndex("Head"); if (headIndex > 0) { @@ -350,7 +351,7 @@ function updateOverlays() { // get diff between target and eye (a vector pointing to the eye from avatar position) var diff = Vec3.subtract(target, eye); - + // move a bit in front, towards the camera target = Vec3.subtract(target, Vec3.multiply(Vec3.normalize(diff), offset)); @@ -361,12 +362,12 @@ function updateOverlays() { overlay.editOverlay({ color: color(ExtendedOverlay.isSelected(id), overlay.hovering, overlay.audioLevel), position: target, - dimensions: 0.032 * distance + dimensions: 0.032 * distance }); if (overlay.model) { overlay.model.ping = pingPong; overlay.model.editOverlay({ - position: target, + position: target, scale: 0.2 * distance, // constant apparent size rotation: Camera.orientation }); @@ -433,7 +434,7 @@ function handleMouseMoveEvent(event) { // find out which overlay (if any) is ove handleMouseMove(pickRay); } function handleTriggerPressed(hand, value) { - // The idea is if you press one trigger, it is the one + // The idea is if you press one trigger, it is the one // we will consider the mouse. Even if the other is pressed, // we ignore it until this one is no longer pressed. isPressed = value > TRIGGER_PRESS_THRESHOLD; @@ -441,10 +442,10 @@ function handleTriggerPressed(hand, value) { currentHandPressed = isPressed ? hand : 0; return; } - if (currentHandPressed == hand) { + if (currentHandPressed == hand) { currentHandPressed = isPressed ? hand : 0; return; - } + } // otherwise, the other hand is still triggered // so do nothing. } @@ -574,41 +575,48 @@ function receiveMessage(channel, messageString, senderID) { Messages.subscribe(CHANNEL); Messages.messageReceived.connect(receiveMessage); - var AVERAGING_RATIO = 0.05; +var LONG_AVERAGING_RATIO = 0.75; var LOUDNESS_FLOOR = 11.0; var LOUDNESS_SCALE = 2.8 / 5.0; var LOG2 = Math.log(2.0); var myData = {}; // we're not includied in ExtendedOverlay.get. +function scaleAudio(val) { + var audioLevel = 0.0; + if (val <= LOUDNESS_FLOOR) { + audioLevel = val / LOUDNESS_FLOOR * LOUDNESS_SCALE; + } else { + audioLevel = (val -(LOUDNESS_FLOOR -1 )) * LOUDNESS_SCALE; + } + if (audioLevel > 1.0) { + audioLevel = 1; + } + return audioLevel; +} function getAudioLevel(id) { // the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged // But of course it gets the data at a different rate, so we tweak the averaging ratio and frequency // of updating (the latter for efficiency too). var avatar = AvatarList.getAvatar(id); var audioLevel = 0.0; + var avgAudioLevel = 0.0; var data = id ? ExtendedOverlay.get(id) : myData; - if (!data) { - return audioLevel; - } + if (data) { - // we will do exponential moving average by taking some the last loudness and averaging - data.accumulatedLevel = AVERAGING_RATIO * (data.accumulatedLevel || 0) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness); + // we will do exponential moving average by taking some the last loudness and averaging + data.accumulatedLevel = AVERAGING_RATIO * (data.accumulatedLevel || 0) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness); + data.longAccumulatedLevel = LONG_AVERAGING_RATIO * (data.longAccumulatedLevel || 0) + (1 - LONG_AVERAGING_RATIO) * (avatar.audioLoudness); - // add 1 to insure we don't go log() and hit -infinity. Math.log is - // natural log, so to get log base 2, just divide by ln(2). - var logLevel = Math.log(data.accumulatedLevel + 1) / LOG2; + // add 1 to insure we don't go log() and hit -infinity. Math.log is + // natural log, so to get log base 2, just divide by ln(2). + audioLevel = scaleAudio(Math.log(data.accumulatedLevel + 1) / LOG2); + avgAudioLevel = scaleAudio(Math.log(data.longAccumulatedLevel + 1) / LOG2); - if (logLevel <= LOUDNESS_FLOOR) { - audioLevel = logLevel / LOUDNESS_FLOOR * LOUDNESS_SCALE; - } else { - audioLevel = (logLevel - (LOUDNESS_FLOOR - 1.0)) * LOUDNESS_SCALE; + data.audioLevel = audioLevel; + data.averageAudioLevel = avgAudioLevel; } - if (audioLevel > 1.0) { - audioLevel = 1; - } - data.audioLevel = audioLevel; - return audioLevel; + return [audioLevel, avgAudioLevel]; } function createAudioInterval(interval) { From d938c70b486c26e9bff3c7dd78a1c9a86586098a Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 17 Feb 2017 11:11:08 -0700 Subject: [PATCH 02/35] volume goes 0-9 now --- interface/resources/qml/hifi/Pal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 0d1da1eed5..e0f2df76ce 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -248,7 +248,7 @@ Rectangle { } Text { id: avgAudioVolume - text: model ? model.avgAudioLevel : 0.0 + text: model ? (10 * model.avgAudioLevel).toFixed(0) : 0.0 visible: isText horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter From 4a4c914ca8df6b1e7d7d66885789deac94263d31 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 23 Feb 2017 18:53:22 -0800 Subject: [PATCH 03/35] First cut at new styling --- .../images/Audio-Loudness-Icons/vol-0.svg | 12 ++++++ .../images/Audio-Loudness-Icons/vol-1.svg | 13 ++++++ .../images/Audio-Loudness-Icons/vol-2.svg | 16 ++++++++ .../images/Audio-Loudness-Icons/vol-3.svg | 19 +++++++++ .../images/Audio-Loudness-Icons/vol-4.svg | 21 ++++++++++ interface/resources/qml/hifi/Pal.qml | 40 +++++++++++-------- scripts/system/pal.js | 19 ++++++++- 7 files changed, 122 insertions(+), 18 deletions(-) create mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-0.svg create mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-1.svg create mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-2.svg create mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-3.svg create mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-4.svg diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-0.svg b/interface/resources/images/Audio-Loudness-Icons/vol-0.svg new file mode 100755 index 0000000000..72f247c238 --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-0.svg @@ -0,0 +1,12 @@ + + + + + diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-1.svg b/interface/resources/images/Audio-Loudness-Icons/vol-1.svg new file mode 100755 index 0000000000..9570b9ae6c --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-1.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-2.svg b/interface/resources/images/Audio-Loudness-Icons/vol-2.svg new file mode 100755 index 0000000000..a2175be39e --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-2.svg @@ -0,0 +1,16 @@ + + + + + + + diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-3.svg b/interface/resources/images/Audio-Loudness-Icons/vol-3.svg new file mode 100755 index 0000000000..21b1095941 --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-3.svg @@ -0,0 +1,19 @@ + + + + + + + + diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-4.svg b/interface/resources/images/Audio-Loudness-Icons/vol-4.svg new file mode 100755 index 0000000000..de0b4027eb --- /dev/null +++ b/interface/resources/images/Audio-Loudness-Icons/vol-4.svg @@ -0,0 +1,21 @@ + + + + + + + + + diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index e0f2df76ce..4735ae9312 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -13,6 +13,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 +import QtGraphicalEffects 1.0 import "../styles-uit" import "../controls-uit" as HifiControls @@ -163,6 +164,14 @@ Rectangle { onSortIndicatorColumnChanged: sortModel() onSortIndicatorOrderChanged: sortModel() + TableViewColumn { + role: "avgAudioLevel" + title: "VOL" + width: actionButtonWidth + movable: false + resizable: false + } + TableViewColumn { id: displayNameHeader role: "displayName" @@ -185,13 +194,6 @@ Rectangle { movable: false resizable: false } - TableViewColumn { - role: "avgAudioLevel" - title: "VOL" - width: actionButtonWidth - movable: false - resizable: false - } TableViewColumn { visible: iAmAdmin role: "mute" @@ -226,7 +228,8 @@ Rectangle { id: itemCell property bool isCheckBox: styleData.role === "personalMute" || styleData.role === "ignore" property bool isButton: styleData.role === "mute" || styleData.role === "kick" - property bool isText: styleData.role == "avgAudioLevel" + property bool isAvgAudio: styleData.role === "avgAudioLevel" + // This NameCard refers to the cell that contains an avatar's // DisplayName and UserName NameCard { @@ -236,7 +239,7 @@ Rectangle { userName: model ? model.userName : "" audioLevel: model ? model.audioLevel : 0.0 avgAudioLevel: model ? model.avgAudioLevel : 0.0 - visible: !isCheckBox && !isButton && !isText + visible: !isCheckBox && !isButton && !isAvgAudio uuid: model ? model.sessionId : "" selected: styleData.selected isAdmin: model && model.admin @@ -246,14 +249,19 @@ Rectangle { // Anchors anchors.left: parent.left } - Text { + Image { + visible: isAvgAudio + function getImage() { + var fileName = "../../../images/Audio-Loudness-Icons/vol-"; + fileName += (4.0*(model ? model.avgAudioLevel : 0.0)).toFixed(0); + fileName += ".svg"; + return fileName; + } id: avgAudioVolume - text: model ? (10 * model.avgAudioLevel).toFixed(0) : 0.0 - visible: isText - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - width: parent.width - height: parent.height + width: hifi.dimensions.tableHeaderHeight + fillMode: Image.PreserveAspectFit + source: getImage() + anchors.verticalCenter: parent.verticalCenter } // This CheckBox belongs in the columns that contain the stateful action buttons ("Mute" & "Ignore" for now) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index e9f5ba0a67..fe4eea48a4 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -197,6 +197,17 @@ HighlightedEntity.updateOverlays = function updateHighlightedEntities() { }); }; +/* this contains current gain for a given node (by session id). More efficient than + * querying it, plus there isn't a getGain function so why write one */ +var sessionGains = {}; +function convertDbToLinear(decibels) { + // +20db = 10x, 0dB = 1x, -10dB = 0.1x, etc... + // but, your perception is that something 2x as loud is +10db + // so we go from -60 to +20 or 1/64x to 4x. For now, we can + // maybe scale the signal this way?? + return Math.pow(2, decibels/10.0); +} + function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. var data; switch (message.method) { @@ -242,6 +253,8 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See UserActivityLogger.palAction("avatar_gain_changed", data['sessionId']); } else { Users.setAvatarGain(data['sessionId'], data['gain']); + sessionGains[data['sessionId']] = convertDbToLinear(data['gain']); + print("set " + data['sessionId'] + " to " + sessionGains[data['sessionId']]); } break; case 'displayNameUpdate': @@ -576,6 +589,7 @@ function scaleAudio(val) { } return audioLevel; } + function getAudioLevel(id) { // the VU meter should work similarly to the one in AvatarInputs: log scale, exponentially averaged // But of course it gets the data at a different rate, so we tweak the averaging ratio and frequency @@ -594,9 +608,10 @@ function getAudioLevel(id) { // natural log, so to get log base 2, just divide by ln(2). audioLevel = scaleAudio(Math.log(data.accumulatedLevel + 1) / LOG2); avgAudioLevel = scaleAudio(Math.log(data.longAccumulatedLevel + 1) / LOG2); - + // scale avgAudioLevel given that there can be a gain (4x to 1/64x) + avgAudioLevel = Math.min(1.0, avgAudioLevel *(sessionGains[id] || 0.75)); + data.avgAudioLevel = avgAudioLevel; data.audioLevel = audioLevel; - data.averageAudioLevel = avgAudioLevel; } return [audioLevel, avgAudioLevel]; } From 2458f95c42398d904fa7d6e7e0829d864169bca0 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 24 Feb 2017 10:31:55 -0800 Subject: [PATCH 04/35] more of a peak loudness with decay, now --- scripts/system/pal.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index fe4eea48a4..bd8a2f5b53 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -197,7 +197,7 @@ HighlightedEntity.updateOverlays = function updateHighlightedEntities() { }); }; -/* this contains current gain for a given node (by session id). More efficient than +/* this contains current gain for a given node (by session id). More efficient than * querying it, plus there isn't a getGain function so why write one */ var sessionGains = {}; function convertDbToLinear(decibels) { @@ -205,7 +205,7 @@ function convertDbToLinear(decibels) { // but, your perception is that something 2x as loud is +10db // so we go from -60 to +20 or 1/64x to 4x. For now, we can // maybe scale the signal this way?? - return Math.pow(2, decibels/10.0); + return Math.pow(2, decibels/10.0); } function fromQml(message) { // messages are {method, params}, like json-rpc. See also sendToQml. @@ -571,10 +571,10 @@ function receiveMessage(channel, messageString, senderID) { } var AVERAGING_RATIO = 0.05; -var LONG_AVERAGING_RATIO = 0.75; var LOUDNESS_FLOOR = 11.0; var LOUDNESS_SCALE = 2.8 / 5.0; var LOG2 = Math.log(2.0); +var AUDIO_PEAK_DECAY = 0.03; var myData = {}; // we're not includied in ExtendedOverlay.get. function scaleAudio(val) { @@ -602,16 +602,19 @@ function getAudioLevel(id) { // we will do exponential moving average by taking some the last loudness and averaging data.accumulatedLevel = AVERAGING_RATIO * (data.accumulatedLevel || 0) + (1 - AVERAGING_RATIO) * (avatar.audioLoudness); - data.longAccumulatedLevel = LONG_AVERAGING_RATIO * (data.longAccumulatedLevel || 0) + (1 - LONG_AVERAGING_RATIO) * (avatar.audioLoudness); // add 1 to insure we don't go log() and hit -infinity. Math.log is // natural log, so to get log base 2, just divide by ln(2). audioLevel = scaleAudio(Math.log(data.accumulatedLevel + 1) / LOG2); - avgAudioLevel = scaleAudio(Math.log(data.longAccumulatedLevel + 1) / LOG2); - // scale avgAudioLevel given that there can be a gain (4x to 1/64x) - avgAudioLevel = Math.min(1.0, avgAudioLevel *(sessionGains[id] || 0.75)); + + // decay avgAudioLevel + avgAudioLevel = Math.max((1-AUDIO_PEAK_DECAY) * (data.avgAudioLevel || 0), audioLevel); + data.avgAudioLevel = avgAudioLevel; data.audioLevel = audioLevel; + + // now scale for the gain + avgAudioLevel = Math.min(1.0, avgAudioLevel *(sessionGains[id] || 0.75)); } return [audioLevel, avgAudioLevel]; } From d6f0d8c96051179741f61b8f5bfae65cce4122be Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 24 Feb 2017 11:45:03 -0800 Subject: [PATCH 05/35] styling changes, first pass --- interface/resources/qml/hifi/Pal.qml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 4735ae9312..91889fcf91 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -30,7 +30,7 @@ Rectangle { property int myCardHeight: 90 property int rowHeight: 70 property int actionButtonWidth: 55 - property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 5 : 3) - 4 - hifi.dimensions.scrollbarBackgroundWidth + property int nameCardWidth: palContainer.width - actionButtonWidth*(iAmAdmin ? 4.5 : 2.5) - 4 - hifi.dimensions.scrollbarBackgroundWidth property var myData: ({displayName: "", userName: "", audioLevel: 0.0, avgAudioLevel: 0.0, admin: true}) // valid dummy until set property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities. @@ -167,7 +167,7 @@ Rectangle { TableViewColumn { role: "avgAudioLevel" title: "VOL" - width: actionButtonWidth + width: actionButtonWidth/2 movable: false resizable: false } @@ -397,7 +397,7 @@ Rectangle { anchors.left: table.left anchors.top: table.top anchors.topMargin: 1 - anchors.leftMargin: nameCardWidth/2 + displayNameHeaderMetrics.width/2 + 6 + anchors.leftMargin: actionButtonWidth/2 + nameCardWidth/2 + displayNameHeaderMetrics.width/2 + 6 RalewayRegular { id: helpText text: "[?]" From 0c84ddc50364aa42a24ca3f599be24ba81151dcf Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 11:33:10 -0800 Subject: [PATCH 06/35] fix indentation --- .../entities/src/EntityScriptingInterface.cpp | 98 +++++++++---------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index cd7f1235bb..fa1b53e324 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -285,7 +285,7 @@ EntityItemProperties EntityScriptingInterface::getEntityProperties(QUuid identit desiredProperties = entity->getEntityProperties(params); desiredProperties.setHasProperty(PROP_LOCAL_POSITION); desiredProperties.setHasProperty(PROP_LOCAL_ROTATION); - } + } results = entity->getProperties(desiredProperties); @@ -825,7 +825,7 @@ bool EntityScriptingInterface::setVoxels(QUuid entityID, EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::setVoxelSphere no entity with ID" << entityID; + qCDebug(entities) << "EntityScriptingInterface::setVoxels no entity with ID" << entityID; return false; } @@ -887,24 +887,24 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c PROFILE_RANGE(script_entities, __FUNCTION__); return setVoxels(entityID, [center, radius, value](PolyVoxEntityItem& polyVoxEntity) { - return polyVoxEntity.setSphere(center, radius, value); - }); + return polyVoxEntity.setSphere(center, radius, value); + }); } bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) { PROFILE_RANGE(script_entities, __FUNCTION__); return setVoxels(entityID, [position, value](PolyVoxEntityItem& polyVoxEntity) { - return polyVoxEntity.setVoxelInVolume(position, value); - }); + return polyVoxEntity.setVoxelInVolume(position, value); + }); } bool EntityScriptingInterface::setAllVoxels(QUuid entityID, int value) { PROFILE_RANGE(script_entities, __FUNCTION__); return setVoxels(entityID, [value](PolyVoxEntityItem& polyVoxEntity) { - return polyVoxEntity.setAll(value); - }); + return polyVoxEntity.setAll(value); + }); } bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, @@ -912,8 +912,8 @@ bool EntityScriptingInterface::setVoxelsInCuboid(QUuid entityID, const glm::vec3 PROFILE_RANGE(script_entities, __FUNCTION__); return setVoxels(entityID, [lowPosition, cuboidSize, value](PolyVoxEntityItem& polyVoxEntity) { - return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value); - }); + return polyVoxEntity.setCuboid(lowPosition, cuboidSize, value); + }); } bool EntityScriptingInterface::setAllPoints(QUuid entityID, const QVector& points) { @@ -1020,25 +1020,25 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, auto actionFactory = DependencyManager::get(); bool success = false; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - // create this action even if the entity doesn't have physics info. it will often be the - // case that a script adds an action immediately after an object is created, and the physicsInfo - // is computed asynchronously. - // if (!entity->getPhysicsInfo()) { - // return false; - // } - EntityActionType actionType = EntityActionInterface::actionTypeFromString(actionTypeString); - if (actionType == ACTION_TYPE_NONE) { - return false; - } - EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments); - if (!action) { - return false; - } - action->setIsMine(true); - success = entity->addAction(simulation, action); - entity->grabSimulationOwnership(); - return false; // Physics will cause a packet to be sent, so don't send from here. - }); + // create this action even if the entity doesn't have physics info. it will often be the + // case that a script adds an action immediately after an object is created, and the physicsInfo + // is computed asynchronously. + // if (!entity->getPhysicsInfo()) { + // return false; + // } + EntityActionType actionType = EntityActionInterface::actionTypeFromString(actionTypeString); + if (actionType == ACTION_TYPE_NONE) { + return false; + } + EntityActionPointer action = actionFactory->factory(actionType, actionID, entity, arguments); + if (!action) { + return false; + } + action->setIsMine(true); + success = entity->addAction(simulation, action); + entity->grabSimulationOwnership(); + return false; // Physics will cause a packet to be sent, so don't send from here. + }); if (success) { return actionID; } @@ -1050,12 +1050,12 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& PROFILE_RANGE(script_entities, __FUNCTION__); return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - bool success = entity->updateAction(simulation, actionID, arguments); - if (success) { - entity->grabSimulationOwnership(); - } - return success; - }); + bool success = entity->updateAction(simulation, actionID, arguments); + if (success) { + entity->grabSimulationOwnership(); + } + return success; + }); } bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& actionID) { @@ -1063,13 +1063,13 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& bool success = false; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - success = entity->removeAction(simulation, actionID); - if (success) { - // reduce from grab to poke - entity->pokeSimulationOwnership(); - } - return false; // Physics will cause a packet to be sent, so don't send from here. - }); + success = entity->removeAction(simulation, actionID); + if (success) { + // reduce from grab to poke + entity->pokeSimulationOwnership(); + } + return false; // Physics will cause a packet to be sent, so don't send from here. + }); return success; } @@ -1078,10 +1078,10 @@ QVector EntityScriptingInterface::getActionIDs(const QUuid& entityID) { QVector result; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - QList actionIDs = entity->getActionIDs(); - result = QVector::fromList(actionIDs); - return false; // don't send an edit packet - }); + QList actionIDs = entity->getActionIDs(); + result = QVector::fromList(actionIDs); + return false; // don't send an edit packet + }); return result; } @@ -1090,9 +1090,9 @@ QVariantMap EntityScriptingInterface::getActionArguments(const QUuid& entityID, QVariantMap result; actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { - result = entity->getActionArguments(actionID); - return false; // don't send an edit packet - }); + result = entity->getActionArguments(actionID); + return false; // don't send an edit packet + }); return result; } From 76c873ce81ef1865b49e44257c43eb3d54149c4c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 11:34:48 -0800 Subject: [PATCH 07/35] don't compute polyvox shapes if they are collisionless --- .../src/RenderablePolyVoxEntityItem.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 7646f0a454..5fe2844176 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -501,6 +501,9 @@ PolyVox::RaycastResult RenderablePolyVoxEntityItem::doRayCast(glm::vec4 originIn // virtual ShapeType RenderablePolyVoxEntityItem::getShapeType() const { + if (_collisionless) { + return SHAPE_TYPE_NONE; + } return SHAPE_TYPE_COMPOUND; } @@ -512,6 +515,11 @@ void RenderablePolyVoxEntityItem::updateRegistrationPoint(const glm::vec3& value } bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { + ShapeType shapeType = getShapeType(); + if (shapeType == SHAPE_TYPE_NONE) { + return true; + } + // we determine if we are ready to compute the physics shape by actually doing so. // if _voxelDataDirty or _volDataDirty is set, don't do this yet -- wait for their // threads to finish before creating the collision shape. @@ -524,6 +532,12 @@ bool RenderablePolyVoxEntityItem::isReadyToComputeShape() { } void RenderablePolyVoxEntityItem::computeShapeInfo(ShapeInfo& info) { + ShapeType shapeType = getShapeType(); + if (shapeType == SHAPE_TYPE_NONE) { + info.setParams(getShapeType(), 0.5f * getDimensions()); + return; + } + // the shape was actually computed in isReadyToComputeShape. Just hand it off, here. withWriteLock([&] { info = _shapeInfo; @@ -736,7 +750,7 @@ glm::vec3 RenderablePolyVoxEntityItem::localCoordsToVoxelCoords(glm::vec3& local void RenderablePolyVoxEntityItem::setVoxelVolumeSize(glm::vec3 voxelVolumeSize) { // This controls how many individual voxels are in the entity. This is unrelated to - // the dimentions of the entity -- it defines the size of the arrays that hold voxel values. + // the dimentions of the entity -- it defines the sizes of the arrays that hold voxel values. // In addition to setting the number of voxels, this is used in a few places for its // side-effect of allocating _volData to be the correct size. withWriteLock([&] { From 0e4b0332dd7f6a6833f92a1bb0ec93bfde211d18 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 11:35:27 -0800 Subject: [PATCH 08/35] avoid a rare crash --- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4f4f3bf67f..55a7221f5d 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -944,7 +944,10 @@ void EntityTreeRenderer::entityScriptChanging(const EntityItemID& entityID, cons void EntityTreeRenderer::checkAndCallPreload(const EntityItemID& entityID, const bool reload, const bool unloadFirst) { if (_tree && !_shuttingDown) { EntityItemPointer entity = getTree()->findEntityByEntityItemID(entityID); - bool shouldLoad = entity && entity->shouldPreloadScript() && _entitiesScriptEngine; + if (!entity) { + return; + } + bool shouldLoad = entity->shouldPreloadScript() && _entitiesScriptEngine; QString scriptUrl = entity->getScript(); if ((unloadFirst && shouldLoad) || scriptUrl.isEmpty()) { _entitiesScriptEngine->unloadEntityScript(entityID); From 1e81edbaea7199e3d1cc6ac22167152f3fd4ba45 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 15:32:08 -0800 Subject: [PATCH 09/35] make a copy of volData before computing the visual mesh --- .../src/RenderablePolyVoxEntityItem.cpp | 67 +++++++++++-------- 1 file changed, 40 insertions(+), 27 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5fe2844176..340f8f7d4b 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef _WIN32 #pragma warning(pop) #endif @@ -1128,36 +1129,48 @@ void RenderablePolyVoxEntityItem::getMesh() { // A mesh object to hold the result of surface extraction PolyVox::SurfaceMesh polyVoxMesh; + PolyVox::SimpleVolume* volData = nullptr; + entity->withReadLock([&] { - PolyVox::SimpleVolume* volData = entity->getVolData(); - switch (voxelSurfaceStyle) { - case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: { - PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { - PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: { - PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_CUBIC: { - PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - } + PolyVox::SimpleVolume* entityVolData = entity->getVolData(); + PolyVox::Region region = entityVolData->getEnclosingRegion(); + volData = new PolyVox::SimpleVolume(region); + volData->setBorderValue(255); + PolyVox::VolumeResampler, + PolyVox::SimpleVolume> copier = + PolyVox::VolumeResampler, + PolyVox::SimpleVolume>(entityVolData, region, volData, region); + copier.execute(); }); + switch (voxelSurfaceStyle) { + case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: { + PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { + PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: { + PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_CUBIC: { + PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + } + delete volData; + // convert PolyVox mesh to a Sam mesh const std::vector& vecIndices = polyVoxMesh.getIndices(); auto indexBuffer = std::make_shared(vecIndices.size() * sizeof(uint32_t), From 7a31a99e3c488c62665679d1adff26e3928594e7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 21:13:20 -0800 Subject: [PATCH 10/35] back out previous experiment --- .../src/RenderablePolyVoxEntityItem.cpp | 67 ++++++++----------- plugins/openvr/src/OpenVrDisplayPlugin.cpp | 2 +- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 340f8f7d4b..5fe2844176 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #ifdef _WIN32 #pragma warning(pop) #endif @@ -1129,48 +1128,36 @@ void RenderablePolyVoxEntityItem::getMesh() { // A mesh object to hold the result of surface extraction PolyVox::SurfaceMesh polyVoxMesh; - PolyVox::SimpleVolume* volData = nullptr; - entity->withReadLock([&] { - PolyVox::SimpleVolume* entityVolData = entity->getVolData(); - PolyVox::Region region = entityVolData->getEnclosingRegion(); - volData = new PolyVox::SimpleVolume(region); - volData->setBorderValue(255); - PolyVox::VolumeResampler, - PolyVox::SimpleVolume> copier = - PolyVox::VolumeResampler, - PolyVox::SimpleVolume>(entityVolData, region, volData, region); - copier.execute(); + PolyVox::SimpleVolume* volData = entity->getVolData(); + switch (voxelSurfaceStyle) { + case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: { + PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { + PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: { + PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + case PolyVoxEntityItem::SURFACE_CUBIC: { + PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor + (volData, volData->getEnclosingRegion(), &polyVoxMesh); + surfaceExtractor.execute(); + break; + } + } }); - switch (voxelSurfaceStyle) { - case PolyVoxEntityItem::SURFACE_EDGED_MARCHING_CUBES: { - PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_MARCHING_CUBES: { - PolyVox::MarchingCubesSurfaceExtractor> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_EDGED_CUBIC: { - PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - case PolyVoxEntityItem::SURFACE_CUBIC: { - PolyVox::CubicSurfaceExtractorWithNormals> surfaceExtractor - (volData, volData->getEnclosingRegion(), &polyVoxMesh); - surfaceExtractor.execute(); - break; - } - } - delete volData; - // convert PolyVox mesh to a Sam mesh const std::vector& vecIndices = polyVoxMesh.getIndices(); auto indexBuffer = std::make_shared(vecIndices.size() * sizeof(uint32_t), diff --git a/plugins/openvr/src/OpenVrDisplayPlugin.cpp b/plugins/openvr/src/OpenVrDisplayPlugin.cpp index 42f3ece9cd..6d503a208a 100644 --- a/plugins/openvr/src/OpenVrDisplayPlugin.cpp +++ b/plugins/openvr/src/OpenVrDisplayPlugin.cpp @@ -545,7 +545,7 @@ bool OpenVrDisplayPlugin::beginFrameRender(uint32_t frameIndex) { // HACK: when interface is launched and steam vr is NOT running, openvr will return bad HMD poses for a few frames // To workaround this, filter out any hmd poses that are obviously bad, i.e. beneath the floor. if (isBadPose(&nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking)) { - qDebug() << "WARNING: ignoring bad hmd pose from openvr"; + // qDebug() << "WARNING: ignoring bad hmd pose from openvr"; // use the last known good HMD pose nextSimPoseData.vrPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking = _lastGoodHMDPose; From 422b0bb952df78b51a59166e66ef3ef2f52d4a8e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sat, 25 Feb 2017 21:14:13 -0800 Subject: [PATCH 11/35] don't set _dirtyFlags if polyvox is collisionless --- .../entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 5fe2844176..47ef598502 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -1188,7 +1188,9 @@ void RenderablePolyVoxEntityItem::setMesh(model::MeshPointer mesh) { // this catches the payload from getMesh bool neighborsNeedUpdate; withWriteLock([&] { - _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; + if (!_collisionless) { + _dirtyFlags |= Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS; + } _mesh = mesh; _meshDirty = true; _meshInitialized = true; From 6227db9fc0032c2cf6e29610bd46f6d562daf99a Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 26 Feb 2017 08:30:29 -0800 Subject: [PATCH 12/35] optimize RenderablePolyVoxEntityItem::setSphere --- .../src/RenderablePolyVoxEntityItem.cpp | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 47ef598502..3ea58f7550 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -365,12 +365,28 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r } glm::mat4 vtwMatrix = voxelToWorldMatrix(); + glm::mat4 wtvMatrix = glm::inverse(vtwMatrix); - // This three-level for loop iterates over every voxel in the volume + glm::vec3 dimensions = getDimensions(); + glm::vec3 voxelSize = dimensions / _voxelVolumeSize; + float smallestDimensionSize = voxelSize.x; + smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y); + smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.z); + + glm::vec3 maxRadiusInVoxelCoords = glm::vec3(radiusWorldCoords / smallestDimensionSize); + glm::vec3 centerInVoxelCoords = wtvMatrix * glm::vec4(centerWorldCoords, 1.0f); + + glm::vec3 low = glm::floor(centerInVoxelCoords - maxRadiusInVoxelCoords); + glm::vec3 high = glm::ceil(centerInVoxelCoords + maxRadiusInVoxelCoords); + + glm::ivec3 lowI = glm::clamp(low, glm::vec3(0.0f), _voxelVolumeSize); + glm::ivec3 highI = glm::clamp(high, glm::vec3(0.0f), _voxelVolumeSize); + + // This three-level for loop iterates over every voxel in the volume that might be in the sphere withWriteLock([&] { - for (int z = 0; z < _voxelVolumeSize.z; z++) { - for (int y = 0; y < _voxelVolumeSize.y; y++) { - for (int x = 0; x < _voxelVolumeSize.x; x++) { + for (int z = lowI.z; z < highI.z; z++) { + for (int y = lowI.y; y < highI.y; y++) { + for (int x = lowI.x; x < highI.x; x++) { // Store our current position as a vector... glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates // convert to world coordinates From 542cb7ab85aa61558fa50b0feb130f56a11b4842 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 26 Feb 2017 09:03:34 -0800 Subject: [PATCH 13/35] optimize RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket --- .../src/RenderablePolyVoxEntityItem.cpp | 42 ++++++++++++++----- .../src/RenderablePolyVoxEntityItem.h | 3 +- 2 files changed, 33 insertions(+), 12 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index 3ea58f7550..d3023c573a 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -266,6 +266,35 @@ void RenderablePolyVoxEntityItem::forEachVoxelValue(quint16 voxelXSize, quint16 }); } +QByteArray RenderablePolyVoxEntityItem::volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const { + int totalSize = voxelXSize * voxelYSize * voxelZSize; + QByteArray result = QByteArray(totalSize, '\0'); + int index = 0; + int lowX = 0; + int lowY = 0; + int lowZ = 0; + + withReadLock([&] { + if (isEdged(_voxelSurfaceStyle)) { + lowX++; + lowY++; + lowZ++; + voxelXSize++; + voxelYSize++; + voxelYSize++; + } + + for (int z = lowZ; z < voxelZSize; z++) { + for (int y = lowY; y < voxelYSize; y++) { + for (int x = lowX; x < voxelXSize; x++) { + result[index++] = _volData->getVoxelAt(x, y, z); + } + } + } + }); + + return result; +} bool RenderablePolyVoxEntityItem::setAll(uint8_t toValue) { bool result = false; @@ -837,7 +866,7 @@ uint8_t RenderablePolyVoxEntityItem::getVoxel(int x, int y, int z) { } -uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(int x, int y, int z) { +uint8_t RenderablePolyVoxEntityItem::getVoxelInternal(int x, int y, int z) const { if (!inUserBounds(_volData, _voxelSurfaceStyle, x, y, z)) { return 0; } @@ -979,17 +1008,8 @@ void RenderablePolyVoxEntityItem::compressVolumeDataAndSendEditPacket() { EntityTreePointer tree = element ? element->getTree() : nullptr; QtConcurrent::run([voxelXSize, voxelYSize, voxelZSize, entity, tree] { - int rawSize = voxelXSize * voxelYSize * voxelZSize; - QByteArray uncompressedData = QByteArray(rawSize, '\0'); - auto polyVoxEntity = std::static_pointer_cast(entity); - polyVoxEntity->forEachVoxelValue(voxelXSize, voxelYSize, voxelZSize, [&] (int x, int y, int z, uint8_t uVoxelValue) { - int uncompressedIndex = - z * voxelYSize * voxelXSize + - y * voxelXSize + - x; - uncompressedData[uncompressedIndex] = uVoxelValue; - }); + QByteArray uncompressedData = polyVoxEntity->volDataToArray(voxelXSize, voxelYSize, voxelZSize); QByteArray newVoxelData; QDataStream writer(&newVoxelData, QIODevice::WriteOnly | QIODevice::Truncate); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index ee4c3b318f..278f658a46 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -128,12 +128,13 @@ public: void setVoxelsFromData(QByteArray uncompressedData, quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize); void forEachVoxelValue(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize, std::function thunk); + QByteArray volDataToArray(quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize) const; void setMesh(model::MeshPointer mesh); void setCollisionPoints(ShapeInfo::PointCollection points, AABox box); PolyVox::SimpleVolume* getVolData() { return _volData; } - uint8_t getVoxelInternal(int x, int y, int z); + uint8_t getVoxelInternal(int x, int y, int z) const; bool setVoxelInternal(int x, int y, int z, uint8_t toValue); void setVolDataDirty() { withWriteLock([&] { _volDataDirty = true; }); } From 88c850afa233882d2cb68effd43822502707e755 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Sun, 26 Feb 2017 12:56:17 -0800 Subject: [PATCH 14/35] voxel-paint paints with capsules rather than spheres --- .../src/RenderablePolyVoxEntityItem.cpp | 53 +++++++++++++++++++ .../src/RenderablePolyVoxEntityItem.h | 2 + .../entities/src/EntityScriptingInterface.cpp | 18 +++++++ .../entities/src/EntityScriptingInterface.h | 6 +++ libraries/entities/src/PolyVoxEntityItem.h | 2 + libraries/shared/src/GeometryUtil.cpp | 27 ++++++++++ libraries/shared/src/GeometryUtil.h | 3 ++ 7 files changed, 111 insertions(+) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index d3023c573a..a5b4896d45 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -437,6 +437,59 @@ bool RenderablePolyVoxEntityItem::setSphere(glm::vec3 centerWorldCoords, float r return result; } +bool RenderablePolyVoxEntityItem::setCapsule(glm::vec3 startWorldCoords, glm::vec3 endWorldCoords, + float radiusWorldCoords, uint8_t toValue) { + bool result = false; + if (_locked) { + return result; + } + + glm::mat4 vtwMatrix = voxelToWorldMatrix(); + glm::mat4 wtvMatrix = glm::inverse(vtwMatrix); + + glm::vec3 dimensions = getDimensions(); + glm::vec3 voxelSize = dimensions / _voxelVolumeSize; + float smallestDimensionSize = voxelSize.x; + smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.y); + smallestDimensionSize = glm::min(smallestDimensionSize, voxelSize.z); + + glm::vec3 maxRadiusInVoxelCoords = glm::vec3(radiusWorldCoords / smallestDimensionSize); + + glm::vec3 startInVoxelCoords = wtvMatrix * glm::vec4(startWorldCoords, 1.0f); + glm::vec3 endInVoxelCoords = wtvMatrix * glm::vec4(endWorldCoords, 1.0f); + + glm::vec3 low = glm::min(glm::floor(startInVoxelCoords - maxRadiusInVoxelCoords), + glm::floor(endInVoxelCoords - maxRadiusInVoxelCoords)); + glm::vec3 high = glm::max(glm::ceil(startInVoxelCoords + maxRadiusInVoxelCoords), + glm::ceil(endInVoxelCoords + maxRadiusInVoxelCoords)); + + glm::ivec3 lowI = glm::clamp(low, glm::vec3(0.0f), _voxelVolumeSize); + glm::ivec3 highI = glm::clamp(high, glm::vec3(0.0f), _voxelVolumeSize); + + // This three-level for loop iterates over every voxel in the volume that might be in the capsule + withWriteLock([&] { + for (int z = lowI.z; z < highI.z; z++) { + for (int y = lowI.y; y < highI.y; y++) { + for (int x = lowI.x; x < highI.x; x++) { + // Store our current position as a vector... + glm::vec4 pos(x + 0.5f, y + 0.5f, z + 0.5f, 1.0); // consider voxels cenetered on their coordinates + // convert to world coordinates + glm::vec3 worldPos = glm::vec3(vtwMatrix * pos); + if (pointInCapsule(worldPos, startWorldCoords, endWorldCoords, radiusWorldCoords)) { + result |= setVoxelInternal(x, y, z, toValue); + } + } + } + } + }); + + if (result) { + compressVolumeDataAndSendEditPacket(); + } + return result; +} + + class RaycastFunctor { public: diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index 278f658a46..45842c2fb9 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -94,6 +94,8 @@ public: // coords are in world-space virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) override; + virtual bool setCapsule(glm::vec3 startWorldCoords, glm::vec3 endWorldCoords, + float radiusWorldCoords, uint8_t toValue) override; virtual bool setAll(uint8_t toValue) override; virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int toValue) override; diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index fa1b53e324..eb634568f0 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -891,6 +891,16 @@ bool EntityScriptingInterface::setVoxelSphere(QUuid entityID, const glm::vec3& c }); } +bool EntityScriptingInterface::setVoxelCapsule(QUuid entityID, + const glm::vec3& start, const glm::vec3& end, + float radius, int value) { + PROFILE_RANGE(script_entities, __FUNCTION__); + + return setVoxels(entityID, [start, end, radius, value](PolyVoxEntityItem& polyVoxEntity) { + return polyVoxEntity.setCapsule(start, end, radius, value); + }); +} + bool EntityScriptingInterface::setVoxel(QUuid entityID, const glm::vec3& position, int value) { PROFILE_RANGE(script_entities, __FUNCTION__); @@ -1524,3 +1534,11 @@ QObject* EntityScriptingInterface::getWebViewRoot(const QUuid& entityID) { return nullptr; } } + +// TODO move this someplace that makes more sense... +bool EntityScriptingInterface::AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, + const glm::vec3& start, const glm::vec3& end, float radius) { + glm::vec3 penetration; + AABox aaBox(low, dimensions); + return aaBox.findCapsulePenetration(start, end, radius, penetration); +} diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 0353fa08a8..e9f0637830 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -223,6 +223,8 @@ public slots: Q_INVOKABLE bool getDrawZoneBoundaries() const; Q_INVOKABLE bool setVoxelSphere(QUuid entityID, const glm::vec3& center, float radius, int value); + Q_INVOKABLE bool setVoxelCapsule(QUuid entityID, const glm::vec3& start, const glm::vec3& end, float radius, int value); + Q_INVOKABLE bool setVoxel(QUuid entityID, const glm::vec3& position, int value); Q_INVOKABLE bool setAllVoxels(QUuid entityID, int value); Q_INVOKABLE bool setVoxelsInCuboid(QUuid entityID, const glm::vec3& lowPosition, @@ -287,6 +289,10 @@ public slots: Q_INVOKABLE QObject* getWebViewRoot(const QUuid& entityID); + Q_INVOKABLE bool AABoxIntersectsCapsule(const glm::vec3& low, const glm::vec3& dimensions, + const glm::vec3& start, const glm::vec3& end, float radius); + + signals: void collisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/entities/src/PolyVoxEntityItem.h b/libraries/entities/src/PolyVoxEntityItem.h index 4f478c8bf7..910d8eff88 100644 --- a/libraries/entities/src/PolyVoxEntityItem.h +++ b/libraries/entities/src/PolyVoxEntityItem.h @@ -86,6 +86,8 @@ class PolyVoxEntityItem : public EntityItem { // coords are in world-space virtual bool setSphere(glm::vec3 center, float radius, uint8_t toValue) { return false; } + virtual bool setCapsule(glm::vec3 startWorldCoords, glm::vec3 endWorldCoords, + float radiusWorldCoords, uint8_t toValue) { return false; } virtual bool setAll(uint8_t toValue) { return false; } virtual bool setCuboid(const glm::vec3& lowPosition, const glm::vec3& cuboidSize, int value) { return false; } diff --git a/libraries/shared/src/GeometryUtil.cpp b/libraries/shared/src/GeometryUtil.cpp index 92fe138021..c137ebd438 100644 --- a/libraries/shared/src/GeometryUtil.cpp +++ b/libraries/shared/src/GeometryUtil.cpp @@ -205,6 +205,33 @@ bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& directi return true; } +bool pointInSphere(const glm::vec3& origin, const glm::vec3& center, float radius) { + glm::vec3 relativeOrigin = origin - center; + float c = glm::dot(relativeOrigin, relativeOrigin) - radius * radius; + return c <= 0.0f; +} + + +bool pointInCapsule(const glm::vec3& origin, const glm::vec3& start, const glm::vec3& end, float radius) { + glm::vec3 relativeOrigin = origin - start; + glm::vec3 relativeEnd = end - start; + float capsuleLength = glm::length(relativeEnd); + relativeEnd /= capsuleLength; + float originProjection = glm::dot(relativeEnd, relativeOrigin); + glm::vec3 constant = relativeOrigin - relativeEnd * originProjection; + float c = glm::dot(constant, constant) - radius * radius; + if (c < 0.0f) { // starts inside cylinder + if (originProjection < 0.0f) { // below start + return pointInSphere(origin, start, radius); + } else if (originProjection > capsuleLength) { // above end + return pointInSphere(origin, end, radius); + } else { // between start and end + return true; + } + } + return false; +} + bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& start, const glm::vec3& end, float radius, float& distance) { if (start == end) { diff --git a/libraries/shared/src/GeometryUtil.h b/libraries/shared/src/GeometryUtil.h index 1c951ca09a..2fdc1aa25f 100644 --- a/libraries/shared/src/GeometryUtil.h +++ b/libraries/shared/src/GeometryUtil.h @@ -73,6 +73,9 @@ glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& bool findRaySphereIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& center, float radius, float& distance); +bool pointInSphere(const glm::vec3& origin, const glm::vec3& center, float radius); +bool pointInCapsule(const glm::vec3& origin, const glm::vec3& start, const glm::vec3& end, float radius); + bool findRayCapsuleIntersection(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& start, const glm::vec3& end, float radius, float& distance); From 2ceb3d85bd6481179f3c14270169f6013fdf13c4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 24 Feb 2017 16:03:22 -0800 Subject: [PATCH 15/35] increase max renderable web entity FPS to 30 --- libraries/entities-renderer/src/RenderableWebEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 972c23d534..8c30c01e50 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -113,7 +113,7 @@ bool RenderableWebEntityItem::buildWebSurface(QSharedPointer // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // and the current rendering load) - _webSurface->setMaxFps(10); + _webSurface->setMaxFps(30); // The lifetime of the QML surface MUST be managed by the main thread // Additionally, we MUST use local variables copied by value, rather than From d18936ea1864063ede40cb8cae4c9a66caa8b038 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Feb 2017 09:43:02 -0800 Subject: [PATCH 16/35] only force youtube web entities to 30 FPS --- .../entities-renderer/src/RenderableWebEntityItem.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 8c30c01e50..7cd1b62e3b 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -113,7 +113,14 @@ bool RenderableWebEntityItem::buildWebSurface(QSharedPointer // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // and the current rendering load) - _webSurface->setMaxFps(30); + + // We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS. + if (QUrl(_sourceUrl).host().endsWith("youtube.com", Qt::CaseInsensitive)) { + _webSurface->setMaxFps(30); + } else { + _webSurface->setMaxFps(10); + } + // The lifetime of the QML surface MUST be managed by the main thread // Additionally, we MUST use local variables copied by value, rather than From 80af749b6949cbd66ba9309cce51019d611457d7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 27 Feb 2017 11:09:17 -0800 Subject: [PATCH 17/35] change max FPS for youtube on URL change --- .../src/RenderableWebEntityItem.cpp | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 7cd1b62e3b..6c44794c3e 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -37,6 +37,8 @@ static uint64_t MAX_NO_RENDER_INTERVAL = 30 * USECS_PER_SECOND; static int MAX_WINDOW_SIZE = 4096; static float OPAQUE_ALPHA_THRESHOLD = 0.99f; +static int DEFAULT_MAX_FPS = 10; +static int YOUTUBE_MAX_FPS = 30; EntityItemPointer RenderableWebEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { EntityItemPointer entity{ new RenderableWebEntityItem(entityID) }; @@ -113,14 +115,7 @@ bool RenderableWebEntityItem::buildWebSurface(QSharedPointer // FIXME, the max FPS could be better managed by being dynamic (based on the number of current surfaces // and the current rendering load) - - // We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS. - if (QUrl(_sourceUrl).host().endsWith("youtube.com", Qt::CaseInsensitive)) { - _webSurface->setMaxFps(30); - } else { - _webSurface->setMaxFps(10); - } - + _webSurface->setMaxFps(DEFAULT_MAX_FPS); // The lifetime of the QML surface MUST be managed by the main thread // Additionally, we MUST use local variables copied by value, rather than @@ -263,12 +258,22 @@ void RenderableWebEntityItem::loadSourceURL() { _sourceUrl.toLower().endsWith(".htm") || _sourceUrl.toLower().endsWith(".html")) { _contentType = htmlContent; _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "qml/controls/")); + + // We special case YouTube URLs since we know they are videos that we should play with at least 30 FPS. + if (sourceUrl.host().endsWith("youtube.com", Qt::CaseInsensitive)) { + _webSurface->setMaxFps(YOUTUBE_MAX_FPS); + } else { + _webSurface->setMaxFps(DEFAULT_MAX_FPS); + } + _webSurface->load("WebView.qml", [&](QQmlContext* context, QObject* obj) { context->setContextProperty("eventBridgeJavaScriptToInject", QVariant(_javaScriptToInject)); }); _webSurface->getRootItem()->setProperty("url", _sourceUrl); _webSurface->getRootContext()->setContextProperty("desktop", QVariant()); + + } else { _contentType = qmlContent; _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath())); From e7c8085bc8ff5c796a73502289a8e4d7473a4817 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 27 Feb 2017 12:44:23 -0700 Subject: [PATCH 18/35] switch to using glyph button --- .../images/Audio-Loudness-Icons/vol-0.svg | 12 ------- .../images/Audio-Loudness-Icons/vol-1.svg | 13 ------- .../images/Audio-Loudness-Icons/vol-2.svg | 16 --------- .../images/Audio-Loudness-Icons/vol-3.svg | 19 ---------- .../images/Audio-Loudness-Icons/vol-4.svg | 21 ----------- interface/resources/qml/hifi/Pal.qml | 36 ++++++------------- .../qml/styles-uit/HifiConstants.qml | 10 ++++++ 7 files changed, 20 insertions(+), 107 deletions(-) delete mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-0.svg delete mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-1.svg delete mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-2.svg delete mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-3.svg delete mode 100755 interface/resources/images/Audio-Loudness-Icons/vol-4.svg diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-0.svg b/interface/resources/images/Audio-Loudness-Icons/vol-0.svg deleted file mode 100755 index 72f247c238..0000000000 --- a/interface/resources/images/Audio-Loudness-Icons/vol-0.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-1.svg b/interface/resources/images/Audio-Loudness-Icons/vol-1.svg deleted file mode 100755 index 9570b9ae6c..0000000000 --- a/interface/resources/images/Audio-Loudness-Icons/vol-1.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-2.svg b/interface/resources/images/Audio-Loudness-Icons/vol-2.svg deleted file mode 100755 index a2175be39e..0000000000 --- a/interface/resources/images/Audio-Loudness-Icons/vol-2.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-3.svg b/interface/resources/images/Audio-Loudness-Icons/vol-3.svg deleted file mode 100755 index 21b1095941..0000000000 --- a/interface/resources/images/Audio-Loudness-Icons/vol-3.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - diff --git a/interface/resources/images/Audio-Loudness-Icons/vol-4.svg b/interface/resources/images/Audio-Loudness-Icons/vol-4.svg deleted file mode 100755 index de0b4027eb..0000000000 --- a/interface/resources/images/Audio-Loudness-Icons/vol-4.svg +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index a7651e24d9..1db83a0223 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -214,13 +214,6 @@ Rectangle { movable: false resizable: false } - //TableViewColumn { - // role: "personalMute" - // title: "MUTE" - // width: actionButtonWidth - // movable: false - // resizable: false - //} TableViewColumn { role: "ignore" title: "IGNORE" @@ -283,12 +276,19 @@ Rectangle { // Anchors anchors.left: parent.left } - HifiControls.Button { + HifiControls.GlyphButton { + function getGlyph() { + var fileName = "vol_"; + if (model["personalMute"]) { + fileName += "x_"; + } + fileName += (4.0*(model ? model.avgAudioLevel : 0.0)).toFixed(0); + return hifi.glyphs[fileName]; + } id: avgAudioVolume visible: isAvgAudio + glyph: getGlyph() width: 32 - height: 32 - iconSource: getImage() anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter onClicked: { @@ -298,22 +298,6 @@ Rectangle { Users["personalMute"](model.sessionId, newValue) UserActivityLogger["palAction"](newValue ? "personalMute" : "un-personalMute", model.sessionId) } - HiFiGlyphs { - function getGlyph() { - var fileName = "vol-"; - if (model["personalMute"]) { - fileName += "x-"; - } - fileName += (4.0*(model ? model.avgAudioLevel : 0.0)).toFixed(0); - return hifi.glyphs[fileName]; - } - text: getGlyph() - size: parent.height*1.3 - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - color: enabled ? hifi.buttons.textColor[actionButton.color] - : hifi.buttons.disabledTextColor[actionButton.colorScheme] - } } // This CheckBox belongs in the columns that contain the stateful action buttons ("Mute" & "Ignore" for now) // KNOWN BUG with the Checkboxes: When clicking in the center of the sorting header, the checkbox diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/styles-uit/HifiConstants.qml index e261e2198f..031e80283e 100644 --- a/interface/resources/qml/styles-uit/HifiConstants.qml +++ b/interface/resources/qml/styles-uit/HifiConstants.qml @@ -318,5 +318,15 @@ Item { readonly property string deg: "\\" readonly property string px: "|" readonly property string editPencil: "\ue00d" + readonly property string vol_0: "\ue00e" + readonly property string vol_1: "\ue00f" + readonly property string vol_2: "\ue010" + readonly property string vol_3: "\ue011" + readonly property string vol_4: "\ue012" + readonly property string vol_x_0: "\ue013" + readonly property string vol_x_1: "\ue014" + readonly property string vol_x_2: "\ue015" + readonly property string vol_x_3: "\ue016" + readonly property string vol_x_4: "\ue017" } } From 3bf3f16a6ab53576d2d11d6dae901a8d0918e144 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 27 Feb 2017 12:56:03 -0700 Subject: [PATCH 19/35] whitespace --- interface/resources/qml/hifi/Pal.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 1db83a0223..f8b2f6ed25 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -32,7 +32,7 @@ Rectangle { property int rowHeight: 70 property int actionButtonWidth: 55 property int actionButtonAllowance: actionButtonWidth * 2 - property int minNameCardWidth: palContainer.width - (actionButtonAllowance * 2 ) - 4 - hifi.dimensions.scrollbarBackgroundWidth + property int minNameCardWidth: palContainer.width - (actionButtonAllowance * 2) - 4 - hifi.dimensions.scrollbarBackgroundWidth property int nameCardWidth: minNameCardWidth + (iAmAdmin ? 0 : actionButtonAllowance) property var myData: ({displayName: "", userName: "", audioLevel: 0.0, avgAudioLevel: 0.0, admin: true}) // valid dummy until set property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. From c04fd0ec66d31d6a0476be57d81cdc8fbc59e358 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Mon, 27 Feb 2017 16:07:05 -0800 Subject: [PATCH 20/35] smaller glyph size --- interface/resources/qml/hifi/Pal.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index f8b2f6ed25..99700bc0f2 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -289,6 +289,7 @@ Rectangle { visible: isAvgAudio glyph: getGlyph() width: 32 + size: height anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter onClicked: { From 6b230bad1453b025c2438cebcea875580187f8d0 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Mon, 27 Feb 2017 20:56:25 -0800 Subject: [PATCH 21/35] oops --- libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index a5b4896d45..7359a548fc 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -281,7 +281,7 @@ QByteArray RenderablePolyVoxEntityItem::volDataToArray(quint16 voxelXSize, quint lowZ++; voxelXSize++; voxelYSize++; - voxelYSize++; + voxelZSize++; } for (int z = lowZ; z < voxelZSize; z++) { From 1fc57ce9a68a40de030890c7e2aefb73b3de5375 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 28 Feb 2017 11:51:40 -0700 Subject: [PATCH 22/35] alan's feedback --- scripts/system/pal.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/system/pal.js b/scripts/system/pal.js index a609de43a1..67aa94a2f7 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -634,7 +634,7 @@ var AVERAGING_RATIO = 0.05; var LOUDNESS_FLOOR = 11.0; var LOUDNESS_SCALE = 2.8 / 5.0; var LOG2 = Math.log(2.0); -var AUDIO_PEAK_DECAY = 0.03; +var AUDIO_PEAK_DECAY = 0.02; var myData = {}; // we're not includied in ExtendedOverlay.get. function scaleAudio(val) { @@ -673,8 +673,9 @@ function getAudioLevel(id) { data.avgAudioLevel = avgAudioLevel; data.audioLevel = audioLevel; - // now scale for the gain - avgAudioLevel = Math.min(1.0, avgAudioLevel *(sessionGains[id] || 0.75)); + // now scale for the gain. Also, asked to boost the low end, so one simple way is + // to take sqrt of the value. Lets try that, see how it feels. + avgAudioLevel = Math.min(1.0, Math.sqrt(avgAudioLevel *(sessionGains[id] || 0.75))); } return [audioLevel, avgAudioLevel]; } From 8562a294fa0d666f13c26e56b9520924b0782cee Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 28 Feb 2017 13:24:41 -0800 Subject: [PATCH 23/35] cleanup some extra spacing --- libraries/entities-renderer/src/RenderableWebEntityItem.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 6c44794c3e..d7d7013f59 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -269,11 +269,10 @@ void RenderableWebEntityItem::loadSourceURL() { _webSurface->load("WebView.qml", [&](QQmlContext* context, QObject* obj) { context->setContextProperty("eventBridgeJavaScriptToInject", QVariant(_javaScriptToInject)); }); + _webSurface->getRootItem()->setProperty("url", _sourceUrl); _webSurface->getRootContext()->setContextProperty("desktop", QVariant()); - - } else { _contentType = qmlContent; _webSurface->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath())); From c10b0389de7ebe6f50f3d9994164d968b9abd201 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 28 Feb 2017 14:45:34 -0700 Subject: [PATCH 24/35] Add a getAvatarGain method to NodeList and UsersScriptingInterface --- libraries/networking/src/NodeList.cpp | 50 ++++++++++++------- libraries/networking/src/NodeList.h | 13 +++-- .../src/UsersScriptingInterface.cpp | 6 ++- .../src/UsersScriptingInterface.h | 8 +++ 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index f4a02ad805..7bd6800921 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -49,7 +49,7 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) setCustomDeleter([](Dependency* dependency){ static_cast(dependency)->deleteLater(); }); - + auto addressManager = DependencyManager::get(); // handle domain change signals from AddressManager @@ -85,8 +85,8 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) connect(&_domainHandler, &DomainHandler::icePeerSocketsReceived, this, &NodeList::pingPunchForDomainServer); auto accountManager = DependencyManager::get(); - - // assume that we may need to send a new DS check in anytime a new keypair is generated + + // assume that we may need to send a new DS check in anytime a new keypair is generated connect(accountManager.data(), &AccountManager::newKeypair, this, &NodeList::sendDomainServerCheckIn); // clear out NodeList when login is finished @@ -101,7 +101,7 @@ NodeList::NodeList(char newOwnerType, int socketListenPort, int dtlsListenPort) // anytime we get a new node we may need to re-send our set of ignored node IDs to it connect(this, &LimitedNodeList::nodeActivated, this, &NodeList::maybeSendIgnoreSetToNode); - + // setup our timer to send keepalive pings (it's started and stopped on domain connect/disconnect) _keepAlivePingTimer.setInterval(KEEPALIVE_PING_INTERVAL_MS); // 1s, Qt::CoarseTimer acceptable connect(&_keepAlivePingTimer, &QTimer::timeout, this, &NodeList::sendKeepAlivePings); @@ -161,11 +161,11 @@ qint64 NodeList::sendStatsToDomainServer(QJsonObject statsObject) { void NodeList::timePingReply(ReceivedMessage& message, const SharedNodePointer& sendingNode) { PingType_t pingType; - + quint64 ourOriginalTime, othersReplyTime; - + message.seek(0); - + message.readPrimitive(&pingType); message.readPrimitive(&ourOriginalTime); message.readPrimitive(&othersReplyTime); @@ -199,7 +199,7 @@ void NodeList::timePingReply(ReceivedMessage& message, const SharedNodePointer& } void NodeList::processPingPacket(QSharedPointer message, SharedNodePointer sendingNode) { - + // send back a reply auto replyPacket = constructPingReplyPacket(*message); const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); @@ -329,7 +329,7 @@ void NodeList::sendDomainServerCheckIn() { } auto domainPacket = NLPacket::create(domainPacketType); - + QDataStream packetStream(domainPacket.get()); if (domainPacketType == PacketType::DomainConnectRequest) { @@ -488,7 +488,7 @@ void NodeList::processDomainServerPathResponse(QSharedPointer m qCDebug(networking) << "Could not read query path from DomainServerPathQueryResponse. Bailing."; return; } - + QString pathQuery = QString::fromUtf8(message->getRawMessage() + message->getPosition(), numPathBytes); message->seek(message->getPosition() + numPathBytes); @@ -500,10 +500,10 @@ void NodeList::processDomainServerPathResponse(QSharedPointer m qCDebug(networking) << "Could not read resulting viewpoint from DomainServerPathQueryReponse. Bailing"; return; } - + // pull the viewpoint from the packet QString viewpoint = QString::fromUtf8(message->getRawMessage() + message->getPosition(), numViewpointBytes); - + // Hand it off to the AddressManager so it can handle it as a relative viewpoint if (DependencyManager::get()->goToViewpointForPath(viewpoint, pathQuery)) { qCDebug(networking) << "Going to viewpoint" << viewpoint << "which was the lookup result for path" << pathQuery; @@ -664,16 +664,16 @@ void NodeList::parseNodeFromPacketStream(QDataStream& packetStream) { } void NodeList::sendAssignment(Assignment& assignment) { - + PacketType assignmentPacketType = assignment.getCommand() == Assignment::CreateCommand ? PacketType::CreateAssignment : PacketType::RequestAssignment; auto assignmentPacket = NLPacket::create(assignmentPacketType); - + QDataStream packetStream(assignmentPacket.get()); packetStream << assignment; - + sendPacket(std::move(assignmentPacket), _assignmentServerSocket); } @@ -833,7 +833,7 @@ void NodeList::ignoreNodeBySessionID(const QUuid& nodeID, bool ignoreEnabled) { _ignoredNodeIDs.insert(nodeID); } { - QReadLocker personalMutedSetLocker{ &_personalMutedSetLock }; // read lock for insert + QReadLocker personalMutedSetLocker{ &_personalMutedSetLock }; // read lock for insert // add this nodeID to our set of personal muted IDs _personalMutedNodeIDs.insert(nodeID); } @@ -896,7 +896,7 @@ void NodeList::personalMuteNodeBySessionID(const QUuid& nodeID, bool muteEnabled if (muteEnabled) { - QReadLocker personalMutedSetLocker{ &_personalMutedSetLock }; // read lock for insert + QReadLocker personalMutedSetLocker{ &_personalMutedSetLock }; // read lock for insert // add this nodeID to our set of personal muted IDs _personalMutedNodeIDs.insert(nodeID); } else { @@ -981,7 +981,7 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { if (audioMixer) { // setup the packet auto setAvatarGainPacket = NLPacket::create(PacketType::PerAvatarGainSet, NUM_BYTES_RFC4122_UUID + sizeof(float), true); - + // write the node ID to the packet setAvatarGainPacket->write(nodeID.toRfc4122()); // We need to convert the gain in dB (from the script) to an amplitude before packing it. @@ -990,6 +990,9 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { qCDebug(networking) << "Sending Set Avatar Gain packet UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; sendPacket(std::move(setAvatarGainPacket), *audioMixer); + QWriteLocker{ &_avatarGainMapLock }; + _avatarGainMap[nodeID] = gain; + } else { qWarning() << "Couldn't find audio mixer to send set gain request"; } @@ -998,6 +1001,15 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { } } +float NodeList::getAvatarGain(const QUuid& nodeID) { + QReadLocker{ &_avatarGainMapLock }; + auto it = _avatarGainMap.find(nodeID); + if (it != _avatarGainMap.cend()) { + return it->second; + } + return 0.0f; +} + void NodeList::kickNodeBySessionID(const QUuid& nodeID) { // send a request to domain-server to kick the node with the given session ID // the domain-server will handle the persistence of the kick (via username or IP) @@ -1036,7 +1048,7 @@ void NodeList::muteNodeBySessionID(const QUuid& nodeID) { mutePacket->write(nodeID.toRfc4122()); qCDebug(networking) << "Sending packet to mute node" << uuidStringWithoutCurlyBraces(nodeID); - + sendPacket(std::move(mutePacket), *audioMixer); } else { qWarning() << "Couldn't find audio mixer to send node mute request"; diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index 0e0a2fd6c8..293b0942d6 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -68,7 +68,7 @@ public: void setAssignmentServerSocket(const HifiSockAddr& serverSocket) { _assignmentServerSocket = serverSocket; } void sendAssignment(Assignment& assignment); - + void setIsShuttingDown(bool isShuttingDown) { _isShuttingDown = isShuttingDown; } void ignoreNodesInRadius(bool enabled = true); @@ -83,6 +83,7 @@ public: void personalMuteNodeBySessionID(const QUuid& nodeID, bool muteEnabled); bool isPersonalMutingNode(const QUuid& nodeID) const; void setAvatarGain(const QUuid& nodeID, float gain); + float getAvatarGain(const QUuid& nodeID); void kickNodeBySessionID(const QUuid& nodeID); void muteNodeBySessionID(const QUuid& nodeID); @@ -103,7 +104,7 @@ public slots: void processDomainServerPathResponse(QSharedPointer message); void processDomainServerConnectionTokenPacket(QSharedPointer message); - + void processPingPacket(QSharedPointer message, SharedNodePointer sendingNode); void processPingReplyPacket(QSharedPointer message, SharedNodePointer sendingNode); @@ -131,11 +132,11 @@ private slots: void handleNodePingTimeout(); void pingPunchForDomainServer(); - + void sendKeepAlivePings(); void maybeSendIgnoreSetToNode(SharedNodePointer node); - + private: NodeList() : LimitedNodeList(INVALID_PORT, INVALID_PORT) { assert(false); } // Not implemented, needed for DependencyManager templates compile NodeList(char ownerType, int socketListenPort = INVALID_PORT, int dtlsListenPort = INVALID_PORT); @@ -148,7 +149,7 @@ private: void timePingReply(ReceivedMessage& message, const SharedNodePointer& sendingNode); void sendDSPathQuery(const QString& newPath); - + void parseNodeFromPacketStream(QDataStream& packetStream); void pingPunchForInactiveNode(const SharedNodePointer& node); @@ -170,6 +171,8 @@ private: tbb::concurrent_unordered_set _ignoredNodeIDs; mutable QReadWriteLock _personalMutedSetLock; tbb::concurrent_unordered_set _personalMutedNodeIDs; + mutable QReadWriteLock _avatarGainMapLock; + tbb::concurrent_unordered_map _avatarGainMap; void sendIgnoreRadiusStateToNode(const SharedNodePointer& destinationNode); Setting::Handle _ignoreRadiusEnabled { "IgnoreRadiusEnabled", true }; diff --git a/libraries/script-engine/src/UsersScriptingInterface.cpp b/libraries/script-engine/src/UsersScriptingInterface.cpp index 3a3225ec75..6dc3188b3f 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.cpp +++ b/libraries/script-engine/src/UsersScriptingInterface.cpp @@ -47,6 +47,10 @@ void UsersScriptingInterface::setAvatarGain(const QUuid& nodeID, float gain) { DependencyManager::get()->setAvatarGain(nodeID, gain); } +float UsersScriptingInterface::getAvatarGain(const QUuid& nodeID) { + return DependencyManager::get()->getAvatarGain(nodeID); +} + void UsersScriptingInterface::kick(const QUuid& nodeID) { // ask the NodeList to kick the user with the given session ID DependencyManager::get()->kickNodeBySessionID(nodeID); @@ -88,4 +92,4 @@ bool UsersScriptingInterface::getRequestsDomainListData() { } void UsersScriptingInterface::setRequestsDomainListData(bool isRequesting) { DependencyManager::get()->setRequestsDomainListData(isRequesting); -} \ No newline at end of file +} diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 608fa937c8..acaa92d9c8 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -70,6 +70,14 @@ public slots: */ void setAvatarGain(const QUuid& nodeID, float gain); + /**jsdoc + * Gets an avatar's gain for you and you only. + * @function Users.getAvatarGain + * @param {nodeID} nodeID The node or session ID of the user whose gain you want to get. + * @return {float} gain (in dB) + */ + float getAvatarGain(const QUuid& nodeID); + /**jsdoc * Kick another user. * @function Users.kick From 678020fed6d1ff95e8b8e06d0a331942865e6cfd Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 28 Feb 2017 15:03:45 -0700 Subject: [PATCH 25/35] now use it (plus a bit of cleanup) --- interface/resources/qml/hifi/NameCard.qml | 6 +++--- interface/resources/qml/hifi/Pal.qml | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index b55b9c517d..eab9965141 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -335,7 +335,7 @@ Item { } } - // Per-Avatar Gain Slider + // Per-Avatar Gain Slider Slider { id: gainSlider // Size @@ -345,7 +345,7 @@ Item { anchors.verticalCenter: nameCardVUMeter.verticalCenter // Properties visible: !isMyCard && selected - value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : 0.0 + value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : Users.getAvatarGain(uuid) minimumValue: -60.0 maximumValue: 20.0 stepSize: 5 @@ -369,7 +369,7 @@ Item { mouse.accepted = false } onReleased: { - // the above mouse.accepted seems to make this + // the above mouse.accepted seems to make this // never get called, nonetheless... mouse.accepted = false } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index cf5ea98b81..a613af9593 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -2,7 +2,7 @@ // Pal.qml // qml/hifi // -// People Action List +// People Action List // // Created by Howard Stearns on 12/12/2016 // Copyright 2016 High Fidelity, Inc. @@ -270,7 +270,7 @@ Rectangle { // Anchors anchors.left: parent.left } - + // This CheckBox belongs in the columns that contain the stateful action buttons ("Mute" & "Ignore" for now) // KNOWN BUG with the Checkboxes: When clicking in the center of the sorting header, the checkbox // will appear in the "hovered" state. Hovering over the checkbox will fix it. @@ -306,7 +306,7 @@ Rectangle { checked = Qt.binding(function() { return (model[styleData.role])}) } } - + // This Button belongs in the columns that contain the stateless action buttons ("Silence" & "Ban" for now) HifiControls.Button { id: actionButton @@ -538,7 +538,7 @@ Rectangle { } } break; - case 'updateAudioLevel': + case 'updateAudioLevel': for (var userId in message.params) { var audioLevel = message.params[userId]; // If the userId is 0, we're updating "myData". @@ -554,7 +554,7 @@ Rectangle { } } break; - case 'clearLocalQMLData': + case 'clearLocalQMLData': ignored = {}; gainSliderValueDB = {}; break; From 148100b26f7b1b359ab4792660ae9de7b1caa4c9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 28 Feb 2017 15:10:20 -0800 Subject: [PATCH 26/35] fix bug drawing avatar above ground --- interface/src/avatar/SkeletonModel.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 476abf8d4b..88590a6f69 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -179,9 +179,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) { _rig->updateFromEyeParameters(eyeParams); } else { - // no need to call Model::updateRig() because otherAvatars get their joint state - // copied directly from AvtarData::_jointData (there are no Rig animations to blend) - _needsUpdateClusterMatrices = true; + Model::updateRig(deltaTime, parentTransform); // This is a little more work than we really want. // From efe44425a63cc54fd27c02742b19bd4e5b4c93a4 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 1 Mar 2017 09:26:03 -0700 Subject: [PATCH 27/35] cr feedback, plus something I missed --- interface/resources/qml/hifi/NameCard.qml | 13 ++++--------- interface/resources/qml/hifi/Pal.qml | 4 ---- libraries/networking/src/NodeList.cpp | 5 +++++ scripts/system/pal.js | 12 ------------ 4 files changed, 9 insertions(+), 25 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index eab9965141..846f1bec3c 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -345,7 +345,7 @@ Item { anchors.verticalCenter: nameCardVUMeter.verticalCenter // Properties visible: !isMyCard && selected - value: pal.gainSliderValueDB[uuid] ? pal.gainSliderValueDB[uuid] : Users.getAvatarGain(uuid) + value: Users.getAvatarGain(uuid) minimumValue: -60.0 maximumValue: 20.0 stepSize: 5 @@ -393,14 +393,9 @@ Item { } function updateGainFromQML(avatarUuid, sliderValue, isReleased) { - if (isReleased || pal.gainSliderValueDB[avatarUuid] !== sliderValue) { - pal.gainSliderValueDB[avatarUuid] = sliderValue; - var data = { - sessionId: avatarUuid, - gain: sliderValue, - isReleased: isReleased - }; - pal.sendToScript({method: 'updateGain', params: data}); + Users.setAvatarGain(avatarUuid, sliderValue); + if (isReleased) { + UserActivityLogger.palAction("avatar_gain_changed", avatarUuid); } } } diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index a613af9593..7ff4e8a4b1 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -37,9 +37,6 @@ Rectangle { property var ignored: ({}); // Keep a local list of ignored avatars & their data. Necessary because HashMap is slow to respond after ignoring. property var userModelData: [] // This simple list is essentially a mirror of the userModel listModel without all the extra complexities. property bool iAmAdmin: false - // Keep a local list of per-avatar gainSliderValueDBs. Far faster than fetching this data from the server. - // NOTE: if another script modifies the per-avatar gain, this value won't be accurate! - property var gainSliderValueDB: ({}); HifiConstants { id: hifi } @@ -556,7 +553,6 @@ Rectangle { break; case 'clearLocalQMLData': ignored = {}; - gainSliderValueDB = {}; break; case 'avatarDisconnected': var sessionID = message.params[0]; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 7bd6800921..7147682d48 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -252,6 +252,11 @@ void NodeList::reset() { _personalMutedNodeIDs.clear(); _personalMutedSetLock.unlock(); + // lock and clear out set of avatarGains + _avatarGainMapLock.lockForWrite(); + _avatarGainMap.clear(); + _avatarGainMapLock.unlock(); + // refresh the owner UUID to the NULL UUID setSessionUUID(QUuid()); diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 9df4b2df92..106f226a33 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -245,18 +245,6 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See populateUserList(message.params.selected); UserActivityLogger.palAction("refresh", ""); break; - case 'updateGain': - data = message.params; - if (data['isReleased']) { - // isReleased=true happens once at the end of a cycle of dragging - // the slider about, but with same gain as last isReleased=false so - // we don't set the gain in that case, and only here do we want to - // send an analytic event. - UserActivityLogger.palAction("avatar_gain_changed", data['sessionId']); - } else { - Users.setAvatarGain(data['sessionId'], data['gain']); - } - break; case 'displayNameUpdate': if (MyAvatar.displayName !== message.params) { MyAvatar.displayName = message.params; From 55d049ff5caba783d1cbd9be59da2c53e52b518a Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 1 Mar 2017 12:43:45 -0700 Subject: [PATCH 28/35] style updates --- interface/resources/fonts/hifi-glyphs.ttf | Bin 27900 -> 28048 bytes interface/resources/qml/hifi/NameCard.qml | 5 ++++- interface/resources/qml/hifi/Pal.qml | 4 ++-- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/interface/resources/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs.ttf index f6efa8e03952a0b2e926c966a08da697e53d8b79..0d724788143efe22b55d56347e0138961ee55d45 100755 GIT binary patch delta 3431 zcmcJSU2Icj9LAsjIqx~|>F3(6r>EQ6jeVWNHbzU=wczHI1coTchYLa&g8}=WQR1#7nm7`@Gf@MgNX%{|MvWH+H9;MwT{qa6WM8yR`u3v9 z`+I)x|2gOU^BukLJ((Z?E}Vdft074tqt#8KLkb!gyfMr{rh{U#h zyr~tSod9+mNVoSlG=2LrAiM_%OqpRxpd7v|u`A>h};Lu4!{Tt{G0n*AW906BX-?*_iukjB!1Y};9u3bz` zds{e>>a`vbPkB>FqYwQUz!3~$7(><%Vhi<-)UlVSpttJN z>gwu~)z@o!Rs>dz)wa}LU3ntX5^WwClXh<($=juqwPxofQ$QFyaGlOU$66p?t`W=R zFcp&)Xb@srKnv8xl8FbYk(%g1iW@qYwWK#f`oyP3sBe&B$wV@dX3WQBZ;*U0C67Fe zd32|bDH>6MmS0+%$7EtISu7GIHOv*}agijuxv9`Trg{ckDiQNky9HbE8@7Ui0Oui_ z-LG@s_`h5hm|JGWVvp?Mc8Hk`lakx;#>H$o5ZBEz*&m24Z12ipf5`6-%@g2Aw5%*z z27qNioYX?+;70>?pv^kn8Z;LyAQ0EHFcc+`1cljbKBmf&L-cW{2MdQeP6%8KA_ihxe$GTP}DtiyWCBa;x>) zo?y5-Cs#%o&GZ|M=F|@07|tvKI_cKxw$S5?GCV7{JQn9%lD8o*s-$%xs*#qH}Oy8MXkGq$it5qhjJRC6bAUNY&~aDG|?A4A<0&elc_- z+cC`0ljUxjET+KiVxkYmpYyp`J~wGt5hcg?mn0~@JcELozlLwl)sD|DGBwP(NFxk#(vIWsPRBb-aa2|t#>KrLD^090}9WtnYm2Oo>NpTSJ-3|I*Hjl&UEh7OdOg;CpTUcG^;8rifod^ zy%l{#5*55MpS;dOU`wa5j^uIa{Q1W>8{DBfzypvOccY$Fn1q zy^II)7Z>=9yv^IwJ6qr-f+*SqCsW8?;UPgF*~9D(#igjprBPu{&ir^$@NN|J&AZv1Ym0c9L&6~W1B@kuiZd#%ofFtYbcN)!}{8B7O6wTOYTTq1lbjiiOh?RBp}CNunc?u>3XhbQu!!BuC8@}7FK2E^lBK;7Av%V8;i6#UIMq~EM5ENf&GRQK_b?unCAseHYwBMJ{ z^L&2a=YDa3=jY(jzGkwj*hNp58nFpGLRVo5M2B8nhtyd4rDF^ShR6#gTC>r z&Yb{l2e7R#+nZ}{zitA;IY4Ml_YUUn-Gc~Zz5rlLXI|O+*~KT{0HhJ1XS6@nyGQ-D z<2Hbw0VMkSQ${aqq!EC;0K)y*p+gmIzB+&|0JxhO=FKee>I!O<`_JRExzZ@{5s|1wRhOtdv1?8D z9ntQhsJM^2!+>asBUTXCHWzu?vPg(~HGKw|eKYFZ>I-_k!GEfKfY{@Wp-^MUg2?is zJLwF(SdLC~nU{71j9KSe6iziHl3-(sQp$W>vNMnDkescvOuc8q&N#1-9f1;?%++K| zxKfcM*%RI|70AO_l=2QwO*-sH&hn_w+N0mB*i~UP@dBgyvHBYk3EV9ycAL}Y69SBh z3S&-Q@j;&Ge>W3`;o)3N612G;^sTMgQ#tKO!=>T$?_ekljr6w44}hP$9yOE*i`4>S}BP%Hnz=u4~PtCtInF zeDNmV)C1z>zPMB!;y$n6H(4`Q-Q-)wuP2s8q+-*=*D}E-Fs~sI=e9*QXKd>6UqYwH zS1Jxqv3nwJN0}^_k1I~+`1kkw=Vgi$aivOecE3RPk34gUesU z4sPRuK(fFTTN!iF_}z&!GEHoAOKs5ts~>G{Uz=Cu0dAG1p~k9P=X!`H!&D|W#Y(aY zjp)J?Is&W08A;+VinMb#lYxJwqi#d`IN z+;Z#S=62c5M0MS+X(6wk2g+t Date: Wed, 1 Mar 2017 21:31:43 +0100 Subject: [PATCH 29/35] use https in readme/build documentation rather than http --- BUILD.md | 4 ++-- BUILD_OSX.md | 6 +++--- BUILD_WIN.md | 6 +++--- README.md | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/BUILD.md b/BUILD.md index 9c56574cbb..d7fdadf8c7 100644 --- a/BUILD.md +++ b/BUILD.md @@ -12,13 +12,13 @@ * [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82 * [Faceshift](http://www.faceshift.com/) ~> 4.3 * [GLEW](http://glew.sourceforge.net/) -* [glm](http://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4 +* [glm](https://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4 * [gverb](https://github.com/highfidelity/gverb) * [Oculus SDK](https://developer.oculus.com/downloads/) ~> 0.6 (Win32) / 0.5 (Mac / Linux) * [oglplus](http://oglplus.org/) ~> 0.63 * [OpenVR](https://github.com/ValveSoftware/openvr) ~> 0.91 (Win32 only) * [Polyvox](http://www.volumesoffun.com/) ~> 0.2.1 -* [QuaZip](http://sourceforge.net/projects/quazip/files/quazip/) ~> 0.7.1 +* [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/) ~> 0.7.1 * [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3 * [soxr](http://soxr.sourceforge.net) ~> 0.1.1 * [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3 diff --git a/BUILD_OSX.md b/BUILD_OSX.md index 55d4276aa0..980263cbbc 100644 --- a/BUILD_OSX.md +++ b/BUILD_OSX.md @@ -1,7 +1,7 @@ Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file. ###Homebrew -[Homebrew](http://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple. +[Homebrew](https://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple. brew tap homebrew/versions brew install cmake openssl @@ -18,11 +18,11 @@ Note that this uses the version from the homebrew formula at the time of this wr ###Qt You can use the online installer or the offline installer. -* [Download the online installer](http://www.qt.io/download-open-source/#section-2) +* [Download the online installer](https://www.qt.io/download-open-source/#section-2) * When it asks you to select components, select the following: * Qt > Qt 5.6 -* [Download the offline installer](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-mac-x64-clang-5.6.1-1.dmg) +* [Download the offline installer](https://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-mac-x64-clang-5.6.1-1.dmg) Once Qt is installed, you need to manually configure the following: * Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt5.6.1/5.6/clang_64/lib/cmake/` directory. diff --git a/BUILD_WIN.md b/BUILD_WIN.md index b8adaad8d1..45373d3093 100644 --- a/BUILD_WIN.md +++ b/BUILD_WIN.md @@ -33,8 +33,8 @@ You can use the online installer or the offline installer. If you use the offlin * Qt > Qt 5.6.1 > **msvc2013 64-bit** * Download the offline installer, 32- or 64-bit to match your build preference: - * [32-bit](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013-5.6.1-1.exe) - * [64-bit](http://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe) + * [32-bit](https://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013-5.6.1-1.exe) + * [64-bit](https://download.qt.io/official_releases/qt/5.6/5.6.1-1/qt-opensource-windows-x86-msvc2013_64-5.6.1-1.exe) Once Qt is installed, you need to manually configure the following: * Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt\5.6.1\msvc2013\lib\cmake` or `Qt\5.6.1\msvc2013_64\lib\cmake` directory. @@ -72,7 +72,7 @@ Your system may already have several versions of the OpenSSL DLL's (ssleay32.dll QSslSocket: cannot resolve SSL_CTX_set_next_proto_select_cb QSslSocket: cannot resolve SSL_get0_next_proto_negotiated -To prevent these problems, install OpenSSL yourself. Download one of the following binary packages [from this website](http://slproweb.com/products/Win32OpenSSL.html): +To prevent these problems, install OpenSSL yourself. Download one of the following binary packages [from this website](https://slproweb.com/products/Win32OpenSSL.html): * Win32 OpenSSL v1.0.1q * Win64 OpenSSL v1.0.1q diff --git a/README.md b/README.md index 44bfb94634..00e7cbc45b 100644 --- a/README.md +++ b/README.md @@ -11,11 +11,11 @@ We're hiring! We're looking for skilled developers; send your resume to hiring@highfidelity.com ##### Chat with us -Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi! +Come chat with us in [our Gitter](https://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi! Documentation ========= -Documentation is available at [docs.highfidelity.com](http://docs.highfidelity.com), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). +Documentation is available at [docs.highfidelity.com](https://docs.highfidelity.com), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). Build Instructions ========= From 1d3be1607d7160c4add337a0a7f20f053f02c259 Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Wed, 1 Mar 2017 21:35:35 +0100 Subject: [PATCH 30/35] removed broken Faceshift domain from Build manual --- BUILD.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index d7fdadf8c7..5abd8e246e 100644 --- a/BUILD.md +++ b/BUILD.md @@ -10,7 +10,6 @@ * [boostconfig](https://github.com/boostorg/config) ~> 1.58 * [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82 -* [Faceshift](http://www.faceshift.com/) ~> 4.3 * [GLEW](http://glew.sourceforge.net/) * [glm](https://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4 * [gverb](https://github.com/highfidelity/gverb) @@ -20,7 +19,7 @@ * [Polyvox](http://www.volumesoffun.com/) ~> 0.2.1 * [QuaZip](https://sourceforge.net/projects/quazip/files/quazip/) ~> 0.7.1 * [SDL2](https://www.libsdl.org/download-2.0.php) ~> 2.0.3 -* [soxr](http://soxr.sourceforge.net) ~> 0.1.1 +* [soxr](https://sourceforge.net/p/soxr/wiki/Home/) ~> 0.1.1 * [Intel Threading Building Blocks](https://www.threadingbuildingblocks.org/) ~> 4.3 * [Sixense](http://sixense.com/) ~> 071615 * [zlib](http://www.zlib.net/) ~> 1.28 (Win32 only) From dc754cff5f1ce8422c31aedfccba0c74769535c0 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Wed, 1 Mar 2017 13:57:03 -0700 Subject: [PATCH 31/35] magical new glyphs --- interface/resources/fonts/hifi-glyphs.ttf | Bin 28048 -> 27260 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/interface/resources/fonts/hifi-glyphs.ttf b/interface/resources/fonts/hifi-glyphs.ttf index 0d724788143efe22b55d56347e0138961ee55d45..138d7f3ddabaa4d3464b07d36fda995bc96c4f4b 100755 GIT binary patch delta 1114 zcmb`GOGs2v7{~wLeVj9QeB3+ZjCY&~4V&f?iq>ct z1S9Q&7R5x+MhL7$wTNabf*`aOTnI@SxC`1vPclXn4aTDAoW%#<;{5)<@0@e@HGN;9 zEC@guW+38XJl=VJ>eH1uAblCYfitI0$MFOVNVfwx*m0>o+A)8w51?)UUCFV;#PPP( z`+)Eq5L!nPnTgF!h(Nj-fMaCz#;|^2<1HYs1O3yfp~RqbRapkG2Ea_Eh7KpB2(1I; z0T4`$O-}o>-gbaq0QfpOo=o)ES7+|c)y9(Dh3>?7X7ZNd{RRv<06DxBpMb~8y9Wbm z%SV(5D6EyWjr2}^NsmYgV0-7E3JoMqVk-Ye{6b23UA%5KTpgazugi-)SwaA_Sf(!c z0n4yVBczfM;>=S+oavR(HqtAjmbq*{>uZ0CD<2i(48eaTduvB6_V6CaaY~M#!{Gy_y(j|5?s0%UqUx9#>6a z@XkXOx}U$=7Cu`1jTXJJE#YI+qNMR7BR5U1NlsVGolL#+{U2tKA075{=k9;|3Fttx A!2kdN delta 2046 zcmcJQ-)kII7>3{PoHKJ~W`A#XcDB3OB+X`L8fvrac6Ucix+1jO3tQ6GASp)T8rv>) zm!x(BD##SU8xgA){sE#D5kWC`q8AmsS7@o!BDwThDq@w5%r?~|CN&Ut&c(o7&HFsx z`<=gT(7Qj82Lcen6>yxY*Jn;H|L%MOv^xL>j~_i&$H!2C_6&fL>8A^&>90@B0W=HX znT2*^X|nd?`vCh4V6_X4%S&r(;6VEX0PRBS)${j$xm5v_Rp9xzo97xY8n?c?3E&QZ zYO{GR-w;Jw1tAjCeA3xvnzb-9a?!4ice*(=x zK$+G7DrE$aZYU zKFBJQ!m-_4n6flPR&tUht)!JaTym>Nh(7PW6%UC4Ny{2n0^RS4Y4M0dDJyYMo)jvH zkf-vv!G)QXQi+Omkh55d27+3IqAGjD2*!nGm5BlaQYhW764T;jGo~lvr!yga-@c@j zgSwF@%8Rc{m5Hz_5(d8**TZB+E`>}Y#tMNj)3Yx?*$_026pmvK$a@>oI+e1W8;#Hq z9WJ@fu2VYOLD~}it3)_zXlx)9)TVm5AH?<^lKad?T$>@>6sb|OU}gg2|ChVH9W6kv z)9|h#hy+I9;1K3;3CK&U>e$W%N!3b9Q#Dm9>0155Z$SMO*7L<=r2uz4Fxm87`mZAWEp=7@opwxVjTj)$d8k zbDgBLs&1uhSIWIg`5m*81N{QNg}3JeA7-5EEGRTG#-hX+sZn7Bw2)@H{Z`>=p{OYp zjT66mz)6>i#0{oeYHr-%OzJUr4V&7(S5ZKqr|MU_-c#l6#{m>k#~GZ(Jl?^FJNO!= zs;?$Y))1+_A%92QceodY-orQO_Pb?^Lto*``-errh)G4sB#fL0D~hVj??S8RFXsMK lEN#`kITbTRR2E)(?sQmk@#KF+&-Tmo%Irc~8vovje*?u&6$t Date: Wed, 1 Mar 2017 22:04:51 +0100 Subject: [PATCH 32/35] http->https --- BUILD.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BUILD.md b/BUILD.md index 5abd8e246e..644a6690db 100644 --- a/BUILD.md +++ b/BUILD.md @@ -1,7 +1,7 @@ ###Dependencies -* [cmake](http://www.cmake.org/cmake/resources/software.html) ~> 3.3.2 -* [Qt](http://www.qt.io/download-open-source) ~> 5.6.1 +* [cmake](https://cmake.org/download/) ~> 3.3.2 +* [Qt](https://www.qt.io/download-open-source) ~> 5.6.1 * [OpenSSL](https://www.openssl.org/community/binaries.html) * IMPORTANT: Use the latest available version of OpenSSL to avoid security vulnerabilities. * [VHACD](https://github.com/virneo/v-hacd)(clone this repository)(Optional) From 5be952c4e8e5479377bc7db783b88a70314da23c Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 1 Mar 2017 14:51:48 -0800 Subject: [PATCH 33/35] persist sort info for tablet re-opening, and start with column 1 --- interface/resources/qml/hifi/Pal.qml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 16c0fd3dd6..3bad7ee647 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -58,6 +58,8 @@ Rectangle { category: "pal" property bool filtered: false property int nearDistance: 30 + property int sortIndicatorColumn: 1 + property int sortIndicatorOrder: Qt.AscendingOrder } function refreshWithFilter() { // We should just be able to set settings.filtered to filter.checked, but see #3249, so send to .js for saving. @@ -192,8 +194,16 @@ Rectangle { centerHeaderText: true sortIndicatorVisible: true headerVisible: true - onSortIndicatorColumnChanged: sortModel() - onSortIndicatorOrderChanged: sortModel() + sortIndicatorColumn: settings.sortIndicatorColumn + sortIndicatorOrder: settings.sortIndicatorOrder + onSortIndicatorColumnChanged: { + settings.sortIndicatorColumn = sortIndicatorColumn + sortModel() + } + onSortIndicatorOrderChanged: { + settings.sortIndicatorOrder = sortIndicatorOrder + sortModel() + } TableViewColumn { role: "avgAudioLevel" From f42f8cf6025c646447974203a3745ae541a9ceea Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Thu, 2 Mar 2017 02:39:34 +0100 Subject: [PATCH 34/35] bullet moved --- BUILD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BUILD.md b/BUILD.md index 644a6690db..547b79cb08 100644 --- a/BUILD.md +++ b/BUILD.md @@ -9,7 +9,7 @@ ####CMake External Project Dependencies * [boostconfig](https://github.com/boostorg/config) ~> 1.58 -* [Bullet Physics Engine](https://code.google.com/p/bullet/downloads/list) ~> 2.82 +* [Bullet Physics Engine](https://github.com/bulletphysics/bullet3/releases) ~> 2.83 * [GLEW](http://glew.sourceforge.net/) * [glm](https://glm.g-truc.net/0.9.5/index.html) ~> 0.9.5.4 * [gverb](https://github.com/highfidelity/gverb) From 79e440be814ecfeeaad7b148f0bb04d0b61b55b7 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 2 Mar 2017 08:36:58 -0700 Subject: [PATCH 35/35] fix unmute when ignoring in PAL (you can't) --- interface/resources/qml/hifi/Pal.qml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 3bad7ee647..28384f9c1c 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -300,11 +300,14 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter anchors.horizontalCenter: parent.horizontalCenter onClicked: { - var newValue = !model["personalMute"]; - userModel.setProperty(model.userIndex, "personalMute", newValue) - userModelData[model.userIndex]["personalMute"] = newValue // Defensive programming - Users["personalMute"](model.sessionId, newValue) - UserActivityLogger["palAction"](newValue ? "personalMute" : "un-personalMute", model.sessionId) + // cannot change mute status when ignoring + if (!model["ignore"]) { + var newValue = !model["personalMute"]; + userModel.setProperty(model.userIndex, "personalMute", newValue) + userModelData[model.userIndex]["personalMute"] = newValue // Defensive programming + Users["personalMute"](model.sessionId, newValue) + UserActivityLogger["palAction"](newValue ? "personalMute" : "un-personalMute", model.sessionId) + } } } @@ -336,6 +339,7 @@ Rectangle { } else { delete ignored[model.sessionId] } + avgAudioVolume.glyph = avgAudioVolume.getGlyph() } // http://doc.qt.io/qt-5/qtqml-syntax-propertybinding.html#creating-property-bindings-from-javascript // I'm using an explicit binding here because clicking a checkbox breaks the implicit binding as set by