From 15d804168328101fef9e703ee7656284f7111ee0 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 21 Feb 2017 13:14:45 -0800 Subject: [PATCH 01/13] snapshot working, before button change --- interface/resources/qml/hifi/Pal.qml | 30 ++++++++- interface/src/Camera.cpp | 2 + interface/src/avatar/AvatarManager.cpp | 2 +- libraries/avatars/src/AvatarHashMap.cpp | 2 +- .../src/UsersScriptingInterface.h | 1 - scripts/system/pal.js | 63 +++++++++++++++++-- 6 files changed, 89 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index c1fea7c09b..a13e31418a 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -308,6 +308,7 @@ Rectangle { } // Refresh button Rectangle { + id: reload // Size width: hifi.dimensions.tableHeaderHeight-1 height: hifi.dimensions.tableHeaderHeight-1 @@ -338,13 +339,38 @@ Rectangle { // So use onPressed instead of onClicked onPressed: { reloadButton.color = hifi.colors.lightGrayText - pal.sendToScript({method: 'refresh'}) + pal.sendToScript({method: 'refresh', params: {filter: false}}) // fixme re filter } onReleased: reloadButton.color = (containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.darkGray) onEntered: reloadButton.color = hifi.colors.baseGrayHighlight onExited: reloadButton.color = (pressed ? hifi.colors.lightGrayText: hifi.colors.darkGray) } } + HiFiGlyphs { + id: filter + width: hifi.dimensions.tableHeaderHeight - 1 + height: filter.width + text: "\ue007" + size: filter.width + color: hifi.colors.darkGray + anchors { + left: reload.right + leftMargin: 4 + top: reload.top + } + MouseArea { + anchors.fill: parent + hoverEnabled: true + onPressed: { + filter.color = hifi.colors.lightGrayText + pal.sendToScript({method: 'refresh', params: {filter: {distance: 30}}}) + } + onReleased: filter.color = (containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.darkGray) + onEntered: filter.color = hifi.colors.baseGrayHighlight + onExited: filter.color = (pressed ? hifi.colors.lightGrayText : hifi.colors.darkGray) + } + } + // Separator between user and admin functions Rectangle { // Size @@ -501,7 +527,7 @@ Rectangle { if (alreadyRefreshed === true) { letterbox('', '', 'The last editor of this object is either you or not among this list of users.'); } else { - pal.sendToScript({method: 'refresh', params: message.params}); + pal.sendToScript({method: 'refresh', params: {selected: message.params}}); } } else { // If we've already refreshed the PAL and found the avatar in the model diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index f930424569..cf3261ee88 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -192,6 +192,8 @@ QVariantMap Camera::getViewFrustum() { result["orientation"].setValue(frustum.getOrientation()); result["projection"].setValue(frustum.getProjection()); result["centerRadius"].setValue(frustum.getCenterRadius()); + result["fieldOfView"].setValue(frustum.getFieldOfView()); + result["aspectRatio"].setValue(frustum.getAspectRatio()); return result; } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index c3fc974365..0e06c4a238 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -85,7 +85,7 @@ AvatarManager::AvatarManager(QObject* parent) : // immediately remove that avatar instead of waiting for the absence of packets from avatar mixer connect(nodeList.data(), &NodeList::ignoredNode, this, [=](const QUuid& nodeID, bool enabled) { if (enabled) { - removeAvatar(nodeID); + removeAvatar(nodeID, KillAvatarReason::AvatarIgnored); } }); } diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 00c515a635..0652bf6ca3 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -182,7 +182,7 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo void AvatarHashMap::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason) { qCDebug(avatars) << "Removed avatar with UUID" << uuidStringWithoutCurlyBraces(removedAvatar->getSessionUUID()) - << "from AvatarHashMap"; + << "from AvatarHashMap" << removalReason; emit avatarRemovedEvent(removedAvatar->getSessionUUID()); } diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index 76b98c6217..608fa937c8 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -150,7 +150,6 @@ signals: private: bool getRequestsDomainListData(); void setRequestsDomainListData(bool requests); - bool _requestsDomainListData; }; diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 57648da79a..9c0bc1f513 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -33,6 +33,15 @@ var conserveResources = true; Script.include("/~/system/libraries/controllers.js"); +function projectVectorOntoPlane(normalizedVector, planeNormal) { + return Vec3.cross(planeNormal, Vec3.cross(normalizedVector, planeNormal)); +} +function angleBetweenVectorsInPlane(from, to, normal) { + var projectedFrom = projectVectorOntoPlane(from, normal); + var projectedTo = projectVectorOntoPlane(to, normal); + return Vec3.orientedAngle(projectedFrom, projectedTo, normal); +} + // // Overlays. // @@ -234,7 +243,7 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See break; case 'refresh': removeOverlays(); - populateUserList(message.params); + populateUserList(message.params.selected, message.params.filter); UserActivityLogger.palAction("refresh", ""); break; case 'updateGain': @@ -280,13 +289,48 @@ function addAvatarNode(id) { color: color(selected, false, 0.0), ignoreRayIntersection: false}, selected, !conserveResources); } -function populateUserList(selectData) { +var filter = false; +// Each open/refresh will capture a stable set of avatarsOfInterest, within the specified filter. +var avatarsOfInterest = {}; +function populateUserList(selectData, filterRequest) { + if (filterRequest !== undefined) { + filter = filterRequest; + } var data = [], avatars = AvatarList.getAvatarIdentifiers(); - conserveResources = avatars.length > 20; + avatarsOfInterest = {}; + var myPosition = filter && Camera.position, + frustum = filter && Camera.frustum, + verticalHalfAngle = filter && (frustum.fieldOfView / 2), + horizontalHalfAngle = filter && (verticalHalfAngle * frustum.aspectRatio), + orientation = filter && Camera.orientation, + front = filter && Quat.getFront(orientation), + verticalAngleNormal = filter && Quat.getRight(orientation), + horizontalAngleNormal = filter && Quat.getUp(orientation); + print('fixme h/v...myPosition', horizontalHalfAngle, verticalHalfAngle, JSON.stringify(horizontalAngleNormal), JSON.stringify(verticalAngleNormal), JSON.stringify(myPosition)); avatars.forEach(function (id) { // sorting the identifiers is just an aid for debugging var avatar = AvatarList.getAvatar(id); + var name = avatar.sessionDisplayName; + if (!name) { + // Either we got a data packet but no identity yet, or something is really messed up. In any case, + // we won't be able to do anything with this user, so don't include them. + // In normal circumstances, a refresh will bring in the new user, but if we're very heavily loaded, + // we could be losing and gaining people randomly. + print('No avatar identity data for', id); + return; + } + if (id && myPosition && (Vec3.distance(avatar.position, myPosition) > filter.distance)) { + return; + } + var normal = id && filter && Vec3.normalize(Vec3.subtract(avatar.position, myPosition)); + var horizontal = normal && angleBetweenVectorsInPlane(normal, front, horizontalAngleNormal); + var vertical = normal && angleBetweenVectorsInPlane(normal, front, verticalAngleNormal); + print('fixme id/h/v/pos/norm', id, horizontal, vertical, JSON.stringify(avatar.position), JSON.stringify(normal)); + if (id && filter && ((Math.abs(horizontal) > horizontalHalfAngle) || (Math.abs(vertical) > verticalHalfAngle))) { + print('fixme skip out of angle'); + return; + } var avatarPalDatum = { - displayName: avatar.sessionDisplayName, + displayName: name, userName: '', sessionId: id || '', audioLevel: 0.0, @@ -298,10 +342,13 @@ function populateUserList(selectData) { addAvatarNode(id); // No overlay for ourselves // Everyone needs to see admin status. Username and fingerprint returns default constructor output if the requesting user isn't an admin. Users.requestUsernameFromID(id); + avatarsOfInterest[id] = true; } data.push(avatarPalDatum); print('PAL data:', JSON.stringify(avatarPalDatum)); }); + print('fixme avatarsOfInterest', JSON.stringify(avatarsOfInterest)); + conserveResources = Object.keys(avatarsOfInterest).length > 20; sendToQml({ method: 'users', params: data }); if (selectData) { selectData[2] = true; @@ -326,11 +373,13 @@ var pingPong = true; function updateOverlays() { var eye = Camera.position; AvatarList.getAvatarIdentifiers().forEach(function (id) { - if (!id) { - return; // don't update ourself + if (!id || !avatarsOfInterest[id]) { + if (id) print('fixme not updating', id, Object.keys(avatarsOfInterest).length); + return; // don't update ourself, or avatars we're not interested in } var avatar = AvatarList.getAvatar(id); if (!avatar) { + print('fixme not updating missing avatar', id); return; // will be deleted below if there had been an overlay. } var overlay = ExtendedOverlay.get(id); @@ -517,6 +566,7 @@ function off() { triggerMapping.disable(); // It's ok if we disable twice. triggerPressMapping.disable(); // see above removeOverlays(); + print('fixme clear requestsDomainListData'); Users.requestsDomainListData = false; } function onClicked() { @@ -538,6 +588,7 @@ function onClicked() { pal.setVisible(!pal.visible); } else { tablet.loadQMLSource("../Pal.qml"); + print('fixme setting requestsDomainListData'); Users.requestsDomainListData = true; populateUserList(); isWired = true; From f21e17d5123948a805d5a9fee967e5844f0efea3 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 21 Feb 2017 15:32:41 -0800 Subject: [PATCH 02/13] new buttons --- interface/resources/qml/hifi/Pal.qml | 88 ++++++++-------------------- 1 file changed, 23 insertions(+), 65 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index a13e31418a..b17182432a 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -52,6 +52,9 @@ Rectangle { letterboxMessage.visible = true letterboxMessage.popupRadius = 0 } + function refreshWithFilter() { + pal.sendToScript({method: 'refresh', params: {filter: filter.checked && {distance: 30}}}) + } // This is the container for the PAL Rectangle { @@ -93,7 +96,26 @@ Rectangle { // Anchors anchors.left: parent.left } - } + Row { + HifiControls.CheckBox { + id: filter + text: "in view" + boxSize: reload.height + onCheckedChanged: refreshWithFilter() + } + HifiControls.GlyphButton { + id: reload + glyph: hifi.glyphs.reload + width: reload.height + onClicked: refreshWithFilter() + } + spacing: 40 + anchors { + right: parent.right + top: parent.top + topMargin: 10 + } + } // Rectangles used to cover up rounded edges on bottom of MyInfo Rectangle Rectangle { color: pal.color @@ -306,70 +328,6 @@ Rectangle { } } } - // Refresh button - Rectangle { - id: reload - // Size - width: hifi.dimensions.tableHeaderHeight-1 - height: hifi.dimensions.tableHeaderHeight-1 - // Anchors - anchors.left: table.left - anchors.leftMargin: 4 - anchors.top: table.top - // Style - color: hifi.colors.tableBackgroundLight - // Actual refresh icon - HiFiGlyphs { - id: reloadButton - text: hifi.glyphs.reloadSmall - // Size - size: parent.width*1.5 - // Anchors - anchors.fill: parent - // Style - horizontalAlignment: Text.AlignHCenter - color: hifi.colors.darkGray - } - MouseArea { - id: reloadButtonArea - // Anchors - anchors.fill: parent - hoverEnabled: true - // Everyone likes a responsive refresh button! - // So use onPressed instead of onClicked - onPressed: { - reloadButton.color = hifi.colors.lightGrayText - pal.sendToScript({method: 'refresh', params: {filter: false}}) // fixme re filter - } - onReleased: reloadButton.color = (containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.darkGray) - onEntered: reloadButton.color = hifi.colors.baseGrayHighlight - onExited: reloadButton.color = (pressed ? hifi.colors.lightGrayText: hifi.colors.darkGray) - } - } - HiFiGlyphs { - id: filter - width: hifi.dimensions.tableHeaderHeight - 1 - height: filter.width - text: "\ue007" - size: filter.width - color: hifi.colors.darkGray - anchors { - left: reload.right - leftMargin: 4 - top: reload.top - } - MouseArea { - anchors.fill: parent - hoverEnabled: true - onPressed: { - filter.color = hifi.colors.lightGrayText - pal.sendToScript({method: 'refresh', params: {filter: {distance: 30}}}) - } - onReleased: filter.color = (containsMouse ? hifi.colors.baseGrayHighlight : hifi.colors.darkGray) - onEntered: filter.color = hifi.colors.baseGrayHighlight - onExited: filter.color = (pressed ? hifi.colors.lightGrayText : hifi.colors.darkGray) - } - } // Separator between user and admin functions Rectangle { From 1ddc7de5815048502139e9ce0ff7ceca4f03622d Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 21 Feb 2017 15:41:17 -0800 Subject: [PATCH 03/13] remove debugging (and fix missing brace) --- interface/resources/qml/hifi/Pal.qml | 1 + scripts/system/pal.js | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index b17182432a..f87b110ecb 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -116,6 +116,7 @@ Rectangle { topMargin: 10 } } + } // Rectangles used to cover up rounded edges on bottom of MyInfo Rectangle Rectangle { color: pal.color diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 14e11e3fcd..0a135aeddb 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -297,7 +297,6 @@ function populateUserList(selectData, filterRequest) { front = filter && Quat.getFront(orientation), verticalAngleNormal = filter && Quat.getRight(orientation), horizontalAngleNormal = filter && Quat.getUp(orientation); - print('fixme h/v...myPosition', horizontalHalfAngle, verticalHalfAngle, JSON.stringify(horizontalAngleNormal), JSON.stringify(verticalAngleNormal), JSON.stringify(myPosition)); avatars.forEach(function (id) { // sorting the identifiers is just an aid for debugging var avatar = AvatarList.getAvatar(id); var name = avatar.sessionDisplayName; @@ -315,9 +314,7 @@ function populateUserList(selectData, filterRequest) { var normal = id && filter && Vec3.normalize(Vec3.subtract(avatar.position, myPosition)); var horizontal = normal && angleBetweenVectorsInPlane(normal, front, horizontalAngleNormal); var vertical = normal && angleBetweenVectorsInPlane(normal, front, verticalAngleNormal); - print('fixme id/h/v/pos/norm', id, horizontal, vertical, JSON.stringify(avatar.position), JSON.stringify(normal)); if (id && filter && ((Math.abs(horizontal) > horizontalHalfAngle) || (Math.abs(vertical) > verticalHalfAngle))) { - print('fixme skip out of angle'); return; } var avatarPalDatum = { @@ -338,7 +335,6 @@ function populateUserList(selectData, filterRequest) { data.push(avatarPalDatum); print('PAL data:', JSON.stringify(avatarPalDatum)); }); - print('fixme avatarsOfInterest', JSON.stringify(avatarsOfInterest)); conserveResources = Object.keys(avatarsOfInterest).length > 20; sendToQml({ method: 'users', params: data }); if (selectData) { @@ -365,12 +361,10 @@ function updateOverlays() { var eye = Camera.position; AvatarList.getAvatarIdentifiers().forEach(function (id) { if (!id || !avatarsOfInterest[id]) { - if (id) print('fixme not updating', id, Object.keys(avatarsOfInterest).length); return; // don't update ourself, or avatars we're not interested in } var avatar = AvatarList.getAvatar(id); if (!avatar) { - print('fixme not updating missing avatar', id); return; // will be deleted below if there had been an overlay. } var overlay = ExtendedOverlay.get(id); @@ -570,7 +564,6 @@ function off() { triggerMapping.disable(); // It's ok if we disable twice. triggerPressMapping.disable(); // see above removeOverlays(); - print('fixme clear requestsDomainListData'); Users.requestsDomainListData = false; } function onTabletButtonClicked() { From a20590a2f953e06601a6c6dbf6ca0e1fbefa9322 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 21 Feb 2017 16:03:59 -0800 Subject: [PATCH 04/13] fixed myCard width in all cases (admin or not) --- interface/resources/qml/hifi/Pal.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index f87b110ecb..b79f3bc7de 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -29,7 +29,9 @@ 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 int actionButtonAllowance: actionButtonWidth * 2 + 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, 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. @@ -91,7 +93,7 @@ Rectangle { audioLevel: myData.audioLevel isMyCard: true // Size - width: nameCardWidth + width: minNameCardWidth height: parent.height // Anchors anchors.left: parent.left From 023a32563c13d4f554b01664c974410281b1ace8 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 22 Feb 2017 12:59:40 -0800 Subject: [PATCH 05/13] work around .qml settings issues --- interface/resources/qml/hifi/Pal.qml | 11 ++++++++++- scripts/system/pal.js | 13 +++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index b79f3bc7de..cc5bd521ff 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 Qt.labs.settings 1.0 import "../styles-uit" import "../controls-uit" as HifiControls @@ -54,8 +55,15 @@ Rectangle { letterboxMessage.visible = true letterboxMessage.popupRadius = 0 } + Settings { + id: settings + category: "pal" + property bool filtered: false + property int nearDistance: 30 + } function refreshWithFilter() { - pal.sendToScript({method: 'refresh', params: {filter: filter.checked && {distance: 30}}}) + // We should just be able to set settings.filtered to filter.checked, but see #3249, so send to .js for saving. + pal.sendToScript({method: 'refresh', params: {filter: filter.checked && {distance: settings.nearDistance}}}); } // This is the container for the PAL @@ -101,6 +109,7 @@ Rectangle { Row { HifiControls.CheckBox { id: filter + checked: settings.filtered text: "in view" boxSize: reload.height onCheckedChanged: refreshWithFilter() diff --git a/scripts/system/pal.js b/scripts/system/pal.js index 0a135aeddb..8ae4412fae 100644 --- a/scripts/system/pal.js +++ b/scripts/system/pal.js @@ -238,7 +238,11 @@ function fromQml(message) { // messages are {method, params}, like json-rpc. See break; case 'refresh': removeOverlays(); - populateUserList(message.params.selected, message.params.filter); + // If filter is specified from .qml instead of through settings, update the settings. + if (message.params.filter !== undefined) { + Settings.setValue('pal/filtered', !!message.params.filter); + } + populateUserList(message.params.selected); UserActivityLogger.palAction("refresh", ""); break; case 'updateGain': @@ -280,13 +284,10 @@ function addAvatarNode(id) { color: color(selected, false, 0.0), ignoreRayIntersection: false}, selected, !conserveResources); } -var filter = false; // Each open/refresh will capture a stable set of avatarsOfInterest, within the specified filter. var avatarsOfInterest = {}; -function populateUserList(selectData, filterRequest) { - if (filterRequest !== undefined) { - filter = filterRequest; - } +function populateUserList(selectData) { + var filter = Settings.getValue('pal/filtered') && {distance: Settings.getValue('pal/nearDistance')}; var data = [], avatars = AvatarList.getAvatarIdentifiers(); avatarsOfInterest = {}; var myPosition = filter && Camera.position, From de3a0d3d0c7c5504068d7237139459a84e0e440e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 22 Feb 2017 13:02:05 -0800 Subject: [PATCH 06/13] button styling --- interface/resources/qml/hifi/Pal.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index cc5bd521ff..cf5ea98b81 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -111,7 +111,7 @@ Rectangle { id: filter checked: settings.filtered text: "in view" - boxSize: reload.height + boxSize: reload.height * 0.70 onCheckedChanged: refreshWithFilter() } HifiControls.GlyphButton { @@ -120,7 +120,7 @@ Rectangle { width: reload.height onClicked: refreshWithFilter() } - spacing: 40 + spacing: 50 anchors { right: parent.right top: parent.top From 60fd4afc4d94a1af7b4887f3fad4b2a01a658623 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 23 Feb 2017 18:52:10 -0800 Subject: [PATCH 07/13] don't count NoData avatars as having been broadcast, fix avatars slightly out of view from freezing --- .../src/avatars/AvatarMixerSlave.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 8d9a5e6951..dd25aa4c4b 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -384,18 +384,20 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { if (includeThisAvatar) { numAvatarDataBytes += avatarPacketList->write(otherNode->getUUID().toRfc4122()); numAvatarDataBytes += avatarPacketList->write(bytes); - _stats.numOthersIncluded++; - // increment the number of avatars sent to this reciever - nodeData->incrementNumAvatarsSentLastFrame(); + if (detail != AvatarData::NoData) { + _stats.numOthersIncluded++; - // set the last sent sequence number for this sender on the receiver - nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), - otherNodeData->getLastReceivedSequenceNumber()); + // increment the number of avatars sent to this reciever + nodeData->incrementNumAvatarsSentLastFrame(); - // remember the last time we sent details about this other node to the receiver - nodeData->setLastBroadcastTime(otherNode->getUUID(), start); + // set the last sent sequence number for this sender on the receiver + nodeData->setLastBroadcastSequenceNumber(otherNode->getUUID(), + otherNodeData->getLastReceivedSequenceNumber()); + // remember the last time we sent details about this other node to the receiver + nodeData->setLastBroadcastTime(otherNode->getUUID(), start); + } } avatarPacketList->endSegment(); From 70060eb464e4c0dcd53568432e802b07f91a9d7b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Feb 2017 21:27:25 -0800 Subject: [PATCH 08/13] in 2d mode, clicks on tablet don't get used for other things Conflicts: scripts/system/libraries/entitySelectionTool.js --- interface/src/Application.cpp | 40 +++++++++++++------ interface/src/Application.h | 2 + interface/src/ui/overlays/Overlays.cpp | 15 +++---- interface/src/ui/overlays/Overlays.h | 6 +-- scripts/system/controllers/grab.js | 6 +++ scripts/system/edit.js | 5 +++ .../system/libraries/entitySelectionTool.js | 6 +++ 7 files changed, 57 insertions(+), 23 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 02291cc619..bff2a6bae0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3097,17 +3097,23 @@ void Application::mouseMoveEvent(QMouseEvent* event) { if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() || getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y())) != UNKNOWN_OVERLAY_ID) { - getOverlays().mouseMoveEvent(&mappedEvent); - getEntities()->mouseMoveEvent(&mappedEvent); + if (_mouseToOverlays) { + getOverlays().mouseMoveEvent(&mappedEvent); + } else { + getEntities()->mouseMoveEvent(&mappedEvent); + } + } + + if (!_mouseToOverlays) { + _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts } - _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; } - if (_keyboardMouseDevice->isActive()) { + if (!_mouseToOverlays && _keyboardMouseDevice->isActive()) { _keyboardMouseDevice->mouseMoveEvent(event); } } @@ -3115,6 +3121,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { void Application::mousePressEvent(QMouseEvent* event) { // Inhibit the menu if the user is using alt-mouse dragging _altPressed = false; + _mouseToOverlays = false; auto offscreenUi = DependencyManager::get(); // If we get a mouse press event it means it wasn't consumed by the offscreen UI, @@ -3131,21 +3138,23 @@ void Application::mousePressEvent(QMouseEvent* event) { event->buttons(), event->modifiers()); if (!_aboutToQuit) { - getOverlays().mousePressEvent(&mappedEvent); - - if (!_controllerScriptingInterface->areEntityClicksCaptured()) { + if (getOverlays().mousePressEvent(&mappedEvent)) { + _mouseToOverlays = true; + } else if (!_controllerScriptingInterface->areEntityClicksCaptured()) { getEntities()->mousePressEvent(&mappedEvent); } } - _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts + if (!_mouseToOverlays) { + _controllerScriptingInterface->emitMousePressEvent(&mappedEvent); // send events to any registered scripts + } // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; } - if (hasFocus()) { + if (!_mouseToOverlays && hasFocus()) { if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->mousePressEvent(event); } @@ -3179,18 +3188,23 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { event->buttons(), event->modifiers()); if (!_aboutToQuit) { - getOverlays().mouseReleaseEvent(&mappedEvent); - getEntities()->mouseReleaseEvent(&mappedEvent); + if (_mouseToOverlays) { + getOverlays().mouseReleaseEvent(&mappedEvent); + } else { + getEntities()->mouseReleaseEvent(&mappedEvent); + } } - _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts + if (!_mouseToOverlays) { + _controllerScriptingInterface->emitMouseReleaseEvent(&mappedEvent); // send events to any registered scripts + } // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isMouseCaptured()) { return; } - if (hasFocus()) { + if (!_mouseToOverlays && hasFocus()) { if (_keyboardMouseDevice->isActive()) { _keyboardMouseDevice->mouseReleaseEvent(event); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 13c1458aee..fa98f6bd6e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -676,6 +676,8 @@ private: void addAssetToWorldInfoDone(QString modelName); void addAssetToWorldError(QString modelName, QString errorText); + bool _mouseToOverlays { false }; + QQuickItem* _addAssetToWorldMessageBox{ nullptr }; QStringList _addAssetToWorldInfoKeys; // Model name QStringList _addAssetToWorldInfoMessages; // Info message diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 9d2f52bc81..dc1380adb9 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -760,7 +760,7 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionForMouseEvent(PickRa return findRayIntersection(ray); } -void Overlays::mousePressEvent(QMouseEvent* event) { +bool Overlays::mousePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mousePressEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); @@ -773,15 +773,14 @@ void Overlays::mousePressEvent(QMouseEvent* event) { if (thisOverlay) { auto pointerEvent = calculatePointerEvent(thisOverlay, ray, rayPickResult, event, PointerEvent::Press); emit mousePressOnOverlay(_currentClickingOnOverlayID, pointerEvent); - } else { - emit mousePressOffOverlay(); + return true; } - } else { - emit mousePressOffOverlay(); } + emit mousePressOffOverlay(); + return false; } -void Overlays::mouseReleaseEvent(QMouseEvent* event) { +bool Overlays::mouseReleaseEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseReleaseEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); @@ -797,9 +796,10 @@ void Overlays::mouseReleaseEvent(QMouseEvent* event) { } _currentClickingOnOverlayID = UNKNOWN_OVERLAY_ID; + return false; } -void Overlays::mouseMoveEvent(QMouseEvent* event) { +bool Overlays::mouseMoveEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseMoveEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); @@ -843,6 +843,7 @@ void Overlays::mouseMoveEvent(QMouseEvent* event) { _currentHoverOverOverlayID = UNKNOWN_OVERLAY_ID; } } + return false; } QVector Overlays::findOverlays(const glm::vec3& center, float radius) const { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 865df6309a..5c22e46880 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -100,9 +100,9 @@ public: OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); } OverlayID addOverlay(Overlay::Pointer overlay); - void mousePressEvent(QMouseEvent* event); - void mouseReleaseEvent(QMouseEvent* event); - void mouseMoveEvent(QMouseEvent* event); + bool mousePressEvent(QMouseEvent* event); + bool mouseReleaseEvent(QMouseEvent* event); + bool mouseMoveEvent(QMouseEvent* event); void cleanupAllOverlays(); diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 74a3c3d25b..f0b6663bec 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -331,6 +331,12 @@ Grabber.prototype.pressEvent = function(event) { } var pickRay = Camera.computePickRay(event.x, event.y); + + var overlayResult = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); + if (overlayResult.intersects) { + return; + } + var pickResults = Entities.findRayIntersection(pickRay, true); // accurate picking if (!pickResults.intersects) { // didn't click on anything diff --git a/scripts/system/edit.js b/scripts/system/edit.js index da39edf8ba..ad3af3a659 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -564,6 +564,11 @@ function findClickedEntity(event) { var pickRay = Camera.computePickRay(event.x, event.y); + var overlayResult = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); + if (overlayResult.intersects) { + return null; + } + var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking var lightResult = lightOverlayManager.findRayIntersection(pickRay); lightResult.accurate = true; diff --git a/scripts/system/libraries/entitySelectionTool.js b/scripts/system/libraries/entitySelectionTool.js index b9bae72d14..9c1626caf4 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -3866,6 +3866,12 @@ SelectionDisplay = (function() { var somethingClicked = false; var pickRay = generalComputePickRay(event.x, event.y); + var result = Overlays.findRayIntersection(pickRay, true, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); + if (result.intersects) { + // mouse clicks on the tablet should override the edit affordances + return false; + } + // before we do a ray test for grabbers, disable the ray intersection for our selection box Overlays.editOverlay(selectionBox, { ignoreRayIntersection: true From 71ab6a1a84ee81b39e8ab9b3267ea63a56ee8165 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Feb 2017 11:34:10 -0800 Subject: [PATCH 09/13] fix a couple of problems related to grabbing tablet while edit.js is active Conflicts: scripts/system/controllers/handControllerGrab.js --- interface/src/ui/overlays/Overlays.cpp | 33 +++++++++---------- .../system/controllers/handControllerGrab.js | 16 +++++---- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index dc1380adb9..f1f835fea3 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -341,27 +341,26 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { return UNKNOWN_OVERLAY_ID; } QMapIterator i(_overlaysHUD); - i.toBack(); const float LARGE_NEGATIVE_FLOAT = -9999999; glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT); glm::vec3 direction(0, 0, 1); - BoxFace thisFace; + // BoxFace thisFace; glm::vec3 thisSurfaceNormal; - float distance; + // float distance; unsigned int bestStackOrder = 0; OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID; - while (i.hasPrevious()) { - i.previous(); + while (i.hasNext()) { + i.next(); OverlayID thisID = i.key(); if (i.value()->is3D()) { - auto thisOverlay = std::dynamic_pointer_cast(i.value()); - if (thisOverlay && !thisOverlay->getIgnoreRayIntersection()) { - if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace, thisSurfaceNormal)) { - return thisID; - } - } + // auto thisOverlay = std::dynamic_pointer_cast(i.value()); + // if (thisOverlay && !thisOverlay->getIgnoreRayIntersection()) { + // if (thisOverlay->findRayIntersection(origin, direction, distance, thisFace, thisSurfaceNormal)) { + // return thisID; + // } + // } } else { auto thisOverlay = std::dynamic_pointer_cast(i.value()); if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() && @@ -423,9 +422,8 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR RayToOverlayIntersectionResult result; QMapIterator i(_overlaysWorld); - i.toBack(); - while (i.hasPrevious()) { - i.previous(); + while (i.hasNext()) { + i.next(); OverlayID thisID = i.key(); auto thisOverlay = std::dynamic_pointer_cast(i.value()); @@ -850,9 +848,10 @@ QVector Overlays::findOverlays(const glm::vec3& center, float radius) con QVector result; QMapIterator i(_overlaysWorld); - i.toBack(); - while (i.hasPrevious()) { - i.previous(); + int checked = 0; + while (i.hasNext()) { + checked++; + i.next(); OverlayID thisID = i.key(); auto overlay = std::dynamic_pointer_cast(i.value()); if (overlay && overlay->getVisible() && !overlay->getIgnoreRayIntersection() && overlay->isLoaded()) { diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 373007bc60..7863d5a27c 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -862,9 +862,11 @@ function MyController(hand) { }; this.setState = function(newState, reason) { - if ((isInEditMode() && this.grabbedThingID !== HMD.tabletID) && (newState !== STATE_OFF && - newState !== STATE_SEARCHING && - newState !== STATE_OVERLAY_STYLUS_TOUCHING)) { + if ((isInEditMode() && this.grabbedThingID !== HMD.tabletID) && + (newState !== STATE_OFF && + newState !== STATE_SEARCHING && + newState !== STATE_OVERLAY_STYLUS_TOUCHING && + newState !== STATE_OVERLAY_LASER_TOUCHING)) { return; } setGrabCommunications((newState === STATE_DISTANCE_HOLDING) || (newState === STATE_NEAR_GRABBING)); @@ -1439,7 +1441,7 @@ function MyController(hand) { var okToEquipFromOtherHand = ((this.getOtherHandController().state == STATE_NEAR_GRABBING || this.getOtherHandController().state == STATE_DISTANCE_HOLDING) && - this.getOtherHandController().grabbedEntity == hotspot.entityID); + this.getOtherHandController().grabbedThingID == hotspot.entityID); var hasParent = true; if (props.parentID === NULL_UUID) { hasParent = false; @@ -1659,7 +1661,7 @@ function MyController(hand) { grabbableOverlays.sort(function(a, b) { var aPosition = Overlays.getProperty(a, "position"); var aDistance = Vec3.distance(aPosition, handPosition); - var bPosition = Overlays.getProperty(a, "position"); + var bPosition = Overlays.getProperty(b, "position"); var bDistance = Vec3.distance(bPosition, handPosition); return aDistance - bDistance; }); @@ -3332,8 +3334,8 @@ var handleHandMessages = function(channel, message, sender) { selectedController.release(); var wearableEntity = data.entityID; entityPropertiesCache.addEntity(wearableEntity); - selectedController.grabbedEntity = wearableEntity; - var hotspots = selectedController.collectEquipHotspots(selectedController.grabbedEntity); + selectedController.grabbedThingID = wearableEntity; + var hotspots = selectedController.collectEquipHotspots(selectedController.grabbedThingID); if (hotspots.length > 0) { if (hotspotIndex >= hotspots.length) { hotspotIndex = 0; From eedc5c1647cc9f8095fde848a24b9e9e7b46842c Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Feb 2017 12:10:52 -0800 Subject: [PATCH 10/13] don't allow tablet to get stuck to a hand when passing it back and forth between hands --- libraries/entities/src/EntityScriptingInterface.cpp | 3 +-- scripts/system/controllers/handControllerGrab.js | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index cd7f1235bb..a5bd0135e4 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1419,8 +1419,7 @@ QVector EntityScriptingInterface::getChildrenIDsOfJoint(const QUuid& pare return; } parent->forEachChild([&](SpatiallyNestablePointer child) { - if (child->getParentJointIndex() == jointIndex && - child->getNestableType() != NestableType::Overlay) { + if (child->getParentJointIndex() == jointIndex) { result.push_back(child->getID()); } }); diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 7863d5a27c..d313d1cfa1 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -3213,9 +3213,13 @@ function MyController(hand) { } _this.previouslyUnhooked[childID] = now; + // we don't know if it's an entity or an overlay Entities.editEntity(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex }); + Overlays.editOverlay(childID, { parentID: previousParentID, parentJointIndex: previousParentJointIndex }); + } else { Entities.editEntity(childID, { parentID: NULL_UUID }); + Overlays.editOverlay(childID, { parentID: NULL_UUID }); } } }); From 6e9854cad09a0e88a92326c1632f58b540fd06d5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Feb 2017 13:01:01 -0800 Subject: [PATCH 11/13] don't crash if geometry fails to load --- libraries/model-networking/src/model-networking/ModelCache.h | 2 ++ libraries/render-utils/src/Model.h | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index adef3ce2b5..2cd96a84c7 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -44,6 +44,8 @@ public: // Mutable, but must retain structure of vector using NetworkMaterials = std::vector>; + bool isGeometryLoaded() const { return (bool)_fbxGeometry; } + const FBXGeometry& getFBXGeometry() const { return *_fbxGeometry; } const GeometryMeshes& getMeshes() const { return *_meshes; } const std::shared_ptr getShapeMaterial(int shapeID) const; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 2042a16801..7c373274e4 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -114,7 +114,7 @@ public: void setBlendedVertices(int blendNumber, const Geometry::WeakPointer& geometry, const QVector& vertices, const QVector& normals); - bool isLoaded() const { return (bool)_renderGeometry; } + bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); } void setIsWireframe(bool isWireframe) { _isWireframe = isWireframe; } bool isWireframe() const { return _isWireframe; } From b2a35f45db675837dd5e20c991a853e94d76f91d Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Feb 2017 13:04:43 -0800 Subject: [PATCH 12/13] when tablet is an overlay, use the model-fbx from the distribution (local disk copy) rather than the one on s3 --- scripts/system/libraries/WebTablet.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index c4b41bcab5..1768d475a7 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -34,7 +34,7 @@ var TABLET_NATURAL_DIMENSIONS = {x: 33.797, y: 50.129, z: 2.269}; var HOME_BUTTON_TEXTURE = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png"; // var HOME_BUTTON_TEXTURE = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx/tablet-with-home-button.fbm/button-close.png"; var TABLET_MODEL_PATH = "http://hifi-content.s3.amazonaws.com/alan/dev/tablet-with-home-button.fbx"; -// var TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx"; +var LOCAL_TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-button.fbx"; // returns object with two fields: // * position - position in front of the user @@ -112,11 +112,18 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { this.dpi = DEFAULT_DPI * (DEFAULT_WIDTH / this.width); } + var modelURL; + if (Settings.getValue("tabletVisibleToOthers")) { + modelURL = TABLET_MODEL_PATH; + } else { + modelURL = LOCAL_TABLET_MODEL_PATH; + } + var tabletProperties = { name: "WebTablet Tablet", type: "Model", - modelURL: TABLET_MODEL_PATH, - url: TABLET_MODEL_PATH, // for overlay + modelURL: modelURL, + url: modelURL, // for overlay grabbable: true, // for overlay userData: JSON.stringify({ "grabbableKey": {"grabbable": true} From 34755dd75dada0f29cee198e3a792d9a21965221 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Feb 2017 13:57:49 -0800 Subject: [PATCH 13/13] notify children of an overlay when the parent overlay moves --- interface/src/ui/overlays/Base3DOverlay.cpp | 4 ++-- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 10378ff858..70b1fa4b71 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -259,6 +259,8 @@ bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3 } void Base3DOverlay::locationChanged(bool tellPhysics) { + SpatiallyNestable::locationChanged(tellPhysics); + auto itemID = getRenderItemID(); if (render::Item::isValidID(itemID)) { render::ScenePointer scene = qApp->getMain3DScene(); @@ -266,8 +268,6 @@ void Base3DOverlay::locationChanged(bool tellPhysics) { pendingChanges.updateItem(itemID); scene->enqueuePendingChanges(pendingChanges); } - // Overlays can't currently have children. - // SpatiallyNestable::locationChanged(tellPhysics); // tell all the children, also } void Base3DOverlay::parentDeleted() { diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 277a86e93f..aa06741638 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -53,7 +53,7 @@ namespace render { return overlay->getBounds(); } template <> int payloadGetLayer(const Overlay::Pointer& overlay) { - // MAgic number while we are defining the layering mechanism: + // Magic number while we are defining the layering mechanism: const int LAYER_NO_AA = 3; const int LAYER_2D = 2; const int LAYER_3D_FRONT = 1;