From 15d804168328101fef9e703ee7656284f7111ee0 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Tue, 21 Feb 2017 13:14:45 -0800 Subject: [PATCH 01/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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 bfc485394746204e4ebbede093e82b016080f6f2 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Feb 2017 16:50:02 -0800 Subject: [PATCH 07/26] make overlays near-grabbable. make tablet be an overlay --- interface/src/ui/overlays/Base3DOverlay.cpp | 11 +- interface/src/ui/overlays/Base3DOverlay.h | 3 + interface/src/ui/overlays/Overlays.cpp | 22 +++ interface/src/ui/overlays/Overlays.h | 10 ++ .../system/controllers/handControllerGrab.js | 131 ++++++++++++++---- scripts/system/libraries/WebTablet.js | 23 ++- 6 files changed, 165 insertions(+), 35 deletions(-) diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index ff5177ed3a..cf4291cce7 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -39,7 +39,8 @@ Base3DOverlay::Base3DOverlay(const Base3DOverlay* base3DOverlay) : _isDashedLine(base3DOverlay->_isDashedLine), _ignoreRayIntersection(base3DOverlay->_ignoreRayIntersection), _drawInFront(base3DOverlay->_drawInFront), - _isAA(base3DOverlay->_isAA) + _isAA(base3DOverlay->_isAA), + _isGrabbable(base3DOverlay->_isGrabbable) { setTransform(base3DOverlay->getTransform()); } @@ -125,6 +126,11 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { needRenderItemUpdate = true; } + auto isGrabbable = properties["grabbable"]; + if (isGrabbable.isValid()) { + setIsGrabbable(isGrabbable.toBool()); + } + if (properties["position"].isValid()) { setLocalPosition(vec3FromVariant(properties["position"])); needRenderItemUpdate = true; @@ -227,6 +233,9 @@ QVariant Base3DOverlay::getProperty(const QString& property) { if (property == "drawInFront") { return _drawInFront; } + if (property == "grabbable") { + return _isGrabbable; + } if (property == "parentID") { return getParentID(); } diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index 7906b9d6c0..a1c23e5cd8 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -38,6 +38,7 @@ public: bool getIsSolidLine() const { return !_isDashedLine; } bool getIgnoreRayIntersection() const { return _ignoreRayIntersection; } bool getDrawInFront() const { return _drawInFront; } + bool getIsGrabbable() const { return _isGrabbable; } virtual bool isAA() const { return _isAA; } @@ -47,6 +48,7 @@ public: void setIgnoreRayIntersection(bool value) { _ignoreRayIntersection = value; } void setDrawInFront(bool value) { _drawInFront = value; } void setIsAA(bool value) { _isAA = value; } + void setIsGrabbable(bool value) { _isGrabbable = value; } virtual AABox getBounds() const override = 0; @@ -71,6 +73,7 @@ protected: bool _ignoreRayIntersection; bool _drawInFront; bool _isAA; + bool _isGrabbable { false }; }; #endif // hifi_Base3DOverlay_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index c18d9ddaef..00ffaddff3 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -803,3 +803,25 @@ void Overlays::mouseMoveEvent(QMouseEvent* event) { } } } + +QVector Overlays::findOverlays(const glm::vec3& center, float radius) const { + QVector result; + glm::vec3 penetration; + + QMapIterator i(_overlaysWorld); + i.toBack(); + while (i.hasPrevious()) { + i.previous(); + OverlayID thisID = i.key(); + auto thisOverlay = std::dynamic_pointer_cast(i.value()); + if (thisOverlay && thisOverlay->getVisible() && !thisOverlay->getIgnoreRayIntersection() && thisOverlay->isLoaded()) { + // AABox overlayAABox; + // overlayAABox.findSpherePenetration(center, radius, penetration); + if (glm::distance(thisOverlay->getPosition(), center) <= radius) { + result.append(thisID); + } + } + } + + return result; +} diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 7c6ba34f58..38f62fee48 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -206,6 +206,16 @@ public slots: bool visibleOnly = false, bool collidableOnly = false); + /**jsdoc + * Return a list of overlays with centers within a given distance of a point + * + * @function Overlays.findOverlays + * @param {Vec3} center the point to search from. + * @param {float} radius search radius + * @return {List of Overlays.OverlayID} list of overlays withing the radius + */ + QVector findOverlays(const glm::vec3& center, float radius) const; + /**jsdoc * Check whether an overlay's assets have been loaded. For example, if the * overlay is an "image" overlay, this will indicate whether the its image diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index ea76490b7b..ba22abf426 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -14,7 +14,7 @@ /* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings, Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset, setGrabCommunications, - Menu, HMD */ + Menu, HMD, isInEditMode */ /* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function() { // BEGIN LOCAL_SCOPE @@ -28,7 +28,7 @@ Script.include("/~/system/libraries/controllers.js"); // var WANT_DEBUG = false; -var WANT_DEBUG_STATE = false; +var WANT_DEBUG_STATE = true; var WANT_DEBUG_SEARCH_NAME = null; var FORCE_IGNORE_IK = false; @@ -399,7 +399,7 @@ function entityHasActions(entityID) { function findRayIntersection(pickRay, precise, include, exclude) { var entities = Entities.findRayIntersection(pickRay, precise, include, exclude, true); - var overlays = Overlays.findRayIntersection(pickRay); + var overlays = Overlays.findRayIntersection(pickRay, precise, [], [HMD.tabletID]); if (!overlays.intersects || (entities.intersects && (entities.distance <= overlays.distance))) { return entities; } @@ -853,6 +853,9 @@ function MyController(hand) { }; this.callEntityMethodOnGrabbed = function(entityMethodName) { + if (this.grabbedIsOverlay) { + return; + } var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.grabbedEntity, entityMethodName, args); }; @@ -1175,6 +1178,13 @@ function MyController(hand) { } } + var candidateOverlays = Overlays.findOverlays(worldHandPosition, WEB_DISPLAY_STYLUS_DISTANCE); + for (var j = 0; j < candidateOverlays.length; j++) { + if (this.isTablet(candidateOverlays[j])) { + nearWeb = true; + } + } + if (nearWeb) { this.showStylus(); var rayPickInfo = this.calcRayPickInfo(this.hand); @@ -1622,6 +1632,13 @@ function MyController(hand) { return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE); }); + var candidateOverlays = Overlays.findOverlays(handPosition, /*NEAR_GRAB_RADIUS*/ 0.4); + var grabbableOverlays = candidateOverlays.filter(function(overlayID) { + return Overlays.getProperty(overlayID, "grabbable"); + }); + + print("candidateOverlays: " + candidateOverlays.length + ", grabbableOverlays: " + grabbableOverlays.length); + if (rayPickInfo.entityID) { this.intersectionDistance = rayPickInfo.distance; if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) { @@ -1633,6 +1650,16 @@ function MyController(hand) { this.intersectionDistance = 0; } + if (grabbableOverlays.length > 0) { + this.grabbedEntity = grabbableOverlays[0]; // XXX + this.grabbedIsOverlay = true; + if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) { + this.setState(STATE_NEAR_GRABBING, "near grab overlay '" + + Overlays.getProperty(this.grabbedEntity, "name") + "'"); + return; + } + } + var entity; if (grabbableEntities.length > 0) { // sort by distance @@ -1644,6 +1671,7 @@ function MyController(hand) { entity = grabbableEntities[0]; name = entityPropertiesCache.getProps(entity).name; this.grabbedEntity = entity; + this.grabbedIsOverlay = false; if (this.entityWantsTrigger(entity)) { if (this.triggerSmoothedGrab()) { this.setState(STATE_NEAR_TRIGGER, "near trigger '" + name + "'"); @@ -1654,7 +1682,7 @@ function MyController(hand) { } else { // If near something grabbable, grab it! if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) { - this.setState(STATE_NEAR_GRABBING, "near grab '" + name + "'"); + this.setState(STATE_NEAR_GRABBING, "near grab entity '" + name + "'"); return; } else { // potentialNearGrabEntity = entity; @@ -1678,6 +1706,7 @@ function MyController(hand) { if (this.entityWantsTrigger(entity)) { if (this.triggerSmoothedGrab()) { this.grabbedEntity = entity; + this.grabbedIsOverlay = false; this.setState(STATE_FAR_TRIGGER, "far trigger '" + name + "'"); return; } else { @@ -1686,6 +1715,7 @@ function MyController(hand) { } else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) { if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) { this.grabbedEntity = entity; + this.grabbedIsOverlay = false; this.grabbedDistance = rayPickInfo.distance; this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'"); return; @@ -1766,6 +1796,7 @@ function MyController(hand) { } this.grabbedEntity = entity; + this.grabbedIsOverlay = false; this.setState(STATE_ENTITY_STYLUS_TOUCHING, "begin touching entity '" + name + "'"); return true; @@ -1894,6 +1925,7 @@ function MyController(hand) { if (this.triggerSmoothedGrab() && (!isEditing() || this.isTablet(entity))) { this.grabbedEntity = entity; + this.grabbedIsOverlay = false; this.setState(STATE_ENTITY_LASER_TOUCHING, "begin touching entity '" + name + "'"); return true; } @@ -2282,12 +2314,25 @@ function MyController(hand) { this.grabbedEntity = saveGrabbedID; } - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); - if (FORCE_IGNORE_IK) { + var grabbedProperties; + if (this.grabbedIsOverlay) { + grabbedProperties = { + position: Overlays.getProperty(this.grabbedEntity, "position"), + rotation: Overlays.getProperty(this.grabbedEntity, "rotation"), + parentID: Overlays.getProperty(this.grabbedEntity, "parentID"), + parentJointIndex: Overlays.getProperty(this.grabbedEntity, "parentJointIndex"), + dynamic: false, + shapeType: "none" + }; this.ignoreIK = true; } else { - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); - this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; + grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + if (FORCE_IGNORE_IK) { + this.ignoreIK = true; + } else { + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; + } } var handRotation; @@ -2326,7 +2371,8 @@ function MyController(hand) { this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset); } - var isPhysical = propsArePhysical(grabbedProperties) || entityHasActions(this.grabbedEntity); + var isPhysical = propsArePhysical(grabbedProperties) || + (!this.grabbedIsOverlay && entityHasActions(this.grabbedEntity)); if (isPhysical && this.state == STATE_NEAR_GRABBING && grabbedProperties.parentID === NULL_UUID) { // grab entity via action if (!this.setupHoldAction()) { @@ -2359,7 +2405,12 @@ function MyController(hand) { reparentProps.localPosition = this.offsetPosition; reparentProps.localRotation = this.offsetRotation; } - Entities.editEntity(this.grabbedEntity, reparentProps); + + if (this.grabbedIsOverlay) { + Overlays.editOverlay(this.grabbedEntity, reparentProps); + } else { + Entities.editEntity(this.grabbedEntity, reparentProps); + } if (this.thisHandIsParent(grabbedProperties)) { // this should never happen, but if it does, don't set previous parent to be this hand. @@ -2377,11 +2428,13 @@ function MyController(hand) { })); } - Entities.editEntity(this.grabbedEntity, { - velocity: { x: 0, y: 0, z: 0 }, - angularVelocity: { x: 0, y: 0, z: 0 }, - // dynamic: false - }); + if (!this.grabbedIsOverlay) { + Entities.editEntity(this.grabbedEntity, { + velocity: { x: 0, y: 0, z: 0 }, + angularVelocity: { x: 0, y: 0, z: 0 }, + // dynamic: false + }); + } if (this.state == STATE_NEAR_GRABBING) { this.callEntityMethodOnGrabbed("startNearGrab"); @@ -2464,9 +2517,22 @@ function MyController(hand) { this.prevDropDetected = dropDetected; } - var props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "parentJointIndex", + var props; + if (this.grabbedIsOverlay) { + props = { + localPosition: Overlays.getProperty(this.grabbedEntity, "localPosition"), + parentID: Overlays.getProperty(this.grabbedEntity, "parentID"), + parentJointIndex: Overlays.getProperty(this.grabbedEntity, "parentJointIndex"), + position: Overlays.getProperty(this.grabbedEntity, "position"), + rotation: Overlays.getProperty(this.grabbedEntity, "rotation"), + dimensions: Overlays.getProperty(this.grabbedEntity, "dimensions"), + registrationPoint: { x: 0.5, y: 0.5, z: 0.5 } + }; + } else { + props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "parentJointIndex", "position", "rotation", "dimensions", "registrationPoint"]); + } if (!props.position) { // server may have reset, taking our equipped entity with it. move back to "off" state this.callEntityMethodOnGrabbed("releaseGrab"); @@ -2581,7 +2647,7 @@ function MyController(hand) { }; this.maybeScale = function(props) { - if (!objectScalingEnabled || this.isTablet(this.grabbedEntity)) { + if (!objectScalingEnabled || this.isTablet(this.grabbedEntity) || this.grabbedIsOverlay) { return; } @@ -3006,20 +3072,27 @@ function MyController(hand) { Entities.deleteAction(this.grabbedEntity, this.actionID); } else { // no action, so it's a parenting grab - if (this.previousParentID[this.grabbedEntity] === NULL_UUID) { - Entities.editEntity(this.grabbedEntity, { - parentID: this.previousParentID[this.grabbedEntity], - parentJointIndex: this.previousParentJointIndex[this.grabbedEntity] + if (this.grabbedIsOverlay) { + Overlays.editOverlay(this.grabbedEntity, { + parentID: NULL_UUID, + parentJointIndex: -1 }); - this.ensureDynamic(); } else { - // we're putting this back as a child of some other parent, so zero its velocity - Entities.editEntity(this.grabbedEntity, { - parentID: this.previousParentID[this.grabbedEntity], - parentJointIndex: this.previousParentJointIndex[this.grabbedEntity], - velocity: {x: 0, y: 0, z: 0}, - angularVelocity: {x: 0, y: 0, z: 0} - }); + if (this.previousParentID[this.grabbedEntity] === NULL_UUID) { + Entities.editEntity(this.grabbedEntity, { + parentID: this.previousParentID[this.grabbedEntity], + parentJointIndex: this.previousParentJointIndex[this.grabbedEntity] + }); + this.ensureDynamic(); + } else { + // we're putting this back as a child of some other parent, so zero its velocity + Entities.editEntity(this.grabbedEntity, { + parentID: this.previousParentID[this.grabbedEntity], + parentJointIndex: this.previousParentJointIndex[this.grabbedEntity], + velocity: {x: 0, y: 0, z: 0}, + angularVelocity: {x: 0, y: 0, z: 0} + }); + } } } diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 0990440801..26d6174787 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -7,8 +7,8 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -/* global getControllerWorldLocation, setEntityCustomData, Tablet, WebTablet:true, HMD, Settings, Script, - Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp */ +/* global getControllerWorldLocation, Tablet, WebTablet:true, HMD, Settings, Script, + Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp, Controller, Mat4 */ Script.include(Script.resolvePath("../libraries/utils.js")); Script.include(Script.resolvePath("../libraries/controllers.js")); @@ -110,6 +110,8 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { name: "WebTablet Tablet", type: "Model", modelURL: TABLET_MODEL_PATH, + url: TABLET_MODEL_PATH, // for overlay + grabbable: true, // for overlay userData: JSON.stringify({ "grabbableKey": {"grabbable": true} }), @@ -121,7 +123,14 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { this.calculateTabletAttachmentProperties(hand, true, tabletProperties); this.cleanUpOldTablets(); - this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly); + + // this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly); + // this.tabletIsOverlay = false; + + tabletProperties.parentID = "{00000000-0000-0000-0000-000000000000}"; + // tabletProperties.parentJointIndex = -2; + this.tabletEntityID = Overlays.addOverlay("model", tabletProperties); + this.tabletIsOverlay = true; if (this.webOverlayID) { Overlays.deleteOverlay(this.webOverlayID); @@ -236,7 +245,11 @@ WebTablet.prototype.getOverlayObject = function () { WebTablet.prototype.destroy = function () { Overlays.deleteOverlay(this.webOverlayID); - Entities.deleteEntity(this.tabletEntityID); + if (this.tabletIsOverlay) { + Overlays.deleteOverlay(this.tabletEntityID); + } else { + Entities.deleteEntity(this.tabletEntityID); + } Overlays.deleteOverlay(this.homeButtonEntity); HMD.displayModeChanged.disconnect(this.myOnHmdChanged); @@ -432,7 +445,7 @@ WebTablet.prototype.mousePressEvent = function (event) { tablet.gotoHomeScreen(); this.setHomeButtonTexture(); } - } else if (!HMD.active && (!overlayPickResults.intersects || !overlayPickResults.overlayID === this.webOverlayID)) { + } else if (!HMD.active && (!overlayPickResults.intersects || overlayPickResults.overlayID !== this.webOverlayID)) { this.dragging = true; var invCameraXform = new Xform(Camera.orientation, Camera.position).inv(); this.initialLocalIntersectionPoint = invCameraXform.xformPoint(entityPickResults.intersection); From 273f0130f3819ac13d0335610d4fa3ba6f4ae011 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Feb 2017 17:43:09 -0800 Subject: [PATCH 08/26] fix sphere vs box check for grabbing overlays. fix newly introduced equipping bug. --- interface/src/ui/overlays/Overlays.cpp | 18 +++++++++++------ .../system/controllers/handControllerGrab.js | 20 ++++++++++++++++--- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 00ffaddff3..8d1f757cc0 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -806,18 +806,24 @@ void Overlays::mouseMoveEvent(QMouseEvent* event) { QVector Overlays::findOverlays(const glm::vec3& center, float radius) const { QVector result; - glm::vec3 penetration; QMapIterator i(_overlaysWorld); i.toBack(); while (i.hasPrevious()) { i.previous(); OverlayID thisID = i.key(); - auto thisOverlay = std::dynamic_pointer_cast(i.value()); - if (thisOverlay && thisOverlay->getVisible() && !thisOverlay->getIgnoreRayIntersection() && thisOverlay->isLoaded()) { - // AABox overlayAABox; - // overlayAABox.findSpherePenetration(center, radius, penetration); - if (glm::distance(thisOverlay->getPosition(), center) <= radius) { + auto overlay = std::dynamic_pointer_cast(i.value()); + if (overlay && overlay->getVisible() && !overlay->getIgnoreRayIntersection() && overlay->isLoaded()) { + // get AABox in frame of overlay + glm::vec3 dimensions = overlay->getDimensions(); + glm::vec3 low = dimensions * -0.5f; + AABox overlayFrameBox(low, dimensions); + + Transform overlayToWorldMatrix = overlay->getTransform(); + glm::mat4 worldToOverlayMatrix = glm::inverse(overlayToWorldMatrix.getMatrix()); + glm::vec3 overlayFrameSearchPosition = glm::vec3(worldToOverlayMatrix * glm::vec4(center, 1.0f)); + glm::vec3 penetration; + if (overlayFrameBox.findSpherePenetration(overlayFrameSearchPosition, radius, penetration)) { result.append(thisID); } } diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index ba22abf426..1768fbac57 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -644,6 +644,7 @@ EquipHotspotBuddy.prototype.updateHotspot = function(hotspot, timestamp) { // override default sphere with a user specified model, if it exists. overlayInfoSet.overlays.push(Overlays.addOverlay("model", { + name: "hotspot overlay", url: hotspot.modelURL ? hotspot.modelURL : DEFAULT_SPHERE_MODEL_URL, position: hotspot.worldPosition, rotation: { @@ -906,6 +907,7 @@ function MyController(hand) { if (!this.grabPointSphere) { this.grabPointSphere = Overlays.addOverlay("sphere", { + name: "grabPointSphere", localPosition: getGrabPointSphereOffset(this.handToController()), localRotation: { x: 0, y: 0, z: 0, w: 1 }, dimensions: GRAB_POINT_SPHERE_RADIUS * 2, @@ -936,6 +938,7 @@ function MyController(hand) { var brightColor = colorPow(color, 0.06); if (this.searchSphere === null) { var sphereProperties = { + name: "searchSphere", position: location, rotation: rotation, outerRadius: size * 1.2, @@ -958,7 +961,8 @@ function MyController(hand) { innerAlpha: 1.0, outerAlpha: 0.0, outerRadius: size * 1.2, - visible: true + visible: true, + ignoreRayIntersection: true }); } }; @@ -969,6 +973,7 @@ function MyController(hand) { } var stylusProperties = { + name: "stylus", url: Script.resourcesPath() + "meshes/tablet-stylus-fat.fbx", localPosition: Vec3.sum({ x: 0.0, y: WEB_TOUCH_Y_OFFSET, @@ -1003,6 +1008,7 @@ function MyController(hand) { this.overlayLineOn = function(closePoint, farPoint, color) { if (this.overlayLine === null) { var lineProperties = { + name: "line", glow: 1.0, start: closePoint, end: farPoint, @@ -1621,6 +1627,7 @@ function MyController(hand) { if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && holdEnabled) { this.grabbedHotspot = potentialEquipHotspot; this.grabbedEntity = potentialEquipHotspot.entityID; + this.grabbedIsOverlay = false; this.setState(STATE_HOLD, "equipping '" + entityPropertiesCache.getProps(this.grabbedEntity).name + "'"); return; @@ -1632,7 +1639,7 @@ function MyController(hand) { return _this.entityIsNearGrabbable(entity, handPosition, NEAR_GRAB_MAX_DISTANCE); }); - var candidateOverlays = Overlays.findOverlays(handPosition, /*NEAR_GRAB_RADIUS*/ 0.4); + var candidateOverlays = Overlays.findOverlays(handPosition, NEAR_GRAB_RADIUS); var grabbableOverlays = candidateOverlays.filter(function(overlayID) { return Overlays.getProperty(overlayID, "grabbable"); }); @@ -1651,7 +1658,14 @@ function MyController(hand) { } if (grabbableOverlays.length > 0) { - this.grabbedEntity = grabbableOverlays[0]; // XXX + grabbableOverlays.sort(function(a, b) { + var aPosition = Overlays.getProperty(a, "position"); + var aDistance = Vec3.distance(aPosition, handPosition); + var bPosition = Overlays.getProperty(a, "position"); + var bDistance = Vec3.distance(bPosition, handPosition); + return aDistance - bDistance; + }); + this.grabbedEntity = grabbableOverlays[0]; this.grabbedIsOverlay = true; if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) { this.setState(STATE_NEAR_GRABBING, "near grab overlay '" + From b4be942348fc05bbb8c460c4d193e74ef5dabb67 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Feb 2017 19:18:03 -0800 Subject: [PATCH 09/26] trying to get tablet overlay to show up in the right place --- interface/src/ui/overlays/Base3DOverlay.cpp | 2 + .../system/controllers/handControllerGrab.js | 207 +++++++++--------- scripts/system/libraries/WebTablet.js | 14 +- 3 files changed, 115 insertions(+), 108 deletions(-) diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index cf4291cce7..2aec029041 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -56,6 +56,7 @@ QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& propert // make "position" and "orientation" be relative-to-parent if (result["localPosition"].isValid()) { + result.remove("localPosition"); result["position"] = result["localPosition"]; } else if (result["position"].isValid()) { glm::vec3 localPosition = SpatiallyNestable::worldToLocal(vec3FromVariant(result["position"]), @@ -65,6 +66,7 @@ QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& propert if (result["localOrientation"].isValid()) { result["orientation"] = result["localOrientation"]; + result.remove("localOrientation"); } else if (result["orientation"].isValid()) { glm::quat localOrientation = SpatiallyNestable::worldToLocal(quatFromVariant(result["orientation"]), parentID, parentJointIndex, success); diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index 1768fbac57..373007bc60 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -28,7 +28,7 @@ Script.include("/~/system/libraries/controllers.js"); // var WANT_DEBUG = false; -var WANT_DEBUG_STATE = true; +var WANT_DEBUG_STATE = false; var WANT_DEBUG_SEARCH_NAME = null; var FORCE_IGNORE_IK = false; @@ -777,7 +777,7 @@ function MyController(hand) { }; this.actionID = null; // action this script created... - this.grabbedEntity = null; // on this entity. + this.grabbedThingID = null; // on this entity. this.grabbedOverlay = null; this.state = STATE_OFF; this.pointer = null; // entity-id of line object @@ -858,11 +858,11 @@ function MyController(hand) { return; } var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; - Entities.callEntityMethod(this.grabbedEntity, entityMethodName, args); + Entities.callEntityMethod(this.grabbedThingID, entityMethodName, args); }; this.setState = function(newState, reason) { - if ((isInEditMode() && this.grabbedEntity !== HMD.tabletID )&& (newState !== STATE_OFF && + if ((isInEditMode() && this.grabbedThingID !== HMD.tabletID) && (newState !== STATE_OFF && newState !== STATE_SEARCHING && newState !== STATE_OVERLAY_STYLUS_TOUCHING)) { return; @@ -1597,7 +1597,7 @@ function MyController(hand) { var farSearching = this.triggerSmoothedSqueezed() && (Date.now() - this.searchStartTime > FAR_SEARCH_DELAY); - this.grabbedEntity = null; + this.grabbedThingID = null; this.grabbedOverlay = null; this.isInitialGrab = false; this.preparingHoldRelease = false; @@ -1605,7 +1605,7 @@ function MyController(hand) { this.checkForUnexpectedChildren(); if ((this.triggerSmoothedReleased() && this.secondaryReleased())) { - this.grabbedEntity = null; + this.grabbedThingID = null; this.setState(STATE_OFF, "trigger released"); return; } @@ -1626,9 +1626,9 @@ function MyController(hand) { if (potentialEquipHotspot) { if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && holdEnabled) { this.grabbedHotspot = potentialEquipHotspot; - this.grabbedEntity = potentialEquipHotspot.entityID; + this.grabbedThingID = potentialEquipHotspot.entityID; this.grabbedIsOverlay = false; - this.setState(STATE_HOLD, "equipping '" + entityPropertiesCache.getProps(this.grabbedEntity).name + "'"); + this.setState(STATE_HOLD, "equipping '" + entityPropertiesCache.getProps(this.grabbedThingID).name + "'"); return; } @@ -1644,8 +1644,6 @@ function MyController(hand) { return Overlays.getProperty(overlayID, "grabbable"); }); - print("candidateOverlays: " + candidateOverlays.length + ", grabbableOverlays: " + grabbableOverlays.length); - if (rayPickInfo.entityID) { this.intersectionDistance = rayPickInfo.distance; if (this.entityIsGrabbable(rayPickInfo.entityID) && rayPickInfo.distance < NEAR_GRAB_PICK_RADIUS) { @@ -1665,11 +1663,11 @@ function MyController(hand) { var bDistance = Vec3.distance(bPosition, handPosition); return aDistance - bDistance; }); - this.grabbedEntity = grabbableOverlays[0]; + this.grabbedThingID = grabbableOverlays[0]; this.grabbedIsOverlay = true; if ((this.triggerSmoothedGrab() || this.secondarySqueezed()) && nearGrabEnabled) { this.setState(STATE_NEAR_GRABBING, "near grab overlay '" + - Overlays.getProperty(this.grabbedEntity, "name") + "'"); + Overlays.getProperty(this.grabbedThingID, "name") + "'"); return; } } @@ -1684,7 +1682,7 @@ function MyController(hand) { }); entity = grabbableEntities[0]; name = entityPropertiesCache.getProps(entity).name; - this.grabbedEntity = entity; + this.grabbedThingID = entity; this.grabbedIsOverlay = false; if (this.entityWantsTrigger(entity)) { if (this.triggerSmoothedGrab()) { @@ -1719,7 +1717,7 @@ function MyController(hand) { name = entityPropertiesCache.getProps(entity).name; if (this.entityWantsTrigger(entity)) { if (this.triggerSmoothedGrab()) { - this.grabbedEntity = entity; + this.grabbedThingID = entity; this.grabbedIsOverlay = false; this.setState(STATE_FAR_TRIGGER, "far trigger '" + name + "'"); return; @@ -1728,7 +1726,7 @@ function MyController(hand) { } } else if (this.entityIsDistanceGrabbable(rayPickInfo.entityID, handPosition)) { if (this.triggerSmoothedGrab() && !isEditing() && farGrabEnabled && farSearching) { - this.grabbedEntity = entity; + this.grabbedThingID = entity; this.grabbedIsOverlay = false; this.grabbedDistance = rayPickInfo.distance; this.setState(STATE_DISTANCE_HOLDING, "distance hold '" + name + "'"); @@ -1809,7 +1807,7 @@ function MyController(hand) { Entities.sendHoverOverEntity(entity, pointerEvent); } - this.grabbedEntity = entity; + this.grabbedThingID = entity; this.grabbedIsOverlay = false; this.setState(STATE_ENTITY_STYLUS_TOUCHING, "begin touching entity '" + name + "'"); return true; @@ -1938,7 +1936,7 @@ function MyController(hand) { } if (this.triggerSmoothedGrab() && (!isEditing() || this.isTablet(entity))) { - this.grabbedEntity = entity; + this.grabbedThingID = entity; this.grabbedIsOverlay = false; this.setState(STATE_ENTITY_LASER_TOUCHING, "begin touching entity '" + name + "'"); return true; @@ -2050,7 +2048,7 @@ function MyController(hand) { var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES); var now = Date.now(); // add the action and initialize some variables @@ -2080,7 +2078,7 @@ function MyController(hand) { var timeScale = this.distanceGrabTimescale(this.mass, distanceToObject); this.actionID = NULL_UUID; - this.actionID = Entities.addAction("spring", this.grabbedEntity, { + this.actionID = Entities.addAction("spring", this.grabbedThingID, { targetPosition: this.currentObjectPosition, linearTimeScale: timeScale, targetRotation: this.currentObjectRotation, @@ -2105,12 +2103,12 @@ function MyController(hand) { this.ensureDynamic = function() { // if we distance hold something and keep it very still before releasing it, it ends up // non-dynamic in bullet. If it's too still, give it a little bounce so it will fall. - var props = Entities.getEntityProperties(this.grabbedEntity, ["velocity", "dynamic", "parentID"]); + var props = Entities.getEntityProperties(this.grabbedThingID, ["velocity", "dynamic", "parentID"]); if (props.dynamic && props.parentID == NULL_UUID) { var velocity = props.velocity; if (Vec3.length(velocity) < 0.05) { // see EntityMotionState.cpp DYNAMIC_LINEAR_VELOCITY_THRESHOLD velocity = { x: 0.0, y: 0.2, z:0.0 }; - Entities.editEntity(this.grabbedEntity, { velocity: velocity }); + Entities.editEntity(this.grabbedThingID, { velocity: velocity }); } } }; @@ -2132,7 +2130,7 @@ function MyController(hand) { var worldToSensorMat = Mat4.inverse(MyAvatar.getSensorToWorldMatrix()); var roomControllerPosition = Mat4.transformPoint(worldToSensorMat, worldControllerPosition); - var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + var grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES); var now = Date.now(); var deltaObjectTime = (now - this.currentObjectTime) / MSECS_PER_SEC; // convert to seconds @@ -2187,7 +2185,7 @@ function MyController(hand) { newTargetPosition = Vec3.sum(newTargetPosition, this.offsetPosition); var objectToAvatar = Vec3.subtract(this.currentObjectPosition, MyAvatar.position); - var handControllerData = getEntityCustomData('handControllerKey', this.grabbedEntity, defaultMoveWithHeadData); + var handControllerData = getEntityCustomData('handControllerKey', this.grabbedThingID, defaultMoveWithHeadData); if (handControllerData.disableMoveWithHead !== true) { // mix in head motion if (MOVE_WITH_HEAD) { @@ -2216,7 +2214,7 @@ function MyController(hand) { this.overlayLineOn(rayPickInfo.searchRay.origin, Vec3.subtract(grabbedProperties.position, this.offsetPosition), COLORS_GRAB_DISTANCE_HOLD); var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition)); - var success = Entities.updateAction(this.grabbedEntity, this.actionID, { + var success = Entities.updateAction(this.grabbedThingID, this.actionID, { targetPosition: newTargetPosition, linearTimeScale: this.distanceGrabTimescale(this.mass, distanceToObject), targetRotation: this.currentObjectRotation, @@ -2233,7 +2231,7 @@ function MyController(hand) { }; this.setupHoldAction = function() { - this.actionID = Entities.addAction("hold", this.grabbedEntity, { + this.actionID = Entities.addAction("hold", this.grabbedThingID, { hand: this.hand === RIGHT_HAND ? "right" : "left", timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, relativePosition: this.offsetPosition, @@ -2323,28 +2321,28 @@ function MyController(hand) { Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); if (this.entityActivated) { - var saveGrabbedID = this.grabbedEntity; + var saveGrabbedID = this.grabbedThingID; this.release(); - this.grabbedEntity = saveGrabbedID; + this.grabbedThingID = saveGrabbedID; } var grabbedProperties; if (this.grabbedIsOverlay) { grabbedProperties = { - position: Overlays.getProperty(this.grabbedEntity, "position"), - rotation: Overlays.getProperty(this.grabbedEntity, "rotation"), - parentID: Overlays.getProperty(this.grabbedEntity, "parentID"), - parentJointIndex: Overlays.getProperty(this.grabbedEntity, "parentJointIndex"), + position: Overlays.getProperty(this.grabbedThingID, "position"), + rotation: Overlays.getProperty(this.grabbedThingID, "rotation"), + parentID: Overlays.getProperty(this.grabbedThingID, "parentID"), + parentJointIndex: Overlays.getProperty(this.grabbedThingID, "parentJointIndex"), dynamic: false, shapeType: "none" }; this.ignoreIK = true; } else { - grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES); + grabbedProperties = Entities.getEntityProperties(this.grabbedThingID, GRABBABLE_PROPERTIES); if (FORCE_IGNORE_IK) { this.ignoreIK = true; } else { - var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA); + var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedThingID, DEFAULT_GRABBABLE_DATA); this.ignoreIK = (grabbableData.ignoreIK !== undefined) ? grabbableData.ignoreIK : true; } } @@ -2386,7 +2384,7 @@ function MyController(hand) { } var isPhysical = propsArePhysical(grabbedProperties) || - (!this.grabbedIsOverlay && entityHasActions(this.grabbedEntity)); + (!this.grabbedIsOverlay && entityHasActions(this.grabbedThingID)); if (isPhysical && this.state == STATE_NEAR_GRABBING && grabbedProperties.parentID === NULL_UUID) { // grab entity via action if (!this.setupHoldAction()) { @@ -2394,7 +2392,7 @@ function MyController(hand) { } Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ action: 'grab', - grabbedEntity: this.grabbedEntity, + grabbedEntity: this.grabbedThingID, joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); } else { @@ -2421,29 +2419,29 @@ function MyController(hand) { } if (this.grabbedIsOverlay) { - Overlays.editOverlay(this.grabbedEntity, reparentProps); + Overlays.editOverlay(this.grabbedThingID, reparentProps); } else { - Entities.editEntity(this.grabbedEntity, reparentProps); + Entities.editEntity(this.grabbedThingID, reparentProps); } if (this.thisHandIsParent(grabbedProperties)) { // this should never happen, but if it does, don't set previous parent to be this hand. - // this.previousParentID[this.grabbedEntity] = NULL; - // this.previousParentJointIndex[this.grabbedEntity] = -1; + // this.previousParentID[this.grabbedThingID] = NULL; + // this.previousParentJointIndex[this.grabbedThingID] = -1; } else { - this.previousParentID[this.grabbedEntity] = grabbedProperties.parentID; - this.previousParentJointIndex[this.grabbedEntity] = grabbedProperties.parentJointIndex; + this.previousParentID[this.grabbedThingID] = grabbedProperties.parentID; + this.previousParentJointIndex[this.grabbedThingID] = grabbedProperties.parentJointIndex; } Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ action: 'equip', - grabbedEntity: this.grabbedEntity, + grabbedEntity: this.grabbedThingID, joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); } if (!this.grabbedIsOverlay) { - Entities.editEntity(this.grabbedEntity, { + Entities.editEntity(this.grabbedThingID, { velocity: { x: 0, y: 0, z: 0 }, angularVelocity: { x: 0, y: 0, z: 0 }, // dynamic: false @@ -2514,17 +2512,17 @@ function MyController(hand) { if (dropDetected && !this.waitForTriggerRelease && this.triggerSmoothedGrab()) { // store the offset attach points into preferences. - if (USE_ATTACH_POINT_SETTINGS && this.grabbedHotspot && this.grabbedEntity) { - var prefprops = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "localRotation"]); + if (USE_ATTACH_POINT_SETTINGS && this.grabbedHotspot && this.grabbedThingID) { + var prefprops = Entities.getEntityProperties(this.grabbedThingID, ["localPosition", "localRotation"]); if (prefprops && prefprops.localPosition && prefprops.localRotation) { storeAttachPointForHotspotInSettings(this.grabbedHotspot, this.hand, prefprops.localPosition, prefprops.localRotation); } } - var grabbedEntity = this.grabbedEntity; + var grabbedEntity = this.grabbedThingID; this.release(); - this.grabbedEntity = grabbedEntity; + this.grabbedThingID = grabbedEntity; this.setState(STATE_NEAR_GRABBING, "drop gesture detected"); return; } @@ -2534,16 +2532,16 @@ function MyController(hand) { var props; if (this.grabbedIsOverlay) { props = { - localPosition: Overlays.getProperty(this.grabbedEntity, "localPosition"), - parentID: Overlays.getProperty(this.grabbedEntity, "parentID"), - parentJointIndex: Overlays.getProperty(this.grabbedEntity, "parentJointIndex"), - position: Overlays.getProperty(this.grabbedEntity, "position"), - rotation: Overlays.getProperty(this.grabbedEntity, "rotation"), - dimensions: Overlays.getProperty(this.grabbedEntity, "dimensions"), + localPosition: Overlays.getProperty(this.grabbedThingID, "localPosition"), + parentID: Overlays.getProperty(this.grabbedThingID, "parentID"), + parentJointIndex: Overlays.getProperty(this.grabbedThingID, "parentJointIndex"), + position: Overlays.getProperty(this.grabbedThingID, "position"), + rotation: Overlays.getProperty(this.grabbedThingID, "rotation"), + dimensions: Overlays.getProperty(this.grabbedThingID, "dimensions"), registrationPoint: { x: 0.5, y: 0.5, z: 0.5 } }; } else { - props = Entities.getEntityProperties(this.grabbedEntity, ["localPosition", "parentID", "parentJointIndex", + props = Entities.getEntityProperties(this.grabbedThingID, ["localPosition", "parentID", "parentJointIndex", "position", "rotation", "dimensions", "registrationPoint"]); } @@ -2558,7 +2556,7 @@ function MyController(hand) { // someone took it from us or otherwise edited the parentID. end the grab. We don't do this // for equipped things so that they can be adjusted while equipped. this.callEntityMethodOnGrabbed("releaseGrab"); - this.grabbedEntity = null; + this.grabbedThingID = null; this.setState(STATE_OFF, "someone took it"); return; } @@ -2640,7 +2638,7 @@ function MyController(hand) { if (this.actionID && this.actionTimeout - now < ACTION_TTL_REFRESH * MSECS_PER_SEC) { // if less than a 5 seconds left, refresh the actions ttl - var success = Entities.updateAction(this.grabbedEntity, this.actionID, { + var success = Entities.updateAction(this.grabbedThingID, this.actionID, { hand: this.hand === RIGHT_HAND ? "right" : "left", timeScale: NEAR_GRABBING_ACTION_TIMEFRAME, relativePosition: this.offsetPosition, @@ -2654,14 +2652,14 @@ function MyController(hand) { this.actionTimeout = now + (ACTION_TTL * MSECS_PER_SEC); } else { print("continueNearGrabbing -- updateAction failed"); - Entities.deleteAction(this.grabbedEntity, this.actionID); + Entities.deleteAction(this.grabbedThingID, this.actionID); this.setupHoldAction(); } } }; this.maybeScale = function(props) { - if (!objectScalingEnabled || this.isTablet(this.grabbedEntity) || this.grabbedIsOverlay) { + if (!objectScalingEnabled || this.isTablet(this.grabbedThingID) || this.grabbedIsOverlay) { return; } @@ -2683,7 +2681,7 @@ function MyController(hand) { this.getOtherHandController().getHandPosition())); var currentRescale = scalingCurrentDistance / this.scalingStartDistance; var newDimensions = Vec3.multiply(currentRescale, this.scalingStartDimensions); - Entities.editEntity(this.grabbedEntity, { dimensions: newDimensions }); + Entities.editEntity(this.grabbedThingID, { dimensions: newDimensions }); } }; @@ -2734,7 +2732,7 @@ function MyController(hand) { this.nearTrigger = function(deltaTime, timestamp) { if (this.triggerSmoothedReleased()) { this.callEntityMethodOnGrabbed("stopNearTrigger"); - this.grabbedEntity = null; + this.grabbedThingID = null; this.setState(STATE_OFF, "trigger released"); return; } @@ -2744,7 +2742,7 @@ function MyController(hand) { this.farTrigger = function(deltaTime, timestamp) { if (this.triggerSmoothedReleased()) { this.callEntityMethodOnGrabbed("stopFarTrigger"); - this.grabbedEntity = null; + this.grabbedThingID = null; this.setState(STATE_OFF, "trigger released"); return; } @@ -2759,9 +2757,9 @@ function MyController(hand) { var intersection = findRayIntersection(pickRay, true, [], [], true); if (intersection.accurate || intersection.overlayID) { this.lastPickTime = now; - if (intersection.entityID != this.grabbedEntity) { + if (intersection.entityID != this.grabbedThingID) { this.callEntityMethodOnGrabbed("stopFarTrigger"); - this.grabbedEntity = null; + this.grabbedThingID = null; this.setState(STATE_OFF, "laser moved off of entity"); return; } @@ -2783,13 +2781,13 @@ function MyController(hand) { this.entityTouchingEnter = function() { // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { var pointerEvent = { type: "Press", id: this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(this.grabbedEntity, intersectInfo.point), + pos2D: projectOntoEntityXYPlane(this.grabbedThingID, intersectInfo.point), pos3D: intersectInfo.point, normal: intersectInfo.normal, direction: intersectInfo.searchRay.direction, @@ -2797,8 +2795,8 @@ function MyController(hand) { isPrimaryHeld: true }; - Entities.sendMousePressOnEntity(this.grabbedEntity, pointerEvent); - Entities.sendClickDownOnEntity(this.grabbedEntity, pointerEvent); + Entities.sendMousePressOnEntity(this.grabbedThingID, pointerEvent); + Entities.sendClickDownOnEntity(this.grabbedThingID, pointerEvent); this.touchingEnterTimer = 0; this.touchingEnterPointerEvent = pointerEvent; @@ -2820,7 +2818,7 @@ function MyController(hand) { this.entityTouchingExit = function() { // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { var pointerEvent; @@ -2828,7 +2826,7 @@ function MyController(hand) { pointerEvent = { type: "Release", id: this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(this.grabbedEntity, intersectInfo.point), + pos2D: projectOntoEntityXYPlane(this.grabbedThingID, intersectInfo.point), pos3D: intersectInfo.point, normal: intersectInfo.normal, direction: intersectInfo.searchRay.direction, @@ -2841,11 +2839,11 @@ function MyController(hand) { pointerEvent.isPrimaryHeld = false; } - Entities.sendMouseReleaseOnEntity(this.grabbedEntity, pointerEvent); - Entities.sendClickReleaseOnEntity(this.grabbedEntity, pointerEvent); - Entities.sendHoverLeaveEntity(this.grabbedEntity, pointerEvent); + Entities.sendMouseReleaseOnEntity(this.grabbedThingID, pointerEvent); + Entities.sendClickReleaseOnEntity(this.grabbedThingID, pointerEvent); + Entities.sendHoverLeaveEntity(this.grabbedThingID, pointerEvent); } - this.grabbedEntity = null; + this.grabbedThingID = null; this.grabbedOverlay = null; }; @@ -2853,7 +2851,7 @@ function MyController(hand) { this.touchingEnterTimer += dt; - entityPropertiesCache.addEntity(this.grabbedEntity); + entityPropertiesCache.addEntity(this.grabbedThingID); if (this.state == STATE_ENTITY_LASER_TOUCHING && !this.triggerSmoothedGrab()) { this.setState(STATE_OFF, "released trigger"); @@ -2861,7 +2859,7 @@ function MyController(hand) { } // test for intersection between controller laser and web entity plane. - var intersectInfo = handLaserIntersectEntity(this.grabbedEntity, + var intersectInfo = handLaserIntersectEntity(this.grabbedThingID, getControllerWorldLocation(this.handToController(), true)); if (intersectInfo) { @@ -2871,15 +2869,15 @@ function MyController(hand) { return; } - if (Entities.keyboardFocusEntity != this.grabbedEntity) { + if (Entities.keyboardFocusEntity != this.grabbedThingID) { Overlays.keyboardFocusOverlay = 0; - Entities.keyboardFocusEntity = this.grabbedEntity; + Entities.keyboardFocusEntity = this.grabbedThingID; } var pointerEvent = { type: "Move", id: this.hand + 1, // 0 is reserved for hardware mouse - pos2D: projectOntoEntityXYPlane(this.grabbedEntity, intersectInfo.point), + pos2D: projectOntoEntityXYPlane(this.grabbedThingID, intersectInfo.point), pos3D: intersectInfo.point, normal: intersectInfo.normal, direction: intersectInfo.searchRay.direction, @@ -2890,8 +2888,8 @@ function MyController(hand) { var POINTER_PRESS_TO_MOVE_DELAY = 0.25; // seconds if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY || Vec3.distance(intersectInfo.point, this.touchingEnterPointerEvent.pos3D) > this.deadspotRadius) { - Entities.sendMouseMoveOnEntity(this.grabbedEntity, pointerEvent); - Entities.sendHoldingClickOnEntity(this.grabbedEntity, pointerEvent); + Entities.sendMouseMoveOnEntity(this.grabbedThingID, pointerEvent); + Entities.sendHoldingClickOnEntity(this.grabbedThingID, pointerEvent); this.deadspotExpired = true; } @@ -2901,7 +2899,7 @@ function MyController(hand) { } Reticle.setVisible(false); } else { - this.grabbedEntity = null; + this.grabbedThingID = null; this.setState(STATE_OFF, "grabbed entity was destroyed"); return; } @@ -2986,7 +2984,7 @@ function MyController(hand) { Overlays.sendMouseReleaseOnOverlay(this.grabbedOverlay, pointerEvent); Overlays.sendHoverLeaveOverlay(this.grabbedOverlay, pointerEvent); } - this.grabbedEntity = null; + this.grabbedThingID = null; this.grabbedOverlay = null; }; @@ -3009,7 +3007,7 @@ function MyController(hand) { if (this.state == STATE_OVERLAY_STYLUS_TOUCHING && intersectInfo.distance > WEB_STYLUS_LENGTH / 2.0 + WEB_TOUCH_Y_OFFSET + WEB_TOUCH_Y_TOUCH_DEADZONE_SIZE) { - this.grabbedEntity = null; + this.grabbedThingID = null; this.setState(STATE_OFF, "pulled away from overlay"); return; } @@ -3066,7 +3064,7 @@ function MyController(hand) { } Reticle.setVisible(false); } else { - this.grabbedEntity = null; + this.grabbedThingID = null; this.setState(STATE_OFF, "grabbed overlay was destroyed"); return; } @@ -3075,7 +3073,7 @@ function MyController(hand) { this.release = function() { this.turnOffVisualizations(); - if (this.grabbedEntity !== null) { + if (this.grabbedThingID !== null) { if (this.state === STATE_HOLD) { this.callEntityMethodOnGrabbed("releaseEquip"); } @@ -3083,26 +3081,33 @@ function MyController(hand) { // Make a small release haptic pulse if we really were holding something Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand); if (this.actionID !== null) { - Entities.deleteAction(this.grabbedEntity, this.actionID); + Entities.deleteAction(this.grabbedThingID, this.actionID); } else { // no action, so it's a parenting grab - if (this.grabbedIsOverlay) { - Overlays.editOverlay(this.grabbedEntity, { - parentID: NULL_UUID, - parentJointIndex: -1 - }); - } else { - if (this.previousParentID[this.grabbedEntity] === NULL_UUID) { - Entities.editEntity(this.grabbedEntity, { - parentID: this.previousParentID[this.grabbedEntity], - parentJointIndex: this.previousParentJointIndex[this.grabbedEntity] + if (this.previousParentID[this.grabbedThingID] === NULL_UUID) { + if (this.grabbedIsOverlay) { + Overlays.editOverlay(this.grabbedThingID, { + parentID: NULL_UUID, + parentJointIndex: -1 + }); + } else { + Entities.editEntity(this.grabbedThingID, { + parentID: this.previousParentID[this.grabbedThingID], + parentJointIndex: this.previousParentJointIndex[this.grabbedThingID] }); this.ensureDynamic(); + } + } else { + if (this.grabbedIsOverlay) { + Overlays.editOverlay(this.grabbedThingID, { + parentID: this.previousParentID[this.grabbedThingID], + parentJointIndex: this.previousParentJointIndex[this.grabbedThingID], + }); } else { // we're putting this back as a child of some other parent, so zero its velocity - Entities.editEntity(this.grabbedEntity, { - parentID: this.previousParentID[this.grabbedEntity], - parentJointIndex: this.previousParentJointIndex[this.grabbedEntity], + Entities.editEntity(this.grabbedThingID, { + parentID: this.previousParentID[this.grabbedThingID], + parentJointIndex: this.previousParentJointIndex[this.grabbedThingID], velocity: {x: 0, y: 0, z: 0}, angularVelocity: {x: 0, y: 0, z: 0} }); @@ -3112,13 +3117,13 @@ function MyController(hand) { Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({ action: 'release', - grabbedEntity: this.grabbedEntity, + grabbedEntity: this.grabbedThingID, joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand" })); } this.actionID = null; - this.grabbedEntity = null; + this.grabbedThingID = null; this.grabbedOverlay = null; this.grabbedHotspot = null; diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index db7d1ac55f..d9d000ac82 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -130,13 +130,13 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { this.cleanUpOldTablets(); - // this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly); - // this.tabletIsOverlay = false; - - tabletProperties.parentID = "{00000000-0000-0000-0000-000000000000}"; - // tabletProperties.parentJointIndex = -2; - this.tabletEntityID = Overlays.addOverlay("model", tabletProperties); - this.tabletIsOverlay = true; + if (true || Settings.getValue("tabletVisibleToOthers")) { + this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly); + this.tabletIsOverlay = false; + } else { + this.tabletEntityID = Overlays.addOverlay("model", tabletProperties); + this.tabletIsOverlay = true; + } if (this.webOverlayID) { Overlays.deleteOverlay(this.webOverlayID); From 84f95e677675d260154bddd281d7dede1d96c8d9 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Feb 2017 19:18:42 -0800 Subject: [PATCH 10/26] oops --- scripts/system/libraries/WebTablet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index d9d000ac82..746f0b5680 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -130,7 +130,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { this.cleanUpOldTablets(); - if (true || Settings.getValue("tabletVisibleToOthers")) { + if (Settings.getValue("tabletVisibleToOthers")) { this.tabletEntityID = Entities.addEntity(tabletProperties, clientOnly); this.tabletIsOverlay = false; } else { From 1b26c3469f703ba113da165b1bb033dfccbd41b1 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Feb 2017 20:39:34 -0800 Subject: [PATCH 11/26] fix signed/unsigned joint index problem --- interface/src/avatar/Avatar.cpp | 8 ++++++++ interface/src/avatar/MyAvatar.cpp | 8 ++++++++ interface/src/ui/overlays/Base3DOverlay.cpp | 12 +++++++----- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ed8f083a41..74b60bee13 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -938,6 +938,10 @@ glm::vec3 Avatar::getDefaultJointTranslation(int index) const { } glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const { + if (index < 0) { + index += 65536; + } + switch(index) { case SENSOR_TO_WORLD_MATRIX_INDEX: { glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix(); @@ -974,6 +978,10 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const { } glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const { + if (index < 0) { + index += 65536; + } + switch(index) { case SENSOR_TO_WORLD_MATRIX_INDEX: { glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4f24b46ece..47297c6bdb 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2394,6 +2394,10 @@ glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& c } glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const { + if (index < 0) { + index += 65536; + } + switch (index) { case CONTROLLER_LEFTHAND_INDEX: { return getLeftHandControllerPoseInAvatarFrame().getRotation(); @@ -2427,6 +2431,10 @@ glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const { } glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const { + if (index < 0) { + index += 65536; + } + switch (index) { case CONTROLLER_LEFTHAND_INDEX: { return getLeftHandControllerPoseInAvatarFrame().getTranslation(); diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 2aec029041..10378ff858 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -56,21 +56,23 @@ QVariantMap convertOverlayLocationFromScriptSemantics(const QVariantMap& propert // make "position" and "orientation" be relative-to-parent if (result["localPosition"].isValid()) { - result.remove("localPosition"); result["position"] = result["localPosition"]; } else if (result["position"].isValid()) { glm::vec3 localPosition = SpatiallyNestable::worldToLocal(vec3FromVariant(result["position"]), parentID, parentJointIndex, success); - result["position"] = vec3toVariant(localPosition); + if (success) { + result["position"] = vec3toVariant(localPosition); + } } if (result["localOrientation"].isValid()) { result["orientation"] = result["localOrientation"]; - result.remove("localOrientation"); } else if (result["orientation"].isValid()) { glm::quat localOrientation = SpatiallyNestable::worldToLocal(quatFromVariant(result["orientation"]), - parentID, parentJointIndex, success); - result["orientation"] = quatToVariant(localOrientation); + parentID, parentJointIndex, success); + if (success) { + result["orientation"] = quatToVariant(localOrientation); + } } return result; From 41ef7b8dbb03acfc6dfc7a22b2b818e58978fca3 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 22 Feb 2017 21:13:42 -0800 Subject: [PATCH 12/26] add setting to control if tablet is an entity or overlay --- interface/src/Application.cpp | 7 +++++++ interface/src/Application.h | 3 +++ interface/src/ui/PreferencesDialog.cpp | 6 +++++- 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3de7906f56..758953ade4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -548,6 +548,7 @@ const float DEFAULT_HMD_TABLET_SCALE_PERCENT = 100.0f; const float DEFAULT_DESKTOP_TABLET_SCALE_PERCENT = 75.0f; const bool DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR = true; const bool DEFAULT_HMD_TABLET_BECOMES_TOOLBAR = false; +const bool DEFAULT_TABLET_VISIBLE_TO_OTHERS = false; Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bool runServer, QString runServerPathOption) : QApplication(argc, argv), @@ -570,6 +571,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _desktopTabletScale("desktopTabletScale", DEFAULT_DESKTOP_TABLET_SCALE_PERCENT), _desktopTabletBecomesToolbarSetting("desktopTabletBecomesToolbar", DEFAULT_DESKTOP_TABLET_BECOMES_TOOLBAR), _hmdTabletBecomesToolbarSetting("hmdTabletBecomesToolbar", DEFAULT_HMD_TABLET_BECOMES_TOOLBAR), + _tabletVisibleToOthersSetting("tabletVisibleToOthers", DEFAULT_TABLET_VISIBLE_TO_OTHERS), _constrainToolbarPosition("toolbar/constrainToolbarToCenterX", true), _scaleMirror(1.0f), _rotateMirror(0.0f), @@ -2348,6 +2350,11 @@ void Application::setHmdTabletBecomesToolbarSetting(bool value) { updateSystemTabletMode(); } +void Application::setTabletVisibleToOthersSetting(bool value) { + _tabletVisibleToOthersSetting.set(value); + updateSystemTabletMode(); +} + void Application::setSettingConstrainToolbarPosition(bool setting) { _constrainToolbarPosition.set(setting); DependencyManager::get()->setConstrainToolbarToCenterX(setting); diff --git a/interface/src/Application.h b/interface/src/Application.h index 662523ce1d..60001496f9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -218,6 +218,8 @@ public: void setDesktopTabletBecomesToolbarSetting(bool value); bool getHmdTabletBecomesToolbarSetting() { return _hmdTabletBecomesToolbarSetting.get(); } void setHmdTabletBecomesToolbarSetting(bool value); + bool getTabletVisibleToOthersSetting() { return _tabletVisibleToOthersSetting.get(); } + void setTabletVisibleToOthersSetting(bool value); float getSettingConstrainToolbarPosition() { return _constrainToolbarPosition.get(); } void setSettingConstrainToolbarPosition(bool setting); @@ -561,6 +563,7 @@ private: Setting::Handle _desktopTabletScale; Setting::Handle _desktopTabletBecomesToolbarSetting; Setting::Handle _hmdTabletBecomesToolbarSetting; + Setting::Handle _tabletVisibleToOthersSetting; Setting::Handle _constrainToolbarPosition; float _scaleMirror; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index dd05d5c0e1..d291510556 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -102,7 +102,11 @@ void setupPreferences() { auto setter = [](bool value) { qApp->setHmdTabletBecomesToolbarSetting(value); }; preferences->addPreference(new CheckPreference(UI_CATEGORY, "HMD Tablet Becomes Toolbar", getter, setter)); } - + { + auto getter = []()->bool { return qApp->getTabletVisibleToOthersSetting(); }; + auto setter = [](bool value) { qApp->setTabletVisibleToOthersSetting(value); }; + preferences->addPreference(new CheckPreference(UI_CATEGORY, "Tablet Is Visible To Others", getter, setter)); + } // Snapshots static const QString SNAPSHOTS { "Snapshots" }; { From 37004e43471036c37a06e5ad0cf8dd6e980f8f20 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Feb 2017 08:11:31 -0800 Subject: [PATCH 13/26] steps toward making mouse work on tablet --- interface/src/Application.cpp | 7 +++- interface/src/Application.h | 1 + interface/src/avatar/MyAvatar.cpp | 2 +- .../src/scripting/HMDScriptingInterface.h | 12 +++---- scripts/system/libraries/WebTablet.js | 32 +++++++++++++------ scripts/system/tablet-ui/tabletUI.js | 5 ++- 6 files changed, 40 insertions(+), 19 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 758953ade4..02291cc619 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -6909,5 +6909,10 @@ OverlayID Application::getTabletScreenID() const { OverlayID Application::getTabletHomeButtonID() const { auto HMD = DependencyManager::get(); - return HMD->getCurrentHomeButtonUUID(); + return HMD->getCurrentHomeButtonID(); +} + +QUuid Application::getTabletFrameID() const { + auto HMD = DependencyManager::get(); + return HMD->getCurrentTabletFrameID(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 60001496f9..13c1458aee 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -302,6 +302,7 @@ public: OverlayID getTabletScreenID() const; OverlayID getTabletHomeButtonID() const; + QUuid getTabletFrameID() const; // may be an entity or an overlay signals: void svoImportRequested(const QString& url); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 47297c6bdb..2f5a0edd9e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -807,7 +807,7 @@ void MyAvatar::saveData() { auto hmdInterface = DependencyManager::get(); _avatarEntitiesLock.withReadLock([&] { for (auto entityID : _avatarEntityData.keys()) { - if (hmdInterface->getCurrentTabletUIID() == entityID) { + if (hmdInterface->getCurrentTabletFrameID() == entityID) { // don't persist the tablet between domains / sessions continue; } diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index 463a21ded8..d895d5da4c 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -29,8 +29,8 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen Q_PROPERTY(glm::quat orientation READ getOrientation) Q_PROPERTY(bool mounted READ isMounted) Q_PROPERTY(bool showTablet READ getShouldShowTablet) - Q_PROPERTY(QUuid tabletID READ getCurrentTabletUIID WRITE setCurrentTabletUIID) - Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonUUID WRITE setCurrentHomeButtonUUID) + Q_PROPERTY(QUuid tabletID READ getCurrentTabletFrameID WRITE setCurrentTabletFrameID) + Q_PROPERTY(QUuid homeButtonID READ getCurrentHomeButtonID WRITE setCurrentHomeButtonID) Q_PROPERTY(QUuid tabletScreenID READ getCurrentTabletScreenID WRITE setCurrentTabletScreenID) public: @@ -90,11 +90,11 @@ public: void setShouldShowTablet(bool value) { _showTablet = value; } bool getShouldShowTablet() const { return _showTablet; } - void setCurrentTabletUIID(QUuid tabletID) { _tabletUIID = tabletID; } - QUuid getCurrentTabletUIID() const { return _tabletUIID; } + void setCurrentTabletFrameID(QUuid tabletID) { _tabletUIID = tabletID; } + QUuid getCurrentTabletFrameID() const { return _tabletUIID; } - void setCurrentHomeButtonUUID(QUuid homeButtonID) { _homeButtonID = homeButtonID; } - QUuid getCurrentHomeButtonUUID() const { return _homeButtonID; } + void setCurrentHomeButtonID(QUuid homeButtonID) { _homeButtonID = homeButtonID; } + QUuid getCurrentHomeButtonID() const { return _homeButtonID; } void setCurrentTabletScreenID(QUuid tabletID) { _tabletScreenID = tabletID; } QUuid getCurrentTabletScreenID() const { return _tabletScreenID; } diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 746f0b5680..26b6f82520 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -161,7 +161,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { }); var HOME_BUTTON_Y_OFFSET = (this.height / 2) - 0.035; - this.homeButtonEntity = Overlays.addOverlay("sphere", { + this.homeButtonID = Overlays.addOverlay("sphere", { name: "homeButton", localPosition: {x: 0.0, y: -HOME_BUTTON_Y_OFFSET, z: -0.01}, localRotation: Quat.angleAxis(0, Y_AXIS), @@ -174,7 +174,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { }); this.receive = function (channel, senderID, senderUUID, localOnly) { - if (_this.homeButtonEntity == senderID) { + if (_this.homeButtonID == senderID) { var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var onHomeScreen = tablet.onHomeScreen(); if (onHomeScreen) { @@ -256,7 +256,7 @@ WebTablet.prototype.destroy = function () { } else { Entities.deleteEntity(this.tabletEntityID); } - Overlays.deleteOverlay(this.homeButtonEntity); + Overlays.deleteOverlay(this.homeButtonID); HMD.displayModeChanged.disconnect(this.myOnHmdChanged); Controller.mousePressEvent.disconnect(this.myMousePressEvent); @@ -439,10 +439,16 @@ WebTablet.prototype.getPosition = function () { WebTablet.prototype.mousePressEvent = function (event) { var pickRay = Camera.computePickRay(event.x, event.y); - var entityPickResults = Entities.findRayIntersection(pickRay, true, [this.tabletEntityID]); // non-accurate picking - if (entityPickResults.intersects && entityPickResults.entityID === this.tabletEntityID) { - var overlayPickResults = Overlays.findRayIntersection(pickRay); - if (overlayPickResults.intersects && overlayPickResults.overlayID === HMD.homeButtonID) { + var entityPickResults; + if (this.tabletIsOverlay) { + entityPickResults = Overlays.findRayIntersection(pickRay, true, [this.tabletEntityID]); + } else { + entityPickResults = Entities.findRayIntersection(pickRay, true, [this.tabletEntityID]); + } + if (entityPickResults.intersects && (entityPickResults.entityID === this.tabletEntityID || + entityPickResults.overlayID === this.tabletEntityID)) { + var overlayPickResults = Overlays.findRayIntersection(pickRay, true, [this.webOverlayID, this.homeButtonID], []); + if (overlayPickResults.intersects && overlayPickResults.overlayID === this.homeButtonID) { var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); var onHomeScreen = tablet.onHomeScreen(); if (onHomeScreen) { @@ -501,9 +507,15 @@ WebTablet.prototype.mouseMoveEvent = function (event) { var localIntersectionPoint = Vec3.sum(localPickRay.origin, Vec3.multiply(localPickRay.direction, result.distance)); var localOffset = Vec3.subtract(localIntersectionPoint, this.initialLocalIntersectionPoint); var localPosition = Vec3.sum(this.initialLocalPosition, localOffset); - Entities.editEntity(this.tabletEntityID, { - localPosition: localPosition - }); + if (this.tabletIsOverlay) { + Overlays.editOverlay(this.tabletEntityID, { + localPosition: localPosition + }); + } else { + Entities.editEntity(this.tabletEntityID, { + localPosition: localPosition + }); + } } } }; diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 632cb40bb5..42fb32114d 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -31,7 +31,8 @@ UIWebTablet = new WebTablet("qml/hifi/tablet/TabletRoot.qml", DEFAULT_WIDTH * (HMD_TABLET_SCALE / 100), null, activeHand, true); UIWebTablet.register(); HMD.tabletID = UIWebTablet.tabletEntityID; - HMD.homeButtonID = UIWebTablet.homeButtonEntity; + HMD.homeButtonID = UIWebTablet.homeButtonID; + HMD.tabletScreenID = UIWebTablet.webOverlayID; } function hideTabletUI() { @@ -48,6 +49,7 @@ UIWebTablet = null; HMD.tabletID = null; HMD.homeButtonID = null; + HMD.tabletScreenID = null; } } @@ -126,5 +128,6 @@ Entities.deleteEntity(HMD.tabletID); HMD.tabletID = null; HMD.homeButtonID = null; + HMD.tabletScreenID = null; }); }()); // END LOCAL_SCOPE From 2c42309aaa4135a4b1102d146e4e3b33c8ed0a62 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Feb 2017 13:32:24 -0800 Subject: [PATCH 14/26] perfer tablet over other overlays for mouse-clicks --- interface/src/ui/overlays/Overlays.cpp | 55 ++++++++++++++++++++++---- interface/src/ui/overlays/Overlays.h | 6 +++ 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 8d1f757cc0..c9047c5690 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -406,11 +406,21 @@ RayToOverlayIntersectionResult Overlays::findRayIntersection(const PickRay& ray, const QScriptValue& overlayIDsToInclude, const QScriptValue& overlayIDsToDiscard, bool visibleOnly, bool collidableOnly) { - float bestDistance = std::numeric_limits::max(); - bool bestIsFront = false; const QVector overlaysToInclude = qVectorOverlayIDFromScriptValue(overlayIDsToInclude); const QVector overlaysToDiscard = qVectorOverlayIDFromScriptValue(overlayIDsToDiscard); + return findRayIntersectionInternal(ray, precisionPicking, + overlaysToInclude, overlaysToDiscard, visibleOnly, collidableOnly); +} + + +RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickRay& ray, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToDiscard, + bool visibleOnly, bool collidableOnly) { + float bestDistance = std::numeric_limits::max(); + bool bestIsFront = false; + RayToOverlayIntersectionResult result; QMapIterator i(_overlaysWorld); i.toBack(); @@ -700,8 +710,9 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) { } } -PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, - RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event, PointerEvent::EventType eventType) { +PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay ray, + RayToOverlayIntersectionResult rayPickResult, QMouseEvent* event, + PointerEvent::EventType eventType) { auto thisOverlay = std::dynamic_pointer_cast(overlay); @@ -719,11 +730,41 @@ PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay r return pointerEvent; } + +RayToOverlayIntersectionResult Overlays::findRayIntersectionForMouseEvent(PickRay ray) { + QVector overlaysToInclude; + QVector overlaysToDircard; + RayToOverlayIntersectionResult rayPickResult; + + // first priority is tablet screen + overlaysToInclude << qApp->getTabletScreenID(); + rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDircard); + if (rayPickResult.intersects) { + return rayPickResult; + } + // then tablet home button + overlaysToInclude.clear(); + overlaysToInclude << qApp->getTabletHomeButtonID(); + rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDircard); + if (rayPickResult.intersects) { + return rayPickResult; + } + // then tablet frame + overlaysToInclude.clear(); + overlaysToInclude << OverlayID(qApp->getTabletFrameID()); + rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDircard); + if (rayPickResult.intersects) { + return rayPickResult; + } + // then whatever + return findRayIntersection(ray); +} + void Overlays::mousePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mousePressEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray); + RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); if (rayPickResult.intersects) { _currentClickingOnOverlayID = rayPickResult.overlayID; @@ -744,7 +785,7 @@ void Overlays::mouseReleaseEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseReleaseEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray); + RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); if (rayPickResult.intersects) { // Only Web overlays can have focus. @@ -762,7 +803,7 @@ void Overlays::mouseMoveEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseMoveEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = findRayIntersection(ray); + RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); if (rayPickResult.intersects) { // Only Web overlays can have focus. diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 38f62fee48..b369119752 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -327,6 +327,12 @@ private: OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID }; OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID }; + + RayToOverlayIntersectionResult findRayIntersectionInternal(const PickRay& ray, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToDiscard, + bool visibleOnly = false, bool collidableOnly = false); + RayToOverlayIntersectionResult findRayIntersectionForMouseEvent(PickRay ray); }; #endif // hifi_Overlays_h From 9c0104a060d363a985786a8e89f591b5ce16fa83 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Feb 2017 14:55:52 -0800 Subject: [PATCH 15/26] don't use Entities.getEntityProperties on tablet when it's an overlay --- scripts/system/libraries/WebTablet.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/system/libraries/WebTablet.js b/scripts/system/libraries/WebTablet.js index 26b6f82520..c4b41bcab5 100644 --- a/scripts/system/libraries/WebTablet.js +++ b/scripts/system/libraries/WebTablet.js @@ -193,7 +193,16 @@ WebTablet = function (url, width, dpi, hand, clientOnly) { }; this.getLocation = function() { - return Entities.getEntityProperties(_this.tabletEntityID, ["localPosition", "localRotation"]); + if (this.tabletIsOverlay) { + var location = Overlays.getProperty(this.tabletEntityID, "localPosition"); + var orientation = Overlays.getProperty(this.tabletEntityID, "localOrientation"); + return { + localPosition: location, + localRotation: orientation + }; + } else { + return Entities.getEntityProperties(_this.tabletEntityID, ["localPosition", "localRotation"]); + } }; this.clicked = false; @@ -461,7 +470,11 @@ WebTablet.prototype.mousePressEvent = function (event) { this.dragging = true; var invCameraXform = new Xform(Camera.orientation, Camera.position).inv(); this.initialLocalIntersectionPoint = invCameraXform.xformPoint(entityPickResults.intersection); - this.initialLocalPosition = Entities.getEntityProperties(this.tabletEntityID, ["localPosition"]).localPosition; + if (this.tabletIsOverlay) { + this.initialLocalPosition = Overlays.getProperty(this.tabletEntityID, "localPosition"); + } else { + this.initialLocalPosition = Entities.getEntityProperties(this.tabletEntityID, ["localPosition"]).localPosition; + } } } }; From a286c72b3bf20ee67d25604f33ceb734da4749f5 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Feb 2017 15:12:45 -0800 Subject: [PATCH 16/26] cleanups --- interface/src/avatar/Avatar.cpp | 4 ++-- interface/src/avatar/MyAvatar.cpp | 4 ++-- interface/src/ui/overlays/Overlays.cpp | 8 ++++---- interface/src/ui/overlays/Overlays.h | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 74b60bee13..eb66abed2e 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -939,7 +939,7 @@ glm::vec3 Avatar::getDefaultJointTranslation(int index) const { glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const { if (index < 0) { - index += 65536; + index += numeric_limits::max() + 1; // 65536 } switch(index) { @@ -979,7 +979,7 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const { glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const { if (index < 0) { - index += 65536; + index += numeric_limits::max() + 1; // 65536 } switch(index) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ea9ea7dd06..842939d938 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -2411,7 +2411,7 @@ glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& c glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const { if (index < 0) { - index += 65536; + index += numeric_limits::max() + 1; // 65536 } switch (index) { @@ -2448,7 +2448,7 @@ glm::quat MyAvatar::getAbsoluteJointRotationInObjectFrame(int index) const { glm::vec3 MyAvatar::getAbsoluteJointTranslationInObjectFrame(int index) const { if (index < 0) { - index += 65536; + index += numeric_limits::max() + 1; // 65536 } switch (index) { diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index c9047c5690..9d2f52bc81 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -733,26 +733,26 @@ PointerEvent Overlays::calculatePointerEvent(Overlay::Pointer overlay, PickRay r RayToOverlayIntersectionResult Overlays::findRayIntersectionForMouseEvent(PickRay ray) { QVector overlaysToInclude; - QVector overlaysToDircard; + QVector overlaysToDiscard; RayToOverlayIntersectionResult rayPickResult; // first priority is tablet screen overlaysToInclude << qApp->getTabletScreenID(); - rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDircard); + rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } // then tablet home button overlaysToInclude.clear(); overlaysToInclude << qApp->getTabletHomeButtonID(); - rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDircard); + rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } // then tablet frame overlaysToInclude.clear(); overlaysToInclude << OverlayID(qApp->getTabletFrameID()); - rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDircard); + rayPickResult = findRayIntersectionInternal(ray, true, overlaysToInclude, overlaysToDiscard); if (rayPickResult.intersects) { return rayPickResult; } diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index b369119752..865df6309a 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -207,7 +207,7 @@ public slots: bool collidableOnly = false); /**jsdoc - * Return a list of overlays with centers within a given distance of a point + * Return a list of 3d overlays with bounding boxes that touch the given sphere * * @function Overlays.findOverlays * @param {Vec3} center the point to search from. From 0a2a1b1637ddc507531656df2549a40c8b2ea71e Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Feb 2017 15:25:09 -0800 Subject: [PATCH 17/26] include visible_to_others in UserActivityLoggerScriptingInterface::openedTablet --- .../networking/src/UserActivityLoggerScriptingInterface.cpp | 4 ++-- .../networking/src/UserActivityLoggerScriptingInterface.h | 2 +- scripts/system/tablet-ui/tabletUI.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp index f38d24c31f..c8a7b61aa7 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.cpp @@ -16,8 +16,8 @@ void UserActivityLoggerScriptingInterface::enabledEdit() { logAction("enabled_edit"); } -void UserActivityLoggerScriptingInterface::openedTablet() { - logAction("opened_tablet"); +void UserActivityLoggerScriptingInterface::openedTablet(bool visibleToOthers) { + logAction("opened_tablet", { { "visible_to_others", visibleToOthers } }); } void UserActivityLoggerScriptingInterface::closedTablet() { diff --git a/libraries/networking/src/UserActivityLoggerScriptingInterface.h b/libraries/networking/src/UserActivityLoggerScriptingInterface.h index b827b2262a..cf38450891 100644 --- a/libraries/networking/src/UserActivityLoggerScriptingInterface.h +++ b/libraries/networking/src/UserActivityLoggerScriptingInterface.h @@ -21,7 +21,7 @@ class UserActivityLoggerScriptingInterface : public QObject, public Dependency { Q_OBJECT public: Q_INVOKABLE void enabledEdit(); - Q_INVOKABLE void openedTablet(); + Q_INVOKABLE void openedTablet(bool visibleToOthers); Q_INVOKABLE void closedTablet(); Q_INVOKABLE void openedMarketplace(); Q_INVOKABLE void toggledAway(bool isAway); diff --git a/scripts/system/tablet-ui/tabletUI.js b/scripts/system/tablet-ui/tabletUI.js index 42fb32114d..31d069442f 100644 --- a/scripts/system/tablet-ui/tabletUI.js +++ b/scripts/system/tablet-ui/tabletUI.js @@ -79,7 +79,7 @@ hideTabletUI(); HMD.closeTablet(); } else if (HMD.showTablet && !tabletShown && !toolbarMode) { - UserActivityLogger.openedTablet(); + UserActivityLogger.openedTablet(Settings.getValue("tabletVisibleToOthers")); showTabletUI(); } else if (!HMD.showTablet && tabletShown) { UserActivityLogger.closedTablet(); From 60fd4afc4d94a1af7b4887f3fad4b2a01a658623 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Thu, 23 Feb 2017 18:52:10 -0800 Subject: [PATCH 18/26] 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 e43c4c17f508289842a4733217a5097504739eeb Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Feb 2017 21:27:25 -0800 Subject: [PATCH 19/26] in 2d mode, clicks on tablet don't get used for other things --- 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 | 2 +- 7 files changed, 52 insertions(+), 24 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ed8fe8b9b2..dbfd6fb085 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 a783f14102..5cc0686984 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -759,7 +759,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()); @@ -772,15 +772,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()); @@ -796,9 +795,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()); @@ -842,6 +842,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 f954f0d258..404cc26fcb 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -538,6 +538,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 59dd73d77e..cacb8b0872 100644 --- a/scripts/system/libraries/entitySelectionTool.js +++ b/scripts/system/libraries/entitySelectionTool.js @@ -3866,7 +3866,7 @@ SelectionDisplay = (function() { var somethingClicked = false; var pickRay = generalComputePickRay(event.x, event.y); - var result = Overlays.findRayIntersection(pickRay, true, [HMD.tabletScreenID, HMD.homeButtonID]); + 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; From f208f5e2d17b70297ff3ea13fd4ae3da43703ac7 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 24 Feb 2017 11:34:10 -0800 Subject: [PATCH 20/26] fix a couple of problems related to grabbing tablet while edit.js is active --- interface/src/ui/overlays/Overlays.cpp | 33 +++++++++---------- .../system/controllers/handControllerGrab.js | 10 +++--- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 5cc0686984..709d86c305 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()); @@ -849,9 +847,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 015cbf1221..86f080ae8d 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -863,7 +863,7 @@ function MyController(hand) { }; this.setState = function(newState, reason) { - if ((isInEditMode() && this.grabbedEntity !== HMD.tabletID) && + if ((isInEditMode() && this.grabbedThingID !== HMD.tabletID) && (newState !== STATE_OFF && newState !== STATE_SEARCHING && newState !== STATE_OVERLAY_STYLUS_TOUCHING && @@ -1446,7 +1446,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; @@ -1666,7 +1666,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; }); @@ -3352,8 +3352,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 70060eb464e4c0dcd53568432e802b07f91a9d7b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 23 Feb 2017 21:27:25 -0800 Subject: [PATCH 21/26] 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 22/26] 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 23/26] 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 24/26] 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 25/26] 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 26/26] 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;