From 55eed376980dd5f8e485887176f9e5911bab4abb Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 29 Aug 2017 20:47:09 +0200 Subject: [PATCH 001/292] Start working on autocompletion --- interface/resources/qml/Browser.qml | 2 +- .../qml/controls-uit/BaseWebView.qml | 4 +- interface/resources/qml/hifi/Desktop.qml | 2 +- interface/resources/qml/hifi/WebBrowser.qml | 72 ++++++++++++------- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 55927fda24..2809f91923 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.2 import QtWebChannel 1.0 -import QtWebEngine 1.2 +import QtWebEngine 1.5 import "controls-uit" import "styles" as HifiStyles diff --git a/interface/resources/qml/controls-uit/BaseWebView.qml b/interface/resources/qml/controls-uit/BaseWebView.qml index 3ca57f03bf..fdd9c12220 100644 --- a/interface/resources/qml/controls-uit/BaseWebView.qml +++ b/interface/resources/qml/controls-uit/BaseWebView.qml @@ -8,8 +8,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 -import QtWebEngine 1.2 +import QtQuick 2.7 +import QtWebEngine 1.5 WebEngineView { id: root diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index ea9ec2f6c9..96bb359aea 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import QtWebEngine 1.1; +import QtWebEngine 1.5; import Qt.labs.settings 1.0 import "../desktop" as OriginalDesktop diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index af54c86bf4..972c03355c 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -9,12 +9,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -import QtQuick 2.5 -import QtQuick.Controls 1.5 as QQControls +import QtQuick 2.7 +import QtQuick.Controls 2.2 as QQControls import QtQuick.Layouts 1.3 -import QtQuick.Controls.Styles 1.4 -import QtWebEngine 1.2 +import QtWebEngine 1.5 import QtWebChannel 1.0 import "../styles-uit" @@ -66,9 +65,27 @@ Rectangle { } } - QQControls.TextField { + QQControls.ComboBox { id: addressBar + //selectByMouse: true + focus: true + //placeholderText: "Enter URL" + editable: true + flat: true + indicator: Item {} + Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i") + + Keys.onPressed: { + if (event.key === Qt.Key_Return) { + if (editText.indexOf("http") != 0) { + editText = "http://" + editText; + } + webEngineView.url = editText + event.accepted = true; + } + } + Image { anchors.verticalCenter: addressBar.verticalCenter; x: 5 @@ -94,21 +111,18 @@ Rectangle { } } - style: TextFieldStyle { - padding { - left: 26; - right: 26 - } - } - focus: true + leftPadding: 26 + rightPadding: 26 + Layout.fillWidth: true - text: webEngineView.url - onAccepted: webEngineView.url = text + editText: webEngineView.url + onAccepted: webEngineView.url = editText } + HifiControls.WebGlyphButton { checkable: true //only QtWebEngine 1.3 - //checked: webEngineView.audioMuted + checked: webEngineView.audioMuted glyph: checked ? hifi.glyphs.unmuted : hifi.glyphs.muted anchors.verticalCenter: parent.verticalCenter; width: hifi.dimensions.controlLineHeight @@ -120,18 +134,24 @@ Rectangle { QQControls.ProgressBar { id: loadProgressBar - style: ProgressBarStyle { - background: Rectangle { - color: "#6A6A6A" - } - progress: Rectangle{ + background: Rectangle { + implicitHeight: 2 + color: "#6A6A6A" + } + + contentItem: Item { + implicitHeight: 2 + + Rectangle { + width: loadProgressBar.visualPosition * parent.width + height: parent.height color: "#00B4EF" } } width: parent.width; - minimumValue: 0 - maximumValue: 100 + from: 0 + to: 100 value: webEngineView.loadProgress height: 2 } @@ -183,8 +203,8 @@ Rectangle { settings.pluginsEnabled: true settings.fullScreenSupportEnabled: false //from WebEngine 1.3 - // settings.autoLoadIconsForPage: false - // settings.touchIconsEnabled: false + settings.autoLoadIconsForPage: false + settings.touchIconsEnabled: false onCertificateError: { error.defer(); @@ -201,9 +221,7 @@ Rectangle { } onNewViewRequested: { - if (!request.userInitiated) { - print("Warning: Blocked a popup window."); - } + request.openIn(webEngineView); } onRenderProcessTerminated: { From 748ef8bb87663201a260bb71139512f44fe81677 Mon Sep 17 00:00:00 2001 From: vladest Date: Sun, 3 Sep 2017 18:10:53 +0200 Subject: [PATCH 002/292] Enable edit in combobox --- interface/resources/qml/hifi/WebBrowser.qml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index 972c03355c..98ed0f10be 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -72,7 +72,7 @@ Rectangle { focus: true //placeholderText: "Enter URL" editable: true - flat: true + //flat: true indicator: Item {} Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i") @@ -158,14 +158,15 @@ Rectangle { HifiControls.BaseWebView { id: webEngineView + width: parent.width; + property real webViewHeight: root.height - loadProgressBar.height - 48 - 4 + height: keyboardEnabled && keyboardRaised ? webViewHeight - keyboard.height : webViewHeight + + focus: true objectName: "tabletWebEngineView" url: "http://www.highfidelity.com" - property real webViewHeight: root.height - loadProgressBar.height - 48 - 4 - - width: parent.width; - height: keyboardEnabled && keyboardRaised ? webViewHeight - keyboard.height : webViewHeight profile: HFWebEngineProfile; @@ -258,6 +259,7 @@ Rectangle { } } + HifiControls.Keyboard { id: keyboard raised: parent.keyboardEnabled && parent.keyboardRaised From 6de00c796989ba26a6bdf48a89185e2e9d1a1b48 Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 5 Sep 2017 13:11:52 +0200 Subject: [PATCH 003/292] Implemented suggestions popup. Cleanup --- interface/resources/qml/hifi/WebBrowser.qml | 143 ++-- interface/src/Application.cpp | 3 + interface/src/opensearch/opensearchengine.cpp | 650 ++++++++++++++++++ interface/src/opensearch/opensearchengine.h | 128 ++++ .../opensearch/opensearchenginedelegate.cpp | 43 ++ .../src/opensearch/opensearchenginedelegate.h | 18 + 6 files changed, 946 insertions(+), 39 deletions(-) create mode 100644 interface/src/opensearch/opensearchengine.cpp create mode 100644 interface/src/opensearch/opensearchengine.h create mode 100644 interface/src/opensearch/opensearchenginedelegate.cpp create mode 100644 interface/src/opensearch/opensearchenginedelegate.h diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index 98ed0f10be..582e26bbeb 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -21,6 +21,8 @@ import "../controls-uit" as HifiControls import "../windows" import "../controls" +import HifiWeb 1.0 + Rectangle { id: root; @@ -31,17 +33,61 @@ Rectangle { property bool keyboardEnabled: true // FIXME - Keyboard HMD only: Default to false property bool keyboardRaised: false property bool punctuationMode: false + property var suggestionsList: [] + OpenSearchEngine { + id: searchEngine + name: "Google"; + //icon: ":icons/sites/google.png" + searchUrlTemplate: "https://www.google.com/search?client=qupzilla&q=%s"; + suggestionsUrlTemplate: "https://suggestqueries.google.com/complete/search?output=firefox&q=%s"; + suggestionsUrl: "https://suggestqueries.google.com/complete/search?output=firefox&q=%s"; + + onSuggestions: { + if (suggestions.length > 0) { + console.log("suggestions:", suggestions) + suggestionsList = [] + suggestionsList.push(addressBar.editText) //do not overwrite edit text + for(var i = 0; i < suggestions.length; i++) { + suggestionsList.push(suggestions[i]) + } + addressBar.model = suggestionsList + if (!addressBar.popup.visible) { + addressBar.popup.open() + } + } + } + } + + Timer { + id: suggestionRequestTimer + interval: 200 + repeat: false + onTriggered: { + if (addressBar.editText !== "") { + searchEngine.requestSuggestions(addressBar.editText) + } + } + } color: hifi.colors.baseGray; - // only show the title if loaded through a "loader" + function goTo(url) { + if (url.indexOf("http") !== 0) { + url = "http://" + url; + } + webEngineView.url = url + event.accepted = true; + suggestionRequestTimer.stop() + addressBar.popup.close() + } Column { spacing: 2 width: parent.width; RowLayout { + id: addressBarRow width: parent.width; height: 48 @@ -70,50 +116,65 @@ Rectangle { //selectByMouse: true focus: true - //placeholderText: "Enter URL" + editable: true //flat: true indicator: Item {} + background: Item {} + onActivated: { + goTo(textAt(index)) + } + + contentItem: QQControls.TextField { + id: addressBarInput + leftPadding: 26 + rightPadding: hifi.dimensions.controlLineHeight + text: addressBar.editText + placeholderText: qsTr("Enter URL") + font: addressBar.font + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + + Image { + anchors.verticalCenter: parent.verticalCenter; + x: 5 + z: 2 + id: faviconImage + width: 16; height: 16 + sourceSize: Qt.size(width, height) + source: webEngineView.icon + onSourceChanged: console.log("web icon", source) + } + + HifiControls.WebGlyphButton { + glyph: webEngineView.loading ? hifi.glyphs.closeSmall : hifi.glyphs.reloadSmall; + anchors.verticalCenter: parent.verticalCenter; + width: hifi.dimensions.controlLineHeight + z: 2 + x: addressBarInput.width - implicitWidth + onClicked: { + if (webEngineView.loading) { + webEngineView.stop() + } else { + reloadTimer.start() + } + } + } + } + Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i") Keys.onPressed: { if (event.key === Qt.Key_Return) { - if (editText.indexOf("http") != 0) { - editText = "http://" + editText; - } - webEngineView.url = editText - event.accepted = true; + goTo(editText) } } - Image { - anchors.verticalCenter: addressBar.verticalCenter; - x: 5 - z: 2 - id: faviconImage - width: 16; height: 16 - sourceSize: Qt.size(width, height) - source: webEngineView.icon + onEditTextChanged: { + console.log("edit text", addressBar.editText) + suggestionRequestTimer.restart() } - HifiControls.WebGlyphButton { - glyph: webEngineView.loading ? hifi.glyphs.closeSmall : hifi.glyphs.reloadSmall; - anchors.verticalCenter: parent.verticalCenter; - width: hifi.dimensions.controlLineHeight - z: 2 - x: addressBar.width - 28 - onClicked: { - if (webEngineView.loading) { - webEngineView.stop() - } else { - reloadTimer.start() - } - } - } - - leftPadding: 26 - rightPadding: 26 - Layout.fillWidth: true editText: webEngineView.url onAccepted: webEngineView.url = editText @@ -121,7 +182,6 @@ Rectangle { HifiControls.WebGlyphButton { checkable: true - //only QtWebEngine 1.3 checked: webEngineView.audioMuted glyph: checked ? hifi.glyphs.unmuted : hifi.glyphs.muted anchors.verticalCenter: parent.verticalCenter; @@ -162,7 +222,6 @@ Rectangle { property real webViewHeight: root.height - loadProgressBar.height - 48 - 4 height: keyboardEnabled && keyboardRaised ? webViewHeight - keyboard.height : webViewHeight - focus: true objectName: "tabletWebEngineView" @@ -172,6 +231,13 @@ Rectangle { property string userScriptUrl: "" + onLoadingChanged: { + if (!loading) { + suggestionRequestTimer.stop() + addressBar.popup.close() + } + } + // creates a global EventBridge object. WebEngineScript { id: createGlobalEventBridge @@ -202,10 +268,9 @@ Rectangle { settings.javascriptEnabled: true settings.errorPageEnabled: true settings.pluginsEnabled: true - settings.fullScreenSupportEnabled: false - //from WebEngine 1.3 - settings.autoLoadIconsForPage: false - settings.touchIconsEnabled: false + settings.fullScreenSupportEnabled: true + settings.autoLoadIconsForPage: true + settings.touchIconsEnabled: true onCertificateError: { error.defer(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe6ea2a0b3..726e5ba6e4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -201,6 +201,8 @@ #include "commerce/Wallet.h" #include "commerce/QmlCommerce.h" +#include "opensearch/opensearchengine.h" + // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. #if defined(Q_OS_WIN) @@ -2224,6 +2226,7 @@ void Application::initializeUi() { QmlCommerce::registerType(); qmlRegisterType("Hifi", 1, 0, "ResourceImageItem"); qmlRegisterType("Hifi", 1, 0, "Preference"); + qmlRegisterType("HifiWeb", 1, 0, "OpenSearchEngine"); auto offscreenUi = DependencyManager::get(); offscreenUi->create(); diff --git a/interface/src/opensearch/opensearchengine.cpp b/interface/src/opensearch/opensearchengine.cpp new file mode 100644 index 0000000000..28cacab256 --- /dev/null +++ b/interface/src/opensearch/opensearchengine.cpp @@ -0,0 +1,650 @@ +#include "opensearchengine.h" +#include "qregexp.h" +#include "opensearchenginedelegate.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + + +/*! + \class OpenSearchEngine + \brief A class representing a single search engine described in OpenSearch format + + OpenSearchEngine is a class that represents a single search engine based on + the OpenSearch format. + For more information about the format, see http://www.opensearch.org/. + + Instances of the class hold all the data associated with the corresponding search + engines, such as name(), description() and also URL templates that are used + to construct URLs, which can be used later to perform search queries. Search engine + can also have an image, even an external one, in this case it will be downloaded + automatically from the network. + + OpenSearchEngine instances can be constructed from scratch but also read from + external sources and written back to them. OpenSearchReader and OpenSearchWriter + are the classes provided for reading and writing OpenSearch descriptions. + + Default constructed engines need to be filled with the necessary information before + they can be used to peform search requests. First of all, a search engine should have + the metadata including the name and the description. + However, the most important are URL templates, which are the construction of URLs + but can also contain template parameters, that are replaced with corresponding values + at the time of constructing URLs. + + There are two types of URL templates: search URL template and suggestions URL template. + Search URL template is needed for constructing search URLs, which point directly to + search results. Suggestions URL template is necessary to construct suggestion queries + URLs, which are then used for requesting contextual suggestions, a popular service + offered along with search results that provides search terms related to what has been + supplied by the user. + + Both types of URLs are constructed by the class, by searchUrl() and suggestionsUrl() + functions respectively. However, search requests are supposed to be performed outside + the class, while suggestion queries can be executed using the requestSuggestions() + method. The class will take care of peforming the network request and parsing the + JSON response. + + Both the image request and suggestion queries need network access. The class can + perform network requests on its own, though the client application needs to provide + a network access manager, which then will to be used for network operations. + Without that, both images delivered from remote locations and contextual suggestions + will be disabled. + + \sa OpenSearchReader, OpenSearchWriter +*/ + +/*! + Constructs an engine with a given \a parent. +*/ +OpenSearchEngine::OpenSearchEngine(QObject* parent) + : QObject(parent) + , m_searchMethod(QLatin1String("get")) + , m_suggestionsMethod(QLatin1String("get")) + , m_suggestionsReply(0) + , m_delegate(0) +{ + m_requestMethods.insert(QLatin1String("get"), QNetworkAccessManager::GetOperation); + m_requestMethods.insert(QLatin1String("post"), QNetworkAccessManager::PostOperation); +} + +/*! + A destructor. +*/ +OpenSearchEngine::~OpenSearchEngine() +{ +} + +QString OpenSearchEngine::parseTemplate(const QString &searchTerm, const QString &searchTemplate) +{ + QString language = QLocale().name(); + // Simple conversion to RFC 3066. + language = language.replace(QLatin1Char('_'), QLatin1Char('-')); + + QString result = searchTemplate; + result.replace(QLatin1String("{count}"), QLatin1String("20")); + result.replace(QLatin1String("{startIndex}"), QLatin1String("0")); + result.replace(QLatin1String("{startPage}"), QLatin1String("0")); + result.replace(QLatin1String("{language}"), language); + result.replace(QLatin1String("{inputEncoding}"), QLatin1String("UTF-8")); + result.replace(QLatin1String("{outputEncoding}"), QLatin1String("UTF-8")); + result.replace(QRegExp(QLatin1String("\\{([^\\}]*:|)source\\??\\}")), QCoreApplication::applicationName()); + result.replace(QLatin1String("{searchTerms}"), QLatin1String(QUrl::toPercentEncoding(searchTerm))); + + return result; +} + +/*! + \property OpenSearchEngine::name + \brief the name of the engine + + \sa description() +*/ +QString OpenSearchEngine::name() const +{ + return m_name; +} + +void OpenSearchEngine::setName(const QString &name) +{ + m_name = name; +} + +/*! + \property OpenSearchEngine::description + \brief the description of the engine + + \sa name() +*/ +QString OpenSearchEngine::description() const +{ + return m_description; +} + +void OpenSearchEngine::setDescription(const QString &description) +{ + m_description = description; +} + +/*! + \property OpenSearchEngine::searchUrlTemplate + \brief the template of the search URL + + \sa searchUrl(), searchParameters(), suggestionsUrlTemplate() +*/ +QString OpenSearchEngine::searchUrlTemplate() const +{ + return m_searchUrlTemplate; +} + +void OpenSearchEngine::setSearchUrlTemplate(const QString &searchUrlTemplate) +{ + if (!searchUrlTemplate.startsWith(QLatin1String("http://")) && !searchUrlTemplate.startsWith(QLatin1String("https://"))) { + return; + } + + m_searchUrlTemplate = searchUrlTemplate; +} + +/*! + Constructs and returns a search URL with a given \a searchTerm. + + The URL template is processed according to the specification: + http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax + + A list of template parameters currently supported and what they are replaced with: + \table + \header \o parameter + \o value + \row \o "{count}" + \o "20" + \row \o "{startIndex}" + \o "0" + \row \o "{startPage}" + \o "0" + \row \o "{language}" + \o "the default language code (RFC 3066)" + \row \o "{inputEncoding}" + \o "UTF-8" + \row \o "{outputEncoding}" + \o "UTF-8" + \row \o "{*:source}" + \o "application name, QCoreApplication::applicationName()" + \row \o "{searchTerms}" + \o "the string supplied by the user" + \endtable + + \sa searchUrlTemplate(), searchParameters(), suggestionsUrl() +*/ +QUrl OpenSearchEngine::searchUrl(const QString &searchTerm) const +{ + if (m_searchUrlTemplate.isEmpty()) { + return QUrl(); + } + + QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_searchUrlTemplate).toUtf8()); + + QUrlQuery query(retVal); + if (m_searchMethod != QLatin1String("post")) { + Parameters::const_iterator end = m_searchParameters.constEnd(); + Parameters::const_iterator i = m_searchParameters.constBegin(); + for (; i != end; ++i) { + query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); + } + retVal.setQuery(query); + } + + return retVal; +} + +QByteArray OpenSearchEngine::getPostData(const QString &searchTerm) const +{ + if (m_searchMethod != QLatin1String("post")) { + return QByteArray(); + } + + QUrl retVal = QUrl("http://foo.bar"); + + QUrlQuery query(retVal); + Parameters::const_iterator end = m_searchParameters.constEnd(); + Parameters::const_iterator i = m_searchParameters.constBegin(); + for (; i != end; ++i) { + query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); + } + retVal.setQuery(query); + + QByteArray data = retVal.toEncoded(QUrl::RemoveScheme); + return data.contains('?') ? data.mid(data.lastIndexOf('?') + 1) : QByteArray(); +} + +/*! + \property providesSuggestions + \brief indicates whether the engine supports contextual suggestions +*/ +bool OpenSearchEngine::providesSuggestions() const +{ + return (!m_suggestionsUrlTemplate.isEmpty() || !m_preparedSuggestionsUrl.isEmpty()); +} + +/*! + \property OpenSearchEngine::suggestionsUrlTemplate + \brief the template of the suggestions URL + + \sa suggestionsUrl(), suggestionsParameters(), searchUrlTemplate() +*/ +QString OpenSearchEngine::suggestionsUrlTemplate() const +{ + return m_suggestionsUrlTemplate; +} + +void OpenSearchEngine::setSuggestionsUrlTemplate(const QString &suggestionsUrlTemplate) +{ + if (!suggestionsUrlTemplate.startsWith(QLatin1String("http://")) && !suggestionsUrlTemplate.startsWith(QLatin1String("https://"))) { + return; + } + + m_suggestionsUrlTemplate = suggestionsUrlTemplate; +} + +/*! + Constructs a suggestions URL with a given \a searchTerm. + + The URL template is processed according to the specification: + http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax + + See searchUrl() for more information about processing template parameters. + + \sa suggestionsUrlTemplate(), suggestionsParameters(), searchUrl() +*/ +QUrl OpenSearchEngine::suggestionsUrl(const QString &searchTerm) const +{ + if (!m_preparedSuggestionsUrl.isEmpty()) { + QString s = m_preparedSuggestionsUrl; + s.replace(QLatin1String("%s"), searchTerm); + return QUrl(s); + } + + if (m_suggestionsUrlTemplate.isEmpty()) { + return QUrl(); + } + + QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_suggestionsUrlTemplate).toUtf8()); + + QUrlQuery query(retVal); + if (m_suggestionsMethod != QLatin1String("post")) { + Parameters::const_iterator end = m_suggestionsParameters.constEnd(); + Parameters::const_iterator i = m_suggestionsParameters.constBegin(); + for (; i != end; ++i) { + query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); + } + retVal.setQuery(query); + } + + return retVal; +} + +/*! + \property searchParameters + \brief additional parameters that will be included in the search URL + + For more information see: + http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0 +*/ +OpenSearchEngine::Parameters OpenSearchEngine::searchParameters() const +{ + return m_searchParameters; +} + +void OpenSearchEngine::setSearchParameters(const Parameters &searchParameters) +{ + m_searchParameters = searchParameters; +} + +/*! + \property suggestionsParameters + \brief additional parameters that will be included in the suggestions URL + + For more information see: + http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0 +*/ +OpenSearchEngine::Parameters OpenSearchEngine::suggestionsParameters() const +{ + return m_suggestionsParameters; +} + +void OpenSearchEngine::setSuggestionsParameters(const Parameters &suggestionsParameters) +{ + m_suggestionsParameters = suggestionsParameters; +} + +/*! + \property searchMethod + \brief HTTP request method that will be used to perform search requests +*/ +QString OpenSearchEngine::searchMethod() const +{ + return m_searchMethod; +} + +void OpenSearchEngine::setSearchMethod(const QString &method) +{ + QString requestMethod = method.toLower(); + if (!m_requestMethods.contains(requestMethod)) { + return; + } + + m_searchMethod = requestMethod; +} + +/*! + \property suggestionsMethod + \brief HTTP request method that will be used to perform suggestions requests +*/ +QString OpenSearchEngine::suggestionsMethod() const +{ + return m_suggestionsMethod; +} + +void OpenSearchEngine::setSuggestionsMethod(const QString &method) +{ + QString requestMethod = method.toLower(); + if (!m_requestMethods.contains(requestMethod)) { + return; + } + + m_suggestionsMethod = requestMethod; +} + +/*! + \property imageUrl + \brief the image URL of the engine + + When setting a new image URL, it won't be loaded immediately. The first request will be + deferred until image() is called for the first time. + + \note To be able to request external images, you need to provide a network access manager, + which will be used for network operations. + + \sa image(), networkAccessManager() +*/ +QString OpenSearchEngine::imageUrl() const +{ + return m_imageUrl; +} + +void OpenSearchEngine::setImageUrl(const QString &imageUrl) +{ + m_imageUrl = imageUrl; +} + +void OpenSearchEngine::loadImage() const +{ + if (m_imageUrl.isEmpty()) { + return; + } + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + + QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(QUrl::fromEncoded(m_imageUrl.toUtf8()))); + connect(reply, SIGNAL(finished()), this, SLOT(imageObtained())); +} + +void OpenSearchEngine::imageObtained() +{ + QNetworkReply* reply = qobject_cast(sender()); + + if (!reply) { + return; + } + + QByteArray response = reply->readAll(); + + reply->close(); + reply->deleteLater(); + + if (response.isEmpty()) { + return; + } + + m_image.loadFromData(response); + emit imageChanged(); +} + +/*! + \property image + \brief the image of the engine + + When no image URL has been set and an image will be set explicitly, a new data URL + will be constructed, holding the image data encoded with Base64. + + \sa imageUrl() +*/ +QImage OpenSearchEngine::image() const +{ + if (m_image.isNull()) { + loadImage(); + } + return m_image; +} + +void OpenSearchEngine::setImage(const QImage &image) +{ + if (m_imageUrl.isEmpty()) { + QBuffer imageBuffer; + imageBuffer.open(QBuffer::ReadWrite); + if (image.save(&imageBuffer, "PNG")) { + m_imageUrl = QString(QLatin1String("data:image/png;base64,%1")) + .arg(QLatin1String(imageBuffer.buffer().toBase64())); + } + } + + m_image = image; + emit imageChanged(); +} + +/*! + \property valid + \brief indicates whether the engine is valid i.e. the description was properly formed and included all necessary information +*/ +bool OpenSearchEngine::isValid() const +{ + return (!m_name.isEmpty() && !m_searchUrlTemplate.isEmpty()); +} + +bool OpenSearchEngine::operator==(const OpenSearchEngine &other) const +{ + return (m_name == other.m_name + && m_description == other.m_description + && m_imageUrl == other.m_imageUrl + && m_searchUrlTemplate == other.m_searchUrlTemplate + && m_suggestionsUrlTemplate == other.m_suggestionsUrlTemplate + && m_searchParameters == other.m_searchParameters + && m_suggestionsParameters == other.m_suggestionsParameters); +} + +bool OpenSearchEngine::operator<(const OpenSearchEngine &other) const +{ + return (m_name < other.m_name); +} + +/*! + Requests contextual suggestions on the search engine, for a given \a searchTerm. + + If succeeded, suggestions() signal will be emitted once the suggestions are received. + + \note To be able to request suggestions, you need to provide a network access manager, + which will be used for network operations. + + \sa requestSearchResults() +*/ + +void OpenSearchEngine::setSuggestionsParameters(const QByteArray ¶meters) +{ + m_preparedSuggestionsParameters = parameters; +} + +void OpenSearchEngine::setSuggestionsUrl(const QString &string) +{ + m_preparedSuggestionsUrl = string; +} + +QString OpenSearchEngine::getSuggestionsUrl() +{ + return suggestionsUrl("searchstring").toString().replace(QLatin1String("searchstring"), QLatin1String("%s")); +} + +QByteArray OpenSearchEngine::getSuggestionsParameters() +{ + QStringList parameters; + Parameters::const_iterator end = m_suggestionsParameters.constEnd(); + Parameters::const_iterator i = m_suggestionsParameters.constBegin(); + for (; i != end; ++i) { + parameters.append(i->first + QLatin1String("=") + i->second); + } + + QByteArray data = parameters.join(QLatin1String("&")).toUtf8(); + + return data; +} + +void OpenSearchEngine::requestSuggestions(const QString &searchTerm) +{ + if (searchTerm.isEmpty() || !providesSuggestions()) { + return; + } + + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); + + if (m_suggestionsReply) { + m_suggestionsReply->disconnect(this); + m_suggestionsReply->abort(); + m_suggestionsReply->deleteLater(); + m_suggestionsReply = 0; + } + + Q_ASSERT(m_requestMethods.contains(m_suggestionsMethod)); + if (m_suggestionsMethod == QLatin1String("get")) { + m_suggestionsReply = networkAccessManager.get(QNetworkRequest(suggestionsUrl(searchTerm))); + } + else { + QStringList parameters; + Parameters::const_iterator end = m_suggestionsParameters.constEnd(); + Parameters::const_iterator i = m_suggestionsParameters.constBegin(); + for (; i != end; ++i) { + parameters.append(i->first + QLatin1String("=") + i->second); + } + + QByteArray data = parameters.join(QLatin1String("&")).toUtf8(); + m_suggestionsReply = networkAccessManager.post(QNetworkRequest(suggestionsUrl(searchTerm)), data); + } + + connect(m_suggestionsReply, SIGNAL(finished()), this, SLOT(suggestionsObtained())); +} + +/*! + Requests search results on the search engine, for a given \a searchTerm. + + The default implementation does nothing, to supply your own you need to create your own + OpenSearchEngineDelegate subclass and supply it to the engine. Then the function will call + the performSearchRequest() method of the delegate, which can then handle the request + in a custom way. + + \sa requestSuggestions(), delegate() +*/ +void OpenSearchEngine::requestSearchResults(const QString &searchTerm) +{ + if (!m_delegate || searchTerm.isEmpty()) { + return; + } + + Q_ASSERT(m_requestMethods.contains(m_searchMethod)); + + QNetworkRequest request(QUrl(searchUrl(searchTerm))); + QByteArray data; + QNetworkAccessManager::Operation operation = m_requestMethods.value(m_searchMethod); + + if (operation == QNetworkAccessManager::PostOperation) { + QStringList parameters; + Parameters::const_iterator end = m_searchParameters.constEnd(); + Parameters::const_iterator i = m_searchParameters.constBegin(); + for (; i != end; ++i) { + parameters.append(i->first + QLatin1String("=") + i->second); + } + + data = parameters.join(QLatin1String("&")).toUtf8(); + } + + m_delegate->performSearchRequest(request, operation, data); +} + +void OpenSearchEngine::suggestionsObtained() +{ + const QByteArray response = m_suggestionsReply->readAll(); + + m_suggestionsReply->close(); + m_suggestionsReply->deleteLater(); + m_suggestionsReply = 0; + + QJsonParseError err; + QJsonDocument json = QJsonDocument::fromJson(response, &err); + const QVariant res = json.toVariant(); + + if (err.error != QJsonParseError::NoError || res.type() != QVariant::List) + return; + + const QVariantList list = res.toList(); + + if (list.size() < 2) + return; + + QStringList out; + + foreach (const QVariant &v, list.at(1).toList()) + out.append(v.toString()); + + emit suggestions(out); +} + + +/*! + \property delegate + \brief the delegate that is used to perform specific tasks. + + It can be currently supplied to provide a custom behaviour ofthe requetSearchResults() method. + The default implementation does nothing. +*/ +OpenSearchEngineDelegate* OpenSearchEngine::delegate() const +{ + return m_delegate; +} + +void OpenSearchEngine::setDelegate(OpenSearchEngineDelegate* delegate) +{ + m_delegate = delegate; +} + +/*! + \fn void OpenSearchEngine::imageChanged() + + This signal is emitted whenever the image of the engine changes. + + \sa image(), imageUrl() +*/ + +/*! + \fn void OpenSearchEngine::suggestions(const QStringList &suggestions) + + This signal is emitted whenever new contextual suggestions have been provided + by the search engine. To request suggestions, use requestSuggestions(). + The suggestion set is specified by \a suggestions. + + \sa requestSuggestions() +*/ diff --git a/interface/src/opensearch/opensearchengine.h b/interface/src/opensearch/opensearchengine.h new file mode 100644 index 0000000000..2b717fab7e --- /dev/null +++ b/interface/src/opensearch/opensearchengine.h @@ -0,0 +1,128 @@ +#ifndef OPENSEARCHENGINE_H +#define OPENSEARCHENGINE_H + +#include +#include +#include +#include +#include +#include + +class QNetworkReply; + +class OpenSearchEngineDelegate; +class OpenSearchEngine : public QObject +{ + Q_OBJECT + +signals: + void imageChanged(); + void suggestions(const QStringList &suggestions); + +public: + typedef QPair Parameter; + typedef QList Parameters; + + Q_PROPERTY(QString name READ name WRITE setName) + Q_PROPERTY(QString description READ description WRITE setDescription) + Q_PROPERTY(QString searchUrlTemplate READ searchUrlTemplate WRITE setSearchUrlTemplate) + Q_PROPERTY(Parameters searchParameters READ searchParameters WRITE setSearchParameters) + Q_PROPERTY(QString searchMethod READ searchMethod WRITE setSearchMethod) + Q_PROPERTY(QString suggestionsUrlTemplate READ suggestionsUrlTemplate WRITE setSuggestionsUrlTemplate) + Q_PROPERTY(QString suggestionsUrl READ getSuggestionsUrl WRITE setSuggestionsUrl) + Q_PROPERTY(Parameters suggestionsParameters READ suggestionsParameters WRITE setSuggestionsParameters) + Q_PROPERTY(QString suggestionsMethod READ suggestionsMethod WRITE setSuggestionsMethod) + Q_PROPERTY(bool providesSuggestions READ providesSuggestions) + Q_PROPERTY(QString imageUrl READ imageUrl WRITE setImageUrl) + Q_PROPERTY(bool valid READ isValid) + + OpenSearchEngine(QObject* parent = 0); + ~OpenSearchEngine(); + + QString name() const; + void setName(const QString &name); + + QString description() const; + void setDescription(const QString &description); + + QString searchUrlTemplate() const; + void setSearchUrlTemplate(const QString &searchUrl); + QUrl searchUrl(const QString &searchTerm) const; + + QByteArray getPostData(const QString &searchTerm) const; + + bool providesSuggestions() const; + + QString suggestionsUrlTemplate() const; + void setSuggestionsUrlTemplate(const QString &suggestionsUrl); + QUrl suggestionsUrl(const QString &searchTerm) const; + + Parameters searchParameters() const; + void setSearchParameters(const Parameters &searchParameters); + + Parameters suggestionsParameters() const; + void setSuggestionsParameters(const Parameters &suggestionsParameters); + + QString searchMethod() const; + void setSearchMethod(const QString &method); + + QString suggestionsMethod() const; + void setSuggestionsMethod(const QString &method); + + QString imageUrl() const; + void setImageUrl(const QString &url); + + QImage image() const; + void setImage(const QImage &image); + + bool isValid() const; + + void setSuggestionsUrl(const QString &string); + void setSuggestionsParameters(const QByteArray ¶meters); + QString getSuggestionsUrl(); + QByteArray getSuggestionsParameters(); + + OpenSearchEngineDelegate* delegate() const; + void setDelegate(OpenSearchEngineDelegate* delegate); + + bool operator==(const OpenSearchEngine &other) const; + bool operator<(const OpenSearchEngine &other) const; + +public slots: + void requestSuggestions(const QString &searchTerm); + void requestSearchResults(const QString &searchTerm); + +protected: + static QString parseTemplate(const QString &searchTerm, const QString &searchTemplate); + void loadImage() const; + +private slots: + void imageObtained(); + void suggestionsObtained(); + +private: + QString m_name; + QString m_description; + + QString m_imageUrl; + QImage m_image; + + QString m_searchUrlTemplate; + QString m_suggestionsUrlTemplate; + Parameters m_searchParameters; + Parameters m_suggestionsParameters; + QString m_searchMethod; + QString m_suggestionsMethod; + + QByteArray m_preparedSuggestionsParameters; + QString m_preparedSuggestionsUrl; + + QMap m_requestMethods; + + QNetworkReply* m_suggestionsReply; + + OpenSearchEngineDelegate* m_delegate; +}; + +#endif // OPENSEARCHENGINE_H + diff --git a/interface/src/opensearch/opensearchenginedelegate.cpp b/interface/src/opensearch/opensearchenginedelegate.cpp new file mode 100644 index 0000000000..2c9c18ece0 --- /dev/null +++ b/interface/src/opensearch/opensearchenginedelegate.cpp @@ -0,0 +1,43 @@ +#include "opensearchenginedelegate.h" + +/*! + \class OpenSearchEngineDelegate + \brief An abstract class providing custom processing of specific activities. + + OpenSearchEngineDelegate is an abstract class that can be subclassed and set on + an OpenSearchEngine. It allows to customize some parts of the default implementation + or even extend it with missing bits. + + Currently subclasses can only provide a custom way of handling search requests by + reimplementing the performSearchRequest() method. + + \sa OpenSearchEngine +*/ + +/*! + Constructs the delegate. +*/ +OpenSearchEngineDelegate::OpenSearchEngineDelegate() +{ +} + +/*! + Destructs the delegate. +*/ +OpenSearchEngineDelegate::~OpenSearchEngineDelegate() +{ +} + +/*! + \fn void performSearchRequest(const QNetworkRequest &request, + QNetworkAccessManager::Operation operation, const QByteArray &data) = 0 + + This method will be used after OpenSearchEngine::requestResults() is called. + + For example, a console application that uses the OpenSearchEngine class to generate + a search URL for a search term supplied by the user would reimplement the function + and forward the request to e.g. a web browser. + + Likewise, a web browser that uses the OpenSearchEngine class to support multiple search + engines e.g. in a toolbar would perform the request and navigate to the search results site. +*/ diff --git a/interface/src/opensearch/opensearchenginedelegate.h b/interface/src/opensearch/opensearchenginedelegate.h new file mode 100644 index 0000000000..ae7b5ef876 --- /dev/null +++ b/interface/src/opensearch/opensearchenginedelegate.h @@ -0,0 +1,18 @@ +#ifndef OPENSEARCHENGINEDELEGATE_H +#define OPENSEARCHENGINEDELEGATE_H + +#include +#include + +class OpenSearchEngineDelegate +{ +public: + OpenSearchEngineDelegate(); + virtual ~OpenSearchEngineDelegate(); + + virtual void performSearchRequest(const QNetworkRequest &request, + QNetworkAccessManager::Operation operation, + const QByteArray &data) = 0; +}; + +#endif // OPENSEARCHENGINEDELEGATE_H From 33767862888359beeb85fa2a41e7e24c3bbff933 Mon Sep 17 00:00:00 2001 From: vladest Date: Wed, 20 Sep 2017 17:02:54 +0200 Subject: [PATCH 004/292] Added text selection on focus. Added basic check for text within url input field to decide is this something for search or for goto. Limited popup list height to do not cover virtual keyboard --- interface/resources/qml/hifi/WebBrowser.qml | 37 ++++++++++++++++++--- interface/src/opensearch/opensearchengine.h | 2 +- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index 582e26bbeb..f1c6efde9a 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -39,7 +39,7 @@ Rectangle { id: searchEngine name: "Google"; //icon: ":icons/sites/google.png" - searchUrlTemplate: "https://www.google.com/search?client=qupzilla&q=%s"; + searchUrlTemplate: "https://www.google.com/search?client=hifibrowser&q={searchTerms}"; suggestionsUrlTemplate: "https://suggestqueries.google.com/complete/search?output=firefox&q=%s"; suggestionsUrl: "https://suggestqueries.google.com/complete/search?output=firefox&q=%s"; @@ -73,11 +73,14 @@ Rectangle { color: hifi.colors.baseGray; function goTo(url) { - if (url.indexOf("http") !== 0) { + //must be valid attempt to open an site with dot + if (url.indexOf("http") <= 0 && url.indexOf(".") > 0) { url = "http://" + url; + } else { + url = searchEngine.searchUrl(url) } + webEngineView.url = url - event.accepted = true; suggestionRequestTimer.stop() addressBar.popup.close() } @@ -125,6 +128,14 @@ Rectangle { goTo(textAt(index)) } + popup.bottomPadding: keyboard.height + + onFocusChanged: { + if (focus) { + addressBarInput.selectAll() + } + } + contentItem: QQControls.TextField { id: addressBarInput leftPadding: 26 @@ -132,8 +143,25 @@ Rectangle { text: addressBar.editText placeholderText: qsTr("Enter URL") font: addressBar.font + selectByMouse: true horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter + onFocusChanged: { + if (focus) { + selectAll() + } + } + + Keys.onDeletePressed: { + editText = "" + } + + Keys.onPressed: { + if (event.key === Qt.Key_Return) { + goTo(editText) + event.accepted = true; + } + } Image { anchors.verticalCenter: parent.verticalCenter; @@ -167,6 +195,7 @@ Rectangle { Keys.onPressed: { if (event.key === Qt.Key_Return) { goTo(editText) + event.accepted = true; } } @@ -177,7 +206,7 @@ Rectangle { Layout.fillWidth: true editText: webEngineView.url - onAccepted: webEngineView.url = editText + onAccepted: goTo(editText) } HifiControls.WebGlyphButton { diff --git a/interface/src/opensearch/opensearchengine.h b/interface/src/opensearch/opensearchengine.h index 2b717fab7e..fa714b85d3 100644 --- a/interface/src/opensearch/opensearchengine.h +++ b/interface/src/opensearch/opensearchengine.h @@ -47,7 +47,6 @@ public: QString searchUrlTemplate() const; void setSearchUrlTemplate(const QString &searchUrl); - QUrl searchUrl(const QString &searchTerm) const; QByteArray getPostData(const QString &searchTerm) const; @@ -89,6 +88,7 @@ public: bool operator<(const OpenSearchEngine &other) const; public slots: + QUrl searchUrl(const QString &searchTerm) const; void requestSuggestions(const QString &searchTerm); void requestSearchResults(const QString &searchTerm); From 45f1f074dff350da0762b180884383e7ae8f8851 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 12 Oct 2017 20:52:40 +0200 Subject: [PATCH 005/292] Reduce combobox dropdown height taking keyboard in account --- interface/resources/qml/hifi/WebBrowser.qml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index f1c6efde9a..1b49701bdf 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -38,14 +38,12 @@ Rectangle { OpenSearchEngine { id: searchEngine name: "Google"; - //icon: ":icons/sites/google.png" searchUrlTemplate: "https://www.google.com/search?client=hifibrowser&q={searchTerms}"; suggestionsUrlTemplate: "https://suggestqueries.google.com/complete/search?output=firefox&q=%s"; suggestionsUrl: "https://suggestqueries.google.com/complete/search?output=firefox&q=%s"; onSuggestions: { if (suggestions.length > 0) { - console.log("suggestions:", suggestions) suggestionsList = [] suggestionsList.push(addressBar.editText) //do not overwrite edit text for(var i = 0; i < suggestions.length; i++) { @@ -128,7 +126,7 @@ Rectangle { goTo(textAt(index)) } - popup.bottomPadding: keyboard.height + popup.height: webEngineView.height onFocusChanged: { if (focus) { From 596be8ec271139a94c9c6b40ddf5a38644a46065 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 17 Oct 2017 12:00:56 -0700 Subject: [PATCH 006/292] pickmanager wip --- interface/src/raypick/JointRayPick.cpp | 4 +- interface/src/raypick/JointRayPick.h | 6 +- interface/src/raypick/MouseRayPick.cpp | 5 +- interface/src/raypick/MouseRayPick.h | 6 +- interface/src/raypick/Pick.cpp | 10 + .../RayPick.h => interface/src/raypick/Pick.h | 135 ++++++++-- interface/src/raypick/PickManager.h | 244 ++++++++++++++++++ interface/src/raypick/RayPick.cpp | 39 +++ interface/src/raypick/RayPick.h | 35 +++ interface/src/raypick/RayPickManager.cpp | 192 +------------- interface/src/raypick/RayPickManager.h | 58 +---- .../src/raypick}/StaticRayPick.cpp | 4 +- .../src/raypick}/StaticRayPick.h | 4 +- .../pointers/src/pointers/rays/RayPick.cpp | 75 ------ libraries/shared/src/RegisteredMetaTypes.h | 15 ++ 15 files changed, 487 insertions(+), 345 deletions(-) create mode 100644 interface/src/raypick/Pick.cpp rename libraries/pointers/src/pointers/rays/RayPick.h => interface/src/raypick/Pick.h (51%) create mode 100644 interface/src/raypick/PickManager.h create mode 100644 interface/src/raypick/RayPick.cpp create mode 100644 interface/src/raypick/RayPick.h rename {libraries/pointers/src/pointers/rays => interface/src/raypick}/StaticRayPick.cpp (73%) rename {libraries/pointers/src/pointers/rays => interface/src/raypick}/StaticRayPick.h (75%) delete mode 100644 libraries/pointers/src/pointers/rays/RayPick.cpp diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index cf3f380ca0..d3991eac24 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -12,7 +12,7 @@ #include "avatar/AvatarManager.h" -JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled) : +JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _jointName(jointName), _posOffset(posOffset), @@ -20,7 +20,7 @@ JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOff { } -const PickRay JointRayPick::getPickRay(bool& valid) const { +const PickRay JointRayPick::getMathematicalPick(bool& valid) const { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(QString::fromStdString(_jointName)); bool useAvatarHead = _jointName == "Avatar"; diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index e3e5670e20..b2bffe83c4 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -11,14 +11,14 @@ #ifndef hifi_JointRayPick_h #define hifi_JointRayPick_h -#include +#include "RayPick.h" class JointRayPick : public RayPick { public: - JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay(bool& valid) const override; + const PickRay getMathematicalPick(bool& valid) const override; private: std::string _jointName; diff --git a/interface/src/raypick/MouseRayPick.cpp b/interface/src/raypick/MouseRayPick.cpp index de59fde88d..27080f5857 100644 --- a/interface/src/raypick/MouseRayPick.cpp +++ b/interface/src/raypick/MouseRayPick.cpp @@ -10,16 +10,15 @@ // #include "MouseRayPick.h" -#include "DependencyManager.h" #include "Application.h" #include "display-plugins/CompositorHelper.h" -MouseRayPick::MouseRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) : +MouseRayPick::MouseRayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled) { } -const PickRay MouseRayPick::getPickRay(bool& valid) const { +const PickRay MouseRayPick::getMathematicalPick(bool& valid) const { QVariant position = qApp->getApplicationCompositor().getReticleInterface()->getPosition(); if (position.isValid()) { QVariantMap posMap = position.toMap(); diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h index 47f9404f3a..c565a03db7 100644 --- a/interface/src/raypick/MouseRayPick.h +++ b/interface/src/raypick/MouseRayPick.h @@ -11,14 +11,14 @@ #ifndef hifi_MouseRayPick_h #define hifi_MouseRayPick_h -#include +#include "RayPick.h" class MouseRayPick : public RayPick { public: - MouseRayPick(const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay(bool& valid) const override; + const PickRay getMathematicalPick(bool& valid) const override; }; #endif // hifi_MouseRayPick_h diff --git a/interface/src/raypick/Pick.cpp b/interface/src/raypick/Pick.cpp new file mode 100644 index 0000000000..030d2ef4b7 --- /dev/null +++ b/interface/src/raypick/Pick.cpp @@ -0,0 +1,10 @@ +// +// Created by Sam Gondelman 10/17/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "Pick.h" + +const PickFilter PickFilter::NOTHING; \ No newline at end of file diff --git a/libraries/pointers/src/pointers/rays/RayPick.h b/interface/src/raypick/Pick.h similarity index 51% rename from libraries/pointers/src/pointers/rays/RayPick.h rename to interface/src/raypick/Pick.h index 5a53891dc6..561c336f3b 100644 --- a/libraries/pointers/src/pointers/rays/RayPick.h +++ b/interface/src/raypick/Pick.h @@ -1,12 +1,12 @@ // -// Created by Sam Gondelman 7/11/2017 +// Created by Sam Gondelman 10/17/2017 // Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_RayPick_h -#define hifi_RayPick_h +#ifndef hifi_Pick_h +#define hifi_Pick_h #include #include @@ -16,7 +16,10 @@ #include #include -class RayPickFilter { +#include "EntityScriptingInterface.h" +#include "ui/overlays/Overlays.h" + +class PickFilter { public: enum FlagBit { PICK_ENTITIES = 0, @@ -39,11 +42,11 @@ public: // The key is the Flags Flags _flags; - RayPickFilter() {} - RayPickFilter(const Flags& flags) : _flags(flags) {} + PickFilter() {} + PickFilter(const Flags& flags) : _flags(flags) {} - bool operator== (const RayPickFilter& rhs) const { return _flags == rhs._flags; } - bool operator!= (const RayPickFilter& rhs) const { return _flags != rhs._flags; } + bool operator== (const PickFilter& rhs) const { return _flags == rhs._flags; } + bool operator!= (const PickFilter& rhs) const { return _flags != rhs._flags; } void setFlag(FlagBit flag, bool value) { _flags[flag] = value; } @@ -91,29 +94,42 @@ public: static constexpr unsigned int getBitMask(FlagBit bit) { return 1 << bit; } - static const RayPickFilter NOTHING; + static const PickFilter NOTHING; }; -class RayPick : protected ReadWriteLockable { +template +class Pick : protected ReadWriteLockable { public: - using Pointer = std::shared_ptr; + using Pointer = std::shared_ptr>; - RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled); + Pick(const PickFilter& filter, const float maxDistance, const bool enabled); - virtual const PickRay getPickRay(bool& valid) const = 0; + virtual const T getMathematicalPick(bool& valid) const = 0; + virtual RayToEntityIntersectionResult getEntityIntersection(const T& pick, bool precisionPicking, + const QVector& entitiesToInclude, + const QVector& entitiesToIgnore, + bool visibleOnly, bool collidableOnly) = 0; + virtual RayToOverlayIntersectionResult getOverlayIntersection(const T& pick, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToIgnore, + bool visibleOnly, bool collidableOnly) = 0; + virtual RayToAvatarIntersectionResult getAvatarIntersection(const T& pick, + const QVector& avatarsToInclude, + const QVector& avatarsToIgnore) = 0; + virtual glm::vec3 getHUDIntersection(const T& pick) = 0; void enable(bool enabled = true); void disable() { enable(false); } - RayPickFilter getFilter() const; + PickFilter getFilter() const; float getMaxDistance() const; bool isEnabled() const; - RayPickResult getPrevRayPickResult() const; + RayPickResult getPrevPickResult() const; void setPrecisionPicking(bool precisionPicking); - void setRayPickResult(const RayPickResult& rayPickResult); + void setPickResult(const RayPickResult& rayPickResult); QVector getIgnoreItems() const; QVector getIncludeItems() const; @@ -144,7 +160,7 @@ public: void setIncludeItems(const QVector& items); private: - RayPickFilter _filter; + PickFilter _filter; const float _maxDistance; bool _enabled; RayPickResult _prevResult; @@ -153,4 +169,87 @@ private: QVector _includeItems; }; -#endif // hifi_RayPick_h + +template +Pick::Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : + _filter(filter), + _maxDistance(maxDistance), + _enabled(enabled) { +} + +template +void Pick::enable(bool enabled) { + withWriteLock([&] { + _enabled = enabled; + }); +} + +template +PickFilter Pick::getFilter() const { + return resultWithReadLock([&] { + return _filter; + }); +} + +template +float Pick::getMaxDistance() const { + return _maxDistance; +} + +template +bool Pick::isEnabled() const { + withReadLock([&]) { + return _enabled; + } +} + +template +void Pick::setPrecisionPicking(bool precisionPicking) { + withWriteLock([&] { + _filter.setFlag(PickFilter::PICK_COARSE, !precisionPicking); + }); +} + +template +void Pick::setPickResult(const RayPickResult& PickResult) { + withWriteLock([&] { + _prevResult = PickResult; + }); +} + +template +QVector Pick::getIgnoreItems() const { + withReadLock([&]) { + return _ignoreItems; + } +} + +template +QVector Pick::getIncludeItems() const { + withReadLock([&]) { + return _includeItems; + } +} + +template +RayPickResult Pick::getPrevPickResult() const { + return resultWithReadLock([&] { + return _prevResult; + }); +} + +template +void Pick::setIgnoreItems(const QVector& ignoreItems) { + withWriteLock([&] { + _ignoreItems = ignoreItems; + }); +} + +template +void Pick::setIncludeItems(const QVector& includeItems) { + withWriteLock([&] { + _includeItems = includeItems; + }); +} + +#endif // hifi_Pick_h diff --git a/interface/src/raypick/PickManager.h b/interface/src/raypick/PickManager.h new file mode 100644 index 0000000000..228631449f --- /dev/null +++ b/interface/src/raypick/PickManager.h @@ -0,0 +1,244 @@ +// +// PickManager.h +// interface/src/raypick +// +// Created by Sam Gondelman 10/16/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_PickManager_h +#define hifi_PickManager_h + +#include + +#include "Pick.h" + +typedef struct RayCacheKey { + PickFilter::Flags mask; + QVector include; + QVector ignore; + + bool operator==(const RayCacheKey& other) const { + return (mask == other.mask && include == other.include && ignore == other.ignore); + } +} RayCacheKey; + +namespace std { + template <> + struct hash { + size_t operator()(const RayCacheKey& k) const { + return ((hash()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1); + } + }; +} + +// T is a mathematical representation of a Pick. +// For example: origin and direction for RayPick +template +class PickManager : protected ReadWriteLockable { + +public: + virtual void update(); + + RayPickResult getPrevPickResult(const QUuid& uid) const; + + void removePick(const QUuid& uid); + void enablePick(const QUuid& uid) const; + void disablePick(const QUuid& uid) const; + + void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; + void setIgnoreItems(const QUuid& uid, const QVector& ignore) const; + void setIncludeItems(const QUuid& uid, const QVector& include) const; + +protected: + Pick::Pointer findPick(const QUuid& uid) const; + QHash::Pointer> _picks; + + typedef QHash> RayPickCache; + + // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer + bool checkAndCompareCachedResults(T& pick, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key); + void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, T& pick, RayPickCache& cache); +}; + +template +RayPick::Pointer PickManager::findPick(const QUuid& uid) const { + return resultWithReadLock([&] { + if (_picks.contains(uid)) { + return _picks[uid]; + } + return RayPick::Pointer(); + }); +} + +template +bool PickManager::checkAndCompareCachedResults(T& pick, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) { + if (cache.contains(pick) && cache[pick].find(key) != cache[pick].end()) { + if (cache[pick][key].distance < res.distance) { + res = cache[pick][key]; + } + return true; + } + return false; +} + +template +void PickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, T& pick, RayPickCache& cache) { + if (intersects) { + cache[pick][key] = resTemp; + if (resTemp.distance < res.distance) { + res = resTemp; + } + } else { + cache[pick][key] = RayPickResult(res.searchRay); + } +} + +template +void PickManager::update() { + RayPickCache results; + QHash::Pointer> cachedPicks; + withReadLock([&] { + cachedPicks = _picks; + }); + + for (const auto& uid : cachedPicks.keys()) { + Pick::Pointer pick = cachedPicks[uid]; + if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) { + continue; + } + + T mathematicalPick; + + { + bool valid; + mathematicalPick = pick->getPickRay(valid); + if (!valid) { + continue; + } + } + + RayPickResult res = RayPickResult(mathematicalPick); + + if (pick->getFilter().doesPickEntities()) { + RayToEntityIntersectionResult entityRes; + bool fromCache = true; + bool invisible = pick->getFilter().doesPickInvisible(); + bool nonCollidable = pick->getFilter().doesPickNonCollidable(); + RayCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { + entityRes = pick->getEntityIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), + pick->getIncludeItemsAs(), pick->getIgnoreItemsAs(), !invisible, !nonCollidable); + fromCache = false; + } + + if (!fromCache) { + cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, mathematicalPick, entityRes.surfaceNormal), + entityKey, res, mathematicalPick, results); + } + } + + if (pick->getFilter().doesPickOverlays()) { + RayToOverlayIntersectionResult overlayRes; + bool fromCache = true; + bool invisible = pick->getFilter().doesPickInvisible(); + bool nonCollidable = pick->getFilter().doesPickNonCollidable(); + RayCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { + overlayRes = pick->getOverlayIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), + pick->getIncludeItemsAs(), pick->getIgnoreItemsAs(), !invisible, !nonCollidable); + fromCache = false; + } + + if (!fromCache) { + cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, mathematicalPick, overlayRes.surfaceNormal), + overlayKey, res, mathematicalPick, results); + } + } + + if (pick->getFilter().doesPickAvatars()) { + RayCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { + RayToAvatarIntersectionResult avatarRes = pick->getAvatarIntersection(mathematicalPick, + pick->getIncludeItemsAs(), pick->getIgnoreItemsAs()); + cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, mathematicalPick), avatarKey, res, mathematicalPick, results); + } + } + + // Can't intersect with HUD in desktop mode + if (pick->getFilter().doesPickHUD() && DependencyManager::get()->isHMDMode()) { + RayCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { + glm::vec3 hudRes = pick->getHUDIntersection(mathematicalPick.origin, mathematicalPick.direction); + cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(mathematicalPick.origin, hudRes), hudRes, mathematicalPick), hudKey, res, mathematicalPick, results); + } + } + + if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res.distance < pick->getMaxDistance())) { + pick->setPickResult(res); + } else { + pick->setPickResult(RayPickResult(mathematicalPick)); + } + } +} + +template +RayPickResult PickManager::getPrevPickResult(const QUuid& uid) const { + auto rayPick = findPick(uid); + if (rayPick) { + return rayPick->getPrevPickResult(); + } + return RayPickResult(); +} + +template +void PickManager::removePick(const QUuid& uid) { + withWriteLock([&] { + _picks.remove(uid); + }); +} + +template +void PickManager::enablePick(const QUuid& uid) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->enable(); + } +} + +template +void PickManager::disablePick(const QUuid& uid) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->disable(); + } +} + +template +void PickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->setPrecisionPicking(precisionPicking); + } +} + +template +void PickManager::setIgnoreItems(const QUuid& uid, const QVector& ignore) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->setIgnoreItems(ignore); + } +} + +template +void PickManager::setIncludeItems(const QUuid& uid, const QVector& include) const { + auto rayPick = findPick(uid); + if (rayPick) { + rayPick->setIncludeItems(include); + } +} + + +#endif // hifi_PickManager_h \ No newline at end of file diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp new file mode 100644 index 0000000000..f12320ee35 --- /dev/null +++ b/interface/src/raypick/RayPick.cpp @@ -0,0 +1,39 @@ +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "RayPick.h" + +#include "Application.h" +#include "avatar/AvatarManager.h" +#include "scripting/HMDScriptingInterface.h" +#include "DependencyManager.h" + +RayToEntityIntersectionResult RayPick::getEntityIntersection(const PickRay& pick, bool precisionPicking, + const QVector& entitiesToInclude, + const QVector& entitiesToIgnore, + bool visibleOnly, bool collidableOnly) { + return DependencyManager::get()->findRayIntersectionVector(pick, precisionPicking, + entitiesToInclude, entitiesToIgnore, visibleOnly, collidableOnly); +} + +RayToOverlayIntersectionResult RayPick::getOverlayIntersection(const PickRay& pick, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToIgnore, + bool visibleOnly, bool collidableOnly) { + return qApp->getOverlays().findRayIntersectionVector(pick, precisionPicking, + overlaysToInclude, overlaysToIgnore, visibleOnly, collidableOnly); +} + +RayToAvatarIntersectionResult RayPick::getAvatarIntersection(const PickRay& pick, + const QVector& avatarsToInclude, + const QVector& avatarsToIgnore) { + return DependencyManager::get()->findRayIntersectionVector(pick, avatarsToInclude, avatarsToIgnore); +} + +glm::vec3 RayPick::getHUDIntersection(const PickRay& pick) { + return DependencyManager::get()->calculateRayUICollisionPoint(pick.origin, pick.direction); +} \ No newline at end of file diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h new file mode 100644 index 0000000000..92778e74a2 --- /dev/null +++ b/interface/src/raypick/RayPick.h @@ -0,0 +1,35 @@ +// +// Created by Sam Gondelman 7/11/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RayPick_h +#define hifi_RayPick_h + +#include "Pick.h" + +class EntityItemID; +class OverlayID; + +class RayPick : public Pick { + +public: + RayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : Pick(filter, maxDistance, enabled) {} + + RayToEntityIntersectionResult getEntityIntersection(const PickRay& pick, bool precisionPicking, + const QVector& entitiesToInclude, + const QVector& entitiesToIgnore, + bool visibleOnly, bool collidableOnly) override; + RayToOverlayIntersectionResult getOverlayIntersection(const PickRay& pick, bool precisionPicking, + const QVector& overlaysToInclude, + const QVector& overlaysToIgnore, + bool visibleOnly, bool collidableOnly) override; + RayToAvatarIntersectionResult getAvatarIntersection(const PickRay& pick, + const QVector& avatarsToInclude, + const QVector& avatarsToIgnore) override; + glm::vec3 getHUDIntersection(const PickRay& pick) override; +}; + +#endif // hifi_RayPick_h diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index beb0075428..f4a45312bf 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -10,209 +10,33 @@ // #include "RayPickManager.h" -#include - -#include "Application.h" -#include "EntityScriptingInterface.h" -#include "ui/overlays/Overlays.h" -#include "avatar/AvatarManager.h" -#include "scripting/HMDScriptingInterface.h" -#include "DependencyManager.h" - +#include "StaticRayPick.h" #include "JointRayPick.h" #include "MouseRayPick.h" -bool RayPickManager::checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) { - if (cache.contains(ray) && cache[ray].find(key) != cache[ray].end()) { - if (cache[ray][key].distance < res.distance) { - res = cache[ray][key]; - } - return true; - } - return false; -} - -void RayPickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair& ray, RayPickCache& cache) { - if (intersects) { - cache[ray][key] = resTemp; - if (resTemp.distance < res.distance) { - res = resTemp; - } - } else { - cache[ray][key] = RayPickResult(res.searchRay); - } -} - -void RayPickManager::update() { - RayPickCache results; - QHash cachedRayPicks; - withReadLock([&] { - cachedRayPicks = _rayPicks; - }); - - for (const auto& uid : cachedRayPicks.keys()) { - std::shared_ptr rayPick = cachedRayPicks[uid]; - if (!rayPick->isEnabled() || rayPick->getFilter().doesPickNothing() || rayPick->getMaxDistance() < 0.0f) { - continue; - } - - PickRay ray; - - { - bool valid; - ray = rayPick->getPickRay(valid); - if (!valid) { - continue; - } - } - - QPair rayKey = QPair(ray.origin, ray.direction); - RayPickResult res = RayPickResult(ray); - - if (rayPick->getFilter().doesPickEntities()) { - RayToEntityIntersectionResult entityRes; - bool fromCache = true; - bool invisible = rayPick->getFilter().doesPickInvisible(); - bool nonCollidable = rayPick->getFilter().doesPickNonCollidable(); - RayCacheKey entityKey = { rayPick->getFilter().getEntityFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(rayKey, results, res, entityKey)) { - entityRes = DependencyManager::get()->findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(), - rayPick->getIncludeItemsAs(), rayPick->getIgnoreItemsAs(), !invisible, !nonCollidable); - fromCache = false; - } - - if (!fromCache) { - cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, ray, entityRes.surfaceNormal), - entityKey, res, rayKey, results); - } - } - - if (rayPick->getFilter().doesPickOverlays()) { - RayToOverlayIntersectionResult overlayRes; - bool fromCache = true; - bool invisible = rayPick->getFilter().doesPickInvisible(); - bool nonCollidable = rayPick->getFilter().doesPickNonCollidable(); - RayCacheKey overlayKey = { rayPick->getFilter().getOverlayFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(rayKey, results, res, overlayKey)) { - overlayRes = qApp->getOverlays().findRayIntersectionVector(ray, !rayPick->getFilter().doesPickCoarse(), - rayPick->getIncludeItemsAs(), rayPick->getIgnoreItemsAs(), !invisible, !nonCollidable); - fromCache = false; - } - - if (!fromCache) { - cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, ray, overlayRes.surfaceNormal), - overlayKey, res, rayKey, results); - } - } - - if (rayPick->getFilter().doesPickAvatars()) { - RayCacheKey avatarKey = { rayPick->getFilter().getAvatarFlags(), rayPick->getIncludeItems(), rayPick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(rayKey, results, res, avatarKey)) { - RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersectionVector(ray, - rayPick->getIncludeItemsAs(), rayPick->getIgnoreItemsAs()); - cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, ray), avatarKey, res, rayKey, results); - } - } - - // Can't intersect with HUD in desktop mode - if (rayPick->getFilter().doesPickHUD() && DependencyManager::get()->isHMDMode()) { - RayPickFilter::Flags hudMask = rayPick->getFilter().getHUDFlags(); - RayCacheKey hudKey = { rayPick->getFilter().getHUDFlags() }; - if (!checkAndCompareCachedResults(rayKey, results, res, hudKey)) { - glm::vec3 hudRes = DependencyManager::get()->calculateRayUICollisionPoint(ray.origin, ray.direction); - cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(ray.origin, hudRes), hudRes, ray), hudKey, res, rayKey, results); - } - } - - if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) { - rayPick->setRayPickResult(res); - } else { - rayPick->setRayPickResult(RayPickResult(ray)); - } - } -} - -QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, float maxDistance, bool enabled) { +QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, float maxDistance, bool enabled) { auto newRayPick = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled); QUuid id = QUuid::createUuid(); withWriteLock([&] { - _rayPicks[id] = newRayPick; + _picks[id] = newRayPick; }); return id; } -QUuid RayPickManager::createRayPick(const RayPickFilter& filter, float maxDistance, bool enabled) { +QUuid RayPickManager::createRayPick(const PickFilter& filter, float maxDistance, bool enabled) { QUuid id = QUuid::createUuid(); auto newRayPick = std::make_shared(filter, maxDistance, enabled); withWriteLock([&] { - _rayPicks[id] = newRayPick; + _picks[id] = newRayPick; }); return id; } -QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, float maxDistance, bool enabled) { +QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, float maxDistance, bool enabled) { QUuid id = QUuid::createUuid(); auto newRayPick = std::make_shared(position, direction, filter, maxDistance, enabled); withWriteLock([&] { - _rayPicks[id] = newRayPick; + _picks[id] = newRayPick; }); return id; -} - -void RayPickManager::removeRayPick(const QUuid& uid) { - withWriteLock([&] { - _rayPicks.remove(uid); - }); -} - -RayPick::Pointer RayPickManager::findRayPick(const QUuid& uid) const { - return resultWithReadLock([&] { - if (_rayPicks.contains(uid)) { - return _rayPicks[uid]; - } - return RayPick::Pointer(); - }); -} - -void RayPickManager::enableRayPick(const QUuid& uid) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->enable(); - } -} - -void RayPickManager::disableRayPick(const QUuid& uid) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->disable(); - } -} - -RayPickResult RayPickManager::getPrevRayPickResult(const QUuid& uid) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - return rayPick->getPrevRayPickResult(); - } - return RayPickResult(); -} - -void RayPickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->setPrecisionPicking(precisionPicking); - } -} - -void RayPickManager::setIgnoreItems(const QUuid& uid, const QVector& ignore) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->setIgnoreItems(ignore); - } -} - -void RayPickManager::setIncludeItems(const QUuid& uid, const QVector& include) const { - auto rayPick = findRayPick(uid); - if (rayPick) { - rayPick->setIncludeItems(include); - } -} +} \ No newline at end of file diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index fd2c6f4a6b..7673e402f4 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -11,64 +11,16 @@ #ifndef hifi_RayPickManager_h #define hifi_RayPickManager_h - -#include -#include -#include - -#include - -#include -#include - +#include "PickManager.h" class RayPickResult; -typedef struct RayCacheKey { - RayPickFilter::Flags mask; - QVector include; - QVector ignore; - - bool operator==(const RayCacheKey& other) const { - return (mask == other.mask && include == other.include && ignore == other.ignore); - } -} RayCacheKey; - -namespace std { - template <> - struct hash { - size_t operator()(const RayCacheKey& k) const { - return ((hash()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1); - } - }; -} - -class RayPickManager : protected ReadWriteLockable { +class RayPickManager : public PickManager { public: - void update(); - - QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const RayPickFilter& filter, const float maxDistance, const bool enabled); - QUuid createRayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled); - QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled); - void removeRayPick(const QUuid& uid); - void enableRayPick(const QUuid& uid) const; - void disableRayPick(const QUuid& uid) const; - RayPickResult getPrevRayPickResult(const QUuid& uid) const; - - void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; - void setIgnoreItems(const QUuid& uid, const QVector& ignore) const; - void setIncludeItems(const QUuid& uid, const QVector& include) const; - -private: - RayPick::Pointer findRayPick(const QUuid& uid) const; - QHash _rayPicks; - - typedef QHash, std::unordered_map> RayPickCache; - - // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer - bool checkAndCompareCachedResults(QPair& ray, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key); - void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, QPair& ray, RayPickCache& cache); + QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled); + QUuid createRayPick(const PickFilter& filter, const float maxDistance, const bool enabled); + QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled); }; #endif // hifi_RayPickManager_h \ No newline at end of file diff --git a/libraries/pointers/src/pointers/rays/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp similarity index 73% rename from libraries/pointers/src/pointers/rays/StaticRayPick.cpp rename to interface/src/raypick/StaticRayPick.cpp index e507341021..5db054c2e4 100644 --- a/libraries/pointers/src/pointers/rays/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -7,13 +7,13 @@ // #include "StaticRayPick.h" -StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance, const bool enabled) : +StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled) : RayPick(filter, maxDistance, enabled), _pickRay(position, direction) { } -const PickRay StaticRayPick::getPickRay(bool& valid) const { +const PickRay StaticRayPick::getMathematicalPick(bool& valid) const { valid = true; return _pickRay; } \ No newline at end of file diff --git a/libraries/pointers/src/pointers/rays/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h similarity index 75% rename from libraries/pointers/src/pointers/rays/StaticRayPick.h rename to interface/src/raypick/StaticRayPick.h index de5ec234a5..c26ea386d6 100644 --- a/libraries/pointers/src/pointers/rays/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -13,9 +13,9 @@ class StaticRayPick : public RayPick { public: - StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const RayPickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getPickRay(bool& valid) const override; + const PickRay getMathematicalPick(bool& valid) const override; private: PickRay _pickRay; diff --git a/libraries/pointers/src/pointers/rays/RayPick.cpp b/libraries/pointers/src/pointers/rays/RayPick.cpp deleted file mode 100644 index 36756cdb79..0000000000 --- a/libraries/pointers/src/pointers/rays/RayPick.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#include "RayPick.h" - -const RayPickFilter RayPickFilter::NOTHING; - -RayPick::RayPick(const RayPickFilter& filter, const float maxDistance, const bool enabled) : - _filter(filter), - _maxDistance(maxDistance), - _enabled(enabled) -{ -} - -void RayPick::enable(bool enabled) { - withWriteLock([&] { - _enabled = enabled; - }); -} - -RayPickFilter RayPick::getFilter() const { - return resultWithReadLock([&] { - return _filter; - }); -} - -float RayPick::getMaxDistance() const { - return _maxDistance; -} - -bool RayPick::isEnabled() const { - return _enabled; -} - -void RayPick::setPrecisionPicking(bool precisionPicking) { - withWriteLock([&]{ - _filter.setFlag(RayPickFilter::PICK_COARSE, !precisionPicking); - }); -} - -void RayPick::setRayPickResult(const RayPickResult& rayPickResult) { - withWriteLock([&] { - _prevResult = rayPickResult; - }); -} - -QVector RayPick::getIgnoreItems() const { - return _ignoreItems; -} - -QVector RayPick::getIncludeItems() const { - return _includeItems; -} - -RayPickResult RayPick::getPrevRayPickResult() const { - return resultWithReadLock([&] { - return _prevResult; - }); -} - -void RayPick::setIgnoreItems(const QVector& ignoreItems) { - withWriteLock([&] { - _ignoreItems = ignoreItems; - }); -} - -void RayPick::setIncludeItems(const QVector& includeItems) { - withWriteLock([&] { - _includeItems = includeItems; - }); -} diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 7b7d8d8f47..01b59f27e0 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -131,7 +131,22 @@ public: PickRay(const glm::vec3& origin, const glm::vec3 direction) : origin(origin), direction(direction) {} glm::vec3 origin; glm::vec3 direction; + + bool operator==(const PickRay& other) const { + return (origin == other.origin && direction == other.direction); + } }; +namespace std { + template <> + struct hash { + size_t operator()(const glm::vec3& a) const { + return ((hash()(a.x) ^ (hash()(a.y) << 1)) >> 1) ^ (hash()(a.z) << 1); + } + }; +} +uint qHash(const PickRay& a) { + return (uint)(std::hash()(a.origin) ^ (std::hash()(a.direction) << 1)); +} Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); From 3ef7ebffba07e1c055c57499243505b1a483a3c4 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 17 Oct 2017 15:09:41 -0700 Subject: [PATCH 007/292] working generalized pickmanager --- interface/src/Application.cpp | 4 +- interface/src/raypick/LaserPointer.cpp | 8 +- interface/src/raypick/Pick.h | 16 ++-- interface/src/raypick/PickManager.h | 88 ++++++++++--------- .../src/raypick/RayPickScriptingInterface.cpp | 12 +-- .../src/raypick/RayPickScriptingInterface.h | 18 ++-- libraries/shared/src/RegisteredMetaTypes.h | 2 +- 7 files changed, 74 insertions(+), 74 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e5d5e696a1..b8d3168f10 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1819,11 +1819,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Setup the mouse ray pick and related operators DependencyManager::get()->setMouseRayPickID(_rayPickManager.createRayPick( - RayPickFilter(DependencyManager::get()->PICK_ENTITIES() | DependencyManager::get()->PICK_INCLUDE_NONCOLLIDABLE()), + PickFilter(DependencyManager::get()->PICK_ENTITIES() | DependencyManager::get()->PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true)); DependencyManager::get()->setMouseRayPickResultOperator([&](QUuid rayPickID) { RayToEntityIntersectionResult entityResult; - RayPickResult result = _rayPickManager.getPrevRayPickResult(rayPickID); + RayPickResult result = _rayPickManager.getPrevPickResult(rayPickID); entityResult.intersects = result.type != DependencyManager::get()->INTERSECTED_NONE(); if (entityResult.intersects) { entityResult.intersection = result.intersection; diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index a2f7c7a521..1c5073b9c9 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -39,7 +39,7 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende } LaserPointer::~LaserPointer() { - qApp->getRayPickManager().removeRayPick(_rayPickUID); + qApp->getRayPickManager().removePick(_rayPickUID); for (auto& renderState : _renderStates) { renderState.second.deleteOverlays(); @@ -50,14 +50,14 @@ LaserPointer::~LaserPointer() { } void LaserPointer::enable() { - qApp->getRayPickManager().enableRayPick(_rayPickUID); + qApp->getRayPickManager().enablePick(_rayPickUID); withWriteLock([&] { _renderingEnabled = true; }); } void LaserPointer::disable() { - qApp->getRayPickManager().disableRayPick(_rayPickUID); + qApp->getRayPickManager().disablePick(_rayPickUID); withWriteLock([&] { _renderingEnabled = false; if (!_currentRenderState.empty()) { @@ -198,7 +198,7 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { void LaserPointer::update() { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { - RayPickResult prevRayPickResult = qApp->getRayPickManager().getPrevRayPickResult(_rayPickUID); + RayPickResult prevRayPickResult = qApp->getRayPickManager().getPrevPickResult(_rayPickUID); if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && (prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance; diff --git a/interface/src/raypick/Pick.h b/interface/src/raypick/Pick.h index 561c336f3b..c8d637bcb7 100644 --- a/interface/src/raypick/Pick.h +++ b/interface/src/raypick/Pick.h @@ -8,6 +8,7 @@ #ifndef hifi_Pick_h #define hifi_Pick_h +#include #include #include @@ -101,8 +102,6 @@ template class Pick : protected ReadWriteLockable { public: - using Pointer = std::shared_ptr>; - Pick(const PickFilter& filter, const float maxDistance, const bool enabled); virtual const T getMathematicalPick(bool& valid) const = 0; @@ -169,7 +168,6 @@ private: QVector _includeItems; }; - template Pick::Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : _filter(filter), @@ -198,9 +196,9 @@ float Pick::getMaxDistance() const { template bool Pick::isEnabled() const { - withReadLock([&]) { + return resultWithReadLock([&] { return _enabled; - } + }); } template @@ -219,16 +217,16 @@ void Pick::setPickResult(const RayPickResult& PickResult) { template QVector Pick::getIgnoreItems() const { - withReadLock([&]) { + return resultWithReadLock>([&] { return _ignoreItems; - } + }); } template QVector Pick::getIncludeItems() const { - withReadLock([&]) { + return resultWithReadLock>([&] { return _includeItems; - } + }); } template diff --git a/interface/src/raypick/PickManager.h b/interface/src/raypick/PickManager.h index 228631449f..1c6093d2f0 100644 --- a/interface/src/raypick/PickManager.h +++ b/interface/src/raypick/PickManager.h @@ -13,29 +13,31 @@ #include +#include "scripting/HMDScriptingInterface.h" + #include "Pick.h" -typedef struct RayCacheKey { +typedef struct PickCacheKey { PickFilter::Flags mask; QVector include; QVector ignore; - bool operator==(const RayCacheKey& other) const { + bool operator==(const PickCacheKey& other) const { return (mask == other.mask && include == other.include && ignore == other.ignore); } -} RayCacheKey; +} PickCacheKey; namespace std { template <> - struct hash { - size_t operator()(const RayCacheKey& k) const { + struct hash { + size_t operator()(const PickCacheKey& k) const { return ((hash()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1); } }; } // T is a mathematical representation of a Pick. -// For example: origin and direction for RayPick +// For example: PickRay for RayPick template class PickManager : protected ReadWriteLockable { @@ -53,28 +55,28 @@ public: void setIncludeItems(const QUuid& uid, const QVector& include) const; protected: - Pick::Pointer findPick(const QUuid& uid) const; - QHash::Pointer> _picks; + std::shared_ptr> findPick(const QUuid& uid) const; + QHash>> _picks; - typedef QHash> RayPickCache; + typedef QHash> PickCache; // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer - bool checkAndCompareCachedResults(T& pick, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key); - void cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, T& pick, RayPickCache& cache); + bool checkAndCompareCachedResults(T& pick, PickCache& cache, RayPickResult& res, const PickCacheKey& key); + void cacheResult(const bool intersects, const RayPickResult& resTemp, const PickCacheKey& key, RayPickResult& res, T& pick, PickCache& cache); }; template -RayPick::Pointer PickManager::findPick(const QUuid& uid) const { - return resultWithReadLock([&] { +std::shared_ptr> PickManager::findPick(const QUuid& uid) const { + return resultWithReadLock>>([&] { if (_picks.contains(uid)) { return _picks[uid]; } - return RayPick::Pointer(); + return std::shared_ptr>(); }); } template -bool PickManager::checkAndCompareCachedResults(T& pick, RayPickCache& cache, RayPickResult& res, const RayCacheKey& key) { +bool PickManager::checkAndCompareCachedResults(T& pick, PickCache& cache, RayPickResult& res, const PickCacheKey& key) { if (cache.contains(pick) && cache[pick].find(key) != cache[pick].end()) { if (cache[pick][key].distance < res.distance) { res = cache[pick][key]; @@ -85,7 +87,7 @@ bool PickManager::checkAndCompareCachedResults(T& pick, RayPickCache& cache, } template -void PickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const RayCacheKey& key, RayPickResult& res, T& pick, RayPickCache& cache) { +void PickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const PickCacheKey& key, RayPickResult& res, T& pick, PickCache& cache) { if (intersects) { cache[pick][key] = resTemp; if (resTemp.distance < res.distance) { @@ -98,14 +100,14 @@ void PickManager::cacheResult(const bool intersects, const RayPickResult& res template void PickManager::update() { - RayPickCache results; - QHash::Pointer> cachedPicks; + PickCache results; + QHash>> cachedPicks; withReadLock([&] { cachedPicks = _picks; }); for (const auto& uid : cachedPicks.keys()) { - Pick::Pointer pick = cachedPicks[uid]; + std::shared_ptr> pick = cachedPicks[uid]; if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) { continue; } @@ -114,7 +116,7 @@ void PickManager::update() { { bool valid; - mathematicalPick = pick->getPickRay(valid); + mathematicalPick = pick->getMathematicalPick(valid); if (!valid) { continue; } @@ -127,7 +129,7 @@ void PickManager::update() { bool fromCache = true; bool invisible = pick->getFilter().doesPickInvisible(); bool nonCollidable = pick->getFilter().doesPickNonCollidable(); - RayCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { entityRes = pick->getEntityIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), pick->getIncludeItemsAs(), pick->getIgnoreItemsAs(), !invisible, !nonCollidable); @@ -145,7 +147,7 @@ void PickManager::update() { bool fromCache = true; bool invisible = pick->getFilter().doesPickInvisible(); bool nonCollidable = pick->getFilter().doesPickNonCollidable(); - RayCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { overlayRes = pick->getOverlayIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), pick->getIncludeItemsAs(), pick->getIgnoreItemsAs(), !invisible, !nonCollidable); @@ -159,7 +161,7 @@ void PickManager::update() { } if (pick->getFilter().doesPickAvatars()) { - RayCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { RayToAvatarIntersectionResult avatarRes = pick->getAvatarIntersection(mathematicalPick, pick->getIncludeItemsAs(), pick->getIgnoreItemsAs()); @@ -169,9 +171,9 @@ void PickManager::update() { // Can't intersect with HUD in desktop mode if (pick->getFilter().doesPickHUD() && DependencyManager::get()->isHMDMode()) { - RayCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; + PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { - glm::vec3 hudRes = pick->getHUDIntersection(mathematicalPick.origin, mathematicalPick.direction); + glm::vec3 hudRes = pick->getHUDIntersection(mathematicalPick); cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(mathematicalPick.origin, hudRes), hudRes, mathematicalPick), hudKey, res, mathematicalPick, results); } } @@ -186,9 +188,9 @@ void PickManager::update() { template RayPickResult PickManager::getPrevPickResult(const QUuid& uid) const { - auto rayPick = findPick(uid); - if (rayPick) { - return rayPick->getPrevPickResult(); + auto pick = findPick(uid); + if (pick) { + return pick->getPrevPickResult(); } return RayPickResult(); } @@ -202,41 +204,41 @@ void PickManager::removePick(const QUuid& uid) { template void PickManager::enablePick(const QUuid& uid) const { - auto rayPick = findPick(uid); - if (rayPick) { - rayPick->enable(); + auto pick = findPick(uid); + if (pick) { + pick->enable(); } } template void PickManager::disablePick(const QUuid& uid) const { - auto rayPick = findPick(uid); - if (rayPick) { - rayPick->disable(); + auto pick = findPick(uid); + if (pick) { + pick->disable(); } } template void PickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { - auto rayPick = findPick(uid); - if (rayPick) { - rayPick->setPrecisionPicking(precisionPicking); + auto pick = findPick(uid); + if (pick) { + pick->setPrecisionPicking(precisionPicking); } } template void PickManager::setIgnoreItems(const QUuid& uid, const QVector& ignore) const { - auto rayPick = findPick(uid); - if (rayPick) { - rayPick->setIgnoreItems(ignore); + auto pick = findPick(uid); + if (pick) { + pick->setIgnoreItems(ignore); } } template void PickManager::setIncludeItems(const QUuid& uid, const QVector& include) const { - auto rayPick = findPick(uid); - if (rayPick) { - rayPick->setIncludeItems(include); + auto pick = findPick(uid); + if (pick) { + pick->setIncludeItems(include); } } diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index 621ae9b738..380971b5e6 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -23,9 +23,9 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { enabled = propMap["enabled"].toBool(); } - RayPickFilter filter = RayPickFilter(); + PickFilter filter = PickFilter(); if (propMap["filter"].isValid()) { - filter = RayPickFilter(propMap["filter"].toUInt()); + filter = PickFilter(propMap["filter"].toUInt()); } float maxDistance = 0.0f; @@ -67,19 +67,19 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { } void RayPickScriptingInterface::enableRayPick(const QUuid& uid) { - qApp->getRayPickManager().enableRayPick(uid); + qApp->getRayPickManager().enablePick(uid); } void RayPickScriptingInterface::disableRayPick(const QUuid& uid) { - qApp->getRayPickManager().disableRayPick(uid); + qApp->getRayPickManager().disablePick(uid); } void RayPickScriptingInterface::removeRayPick(const QUuid& uid) { - qApp->getRayPickManager().removeRayPick(uid); + qApp->getRayPickManager().removePick(uid); } RayPickResult RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) { - return qApp->getRayPickManager().getPrevRayPickResult(uid); + return qApp->getRayPickManager().getPrevPickResult(uid); } void RayPickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) { diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index 099103e4c5..2153c4f3a5 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -15,7 +15,7 @@ #include #include -#include +#include "RayPick.h" class RayPickScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -47,14 +47,14 @@ public slots: Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities); unsigned int PICK_NOTHING() { return 0; } - unsigned int PICK_ENTITIES() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ENTITIES); } - unsigned int PICK_OVERLAYS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_OVERLAYS); } - unsigned int PICK_AVATARS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_AVATARS); } - unsigned int PICK_HUD() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_HUD); } - unsigned int PICK_COARSE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_COARSE); } - unsigned int PICK_INCLUDE_INVISIBLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } - unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } - unsigned int PICK_ALL_INTERSECTIONS() { return RayPickFilter::getBitMask(RayPickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } + unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } + unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); } + unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); } + unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); } + unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); } + unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } + unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } + unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 01b59f27e0..c7b482a917 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -144,7 +144,7 @@ namespace std { } }; } -uint qHash(const PickRay& a) { +inline uint qHash(const PickRay& a) { return (uint)(std::hash()(a.origin) ^ (std::hash()(a.direction) << 1)); } Q_DECLARE_METATYPE(PickRay) From 8a5759df69f989e8e62ba0a1e05856dab5d74b42 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 17 Oct 2017 15:22:39 -0700 Subject: [PATCH 008/292] PickManager::addPick --- interface/src/raypick/PickManager.h | 11 +++++++++++ interface/src/raypick/RayPickManager.cpp | 21 +++------------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/interface/src/raypick/PickManager.h b/interface/src/raypick/PickManager.h index 1c6093d2f0..01cffaeb8e 100644 --- a/interface/src/raypick/PickManager.h +++ b/interface/src/raypick/PickManager.h @@ -38,6 +38,7 @@ namespace std { // T is a mathematical representation of a Pick. // For example: PickRay for RayPick +// TODO: add another template type to replace RayPickResult with a generalized PickResult template class PickManager : protected ReadWriteLockable { @@ -46,6 +47,7 @@ public: RayPickResult getPrevPickResult(const QUuid& uid) const; + QUuid addPick(const std::shared_ptr> pick); void removePick(const QUuid& uid); void enablePick(const QUuid& uid) const; void disablePick(const QUuid& uid) const; @@ -195,6 +197,15 @@ RayPickResult PickManager::getPrevPickResult(const QUuid& uid) const { return RayPickResult(); } +template +QUuid PickManager::addPick(const std::shared_ptr> pick) { + QUuid id = QUuid::createUuid(); + withWriteLock([&] { + _picks[id] = pick; + }); + return id; +} + template void PickManager::removePick(const QUuid& uid) { withWriteLock([&] { diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index f4a45312bf..e6b183133d 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -15,28 +15,13 @@ #include "MouseRayPick.h" QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, float maxDistance, bool enabled) { - auto newRayPick = std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled); - QUuid id = QUuid::createUuid(); - withWriteLock([&] { - _picks[id] = newRayPick; - }); - return id; + return addPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); } QUuid RayPickManager::createRayPick(const PickFilter& filter, float maxDistance, bool enabled) { - QUuid id = QUuid::createUuid(); - auto newRayPick = std::make_shared(filter, maxDistance, enabled); - withWriteLock([&] { - _picks[id] = newRayPick; - }); - return id; + return addPick(std::make_shared(filter, maxDistance, enabled)); } QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, float maxDistance, bool enabled) { - QUuid id = QUuid::createUuid(); - auto newRayPick = std::make_shared(position, direction, filter, maxDistance, enabled); - withWriteLock([&] { - _picks[id] = newRayPick; - }); - return id; + return addPick(std::make_shared(position, direction, filter, maxDistance, enabled)); } \ No newline at end of file From 05f4883104d54d5e65eaaa9ac1cb5e4b051f2e2c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 17 Oct 2017 16:15:54 -0700 Subject: [PATCH 009/292] get rid of valid --- interface/src/raypick/JointRayPick.cpp | 4 +--- interface/src/raypick/JointRayPick.h | 2 +- interface/src/raypick/MouseRayPick.cpp | 4 +--- interface/src/raypick/MouseRayPick.h | 2 +- interface/src/raypick/Pick.h | 2 +- interface/src/raypick/PickManager.h | 14 +++++--------- interface/src/raypick/StaticRayPick.cpp | 3 +-- interface/src/raypick/StaticRayPick.h | 2 +- libraries/shared/src/RegisteredMetaTypes.h | 15 +++++++++++---- 9 files changed, 23 insertions(+), 25 deletions(-) diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index d3991eac24..c2a7fb11e5 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -20,7 +20,7 @@ JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOff { } -const PickRay JointRayPick::getMathematicalPick(bool& valid) const { +const PickRay JointRayPick::getMathematicalPick() const { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(QString::fromStdString(_jointName)); bool useAvatarHead = _jointName == "Avatar"; @@ -38,10 +38,8 @@ const PickRay JointRayPick::getMathematicalPick(bool& valid) const { pos = pos + (rot * (myAvatar->getSensorToWorldScale() * _posOffset)); glm::vec3 dir = rot * glm::normalize(_dirOffset); - valid = true; return PickRay(pos, dir); } - valid = false; return PickRay(); } diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index b2bffe83c4..ab44bf67c8 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -18,7 +18,7 @@ class JointRayPick : public RayPick { public: JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getMathematicalPick(bool& valid) const override; + const PickRay getMathematicalPick() const override; private: std::string _jointName; diff --git a/interface/src/raypick/MouseRayPick.cpp b/interface/src/raypick/MouseRayPick.cpp index 27080f5857..f691dafc01 100644 --- a/interface/src/raypick/MouseRayPick.cpp +++ b/interface/src/raypick/MouseRayPick.cpp @@ -18,14 +18,12 @@ MouseRayPick::MouseRayPick(const PickFilter& filter, const float maxDistance, co { } -const PickRay MouseRayPick::getMathematicalPick(bool& valid) const { +const PickRay MouseRayPick::getMathematicalPick() const { QVariant position = qApp->getApplicationCompositor().getReticleInterface()->getPosition(); if (position.isValid()) { QVariantMap posMap = position.toMap(); - valid = true; return qApp->getCamera().computePickRay(posMap["x"].toFloat(), posMap["y"].toFloat()); } - valid = false; return PickRay(); } diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h index c565a03db7..e9eb3ccabf 100644 --- a/interface/src/raypick/MouseRayPick.h +++ b/interface/src/raypick/MouseRayPick.h @@ -18,7 +18,7 @@ class MouseRayPick : public RayPick { public: MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getMathematicalPick(bool& valid) const override; + const PickRay getMathematicalPick() const override; }; #endif // hifi_MouseRayPick_h diff --git a/interface/src/raypick/Pick.h b/interface/src/raypick/Pick.h index c8d637bcb7..161e9779ce 100644 --- a/interface/src/raypick/Pick.h +++ b/interface/src/raypick/Pick.h @@ -104,7 +104,7 @@ class Pick : protected ReadWriteLockable { public: Pick(const PickFilter& filter, const float maxDistance, const bool enabled); - virtual const T getMathematicalPick(bool& valid) const = 0; + virtual const T getMathematicalPick() const = 0; virtual RayToEntityIntersectionResult getEntityIntersection(const T& pick, bool precisionPicking, const QVector& entitiesToInclude, const QVector& entitiesToIgnore, diff --git a/interface/src/raypick/PickManager.h b/interface/src/raypick/PickManager.h index 01cffaeb8e..424be0aa4f 100644 --- a/interface/src/raypick/PickManager.h +++ b/interface/src/raypick/PickManager.h @@ -60,7 +60,7 @@ protected: std::shared_ptr> findPick(const QUuid& uid) const; QHash>> _picks; - typedef QHash> PickCache; + typedef std::unordered_map> PickCache; // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer bool checkAndCompareCachedResults(T& pick, PickCache& cache, RayPickResult& res, const PickCacheKey& key); @@ -79,7 +79,7 @@ std::shared_ptr> PickManager::findPick(const QUuid& uid) const { template bool PickManager::checkAndCompareCachedResults(T& pick, PickCache& cache, RayPickResult& res, const PickCacheKey& key) { - if (cache.contains(pick) && cache[pick].find(key) != cache[pick].end()) { + if (cache.find(pick) != cache.end() && cache[pick].find(key) != cache[pick].end()) { if (cache[pick][key].distance < res.distance) { res = cache[pick][key]; } @@ -114,14 +114,10 @@ void PickManager::update() { continue; } - T mathematicalPick; + T mathematicalPick = pick->getMathematicalPick(); - { - bool valid; - mathematicalPick = pick->getMathematicalPick(valid); - if (!valid) { - continue; - } + if (!mathematicalPick) { + continue; } RayPickResult res = RayPickResult(mathematicalPick); diff --git a/interface/src/raypick/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp index 5db054c2e4..f7803aade6 100644 --- a/interface/src/raypick/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -13,7 +13,6 @@ StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& directi { } -const PickRay StaticRayPick::getMathematicalPick(bool& valid) const { - valid = true; +const PickRay StaticRayPick::getMathematicalPick() const { return _pickRay; } \ No newline at end of file diff --git a/interface/src/raypick/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h index c26ea386d6..6dc0a809ae 100644 --- a/interface/src/raypick/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -15,7 +15,7 @@ class StaticRayPick : public RayPick { public: StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getMathematicalPick(bool& valid) const override; + const PickRay getMathematicalPick() const override; private: PickRay _pickRay; diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index c7b482a917..45813bb294 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -127,11 +127,15 @@ void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube); class PickRay { public: - PickRay() : origin(0.0f), direction(0.0f) { } + PickRay() : origin(NAN), direction(NAN) { } PickRay(const glm::vec3& origin, const glm::vec3 direction) : origin(origin), direction(direction) {} glm::vec3 origin; glm::vec3 direction; + operator bool() const { + auto isNan = glm::isnan(origin) || glm::isnan(direction); + return !isNan.x && !isNan.y && !isNan.z; + } bool operator==(const PickRay& other) const { return (origin == other.origin && direction == other.direction); } @@ -143,9 +147,12 @@ namespace std { return ((hash()(a.x) ^ (hash()(a.y) << 1)) >> 1) ^ (hash()(a.z) << 1); } }; -} -inline uint qHash(const PickRay& a) { - return (uint)(std::hash()(a.origin) ^ (std::hash()(a.direction) << 1)); + template <> + struct hash { + size_t operator()(const PickRay& a) const { + return (hash()(a.origin) ^ (hash()(a.direction) << 1)); + } + }; } Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); From 640ad514bcfbe2745e5e9fa7f2d784c3aef6ded1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 17 Oct 2017 16:26:55 -0700 Subject: [PATCH 010/292] updates based on austin's comments --- interface/src/Application.cpp | 4 +-- interface/src/raypick/Pick.h | 12 ++++---- interface/src/raypick/PickManager.h | 6 ++-- .../src/raypick/RayPickScriptingInterface.h | 28 +++++++++---------- libraries/shared/src/RegisteredMetaTypes.h | 3 +- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b8d3168f10..98fc3525bc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1819,12 +1819,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Setup the mouse ray pick and related operators DependencyManager::get()->setMouseRayPickID(_rayPickManager.createRayPick( - PickFilter(DependencyManager::get()->PICK_ENTITIES() | DependencyManager::get()->PICK_INCLUDE_NONCOLLIDABLE()), + PickFilter(RayPickScriptingInterface::PICK_ENTITIES() | RayPickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true)); DependencyManager::get()->setMouseRayPickResultOperator([&](QUuid rayPickID) { RayToEntityIntersectionResult entityResult; RayPickResult result = _rayPickManager.getPrevPickResult(rayPickID); - entityResult.intersects = result.type != DependencyManager::get()->INTERSECTED_NONE(); + entityResult.intersects = result.type != RayPickScriptingInterface::INTERSECTED_NONE(); if (entityResult.intersects) { entityResult.intersection = result.intersection; entityResult.distance = result.distance; diff --git a/interface/src/raypick/Pick.h b/interface/src/raypick/Pick.h index 161e9779ce..b4d9fa91b9 100644 --- a/interface/src/raypick/Pick.h +++ b/interface/src/raypick/Pick.h @@ -133,9 +133,9 @@ public: QVector getIgnoreItems() const; QVector getIncludeItems() const; - template - QVector getIgnoreItemsAs() const { - QVector result; + template + QVector getIgnoreItemsAs() const { + QVector result; withReadLock([&] { for (const auto& uid : _ignoreItems) { result.push_back(uid); @@ -144,9 +144,9 @@ public: return result; } - template - QVector getIncludeItemsAs() const { - QVector result; + template + QVector getIncludeItemsAs() const { + QVector result; withReadLock([&] { for (const auto& uid : _includeItems) { result.push_back(uid); diff --git a/interface/src/raypick/PickManager.h b/interface/src/raypick/PickManager.h index 424be0aa4f..3b991d130a 100644 --- a/interface/src/raypick/PickManager.h +++ b/interface/src/raypick/PickManager.h @@ -130,7 +130,7 @@ void PickManager::update() { PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { entityRes = pick->getEntityIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), - pick->getIncludeItemsAs(), pick->getIgnoreItemsAs(), !invisible, !nonCollidable); + pick->(template getIncludeItemsAs()), (template pick->getIgnoreItemsAs()), !invisible, !nonCollidable); fromCache = false; } @@ -148,7 +148,7 @@ void PickManager::update() { PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { overlayRes = pick->getOverlayIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), - pick->getIncludeItemsAs(), pick->getIgnoreItemsAs(), !invisible, !nonCollidable); + pick->(template getIncludeItemsAs()), pick->(template getIgnoreItemsAs()), !invisible, !nonCollidable); fromCache = false; } @@ -162,7 +162,7 @@ void PickManager::update() { PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { RayToAvatarIntersectionResult avatarRes = pick->getAvatarIntersection(mathematicalPick, - pick->getIncludeItemsAs(), pick->getIgnoreItemsAs()); + pick->(template getIncludeItemsAs()), pick->(template getIgnoreItemsAs())); cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, mathematicalPick), avatarKey, res, mathematicalPick, results); } } diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index 2153c4f3a5..b91483addf 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -46,20 +46,20 @@ public slots: Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities); Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities); - unsigned int PICK_NOTHING() { return 0; } - unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } - unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); } - unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); } - unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); } - unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); } - unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } - unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } - unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } - unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } - unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } - unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } - unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } - unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } + static unsigned int PICK_NOTHING() { return 0; } + static unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } + static unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); } + static unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); } + static unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); } + static unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); } + static unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } + static unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } + static unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } + static unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } + static unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } + static unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } + static unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } + static unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } }; #endif // hifi_RayPickScriptingInterface_h diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 45813bb294..8aeabce917 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -133,8 +133,7 @@ public: glm::vec3 direction; operator bool() const { - auto isNan = glm::isnan(origin) || glm::isnan(direction); - return !isNan.x && !isNan.y && !isNan.z; + return !(glm::any(glm::isnan(origin)) || glm::any(glm::isnan(direction))); } bool operator==(const PickRay& other) const { return (origin == other.origin && direction == other.direction); From 3572f7f5db9e989c0100817fabd77d0292eceb61 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 18 Oct 2017 18:43:56 -0700 Subject: [PATCH 011/292] non-templated pickresult wip --- interface/src/Application.cpp | 19 ++-- interface/src/raypick/LaserPointer.cpp | 16 ++-- interface/src/raypick/LaserPointer.h | 4 +- interface/src/raypick/LaserPointerManager.cpp | 4 +- interface/src/raypick/LaserPointerManager.h | 5 +- .../raypick/LaserPointerScriptingInterface.h | 2 +- interface/src/raypick/RayPick.cpp | 48 ++++++---- interface/src/raypick/RayPick.h | 70 ++++++++++++--- interface/src/raypick/RayPickManager.cpp | 3 - interface/src/raypick/RayPickManager.h | 8 +- .../src/raypick/RayPickScriptingInterface.cpp | 2 +- .../src/raypick/RayPickScriptingInterface.h | 30 +++---- .../pointers/src/pointers}/Pick.cpp | 0 .../pointers/src/pointers}/Pick.h | 68 +++++++++----- .../pointers/src/pointers}/PickManager.h | 90 +++++++------------ libraries/shared/src/RegisteredMetaTypes.cpp | 22 ----- libraries/shared/src/RegisteredMetaTypes.h | 32 ++----- 17 files changed, 217 insertions(+), 206 deletions(-) rename {interface/src/raypick => libraries/pointers/src/pointers}/Pick.cpp (100%) rename {interface/src/raypick => libraries/pointers/src/pointers}/Pick.h (78%) rename {interface/src/raypick => libraries/pointers/src/pointers}/PickManager.h (59%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 98fc3525bc..49b150db79 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1823,14 +1823,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo 0.0f, true)); DependencyManager::get()->setMouseRayPickResultOperator([&](QUuid rayPickID) { RayToEntityIntersectionResult entityResult; - RayPickResult result = _rayPickManager.getPrevPickResult(rayPickID); - entityResult.intersects = result.type != RayPickScriptingInterface::INTERSECTED_NONE(); - if (entityResult.intersects) { - entityResult.intersection = result.intersection; - entityResult.distance = result.distance; - entityResult.surfaceNormal = result.surfaceNormal; - entityResult.entityID = result.objectID; - entityResult.entity = DependencyManager::get()->getTree()->findEntityByID(entityResult.entityID); + entityResult.intersects = false; + QVariantMap result = _rayPickManager.getPrevPickResult(rayPickID); + if (result["type"].isValid()) { + entityResult.intersects = result["type"] != RayPickScriptingInterface::INTERSECTED_NONE(); + if (entityResult.intersects) { + entityResult.intersection = vec3FromVariant(result["intersection"]); + entityResult.distance = result["distance"].toFloat(); + entityResult.surfaceNormal = vec3FromVariant(result["surfaceNormal"]); + entityResult.entityID = result["objectID"].toUuid(); + entityResult.entity = DependencyManager::get()->getTree()->findEntityByID(entityResult.entityID); + } } return entityResult; }); diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 32c781b58d..2f3fc13706 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -12,7 +12,6 @@ #include "Application.h" #include "avatar/AvatarManager.h" -#include "RayPickScriptingInterface.h" LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : @@ -101,7 +100,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& } } -const RayPickResult LaserPointer::getPrevRayPickResult() { +const QVariantMap LaserPointer::getPrevRayPickResult() { return qApp->getRayPickManager().getPrevPickResult(_rayPickUID); } @@ -198,15 +197,18 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { void LaserPointer::update() { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { - RayPickResult prevRayPickResult = qApp->getRayPickManager().getPrevPickResult(_rayPickUID); + QVariantMap prevRayPickResult = qApp->getRayPickManager().getPrevPickResult(_rayPickUID); + IntersectionType type = IntersectionType(prevRayPickResult["type"].toInt()); + PickRay pickRay = PickRay(prevRayPickResult["searchRay"].toMap()); + QUuid uid = prevRayPickResult["objectID"].toUuid(); if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && - (prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { - float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult.distance; - updateRenderState(_renderStates[_currentRenderState], prevRayPickResult.type, distance, prevRayPickResult.objectID, prevRayPickResult.searchRay, false); + (type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { + float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult["distance"].toFloat(); + updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay, false); disableRenderState(_defaultRenderStates[_currentRenderState].second); } else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); - updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), prevRayPickResult.searchRay, true); + updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), pickRay, true); } else if (!_currentRenderState.empty()) { disableRenderState(_renderStates[_currentRenderState]); disableRenderState(_defaultRenderStates[_currentRenderState].second); diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 20ea824f50..d6fcf20b9d 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -19,7 +19,7 @@ #include "ui/overlays/Overlay.h" -class RayPickResult; +#include "RayPickScriptingInterface.h" class RenderState { @@ -61,7 +61,7 @@ public: QUuid getRayUID() { return _rayPickUID; } void enable(); void disable(); - const RayPickResult getPrevRayPickResult(); + const QVariantMap getPrevRayPickResult(); void setRenderState(const std::string& state); // You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays. diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp index f65a8a1a84..a300a418a7 100644 --- a/interface/src/raypick/LaserPointerManager.cpp +++ b/interface/src/raypick/LaserPointerManager.cpp @@ -67,12 +67,12 @@ void LaserPointerManager::editRenderState(const QUuid& uid, const std::string& s } } -const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid& uid) const { +const QVariantMap LaserPointerManager::getPrevRayPickResult(const QUuid& uid) const { auto laserPointer = find(uid); if (laserPointer) { return laserPointer->getPrevRayPickResult(); } - return RayPickResult(); + return QVariantMap(); } void LaserPointerManager::update() { diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h index a4689cf16d..547f7cc785 100644 --- a/interface/src/raypick/LaserPointerManager.h +++ b/interface/src/raypick/LaserPointerManager.h @@ -18,9 +18,6 @@ #include "LaserPointer.h" -class RayPickResult; - - class LaserPointerManager : protected ReadWriteLockable { public: @@ -31,7 +28,7 @@ public: void disableLaserPointer(const QUuid& uid) const; void setRenderState(const QUuid& uid, const std::string& renderState) const; void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; - const RayPickResult getPrevRayPickResult(const QUuid& uid) const; + const QVariantMap getPrevRayPickResult(const QUuid& uid) const; void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const; void setLaserLength(const QUuid& uid, const float laserLength) const; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 19262e6e5d..1e34016ab5 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -28,7 +28,7 @@ public slots: Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().removeLaserPointer(uid); } Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { qApp->getLaserPointerManager().setRenderState(uid, renderState.toStdString()); } - Q_INVOKABLE RayPickResult getPrevRayPickResult(QUuid uid) const { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); } + Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); } Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); } Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { qApp->getLaserPointerManager().setLaserLength(uid, laserLength); } diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp index f12320ee35..4e1e0386f1 100644 --- a/interface/src/raypick/RayPick.cpp +++ b/interface/src/raypick/RayPick.cpp @@ -8,32 +8,44 @@ #include "RayPick.h" #include "Application.h" +#include "EntityScriptingInterface.h" +#include "ui/overlays/Overlays.h" #include "avatar/AvatarManager.h" #include "scripting/HMDScriptingInterface.h" #include "DependencyManager.h" -RayToEntityIntersectionResult RayPick::getEntityIntersection(const PickRay& pick, bool precisionPicking, - const QVector& entitiesToInclude, - const QVector& entitiesToIgnore, - bool visibleOnly, bool collidableOnly) { - return DependencyManager::get()->findRayIntersectionVector(pick, precisionPicking, - entitiesToInclude, entitiesToIgnore, visibleOnly, collidableOnly); +PickResultPointer RayPick::getEntityIntersection(const PickRay& pick) { + RayToEntityIntersectionResult entityRes = + DependencyManager::get()->findRayIntersectionVector(pick, !getFilter().doesPickCoarse(), + getIncludeItemsAs(), getIgnoreItemsAs(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable()); + if (entityRes.intersects) { + return std::make_shared(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, pick, entityRes.surfaceNormal); + } else { + return std::make_shared(pick.toVariantMap()); + } } -RayToOverlayIntersectionResult RayPick::getOverlayIntersection(const PickRay& pick, bool precisionPicking, - const QVector& overlaysToInclude, - const QVector& overlaysToIgnore, - bool visibleOnly, bool collidableOnly) { - return qApp->getOverlays().findRayIntersectionVector(pick, precisionPicking, - overlaysToInclude, overlaysToIgnore, visibleOnly, collidableOnly); +PickResultPointer RayPick::getOverlayIntersection(const PickRay& pick) { + RayToOverlayIntersectionResult overlayRes = + qApp->getOverlays().findRayIntersectionVector(pick, !getFilter().doesPickCoarse(), + getIncludeItemsAs(), getIgnoreItemsAs(), !getFilter().doesPickInvisible(), !getFilter().doesPickNonCollidable()); + if (overlayRes.intersects) { + return std::make_shared(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, pick, overlayRes.surfaceNormal); + } else { + return std::make_shared(pick.toVariantMap()); + } } -RayToAvatarIntersectionResult RayPick::getAvatarIntersection(const PickRay& pick, - const QVector& avatarsToInclude, - const QVector& avatarsToIgnore) { - return DependencyManager::get()->findRayIntersectionVector(pick, avatarsToInclude, avatarsToIgnore); +PickResultPointer RayPick::getAvatarIntersection(const PickRay& pick) { + RayToAvatarIntersectionResult avatarRes = DependencyManager::get()->findRayIntersectionVector(pick, getIncludeItemsAs(), getIgnoreItemsAs()); + if (avatarRes.intersects) { + return std::make_shared(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, pick); + } else { + return std::make_shared(pick.toVariantMap()); + } } -glm::vec3 RayPick::getHUDIntersection(const PickRay& pick) { - return DependencyManager::get()->calculateRayUICollisionPoint(pick.origin, pick.direction); +PickResultPointer RayPick::getHUDIntersection(const PickRay& pick) { + glm::vec3 hudRes = DependencyManager::get()->calculateRayUICollisionPoint(pick.origin, pick.direction); + return std::make_shared(IntersectionType::HUD, QUuid(), glm::distance(pick.origin, hudRes), hudRes, pick); } \ No newline at end of file diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 92778e74a2..b5d7ea7c3e 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -8,28 +8,72 @@ #ifndef hifi_RayPick_h #define hifi_RayPick_h -#include "Pick.h" +#include +#include class EntityItemID; class OverlayID; +class RayPickResult : public PickResult { +public: + RayPickResult() {} + RayPickResult(const QVariantMap& pickVariant) : PickResult(pickVariant) {} + RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const PickRay& searchRay, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + PickResult(searchRay.toVariantMap()), type(type), intersects(type != NONE), objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) { + } + + RayPickResult(const RayPickResult& rayPickResult) : PickResult(rayPickResult.pickVariant) { + type = rayPickResult.type; + intersects = rayPickResult.intersects; + objectID = rayPickResult.objectID; + distance = rayPickResult.distance; + intersection = rayPickResult.intersection; + surfaceNormal = rayPickResult.surfaceNormal; + } + + IntersectionType type { NONE }; + bool intersects { false }; + QUuid objectID; + float distance { FLT_MAX }; + glm::vec3 intersection { NAN }; + glm::vec3 surfaceNormal { NAN }; + + virtual QVariantMap toVariantMap() const override { + QVariantMap toReturn; + toReturn["type"] = type; + toReturn["intersects"] = intersects; + toReturn["objectID"] = objectID; + toReturn["distance"] = distance; + toReturn["intersection"] = vec3toVariant(intersection); + toReturn["surfaceNormal"] = vec3toVariant(surfaceNormal); + toReturn["searchRay"] = PickResult::toVariantMap(); + return toReturn; + } + + bool doesIntersect() const override { return intersects; } + bool checkOrFilterAgainstMaxDistance(float maxDistance) override { return distance < maxDistance; } + + PickResultPointer compareAndProcessNewResult(const PickResultPointer newRes) override { + auto newRayRes = std::static_pointer_cast(newRes); + if (newRayRes->distance < distance) { + return std::make_shared(*newRayRes); + } else { + return std::make_shared(*this); + } + } + +}; + class RayPick : public Pick { public: RayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : Pick(filter, maxDistance, enabled) {} - RayToEntityIntersectionResult getEntityIntersection(const PickRay& pick, bool precisionPicking, - const QVector& entitiesToInclude, - const QVector& entitiesToIgnore, - bool visibleOnly, bool collidableOnly) override; - RayToOverlayIntersectionResult getOverlayIntersection(const PickRay& pick, bool precisionPicking, - const QVector& overlaysToInclude, - const QVector& overlaysToIgnore, - bool visibleOnly, bool collidableOnly) override; - RayToAvatarIntersectionResult getAvatarIntersection(const PickRay& pick, - const QVector& avatarsToInclude, - const QVector& avatarsToIgnore) override; - glm::vec3 getHUDIntersection(const PickRay& pick) override; + PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override { return std::make_shared(pickVariant); } + PickResultPointer getEntityIntersection(const PickRay& pick) override; + PickResultPointer getOverlayIntersection(const PickRay& pick) override; + PickResultPointer getAvatarIntersection(const PickRay& pick) override; + PickResultPointer getHUDIntersection(const PickRay& pick) override; }; #endif // hifi_RayPick_h diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp index e6b183133d..2e62c608d8 100644 --- a/interface/src/raypick/RayPickManager.cpp +++ b/interface/src/raypick/RayPickManager.cpp @@ -1,7 +1,4 @@ // -// RayPickManager.cpp -// interface/src/raypick -// // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. // diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h index 7673e402f4..7bc97c8526 100644 --- a/interface/src/raypick/RayPickManager.h +++ b/interface/src/raypick/RayPickManager.h @@ -1,7 +1,4 @@ // -// RayPickManager.h -// interface/src/raypick -// // Created by Sam Gondelman 7/11/2017 // Copyright 2017 High Fidelity, Inc. // @@ -11,9 +8,8 @@ #ifndef hifi_RayPickManager_h #define hifi_RayPickManager_h -#include "PickManager.h" - -class RayPickResult; +#include +#include "RegisteredMetaTypes.h" class RayPickManager : public PickManager { diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index 380971b5e6..11b6b2dfa3 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -78,7 +78,7 @@ void RayPickScriptingInterface::removeRayPick(const QUuid& uid) { qApp->getRayPickManager().removePick(uid); } -RayPickResult RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) { +QVariantMap RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) { return qApp->getRayPickManager().getPrevPickResult(uid); } diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index b91483addf..ebfc3fb9fe 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -40,26 +40,26 @@ public slots: Q_INVOKABLE void enableRayPick(const QUuid& uid); Q_INVOKABLE void disableRayPick(const QUuid& uid); Q_INVOKABLE void removeRayPick(const QUuid& uid); - Q_INVOKABLE RayPickResult getPrevRayPickResult(const QUuid& uid); + Q_INVOKABLE QVariantMap getPrevRayPickResult(const QUuid& uid); Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, const bool precisionPicking); Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities); Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities); - static unsigned int PICK_NOTHING() { return 0; } - static unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } - static unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); } - static unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); } - static unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); } - static unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); } - static unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } - static unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } - static unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } - static unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } - static unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } - static unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } - static unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } - static unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } + static constexpr unsigned int PICK_NOTHING() { return 0; } + static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } + static constexpr unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); } + static constexpr unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); } + static constexpr unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); } + static constexpr unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); } + static constexpr unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } + static constexpr unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } + static constexpr unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } + static constexpr unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } + static constexpr unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } + static constexpr unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } + static constexpr unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } + static constexpr unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } }; #endif // hifi_RayPickScriptingInterface_h diff --git a/interface/src/raypick/Pick.cpp b/libraries/pointers/src/pointers/Pick.cpp similarity index 100% rename from interface/src/raypick/Pick.cpp rename to libraries/pointers/src/pointers/Pick.cpp diff --git a/interface/src/raypick/Pick.h b/libraries/pointers/src/pointers/Pick.h similarity index 78% rename from interface/src/raypick/Pick.h rename to libraries/pointers/src/pointers/Pick.h index b4d9fa91b9..6e11506dd9 100644 --- a/interface/src/raypick/Pick.h +++ b/libraries/pointers/src/pointers/Pick.h @@ -13,12 +13,18 @@ #include #include +#include +#include -#include #include -#include "EntityScriptingInterface.h" -#include "ui/overlays/Overlays.h" +enum IntersectionType { + NONE = 0, + ENTITY, + OVERLAY, + AVATAR, + HUD +}; class PickFilter { public: @@ -98,6 +104,31 @@ public: static const PickFilter NOTHING; }; +class PickResult { +public: + PickResult() {} + PickResult(const QVariantMap& pickVariant) : pickVariant(pickVariant) {} + + virtual QVariantMap toVariantMap() const { + return pickVariant; + } + + virtual bool doesIntersect() const = 0; + + // for example: if we want the closest result, compare based on distance + // if we want all results, combine them + // must return a new pointer + virtual std::shared_ptr compareAndProcessNewResult(const std::shared_ptr newRes) = 0; + + // returns true if this result contains any valid results with distance < maxDistance + // can also filter out results with distance >= maxDistance + virtual bool checkOrFilterAgainstMaxDistance(float maxDistance) = 0; + + QVariantMap pickVariant; +}; + +using PickResultPointer = std::shared_ptr; + template class Pick : protected ReadWriteLockable { @@ -105,18 +136,11 @@ public: Pick(const PickFilter& filter, const float maxDistance, const bool enabled); virtual const T getMathematicalPick() const = 0; - virtual RayToEntityIntersectionResult getEntityIntersection(const T& pick, bool precisionPicking, - const QVector& entitiesToInclude, - const QVector& entitiesToIgnore, - bool visibleOnly, bool collidableOnly) = 0; - virtual RayToOverlayIntersectionResult getOverlayIntersection(const T& pick, bool precisionPicking, - const QVector& overlaysToInclude, - const QVector& overlaysToIgnore, - bool visibleOnly, bool collidableOnly) = 0; - virtual RayToAvatarIntersectionResult getAvatarIntersection(const T& pick, - const QVector& avatarsToInclude, - const QVector& avatarsToIgnore) = 0; - virtual glm::vec3 getHUDIntersection(const T& pick) = 0; + virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0; + virtual PickResultPointer getEntityIntersection(const T& pick) = 0; + virtual PickResultPointer getOverlayIntersection(const T& pick) = 0; + virtual PickResultPointer getAvatarIntersection(const T& pick) = 0; + virtual PickResultPointer getHUDIntersection(const T& pick) = 0; void enable(bool enabled = true); void disable() { enable(false); } @@ -124,11 +148,11 @@ public: PickFilter getFilter() const; float getMaxDistance() const; bool isEnabled() const; - RayPickResult getPrevPickResult() const; void setPrecisionPicking(bool precisionPicking); - void setPickResult(const RayPickResult& rayPickResult); + PickResultPointer getPrevPickResult() const; + void setPickResult(const PickResultPointer& pickResult); QVector getIgnoreItems() const; QVector getIncludeItems() const; @@ -162,7 +186,7 @@ private: PickFilter _filter; const float _maxDistance; bool _enabled; - RayPickResult _prevResult; + PickResultPointer _prevResult; QVector _ignoreItems; QVector _includeItems; @@ -209,9 +233,9 @@ void Pick::setPrecisionPicking(bool precisionPicking) { } template -void Pick::setPickResult(const RayPickResult& PickResult) { +void Pick::setPickResult(const PickResultPointer& pickResult) { withWriteLock([&] { - _prevResult = PickResult; + _prevResult = pickResult; }); } @@ -230,8 +254,8 @@ QVector Pick::getIncludeItems() const { } template -RayPickResult Pick::getPrevPickResult() const { - return resultWithReadLock([&] { +PickResultPointer Pick::getPrevPickResult() const { + return resultWithReadLock([&] { return _prevResult; }); } diff --git a/interface/src/raypick/PickManager.h b/libraries/pointers/src/pointers/PickManager.h similarity index 59% rename from interface/src/raypick/PickManager.h rename to libraries/pointers/src/pointers/PickManager.h index 3b991d130a..5441ff9b72 100644 --- a/interface/src/raypick/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -1,7 +1,4 @@ // -// PickManager.h -// interface/src/raypick -// // Created by Sam Gondelman 10/16/2017 // Copyright 2017 High Fidelity, Inc. // @@ -36,16 +33,20 @@ namespace std { }; } -// T is a mathematical representation of a Pick. -// For example: PickRay for RayPick -// TODO: add another template type to replace RayPickResult with a generalized PickResult +// T is a mathematical representation of a Pick +// For example: RayPicks use T = PickRay +// T needs have the following functions defined: +// - operator bool() const +// - bool operator==(const T& other) const +// - QVariantMap toVariantMap() const +// - an std::hash size_t operator()(const T& a) const template class PickManager : protected ReadWriteLockable { public: virtual void update(); - RayPickResult getPrevPickResult(const QUuid& uid) const; + QVariantMap getPrevPickResult(const QUuid& uid) const; QUuid addPick(const std::shared_ptr> pick); void removePick(const QUuid& uid); @@ -60,11 +61,11 @@ protected: std::shared_ptr> findPick(const QUuid& uid) const; QHash>> _picks; - typedef std::unordered_map> PickCache; + typedef std::unordered_map> PickCache; - // Returns true if this ray exists in the cache, and if it does, update res if the cached result is closer - bool checkAndCompareCachedResults(T& pick, PickCache& cache, RayPickResult& res, const PickCacheKey& key); - void cacheResult(const bool intersects, const RayPickResult& resTemp, const PickCacheKey& key, RayPickResult& res, T& pick, PickCache& cache); + // Returns true if this pick exists in the cache, and if it does, update res if the cached result is closer + bool checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key); + void cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr> pick); }; template @@ -78,25 +79,21 @@ std::shared_ptr> PickManager::findPick(const QUuid& uid) const { } template -bool PickManager::checkAndCompareCachedResults(T& pick, PickCache& cache, RayPickResult& res, const PickCacheKey& key) { +bool PickManager::checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key) { if (cache.find(pick) != cache.end() && cache[pick].find(key) != cache[pick].end()) { - if (cache[pick][key].distance < res.distance) { - res = cache[pick][key]; - } + res = res->compareAndProcessNewResult(cache[pick][key]); return true; } return false; } template -void PickManager::cacheResult(const bool intersects, const RayPickResult& resTemp, const PickCacheKey& key, RayPickResult& res, T& pick, PickCache& cache) { +void PickManager::cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr> pick) { if (intersects) { - cache[pick][key] = resTemp; - if (resTemp.distance < res.distance) { - res = resTemp; - } + cache[mathPick][key] = resTemp; + res = res->compareAndProcessNewResult(resTemp); } else { - cache[pick][key] = RayPickResult(res.searchRay); + cache[mathPick][key] = pick->getDefaultResult(mathPick.toVariantMap()); } } @@ -120,50 +117,29 @@ void PickManager::update() { continue; } - RayPickResult res = RayPickResult(mathematicalPick); + PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap()); if (pick->getFilter().doesPickEntities()) { - RayToEntityIntersectionResult entityRes; - bool fromCache = true; - bool invisible = pick->getFilter().doesPickInvisible(); - bool nonCollidable = pick->getFilter().doesPickNonCollidable(); PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { - entityRes = pick->getEntityIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), - pick->(template getIncludeItemsAs()), (template pick->getIgnoreItemsAs()), !invisible, !nonCollidable); - fromCache = false; - } - - if (!fromCache) { - cacheResult(entityRes.intersects, RayPickResult(IntersectionType::ENTITY, entityRes.entityID, entityRes.distance, entityRes.intersection, mathematicalPick, entityRes.surfaceNormal), - entityKey, res, mathematicalPick, results); + PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick); + cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); } } if (pick->getFilter().doesPickOverlays()) { - RayToOverlayIntersectionResult overlayRes; - bool fromCache = true; - bool invisible = pick->getFilter().doesPickInvisible(); - bool nonCollidable = pick->getFilter().doesPickNonCollidable(); PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { - overlayRes = pick->getOverlayIntersection(mathematicalPick, !pick->getFilter().doesPickCoarse(), - pick->(template getIncludeItemsAs()), pick->(template getIgnoreItemsAs()), !invisible, !nonCollidable); - fromCache = false; - } - - if (!fromCache) { - cacheResult(overlayRes.intersects, RayPickResult(IntersectionType::OVERLAY, overlayRes.overlayID, overlayRes.distance, overlayRes.intersection, mathematicalPick, overlayRes.surfaceNormal), - overlayKey, res, mathematicalPick, results); + PickResultPointer overlayRes = pick->getOverlayIntersection(mathematicalPick); + cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); } } if (pick->getFilter().doesPickAvatars()) { PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { - RayToAvatarIntersectionResult avatarRes = pick->getAvatarIntersection(mathematicalPick, - pick->(template getIncludeItemsAs()), pick->(template getIgnoreItemsAs())); - cacheResult(avatarRes.intersects, RayPickResult(IntersectionType::AVATAR, avatarRes.avatarID, avatarRes.distance, avatarRes.intersection, mathematicalPick), avatarKey, res, mathematicalPick, results); + PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick); + cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); } } @@ -171,26 +147,26 @@ void PickManager::update() { if (pick->getFilter().doesPickHUD() && DependencyManager::get()->isHMDMode()) { PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { - glm::vec3 hudRes = pick->getHUDIntersection(mathematicalPick); - cacheResult(true, RayPickResult(IntersectionType::HUD, 0, glm::distance(mathematicalPick.origin, hudRes), hudRes, mathematicalPick), hudKey, res, mathematicalPick, results); + PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick); + cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick); } } - if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res.distance < pick->getMaxDistance())) { + if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) { pick->setPickResult(res); } else { - pick->setPickResult(RayPickResult(mathematicalPick)); + pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap())); } } } template -RayPickResult PickManager::getPrevPickResult(const QUuid& uid) const { +QVariantMap PickManager::getPrevPickResult(const QUuid& uid) const { auto pick = findPick(uid); - if (pick) { - return pick->getPrevPickResult(); + if (pick && pick->getPrevPickResult()) { + return pick->getPrevPickResult()->toVariantMap(); } - return RayPickResult(); + return QVariantMap(); } template diff --git a/libraries/shared/src/RegisteredMetaTypes.cpp b/libraries/shared/src/RegisteredMetaTypes.cpp index 7d0df3ac78..b4d6ebaa7a 100644 --- a/libraries/shared/src/RegisteredMetaTypes.cpp +++ b/libraries/shared/src/RegisteredMetaTypes.cpp @@ -34,7 +34,6 @@ int vec2MetaTypeId = qRegisterMetaType(); int quatMetaTypeId = qRegisterMetaType(); int xColorMetaTypeId = qRegisterMetaType(); int pickRayMetaTypeId = qRegisterMetaType(); -int rayPickResultMetaTypeId = qRegisterMetaType(); int collisionMetaTypeId = qRegisterMetaType(); int qMapURLStringMetaTypeId = qRegisterMetaType>(); int socketErrorMetaTypeId = qRegisterMetaType(); @@ -57,7 +56,6 @@ void registerMetaTypes(QScriptEngine* engine) { qScriptRegisterMetaType(engine, qColorToScriptValue, qColorFromScriptValue); qScriptRegisterMetaType(engine, qURLToScriptValue, qURLFromScriptValue); qScriptRegisterMetaType(engine, pickRayToScriptValue, pickRayFromScriptValue); - qScriptRegisterMetaType(engine, rayPickResultToScriptValue, rayPickResultFromScriptValue); qScriptRegisterMetaType(engine, collisionToScriptValue, collisionFromScriptValue); qScriptRegisterMetaType(engine, quuidToScriptValue, quuidFromScriptValue); qScriptRegisterMetaType(engine, qSizeFToScriptValue, qSizeFFromScriptValue); @@ -753,26 +751,6 @@ void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay) { } } -QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult) { - QScriptValue obj = engine->newObject(); - obj.setProperty("type", rayPickResult.type); - QScriptValue objectID = quuidToScriptValue(engine, rayPickResult.objectID); - obj.setProperty("objectID", objectID); - obj.setProperty("distance", rayPickResult.distance); - QScriptValue intersection = vec3toScriptValue(engine, rayPickResult.intersection); - obj.setProperty("intersection", intersection); - obj.setProperty("intersects", rayPickResult.type != NONE); - QScriptValue searchRay = pickRayToScriptValue(engine, rayPickResult.searchRay); - obj.setProperty("searchRay", searchRay); - QScriptValue surfaceNormal = vec3toScriptValue(engine, rayPickResult.surfaceNormal); - obj.setProperty("surfaceNormal", surfaceNormal); - return obj; -} - -void rayPickResultFromScriptValue(const QScriptValue& object, RayPickResult& rayPickResult) { - // TODO: cannot currently accept RayPickResults from JS -} - QScriptValue collisionToScriptValue(QScriptEngine* engine, const Collision& collision) { QScriptValue obj = engine->newObject(); obj.setProperty("type", collision.type); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 8aeabce917..3d423d5205 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -128,6 +128,7 @@ void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube); class PickRay { public: PickRay() : origin(NAN), direction(NAN) { } + PickRay(const QVariantMap& pickVariant) : origin(vec3FromVariant(pickVariant["origin"])), direction(vec3FromVariant(pickVariant["direction"])) {} PickRay(const glm::vec3& origin, const glm::vec3 direction) : origin(origin), direction(direction) {} glm::vec3 origin; glm::vec3 direction; @@ -138,6 +139,12 @@ public: bool operator==(const PickRay& other) const { return (origin == other.origin && direction == other.direction); } + QVariantMap toVariantMap() const { + QVariantMap pickRay; + pickRay["origin"] = vec3toVariant(origin); + pickRay["direction"] = vec3toVariant(direction); + return pickRay; + } }; namespace std { template <> @@ -157,31 +164,6 @@ Q_DECLARE_METATYPE(PickRay) QScriptValue pickRayToScriptValue(QScriptEngine* engine, const PickRay& pickRay); void pickRayFromScriptValue(const QScriptValue& object, PickRay& pickRay); -enum IntersectionType { - NONE = 0, - ENTITY, - OVERLAY, - AVATAR, - HUD -}; - -class RayPickResult { -public: - RayPickResult() {} - RayPickResult(const PickRay& searchRay) : searchRay(searchRay) {} - RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const PickRay& searchRay, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : - type(type), objectID(objectID), distance(distance), intersection(intersection), searchRay(searchRay), surfaceNormal(surfaceNormal) {} - IntersectionType type { NONE }; - QUuid objectID; - float distance { FLT_MAX }; - glm::vec3 intersection { NAN }; - PickRay searchRay; - glm::vec3 surfaceNormal { NAN }; -}; -Q_DECLARE_METATYPE(RayPickResult) -QScriptValue rayPickResultToScriptValue(QScriptEngine* engine, const RayPickResult& rayPickResult); -void rayPickResultFromScriptValue(const QScriptValue& object, RayPickResult& rayPickResult); - enum ContactEventType { CONTACT_EVENT_TYPE_START, CONTACT_EVENT_TYPE_CONTINUE, From d7745efc8e1a256f22aa5bf24a14799a2c2f83ef Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 19 Oct 2017 16:55:24 -0700 Subject: [PATCH 012/292] one global pickmanager --- interface/src/Application.cpp | 119 +++++----- interface/src/Application.h | 6 +- interface/src/raypick/LaserPointer.cpp | 16 +- .../LaserPointerScriptingInterface.cpp | 1 - .../raypick/LaserPointerScriptingInterface.h | 1 - interface/src/raypick/RayPickManager.cpp | 24 -- interface/src/raypick/RayPickManager.h | 22 -- .../src/raypick/RayPickScriptingInterface.cpp | 25 ++- libraries/pointers/src/pointers/Pick.cpp | 72 +++++- libraries/pointers/src/pointers/Pick.h | 102 +-------- .../src/pointers/PickCacheOptimizer.h | 127 +++++++++++ .../pointers/src/pointers/PickManager.cpp | 94 ++++++++ libraries/pointers/src/pointers/PickManager.h | 212 ++---------------- libraries/shared/src/RegisteredMetaTypes.h | 12 +- 14 files changed, 417 insertions(+), 416 deletions(-) delete mode 100644 interface/src/raypick/RayPickManager.cpp delete mode 100644 interface/src/raypick/RayPickManager.h create mode 100644 libraries/pointers/src/pointers/PickCacheOptimizer.h create mode 100644 libraries/pointers/src/pointers/PickManager.cpp diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 49b150db79..a727c58f86 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -195,6 +195,7 @@ #include #include +#include #include @@ -750,8 +751,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _notifiedPacketVersionMismatchThisDomain(false), _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0), - _snapshotSound(nullptr) -{ + _snapshotSound(nullptr) { auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::CRASHED, _previousSessionCrashed); @@ -795,7 +795,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo installNativeEventFilter(&MyNativeEventFilter::getInstance()); #endif - + _logger = new FileLogger(this); qInstallMessageHandler(messageHandler); @@ -850,13 +850,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto audioIO = DependencyManager::get(); - audioIO->setPositionGetter([]{ + audioIO->setPositionGetter([] { auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; }); - audioIO->setOrientationGetter([]{ + audioIO->setOrientationGetter([] { auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; @@ -867,7 +867,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioIO->handleRecordedAudioInput(frame->data); }); - connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio){ + connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio) { static auto recorder = DependencyManager::get(); if (recorder->isRecording()) { static const recording::FrameType AUDIO_FRAME_TYPE = recording::Frame::registerFrameType(AudioConstants::getAudioFrameName()); @@ -956,14 +956,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto addressManager = DependencyManager::get(); // use our MyAvatar position and quat for address manager path - addressManager->setPositionGetter([this]{ return getMyAvatar()->getPosition(); }); - addressManager->setOrientationGetter([this]{ return getMyAvatar()->getOrientation(); }); + addressManager->setPositionGetter([this] { return getMyAvatar()->getPosition(); }); + addressManager->setOrientationGetter([this] { return getMyAvatar()->getOrientation(); }); connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); - connect(this, &Application::activeDisplayPluginChanged, this, [](){ + connect(this, &Application::activeDisplayPluginChanged, this, []() { qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); }); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); @@ -973,7 +973,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get().data(), &AddressManager::storeCurrentAddress); auto scriptEngines = DependencyManager::get().data(); - scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){ + scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine) { registerScriptEngineWithApplicationServices(engine); }); @@ -989,7 +989,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }, Qt::QueuedConnection); connect(scriptEngines, &ScriptEngines::scriptLoadError, - scriptEngines, [](const QString& filename, const QString& error){ + scriptEngines, [](const QString& filename, const QString& error) { OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load."); }, Qt::QueuedConnection); @@ -1101,7 +1101,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } // add firstRun flag from settings to launch event - Setting::Handle firstRun { Settings::firstRun, true }; + Setting::Handle firstRun{ Settings::firstRun, true }; // once the settings have been loaded, check if we need to flip the default for UserActivityLogger auto& userActivityLogger = UserActivityLogger::getInstance(); @@ -1202,42 +1202,42 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo static int lastKey = Qt::Key_unknown; bool navAxis = false; switch (actionEnum) { - case Action::UI_NAV_VERTICAL: - navAxis = true; - if (state > 0.0f) { - key = Qt::Key_Up; - } else if (state < 0.0f) { - key = Qt::Key_Down; - } - break; + case Action::UI_NAV_VERTICAL: + navAxis = true; + if (state > 0.0f) { + key = Qt::Key_Up; + } else if (state < 0.0f) { + key = Qt::Key_Down; + } + break; - case Action::UI_NAV_LATERAL: - navAxis = true; - if (state > 0.0f) { - key = Qt::Key_Right; - } else if (state < 0.0f) { - key = Qt::Key_Left; - } - break; + case Action::UI_NAV_LATERAL: + navAxis = true; + if (state > 0.0f) { + key = Qt::Key_Right; + } else if (state < 0.0f) { + key = Qt::Key_Left; + } + break; - case Action::UI_NAV_GROUP: - navAxis = true; - if (state > 0.0f) { - key = Qt::Key_Tab; - } else if (state < 0.0f) { - key = Qt::Key_Backtab; - } - break; + case Action::UI_NAV_GROUP: + navAxis = true; + if (state > 0.0f) { + key = Qt::Key_Tab; + } else if (state < 0.0f) { + key = Qt::Key_Backtab; + } + break; - case Action::UI_NAV_BACK: - key = Qt::Key_Escape; - break; + case Action::UI_NAV_BACK: + key = Qt::Key_Escape; + break; - case Action::UI_NAV_SELECT: - key = Qt::Key_Return; - break; - default: - break; + case Action::UI_NAV_SELECT: + key = Qt::Key_Return; + break; + default: + break; } auto window = tabletScriptingInterface->getTabletWindow(); @@ -1376,8 +1376,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo QTimer* settingsTimer = new QTimer(); - moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{ - connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{ + moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer] { + connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer] { // Disconnect the signal from the save settings QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); // Stop the settings timer @@ -1439,7 +1439,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Now that menu is initialized we can sync myAvatar with it's state. myAvatar->updateMotionBehaviorFromMenu(); -// FIXME spacemouse code still needs cleanup + // FIXME spacemouse code still needs cleanup #if 0 // the 3Dconnexion device wants to be initialized after a window is displayed. SpacemouseManager::getInstance().init(); @@ -1448,7 +1448,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, - [this](const EntityItemID& entityItemID, const PointerEvent& event) { + [this](const EntityItemID& entityItemID, const PointerEvent& event) { if (getEntities()->wantsKeyboardFocus(entityItemID)) { setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); setKeyboardFocusEntity(entityItemID); @@ -1663,8 +1663,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo totalServerOctreeElements += i->second.getTotalElements(); } - properties["local_octree_elements"] = (qint64) OctreeElement::getInternalNodeCount(); - properties["server_octree_elements"] = (qint64) totalServerOctreeElements; + properties["local_octree_elements"] = (qint64)OctreeElement::getInternalNodeCount(); + properties["server_octree_elements"] = (qint64)totalServerOctreeElements; properties["active_display_plugin"] = getActiveDisplayPlugin()->getName(); properties["using_hmd"] = isHMDMode(); @@ -1685,7 +1685,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (_autoSwitchDisplayModeSupportedHMDPlugin) { if (getActiveDisplayPlugin() != _autoSwitchDisplayModeSupportedHMDPlugin && !_autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { - startHMDStandBySession(); + startHMDStandBySession(); } // Poll periodically to check whether the user has worn HMD or not. Switch Display mode accordingly. // If the user wears HMD then switch to VR mode. If the user removes HMD then switch to Desktop mode. @@ -1729,7 +1729,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() { auto avatarManager = DependencyManager::get(); int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(), - NEARBY_AVATAR_RADIUS_METERS) - 1; + NEARBY_AVATAR_RADIUS_METERS) - 1; if (nearbyAvatars != lastCountOfNearbyAvatars) { lastCountOfNearbyAvatars = nearbyAvatars; UserActivityLogger::getInstance().logAction("nearby_avatars", { { "count", nearbyAvatars } }); @@ -1817,14 +1817,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); + _pickManager.setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); + // Setup the mouse ray pick and related operators - DependencyManager::get()->setMouseRayPickID(_rayPickManager.createRayPick( - PickFilter(RayPickScriptingInterface::PICK_ENTITIES() | RayPickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), - 0.0f, true)); + DependencyManager::get()->setMouseRayPickID(_pickManager.addPick(RAY, std::make_shared( + PickFilter(RayPickScriptingInterface::PICK_ENTITIES() | RayPickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true))); DependencyManager::get()->setMouseRayPickResultOperator([&](QUuid rayPickID) { RayToEntityIntersectionResult entityResult; entityResult.intersects = false; - QVariantMap result = _rayPickManager.getPrevPickResult(rayPickID); + QVariantMap result = _pickManager.getPrevPickResult(rayPickID); if (result["type"].isValid()) { entityResult.intersects = result["type"] != RayPickScriptingInterface::INTERSECTED_NONE(); if (entityResult.intersects) { @@ -1838,7 +1839,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return entityResult; }); DependencyManager::get()->setSetPrecisionPickingOperator([&](QUuid rayPickID, bool value) { - _rayPickManager.setPrecisionPicking(rayPickID, value); + _pickManager.setPrecisionPicking(rayPickID, value); }); qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID()); @@ -4910,8 +4911,8 @@ void Application::update(float deltaTime) { // TODO: break these out into distinct perfTimers when they prove interesting { - PROFILE_RANGE(app, "RayPickManager"); - _rayPickManager.update(); + PROFILE_RANGE(app, "PickManager"); + _pickManager.update(); } { diff --git a/interface/src/Application.h b/interface/src/Application.h index 772646f379..a70aaf93c7 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -70,7 +70,7 @@ #include "ui/overlays/Overlays.h" #include "UndoStackScriptingInterface.h" -#include "raypick/RayPickManager.h" +#include #include "raypick/LaserPointerManager.h" #include @@ -299,7 +299,7 @@ public: bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; } LaserPointerManager& getLaserPointerManager() { return _laserPointerManager; } - RayPickManager& getRayPickManager() { return _rayPickManager; } + PickManager& getPickManager() { return _pickManager; } signals: void svoImportRequested(const QString& url); @@ -713,7 +713,7 @@ private: bool _saveAvatarOverrideUrl { false }; QObject* _renderEventHandler{ nullptr }; - RayPickManager _rayPickManager; + PickManager _pickManager; LaserPointerManager _laserPointerManager; friend class RenderEventHandler; diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 2f3fc13706..0a8506ee28 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -38,7 +38,7 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende } LaserPointer::~LaserPointer() { - qApp->getRayPickManager().removePick(_rayPickUID); + qApp->getPickManager().removePick(_rayPickUID); for (auto& renderState : _renderStates) { renderState.second.deleteOverlays(); @@ -49,14 +49,14 @@ LaserPointer::~LaserPointer() { } void LaserPointer::enable() { - qApp->getRayPickManager().enablePick(_rayPickUID); + qApp->getPickManager().enablePick(_rayPickUID); withWriteLock([&] { _renderingEnabled = true; }); } void LaserPointer::disable() { - qApp->getRayPickManager().disablePick(_rayPickUID); + qApp->getPickManager().disablePick(_rayPickUID); withWriteLock([&] { _renderingEnabled = false; if (!_currentRenderState.empty()) { @@ -101,7 +101,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& } const QVariantMap LaserPointer::getPrevRayPickResult() { - return qApp->getRayPickManager().getPrevPickResult(_rayPickUID); + return qApp->getPickManager().getPrevPickResult(_rayPickUID); } void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) { @@ -197,7 +197,7 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { void LaserPointer::update() { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { - QVariantMap prevRayPickResult = qApp->getRayPickManager().getPrevPickResult(_rayPickUID); + QVariantMap prevRayPickResult = qApp->getPickManager().getPrevPickResult(_rayPickUID); IntersectionType type = IntersectionType(prevRayPickResult["type"].toInt()); PickRay pickRay = PickRay(prevRayPickResult["searchRay"].toMap()); QUuid uid = prevRayPickResult["objectID"].toUuid(); @@ -217,7 +217,7 @@ void LaserPointer::update() { } void LaserPointer::setPrecisionPicking(const bool precisionPicking) { - qApp->getRayPickManager().setPrecisionPicking(_rayPickUID, precisionPicking); + qApp->getPickManager().setPrecisionPicking(_rayPickUID, precisionPicking); } void LaserPointer::setLaserLength(const float laserLength) { @@ -233,11 +233,11 @@ void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) { } void LaserPointer::setIgnoreItems(const QVector& ignoreItems) const { - qApp->getRayPickManager().setIgnoreItems(_rayPickUID, ignoreItems); + qApp->getPickManager().setIgnoreItems(_rayPickUID, ignoreItems); } void LaserPointer::setIncludeItems(const QVector& includeItems) const { - qApp->getRayPickManager().setIncludeItems(_rayPickUID, includeItems); + qApp->getPickManager().setIncludeItems(_rayPickUID, includeItems); } RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) : diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 96839160fa..4ff917d8c5 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -14,7 +14,6 @@ #include #include -#include void LaserPointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { qApp->getLaserPointerManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 1e34016ab5..d51420a112 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -13,7 +13,6 @@ #include -#include "RegisteredMetaTypes.h" #include "DependencyManager.h" #include "Application.h" diff --git a/interface/src/raypick/RayPickManager.cpp b/interface/src/raypick/RayPickManager.cpp deleted file mode 100644 index 2e62c608d8..0000000000 --- a/interface/src/raypick/RayPickManager.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#include "RayPickManager.h" - -#include "StaticRayPick.h" -#include "JointRayPick.h" -#include "MouseRayPick.h" - -QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, float maxDistance, bool enabled) { - return addPick(std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); -} - -QUuid RayPickManager::createRayPick(const PickFilter& filter, float maxDistance, bool enabled) { - return addPick(std::make_shared(filter, maxDistance, enabled)); -} - -QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, float maxDistance, bool enabled) { - return addPick(std::make_shared(position, direction, filter, maxDistance, enabled)); -} \ No newline at end of file diff --git a/interface/src/raypick/RayPickManager.h b/interface/src/raypick/RayPickManager.h deleted file mode 100644 index 7bc97c8526..0000000000 --- a/interface/src/raypick/RayPickManager.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#ifndef hifi_RayPickManager_h -#define hifi_RayPickManager_h - -#include -#include "RegisteredMetaTypes.h" - -class RayPickManager : public PickManager { - -public: - QUuid createRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled); - QUuid createRayPick(const PickFilter& filter, const float maxDistance, const bool enabled); - QUuid createRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled); -}; - -#endif // hifi_RayPickManager_h \ No newline at end of file diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index 11b6b2dfa3..de67fdde0f 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -15,6 +15,10 @@ #include "GLMHelpers.h" #include "Application.h" +#include "StaticRayPick.h" +#include "JointRayPick.h" +#include "MouseRayPick.h" + QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { QVariantMap propMap = properties.toMap(); @@ -48,9 +52,10 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { dirOffset = vec3FromVariant(propMap["dirOffset"]); } - return qApp->getRayPickManager().createRayPick(jointName, posOffset, dirOffset, filter, maxDistance, enabled); + return qApp->getPickManager().addPick(RAY, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); + } else { - return qApp->getRayPickManager().createRayPick(filter, maxDistance, enabled); + return qApp->getPickManager().addPick(RAY, std::make_shared(filter, maxDistance, enabled)); } } else if (propMap["position"].isValid()) { glm::vec3 position = vec3FromVariant(propMap["position"]); @@ -60,36 +65,36 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { direction = vec3FromVariant(propMap["direction"]); } - return qApp->getRayPickManager().createRayPick(position, direction, filter, maxDistance, enabled); + return qApp->getPickManager().addPick(RAY, std::make_shared(position, direction, filter, maxDistance, enabled)); } return QUuid(); } void RayPickScriptingInterface::enableRayPick(const QUuid& uid) { - qApp->getRayPickManager().enablePick(uid); + qApp->getPickManager().enablePick(uid); } void RayPickScriptingInterface::disableRayPick(const QUuid& uid) { - qApp->getRayPickManager().disablePick(uid); + qApp->getPickManager().disablePick(uid); } void RayPickScriptingInterface::removeRayPick(const QUuid& uid) { - qApp->getRayPickManager().removePick(uid); + qApp->getPickManager().removePick(uid); } QVariantMap RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) { - return qApp->getRayPickManager().getPrevPickResult(uid); + return qApp->getPickManager().getPrevPickResult(uid); } void RayPickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) { - qApp->getRayPickManager().setPrecisionPicking(uid, precisionPicking); + qApp->getPickManager().setPrecisionPicking(uid, precisionPicking); } void RayPickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) { - qApp->getRayPickManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); + qApp->getPickManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } void RayPickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) { - qApp->getRayPickManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); + qApp->getPickManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/libraries/pointers/src/pointers/Pick.cpp b/libraries/pointers/src/pointers/Pick.cpp index 030d2ef4b7..4e48bc906b 100644 --- a/libraries/pointers/src/pointers/Pick.cpp +++ b/libraries/pointers/src/pointers/Pick.cpp @@ -7,4 +7,74 @@ // #include "Pick.h" -const PickFilter PickFilter::NOTHING; \ No newline at end of file +const PickFilter PickFilter::NOTHING; + +PickQuery::PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled) : + _filter(filter), + _maxDistance(maxDistance), + _enabled(enabled) { +} + +void PickQuery::enable(bool enabled) { + withWriteLock([&] { + _enabled = enabled; + }); +} + +PickFilter PickQuery::getFilter() const { + return resultWithReadLock([&] { + return _filter; + }); +} + +float PickQuery::getMaxDistance() const { + return _maxDistance; +} + +bool PickQuery::isEnabled() const { + return resultWithReadLock([&] { + return _enabled; + }); +} + +void PickQuery::setPrecisionPicking(bool precisionPicking) { + withWriteLock([&] { + _filter.setFlag(PickFilter::PICK_COARSE, !precisionPicking); + }); +} + +void PickQuery::setPickResult(const PickResultPointer& pickResult) { + withWriteLock([&] { + _prevResult = pickResult; + }); +} + +QVector PickQuery::getIgnoreItems() const { + return resultWithReadLock>([&] { + return _ignoreItems; + }); +} + +QVector PickQuery::getIncludeItems() const { + return resultWithReadLock>([&] { + return _includeItems; + }); +} + +PickResultPointer PickQuery::getPrevPickResult() const { + return resultWithReadLock([&] { + return _prevResult; + }); +} + +void PickQuery::setIgnoreItems(const QVector& ignoreItems) { + withWriteLock([&] { + _ignoreItems = ignoreItems; + }); +} + +void PickQuery::setIncludeItems(const QVector& includeItems) { + withWriteLock([&] { + _includeItems = includeItems; + }); +} \ No newline at end of file diff --git a/libraries/pointers/src/pointers/Pick.h b/libraries/pointers/src/pointers/Pick.h index 6e11506dd9..6ac0d6781e 100644 --- a/libraries/pointers/src/pointers/Pick.h +++ b/libraries/pointers/src/pointers/Pick.h @@ -129,18 +129,9 @@ public: using PickResultPointer = std::shared_ptr; -template -class Pick : protected ReadWriteLockable { - +class PickQuery : protected ReadWriteLockable { public: - Pick(const PickFilter& filter, const float maxDistance, const bool enabled); - - virtual const T getMathematicalPick() const = 0; - virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0; - virtual PickResultPointer getEntityIntersection(const T& pick) = 0; - virtual PickResultPointer getOverlayIntersection(const T& pick) = 0; - virtual PickResultPointer getAvatarIntersection(const T& pick) = 0; - virtual PickResultPointer getHUDIntersection(const T& pick) = 0; + PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled); void enable(bool enabled = true); void disable() { enable(false); } @@ -193,85 +184,16 @@ private: }; template -Pick::Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : - _filter(filter), - _maxDistance(maxDistance), - _enabled(enabled) { -} +class Pick : public PickQuery { +public: + Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : PickQuery(filter, maxDistance, enabled) {} -template -void Pick::enable(bool enabled) { - withWriteLock([&] { - _enabled = enabled; - }); -} - -template -PickFilter Pick::getFilter() const { - return resultWithReadLock([&] { - return _filter; - }); -} - -template -float Pick::getMaxDistance() const { - return _maxDistance; -} - -template -bool Pick::isEnabled() const { - return resultWithReadLock([&] { - return _enabled; - }); -} - -template -void Pick::setPrecisionPicking(bool precisionPicking) { - withWriteLock([&] { - _filter.setFlag(PickFilter::PICK_COARSE, !precisionPicking); - }); -} - -template -void Pick::setPickResult(const PickResultPointer& pickResult) { - withWriteLock([&] { - _prevResult = pickResult; - }); -} - -template -QVector Pick::getIgnoreItems() const { - return resultWithReadLock>([&] { - return _ignoreItems; - }); -} - -template -QVector Pick::getIncludeItems() const { - return resultWithReadLock>([&] { - return _includeItems; - }); -} - -template -PickResultPointer Pick::getPrevPickResult() const { - return resultWithReadLock([&] { - return _prevResult; - }); -} - -template -void Pick::setIgnoreItems(const QVector& ignoreItems) { - withWriteLock([&] { - _ignoreItems = ignoreItems; - }); -} - -template -void Pick::setIncludeItems(const QVector& includeItems) { - withWriteLock([&] { - _includeItems = includeItems; - }); -} + virtual const T getMathematicalPick() const = 0; + virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0; + virtual PickResultPointer getEntityIntersection(const T& pick) = 0; + virtual PickResultPointer getOverlayIntersection(const T& pick) = 0; + virtual PickResultPointer getAvatarIntersection(const T& pick) = 0; + virtual PickResultPointer getHUDIntersection(const T& pick) = 0; +}; #endif // hifi_Pick_h diff --git a/libraries/pointers/src/pointers/PickCacheOptimizer.h b/libraries/pointers/src/pointers/PickCacheOptimizer.h new file mode 100644 index 0000000000..c4bf96ab51 --- /dev/null +++ b/libraries/pointers/src/pointers/PickCacheOptimizer.h @@ -0,0 +1,127 @@ +// +// Created by Sam Gondelman 10/16/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_PickCacheOptimizer_h +#define hifi_PickCacheOptimizer_h + +#include + +#include "Pick.h" + +typedef struct PickCacheKey { + PickFilter::Flags mask; + QVector include; + QVector ignore; + + bool operator==(const PickCacheKey& other) const { + return (mask == other.mask && include == other.include && ignore == other.ignore); + } +} PickCacheKey; + +namespace std { + template <> + struct hash { + size_t operator()(const PickCacheKey& k) const { + return ((hash()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1); + } + }; +} + +// T is a mathematical representation of a Pick (a MathPick) +// For example: RayPicks use T = PickRay +template +class PickCacheOptimizer { + +public: + void update(QHash>& picks, bool shouldPickHUD); + +protected: + typedef std::unordered_map> PickCache; + + // Returns true if this pick exists in the cache, and if it does, update res if the cached result is closer + bool checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key); + void cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr> pick); +}; + +template +bool PickCacheOptimizer::checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key) { + if (cache.find(pick) != cache.end() && cache[pick].find(key) != cache[pick].end()) { + res = res->compareAndProcessNewResult(cache[pick][key]); + return true; + } + return false; +} + +template +void PickCacheOptimizer::cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr> pick) { + if (intersects) { + cache[mathPick][key] = resTemp; + res = res->compareAndProcessNewResult(resTemp); + } else { + cache[mathPick][key] = pick->getDefaultResult(mathPick.toVariantMap()); + } +} + +template +void PickCacheOptimizer::update(QHash>& picks, bool shouldPickHUD) { + PickCache results; + for (const auto& uid : picks.keys()) { + std::shared_ptr> pick = std::static_pointer_cast>(picks[uid]); + if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) { + continue; + } + + T mathematicalPick = pick->getMathematicalPick(); + + if (!mathematicalPick) { + continue; + } + + PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap()); + + if (pick->getFilter().doesPickEntities()) { + PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { + PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick); + cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); + } + } + + if (pick->getFilter().doesPickOverlays()) { + PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { + PickResultPointer overlayRes = pick->getOverlayIntersection(mathematicalPick); + cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); + } + } + + if (pick->getFilter().doesPickAvatars()) { + PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { + PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick); + cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); + } + } + + // Can't intersect with HUD in desktop mode + if (pick->getFilter().doesPickHUD() && shouldPickHUD) { + PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; + if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { + PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick); + cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick); + } + } + + if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) { + pick->setPickResult(res); + } else { + pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap())); + } + } +} + +#endif // hifi_PickCacheOptimizer_h \ No newline at end of file diff --git a/libraries/pointers/src/pointers/PickManager.cpp b/libraries/pointers/src/pointers/PickManager.cpp new file mode 100644 index 0000000000..d6c2f44212 --- /dev/null +++ b/libraries/pointers/src/pointers/PickManager.cpp @@ -0,0 +1,94 @@ +// +// Created by Sam Gondelman 10/19/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "PickManager.h" + +PickManager::PickManager() { + setShouldPickHUDOperator([]() { return false; }); +} + +QUuid PickManager::addPick(PickType type, const std::shared_ptr pick) { + QUuid id = QUuid::createUuid(); + withWriteLock([&] { + _picks[type][id] = pick; + _typeMap[id] = type; + }); + return id; +} + +std::shared_ptr PickManager::findPick(const QUuid& uid) const { + return resultWithReadLock>([&] { + auto type = _typeMap.find(uid); + if (type != _typeMap.end()) { + return _picks[type.value()][uid]; + } + return std::shared_ptr(); + }); +} + +void PickManager::removePick(const QUuid& uid) { + withWriteLock([&] { + auto type = _typeMap.find(uid); + if (type != _typeMap.end()) { + _picks[type.value()].remove(uid); + _typeMap.remove(uid); + } + }); +} + +QVariantMap PickManager::getPrevPickResult(const QUuid& uid) const { + auto pick = findPick(uid); + if (pick && pick->getPrevPickResult()) { + return pick->getPrevPickResult()->toVariantMap(); + } + return QVariantMap(); +} + +void PickManager::enablePick(const QUuid& uid) const { + auto pick = findPick(uid); + if (pick) { + pick->enable(); + } +} + +void PickManager::disablePick(const QUuid& uid) const { + auto pick = findPick(uid); + if (pick) { + pick->disable(); + } +} + +void PickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { + auto pick = findPick(uid); + if (pick) { + pick->setPrecisionPicking(precisionPicking); + } +} + +void PickManager::setIgnoreItems(const QUuid& uid, const QVector& ignore) const { + auto pick = findPick(uid); + if (pick) { + pick->setIgnoreItems(ignore); + } +} + +void PickManager::setIncludeItems(const QUuid& uid, const QVector& include) const { + auto pick = findPick(uid); + if (pick) { + pick->setIncludeItems(include); + } +} + +void PickManager::update() { + QHash>> cachedPicks; + withReadLock([&] { + cachedPicks = _picks; + }); + + bool shouldPickHUD = _shouldPickHUDOperator(); + _rayPickCacheOptimizer.update(cachedPicks[RAY], shouldPickHUD); +} \ No newline at end of file diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index 5441ff9b72..9b2f19a63a 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -10,220 +10,44 @@ #include -#include "scripting/HMDScriptingInterface.h" +#include "RegisteredMetaTypes.h" #include "Pick.h" +#include "PickCacheOptimizer.h" -typedef struct PickCacheKey { - PickFilter::Flags mask; - QVector include; - QVector ignore; +enum PickType { + RAY = 0, + STYLUS +}; - bool operator==(const PickCacheKey& other) const { - return (mask == other.mask && include == other.include && ignore == other.ignore); - } -} PickCacheKey; - -namespace std { - template <> - struct hash { - size_t operator()(const PickCacheKey& k) const { - return ((hash()(k.mask) ^ (qHash(k.include) << 1)) >> 1) ^ (qHash(k.ignore) << 1); - } - }; -} - -// T is a mathematical representation of a Pick -// For example: RayPicks use T = PickRay -// T needs have the following functions defined: -// - operator bool() const -// - bool operator==(const T& other) const -// - QVariantMap toVariantMap() const -// - an std::hash size_t operator()(const T& a) const -template class PickManager : protected ReadWriteLockable { public: - virtual void update(); + PickManager(); - QVariantMap getPrevPickResult(const QUuid& uid) const; + void update(); - QUuid addPick(const std::shared_ptr> pick); + QUuid addPick(PickType type, const std::shared_ptr pick); void removePick(const QUuid& uid); void enablePick(const QUuid& uid) const; void disablePick(const QUuid& uid) const; + QVariantMap getPrevPickResult(const QUuid& uid) const; + void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; void setIgnoreItems(const QUuid& uid, const QVector& ignore) const; void setIncludeItems(const QUuid& uid, const QVector& include) const; + void setShouldPickHUDOperator(std::function shouldPickHUDOperator) { _shouldPickHUDOperator = shouldPickHUDOperator; } + protected: - std::shared_ptr> findPick(const QUuid& uid) const; - QHash>> _picks; + std::function _shouldPickHUDOperator; - typedef std::unordered_map> PickCache; + std::shared_ptr findPick(const QUuid& uid) const; + QHash>> _picks; + QHash _typeMap; - // Returns true if this pick exists in the cache, and if it does, update res if the cached result is closer - bool checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key); - void cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr> pick); + PickCacheOptimizer _rayPickCacheOptimizer; }; -template -std::shared_ptr> PickManager::findPick(const QUuid& uid) const { - return resultWithReadLock>>([&] { - if (_picks.contains(uid)) { - return _picks[uid]; - } - return std::shared_ptr>(); - }); -} - -template -bool PickManager::checkAndCompareCachedResults(T& pick, PickCache& cache, PickResultPointer& res, const PickCacheKey& key) { - if (cache.find(pick) != cache.end() && cache[pick].find(key) != cache[pick].end()) { - res = res->compareAndProcessNewResult(cache[pick][key]); - return true; - } - return false; -} - -template -void PickManager::cacheResult(const bool intersects, const PickResultPointer& resTemp, const PickCacheKey& key, PickResultPointer& res, T& mathPick, PickCache& cache, const std::shared_ptr> pick) { - if (intersects) { - cache[mathPick][key] = resTemp; - res = res->compareAndProcessNewResult(resTemp); - } else { - cache[mathPick][key] = pick->getDefaultResult(mathPick.toVariantMap()); - } -} - -template -void PickManager::update() { - PickCache results; - QHash>> cachedPicks; - withReadLock([&] { - cachedPicks = _picks; - }); - - for (const auto& uid : cachedPicks.keys()) { - std::shared_ptr> pick = cachedPicks[uid]; - if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) { - continue; - } - - T mathematicalPick = pick->getMathematicalPick(); - - if (!mathematicalPick) { - continue; - } - - PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap()); - - if (pick->getFilter().doesPickEntities()) { - PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { - PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick); - cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); - } - } - - if (pick->getFilter().doesPickOverlays()) { - PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { - PickResultPointer overlayRes = pick->getOverlayIntersection(mathematicalPick); - cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); - } - } - - if (pick->getFilter().doesPickAvatars()) { - PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; - if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { - PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick); - cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); - } - } - - // Can't intersect with HUD in desktop mode - if (pick->getFilter().doesPickHUD() && DependencyManager::get()->isHMDMode()) { - PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; - if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { - PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick); - cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick); - } - } - - if (pick->getMaxDistance() == 0.0f || (pick->getMaxDistance() > 0.0f && res->checkOrFilterAgainstMaxDistance(pick->getMaxDistance()))) { - pick->setPickResult(res); - } else { - pick->setPickResult(pick->getDefaultResult(mathematicalPick.toVariantMap())); - } - } -} - -template -QVariantMap PickManager::getPrevPickResult(const QUuid& uid) const { - auto pick = findPick(uid); - if (pick && pick->getPrevPickResult()) { - return pick->getPrevPickResult()->toVariantMap(); - } - return QVariantMap(); -} - -template -QUuid PickManager::addPick(const std::shared_ptr> pick) { - QUuid id = QUuid::createUuid(); - withWriteLock([&] { - _picks[id] = pick; - }); - return id; -} - -template -void PickManager::removePick(const QUuid& uid) { - withWriteLock([&] { - _picks.remove(uid); - }); -} - -template -void PickManager::enablePick(const QUuid& uid) const { - auto pick = findPick(uid); - if (pick) { - pick->enable(); - } -} - -template -void PickManager::disablePick(const QUuid& uid) const { - auto pick = findPick(uid); - if (pick) { - pick->disable(); - } -} - -template -void PickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { - auto pick = findPick(uid); - if (pick) { - pick->setPrecisionPicking(precisionPicking); - } -} - -template -void PickManager::setIgnoreItems(const QUuid& uid, const QVector& ignore) const { - auto pick = findPick(uid); - if (pick) { - pick->setIgnoreItems(ignore); - } -} - -template -void PickManager::setIncludeItems(const QUuid& uid, const QVector& include) const { - auto pick = findPick(uid); - if (pick) { - pick->setIncludeItems(include); - } -} - - #endif // hifi_PickManager_h \ No newline at end of file diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index 3d423d5205..a716c9231e 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -125,7 +125,13 @@ QVector qVectorQUuidFromScriptValue(const QScriptValue& array); QScriptValue aaCubeToScriptValue(QScriptEngine* engine, const AACube& aaCube); void aaCubeFromScriptValue(const QScriptValue &object, AACube& aaCube); -class PickRay { +// MathPicks also have to overide operator== for their type +class MathPick { + virtual operator bool() const = 0; + virtual QVariantMap toVariantMap() const = 0; +}; + +class PickRay : public MathPick { public: PickRay() : origin(NAN), direction(NAN) { } PickRay(const QVariantMap& pickVariant) : origin(vec3FromVariant(pickVariant["origin"])), direction(vec3FromVariant(pickVariant["direction"])) {} @@ -133,13 +139,13 @@ public: glm::vec3 origin; glm::vec3 direction; - operator bool() const { + operator bool() const override { return !(glm::any(glm::isnan(origin)) || glm::any(glm::isnan(direction))); } bool operator==(const PickRay& other) const { return (origin == other.origin && direction == other.direction); } - QVariantMap toVariantMap() const { + QVariantMap toVariantMap() const override { QVariantMap pickRay; pickRay["origin"] = vec3toVariant(origin); pickRay["direction"] = vec3toVariant(direction); From 83c14bba5ca412c88468a5bcf8ba3fdcd04f17a3 Mon Sep 17 00:00:00 2001 From: vladest Date: Fri, 20 Oct 2017 11:55:41 +0200 Subject: [PATCH 013/292] Fix popups misbehavior, wrong links with double http etc --- interface/resources/qml/hifi/WebBrowser.qml | 35 +++++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index 1b49701bdf..6a1d61de11 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -1,3 +1,4 @@ + // // WebBrowser.qml // @@ -45,7 +46,7 @@ Rectangle { onSuggestions: { if (suggestions.length > 0) { suggestionsList = [] - suggestionsList.push(addressBar.editText) //do not overwrite edit text + suggestionsList.push(addressBarInput.text) //do not overwrite edit text for(var i = 0; i < suggestions.length; i++) { suggestionsList.push(suggestions[i]) } @@ -63,7 +64,7 @@ Rectangle { repeat: false onTriggered: { if (addressBar.editText !== "") { - searchEngine.requestSuggestions(addressBar.editText) + searchEngine.requestSuggestions(addressBarInput.text) } } } @@ -72,12 +73,16 @@ Rectangle { function goTo(url) { //must be valid attempt to open an site with dot - if (url.indexOf("http") <= 0 && url.indexOf(".") > 0) { - url = "http://" + url; + + if (url.indexOf(".") > 0) { + if (url.indexOf("http") < 0) { + url = "http://" + url; + } } else { url = searchEngine.searchUrl(url) } + addressBar.model = [] webEngineView.url = url suggestionRequestTimer.stop() addressBar.popup.close() @@ -151,12 +156,12 @@ Rectangle { } Keys.onDeletePressed: { - editText = "" + addressBarInput.text = "" } Keys.onPressed: { if (event.key === Qt.Key_Return) { - goTo(editText) + goTo(addressBarInput.text) event.accepted = true; } } @@ -192,19 +197,24 @@ Rectangle { Keys.onPressed: { if (event.key === Qt.Key_Return) { - goTo(editText) + goTo(addressBarInput.text) event.accepted = true; } } onEditTextChanged: { - console.log("edit text", addressBar.editText) - suggestionRequestTimer.restart() + if (addressBar.editText !== "" && addressBar.editText !== webEngineView.url.toString()) { + suggestionRequestTimer.restart(); + } else { + addressBar.model = [] + addressBar.popup.close() + } + } Layout.fillWidth: true editText: webEngineView.url - onAccepted: goTo(editText) + onAccepted: goTo(addressBarInput.text) } HifiControls.WebGlyphButton { @@ -265,6 +275,11 @@ Rectangle { } } + onLinkHovered: { + //TODO: change cursor shape? + console.error("hoveredUrl:", hoveredUrl) + } + // creates a global EventBridge object. WebEngineScript { id: createGlobalEventBridge From 24ce09f91413122d6d92570b4abc75cad44a8223 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 20 Oct 2017 11:19:14 -0700 Subject: [PATCH 014/292] generalized pointer, laserpointermanager -> pointermanager --- interface/src/Application.cpp | 119 ++++++++--------- interface/src/Application.h | 9 -- interface/src/raypick/LaserPointer.cpp | 38 ++---- interface/src/raypick/LaserPointer.h | 33 ++--- interface/src/raypick/LaserPointerManager.cpp | 121 ------------------ interface/src/raypick/LaserPointerManager.h | 47 ------- .../LaserPointerScriptingInterface.cpp | 10 +- .../raypick/LaserPointerScriptingInterface.h | 20 +-- .../src/raypick/RayPickScriptingInterface.cpp | 23 ++-- libraries/pointers/src/pointers/PickManager.h | 4 +- libraries/pointers/src/pointers/Pointer.cpp | 39 ++++++ libraries/pointers/src/pointers/Pointer.h | 46 +++++++ .../pointers/src/pointers/PointerManager.cpp | 113 +++++++++++++++- .../pointers/src/pointers/PointerManager.h | 32 ++++- 14 files changed, 341 insertions(+), 313 deletions(-) delete mode 100644 interface/src/raypick/LaserPointerManager.cpp delete mode 100644 interface/src/raypick/LaserPointerManager.h create mode 100644 libraries/pointers/src/pointers/Pointer.cpp create mode 100644 libraries/pointers/src/pointers/Pointer.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a727c58f86..3476700904 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -193,6 +193,8 @@ #include #include +#include +#include #include #include #include @@ -690,6 +692,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); + DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -751,7 +755,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo _notifiedPacketVersionMismatchThisDomain(false), _maxOctreePPS(maxOctreePacketsPerSecond.get()), _lastFaceTrackerUpdate(0), - _snapshotSound(nullptr) { + _snapshotSound(nullptr) +{ auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); setProperty(hifi::properties::CRASHED, _previousSessionCrashed); @@ -850,13 +855,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto audioIO = DependencyManager::get(); - audioIO->setPositionGetter([] { + audioIO->setPositionGetter([]{ auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; return myAvatar ? myAvatar->getPositionForAudio() : Vectors::ZERO; }); - audioIO->setOrientationGetter([] { + audioIO->setOrientationGetter([]{ auto avatarManager = DependencyManager::get(); auto myAvatar = avatarManager ? avatarManager->getMyAvatar() : nullptr; @@ -867,7 +872,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo audioIO->handleRecordedAudioInput(frame->data); }); - connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio) { + connect(audioIO.data(), &AudioClient::inputReceived, [](const QByteArray& audio){ static auto recorder = DependencyManager::get(); if (recorder->isRecording()) { static const recording::FrameType AUDIO_FRAME_TYPE = recording::Frame::registerFrameType(AudioConstants::getAudioFrameName()); @@ -956,14 +961,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto addressManager = DependencyManager::get(); // use our MyAvatar position and quat for address manager path - addressManager->setPositionGetter([this] { return getMyAvatar()->getPosition(); }); - addressManager->setOrientationGetter([this] { return getMyAvatar()->getOrientation(); }); + addressManager->setPositionGetter([this]{ return getMyAvatar()->getPosition(); }); + addressManager->setOrientationGetter([this]{ return getMyAvatar()->getOrientation(); }); connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); - connect(this, &Application::activeDisplayPluginChanged, this, []() { + connect(this, &Application::activeDisplayPluginChanged, this, [](){ qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); }); connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); @@ -973,7 +978,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get().data(), &AddressManager::storeCurrentAddress); auto scriptEngines = DependencyManager::get().data(); - scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine) { + scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){ registerScriptEngineWithApplicationServices(engine); }); @@ -989,7 +994,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo }, Qt::QueuedConnection); connect(scriptEngines, &ScriptEngines::scriptLoadError, - scriptEngines, [](const QString& filename, const QString& error) { + scriptEngines, [](const QString& filename, const QString& error){ OffscreenUi::asyncWarning(nullptr, "Error Loading Script", filename + " failed to load."); }, Qt::QueuedConnection); @@ -1101,7 +1106,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } // add firstRun flag from settings to launch event - Setting::Handle firstRun{ Settings::firstRun, true }; + Setting::Handle firstRun { Settings::firstRun, true }; // once the settings have been loaded, check if we need to flip the default for UserActivityLogger auto& userActivityLogger = UserActivityLogger::getInstance(); @@ -1202,42 +1207,42 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo static int lastKey = Qt::Key_unknown; bool navAxis = false; switch (actionEnum) { - case Action::UI_NAV_VERTICAL: - navAxis = true; - if (state > 0.0f) { - key = Qt::Key_Up; - } else if (state < 0.0f) { - key = Qt::Key_Down; - } - break; + case Action::UI_NAV_VERTICAL: + navAxis = true; + if (state > 0.0f) { + key = Qt::Key_Up; + } else if (state < 0.0f) { + key = Qt::Key_Down; + } + break; - case Action::UI_NAV_LATERAL: - navAxis = true; - if (state > 0.0f) { - key = Qt::Key_Right; - } else if (state < 0.0f) { - key = Qt::Key_Left; - } - break; + case Action::UI_NAV_LATERAL: + navAxis = true; + if (state > 0.0f) { + key = Qt::Key_Right; + } else if (state < 0.0f) { + key = Qt::Key_Left; + } + break; - case Action::UI_NAV_GROUP: - navAxis = true; - if (state > 0.0f) { - key = Qt::Key_Tab; - } else if (state < 0.0f) { - key = Qt::Key_Backtab; - } - break; + case Action::UI_NAV_GROUP: + navAxis = true; + if (state > 0.0f) { + key = Qt::Key_Tab; + } else if (state < 0.0f) { + key = Qt::Key_Backtab; + } + break; - case Action::UI_NAV_BACK: - key = Qt::Key_Escape; - break; + case Action::UI_NAV_BACK: + key = Qt::Key_Escape; + break; - case Action::UI_NAV_SELECT: - key = Qt::Key_Return; - break; - default: - break; + case Action::UI_NAV_SELECT: + key = Qt::Key_Return; + break; + default: + break; } auto window = tabletScriptingInterface->getTabletWindow(); @@ -1376,8 +1381,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo QTimer* settingsTimer = new QTimer(); - moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer] { - connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer] { + moveToNewNamedThread(settingsTimer, "Settings Thread", [this, settingsTimer]{ + connect(qApp, &Application::beforeAboutToQuit, [this, settingsTimer]{ // Disconnect the signal from the save settings QObject::disconnect(settingsTimer, &QTimer::timeout, this, &Application::saveSettings); // Stop the settings timer @@ -1439,7 +1444,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Now that menu is initialized we can sync myAvatar with it's state. myAvatar->updateMotionBehaviorFromMenu(); - // FIXME spacemouse code still needs cleanup +// FIXME spacemouse code still needs cleanup #if 0 // the 3Dconnexion device wants to be initialized after a window is displayed. SpacemouseManager::getInstance().init(); @@ -1448,7 +1453,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it auto entityScriptingInterface = DependencyManager::get(); connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, - [this](const EntityItemID& entityItemID, const PointerEvent& event) { + [this](const EntityItemID& entityItemID, const PointerEvent& event) { if (getEntities()->wantsKeyboardFocus(entityItemID)) { setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); setKeyboardFocusEntity(entityItemID); @@ -1663,8 +1668,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo totalServerOctreeElements += i->second.getTotalElements(); } - properties["local_octree_elements"] = (qint64)OctreeElement::getInternalNodeCount(); - properties["server_octree_elements"] = (qint64)totalServerOctreeElements; + properties["local_octree_elements"] = (qint64) OctreeElement::getInternalNodeCount(); + properties["server_octree_elements"] = (qint64) totalServerOctreeElements; properties["active_display_plugin"] = getActiveDisplayPlugin()->getName(); properties["using_hmd"] = isHMDMode(); @@ -1685,7 +1690,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo if (_autoSwitchDisplayModeSupportedHMDPlugin) { if (getActiveDisplayPlugin() != _autoSwitchDisplayModeSupportedHMDPlugin && !_autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { - startHMDStandBySession(); + startHMDStandBySession(); } // Poll periodically to check whether the user has worn HMD or not. Switch Display mode accordingly. // If the user wears HMD then switch to VR mode. If the user removes HMD then switch to Desktop mode. @@ -1729,7 +1734,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() { auto avatarManager = DependencyManager::get(); int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(), - NEARBY_AVATAR_RADIUS_METERS) - 1; + NEARBY_AVATAR_RADIUS_METERS) - 1; if (nearbyAvatars != lastCountOfNearbyAvatars) { lastCountOfNearbyAvatars = nearbyAvatars; UserActivityLogger::getInstance().logAction("nearby_avatars", { { "count", nearbyAvatars } }); @@ -1817,15 +1822,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); - _pickManager.setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); + DependencyManager::get()->setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); // Setup the mouse ray pick and related operators - DependencyManager::get()->setMouseRayPickID(_pickManager.addPick(RAY, std::make_shared( + DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(RAY, std::make_shared( PickFilter(RayPickScriptingInterface::PICK_ENTITIES() | RayPickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true))); DependencyManager::get()->setMouseRayPickResultOperator([&](QUuid rayPickID) { RayToEntityIntersectionResult entityResult; entityResult.intersects = false; - QVariantMap result = _pickManager.getPrevPickResult(rayPickID); + QVariantMap result = DependencyManager::get()->getPrevPickResult(rayPickID); if (result["type"].isValid()) { entityResult.intersects = result["type"] != RayPickScriptingInterface::INTERSECTED_NONE(); if (entityResult.intersects) { @@ -1839,7 +1844,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo return entityResult; }); DependencyManager::get()->setSetPrecisionPickingOperator([&](QUuid rayPickID, bool value) { - _pickManager.setPrecisionPicking(rayPickID, value); + DependencyManager::get()->setPrecisionPicking(rayPickID, value); }); qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID()); @@ -4912,12 +4917,12 @@ void Application::update(float deltaTime) { // TODO: break these out into distinct perfTimers when they prove interesting { PROFILE_RANGE(app, "PickManager"); - _pickManager.update(); + DependencyManager::get()->update(); } { - PROFILE_RANGE(app, "LaserPointerManager"); - _laserPointerManager.update(); + PROFILE_RANGE(app, "PointerManager"); + DependencyManager::get()->update(); } { diff --git a/interface/src/Application.h b/interface/src/Application.h index a70aaf93c7..7075745a39 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -70,9 +70,6 @@ #include "ui/overlays/Overlays.h" #include "UndoStackScriptingInterface.h" -#include -#include "raypick/LaserPointerManager.h" - #include #include #include @@ -298,9 +295,6 @@ public: QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; } bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; } - LaserPointerManager& getLaserPointerManager() { return _laserPointerManager; } - PickManager& getPickManager() { return _pickManager; } - signals: void svoImportRequested(const QString& url); @@ -713,9 +707,6 @@ private: bool _saveAvatarOverrideUrl { false }; QObject* _renderEventHandler{ nullptr }; - PickManager _pickManager; - LaserPointerManager _laserPointerManager; - friend class RenderEventHandler; }; #endif // hifi_Application_h diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 0a8506ee28..3100a18dde 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -13,18 +13,20 @@ #include "Application.h" #include "avatar/AvatarManager.h" +#include +#include +#include "RayPickScriptingInterface.h" + LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : + Pointer(DependencyManager::get()->createRayPick(rayProps)), _renderingEnabled(enabled), _renderStates(renderStates), _defaultRenderStates(defaultRenderStates), _faceAvatar(faceAvatar), _centerEndY(centerEndY), - _lockEnd(lockEnd), - _rayPickUID(DependencyManager::get()->createRayPick(rayProps)) + _lockEnd(lockEnd) { - - for (auto& state : _renderStates) { if (!enabled || state.first != _currentRenderState) { disableRenderState(state.second); @@ -38,8 +40,6 @@ LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& rende } LaserPointer::~LaserPointer() { - qApp->getPickManager().removePick(_rayPickUID); - for (auto& renderState : _renderStates) { renderState.second.deleteOverlays(); } @@ -49,14 +49,14 @@ LaserPointer::~LaserPointer() { } void LaserPointer::enable() { - qApp->getPickManager().enablePick(_rayPickUID); + Pointer::enable(); withWriteLock([&] { _renderingEnabled = true; }); } void LaserPointer::disable() { - qApp->getPickManager().disablePick(_rayPickUID); + Pointer::disable(); withWriteLock([&] { _renderingEnabled = false; if (!_currentRenderState.empty()) { @@ -100,10 +100,6 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& } } -const QVariantMap LaserPointer::getPrevRayPickResult() { - return qApp->getPickManager().getPrevPickResult(_rayPickUID); -} - void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) { if (!renderState.getStartID().isNull()) { QVariantMap startProps; @@ -197,7 +193,7 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { void LaserPointer::update() { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { - QVariantMap prevRayPickResult = qApp->getPickManager().getPrevPickResult(_rayPickUID); + QVariantMap prevRayPickResult = DependencyManager::get()->getPrevPickResult(_pickUID); IntersectionType type = IntersectionType(prevRayPickResult["type"].toInt()); PickRay pickRay = PickRay(prevRayPickResult["searchRay"].toMap()); QUuid uid = prevRayPickResult["objectID"].toUuid(); @@ -216,13 +212,9 @@ void LaserPointer::update() { }); } -void LaserPointer::setPrecisionPicking(const bool precisionPicking) { - qApp->getPickManager().setPrecisionPicking(_rayPickUID, precisionPicking); -} - -void LaserPointer::setLaserLength(const float laserLength) { +void LaserPointer::setLength(const float length) { withWriteLock([&] { - _laserLength = laserLength; + _laserLength = length; }); } @@ -232,14 +224,6 @@ void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) { }); } -void LaserPointer::setIgnoreItems(const QVector& ignoreItems) const { - qApp->getPickManager().setIgnoreItems(_rayPickUID, ignoreItems); -} - -void LaserPointer::setIncludeItems(const QVector& includeItems) const { - qApp->getPickManager().setIncludeItems(_rayPickUID, includeItems); -} - RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) : _startID(startID), _pathID(pathID), _endID(endID) { diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index d6fcf20b9d..a0fd1b2417 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -14,12 +14,10 @@ #include #include -#include -#include - #include "ui/overlays/Overlay.h" -#include "RayPickScriptingInterface.h" +#include +#include class RenderState { @@ -45,12 +43,9 @@ private: bool _endIgnoreRays; }; - -class LaserPointer : public ReadWriteLockable { +class LaserPointer : public Pointer { public: - using Pointer = std::shared_ptr; - typedef std::unordered_map RenderStateMap; typedef std::unordered_map> DefaultRenderStateMap; @@ -58,23 +53,17 @@ public: const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); ~LaserPointer(); - QUuid getRayUID() { return _rayPickUID; } - void enable(); - void disable(); - const QVariantMap getPrevRayPickResult(); + void enable() override; + void disable() override; - void setRenderState(const std::string& state); + void setRenderState(const std::string& state) override; // You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays. - void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps); + void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override; - void setPrecisionPicking(const bool precisionPicking); - void setLaserLength(const float laserLength); - void setLockEndUUID(QUuid objectID, const bool isOverlay); + void setLength(const float length) override; + void setLockEndUUID(QUuid objectID, const bool isOverlay) override; - void setIgnoreItems(const QVector& ignoreItems) const; - void setIncludeItems(const QVector& includeItems) const; - - void update(); + void update() override; private: bool _renderingEnabled; @@ -87,8 +76,6 @@ private: bool _lockEnd; std::pair _objectLockEnd { std::pair(QUuid(), false)}; - const QUuid _rayPickUID; - void updateRenderStateOverlay(const OverlayID& id, const QVariant& props); void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState); void disableRenderState(const RenderState& renderState); diff --git a/interface/src/raypick/LaserPointerManager.cpp b/interface/src/raypick/LaserPointerManager.cpp deleted file mode 100644 index a300a418a7..0000000000 --- a/interface/src/raypick/LaserPointerManager.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// -// LaserPointerManager.cpp -// interface/src/raypick -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#include "LaserPointerManager.h" - -QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) { - QUuid result; - std::shared_ptr laserPointer = std::make_shared(rayProps, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); - if (!laserPointer->getRayUID().isNull()) { - result = QUuid::createUuid(); - withWriteLock([&] { _laserPointers[result] = laserPointer; }); - } - return result; -} - - -LaserPointer::Pointer LaserPointerManager::find(const QUuid& uid) const { - return resultWithReadLock([&] { - auto itr = _laserPointers.find(uid); - if (itr != _laserPointers.end()) { - return *itr; - } - return LaserPointer::Pointer(); - }); -} - - -void LaserPointerManager::removeLaserPointer(const QUuid& uid) { - withWriteLock([&] { - _laserPointers.remove(uid); - }); -} - -void LaserPointerManager::enableLaserPointer(const QUuid& uid) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->enable(); - } -} - -void LaserPointerManager::disableLaserPointer(const QUuid& uid) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->disable(); - } -} - -void LaserPointerManager::setRenderState(const QUuid& uid, const std::string& renderState) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->setRenderState(renderState); - } -} - -void LaserPointerManager::editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->editRenderState(state, startProps, pathProps, endProps); - } -} - -const QVariantMap LaserPointerManager::getPrevRayPickResult(const QUuid& uid) const { - auto laserPointer = find(uid); - if (laserPointer) { - return laserPointer->getPrevRayPickResult(); - } - return QVariantMap(); -} - -void LaserPointerManager::update() { - auto cachedLaserPointers = resultWithReadLock>>([&] { - return _laserPointers.values(); - }); - - for (const auto& laserPointer : cachedLaserPointers) { - laserPointer->update(); - } -} - -void LaserPointerManager::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->setPrecisionPicking(precisionPicking); - } -} - -void LaserPointerManager::setLaserLength(const QUuid& uid, const float laserLength) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->setLaserLength(laserLength); - } -} - -void LaserPointerManager::setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->setIgnoreItems(ignoreEntities); - } -} - -void LaserPointerManager::setIncludeItems(const QUuid& uid, const QVector& includeEntities) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->setIncludeItems(includeEntities); - } -} - -void LaserPointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const { - auto laserPointer = find(uid); - if (laserPointer) { - laserPointer->setLockEndUUID(objectID, isOverlay); - } -} diff --git a/interface/src/raypick/LaserPointerManager.h b/interface/src/raypick/LaserPointerManager.h deleted file mode 100644 index 547f7cc785..0000000000 --- a/interface/src/raypick/LaserPointerManager.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// LaserPointerManager.h -// interface/src/raypick -// -// Created by Sam Gondelman 7/11/2017 -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// -#ifndef hifi_LaserPointerManager_h -#define hifi_LaserPointerManager_h - -#include -#include - -#include - -#include "LaserPointer.h" - -class LaserPointerManager : protected ReadWriteLockable { - -public: - QUuid createLaserPointer(const QVariant& rayProps, const LaserPointer::RenderStateMap& renderStates, const LaserPointer::DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); - void removeLaserPointer(const QUuid& uid); - void enableLaserPointer(const QUuid& uid) const; - void disableLaserPointer(const QUuid& uid) const; - void setRenderState(const QUuid& uid, const std::string& renderState) const; - void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; - const QVariantMap getPrevRayPickResult(const QUuid& uid) const; - - void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const; - void setLaserLength(const QUuid& uid, const float laserLength) const; - void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; - void setIncludeItems(const QUuid& uid, const QVector& includeEntities) const; - - void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const; - - void update(); - -private: - LaserPointer::Pointer find(const QUuid& uid) const; - QHash> _laserPointers; -}; - -#endif // hifi_LaserPointerManager_h diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 4ff917d8c5..779f9ff605 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -15,11 +15,13 @@ #include +#include "Application.h" + void LaserPointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { - qApp->getLaserPointerManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); + DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } void LaserPointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) const { - qApp->getLaserPointerManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); + DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) const { @@ -74,7 +76,7 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert } } - return qApp->getLaserPointerManager().createLaserPointer(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled); + return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled)); } void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { @@ -95,7 +97,7 @@ void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QSt endProps = propMap["end"]; } - qApp->getLaserPointerManager().editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps); + DependencyManager::get()->editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps); } RenderState LaserPointerScriptingInterface::buildRenderState(const QVariantMap& propMap) { diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index d51420a112..b2e46f66d6 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -14,7 +14,9 @@ #include #include "DependencyManager.h" -#include "Application.h" +#include + +#include "LaserPointer.h" class LaserPointerScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -22,19 +24,19 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { public slots: Q_INVOKABLE QUuid createLaserPointer(const QVariant& properties) const; - Q_INVOKABLE void enableLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().enableLaserPointer(uid); } - Q_INVOKABLE void disableLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().disableLaserPointer(uid); } - Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { qApp->getLaserPointerManager().removeLaserPointer(uid); } + Q_INVOKABLE void enableLaserPointer(const QUuid& uid) const { DependencyManager::get()->enablePointer(uid); } + Q_INVOKABLE void disableLaserPointer(const QUuid& uid) const { DependencyManager::get()->disablePointer(uid); } + Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { DependencyManager::get()->removePointer(uid); } Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; - Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { qApp->getLaserPointerManager().setRenderState(uid, renderState.toStdString()); } - Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return qApp->getLaserPointerManager().getPrevRayPickResult(uid); } + Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } + Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return DependencyManager::get()->getPrevRayPickResult(uid); } - Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { qApp->getLaserPointerManager().setPrecisionPicking(uid, precisionPicking); } - Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { qApp->getLaserPointerManager().setLaserLength(uid, laserLength); } + Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } + Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const; Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const; - Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { qApp->getLaserPointerManager().setLockEndUUID(uid, objectID, isOverlay); } + Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } private: static RenderState buildRenderState(const QVariantMap& propMap); diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index de67fdde0f..8913138c36 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -13,7 +13,8 @@ #include #include "GLMHelpers.h" -#include "Application.h" + +#include #include "StaticRayPick.h" #include "JointRayPick.h" @@ -52,10 +53,10 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { dirOffset = vec3FromVariant(propMap["dirOffset"]); } - return qApp->getPickManager().addPick(RAY, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); + return DependencyManager::get()->addPick(RAY, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); } else { - return qApp->getPickManager().addPick(RAY, std::make_shared(filter, maxDistance, enabled)); + return DependencyManager::get()->addPick(RAY, std::make_shared(filter, maxDistance, enabled)); } } else if (propMap["position"].isValid()) { glm::vec3 position = vec3FromVariant(propMap["position"]); @@ -65,36 +66,36 @@ QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { direction = vec3FromVariant(propMap["direction"]); } - return qApp->getPickManager().addPick(RAY, std::make_shared(position, direction, filter, maxDistance, enabled)); + return DependencyManager::get()->addPick(RAY, std::make_shared(position, direction, filter, maxDistance, enabled)); } return QUuid(); } void RayPickScriptingInterface::enableRayPick(const QUuid& uid) { - qApp->getPickManager().enablePick(uid); + DependencyManager::get()->enablePick(uid); } void RayPickScriptingInterface::disableRayPick(const QUuid& uid) { - qApp->getPickManager().disablePick(uid); + DependencyManager::get()->disablePick(uid); } void RayPickScriptingInterface::removeRayPick(const QUuid& uid) { - qApp->getPickManager().removePick(uid); + DependencyManager::get()->removePick(uid); } QVariantMap RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) { - return qApp->getPickManager().getPrevPickResult(uid); + return DependencyManager::get()->getPrevPickResult(uid); } void RayPickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) { - qApp->getPickManager().setPrecisionPicking(uid, precisionPicking); + DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } void RayPickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) { - qApp->getPickManager().setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); + DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } void RayPickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) { - qApp->getPickManager().setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); + DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index 9b2f19a63a..07c8d914f3 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -10,6 +10,7 @@ #include +#include #include "RegisteredMetaTypes.h" #include "Pick.h" @@ -20,7 +21,8 @@ enum PickType { STYLUS }; -class PickManager : protected ReadWriteLockable { +class PickManager : public Dependency, protected ReadWriteLockable { + SINGLETON_DEPENDENCY public: PickManager(); diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp new file mode 100644 index 0000000000..6ba8c6072c --- /dev/null +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -0,0 +1,39 @@ +// +// Created by Sam Gondelman 10/19/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "Pointer.h" + +#include +#include "PickManager.h" + +Pointer::~Pointer() { + DependencyManager::get()->removePick(_pickUID); +} + +void Pointer::enable() { + DependencyManager::get()->enablePick(_pickUID); +} + +void Pointer::disable() { + DependencyManager::get()->disablePick(_pickUID); +} + +const QVariantMap Pointer::getPrevPickResult() { + return DependencyManager::get()->getPrevPickResult(_pickUID); +} + +void Pointer::setPrecisionPicking(const bool precisionPicking) { + DependencyManager::get()->setPrecisionPicking(_pickUID, precisionPicking); +} + +void Pointer::setIgnoreItems(const QVector& ignoreItems) const { + DependencyManager::get()->setIgnoreItems(_pickUID, ignoreItems); +} + +void Pointer::setIncludeItems(const QVector& includeItems) const { + DependencyManager::get()->setIncludeItems(_pickUID, includeItems); +} \ No newline at end of file diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h new file mode 100644 index 0000000000..4a105f8a92 --- /dev/null +++ b/libraries/pointers/src/pointers/Pointer.h @@ -0,0 +1,46 @@ +// +// Created by Sam Gondelman 10/17/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_Pointer_h +#define hifi_Pointer_h + +#include +#include +#include + +#include + +class Pointer : protected ReadWriteLockable { +public: + Pointer(const QUuid& uid) : _pickUID(uid) {} + + virtual ~Pointer(); + + virtual void enable(); + virtual void disable(); + virtual const QVariantMap getPrevPickResult(); + + virtual void setRenderState(const std::string& state) = 0; + virtual void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) = 0; + + virtual void setPrecisionPicking(const bool precisionPicking); + virtual void setIgnoreItems(const QVector& ignoreItems) const; + virtual void setIncludeItems(const QVector& includeItems) const; + + // Pointers can choose to implement these + virtual void setLength(const float length) {} + virtual void setLockEndUUID(QUuid objectID, const bool isOverlay) {} + + virtual void update() = 0; + + QUuid getRayUID() { return _pickUID; } + +protected: + const QUuid _pickUID; +}; + +#endif // hifi_Pick_h diff --git a/libraries/pointers/src/pointers/PointerManager.cpp b/libraries/pointers/src/pointers/PointerManager.cpp index 63bd983420..f2c2756d6f 100644 --- a/libraries/pointers/src/pointers/PointerManager.cpp +++ b/libraries/pointers/src/pointers/PointerManager.cpp @@ -1,6 +1,115 @@ +// +// Created by Bradley Austin Davis on 2017/10/16 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + #include "PointerManager.h" -PointerManager::PointerManager() { - +std::shared_ptr PointerManager::find(const QUuid& uid) const { + return resultWithReadLock>([&] { + auto itr = _pointers.find(uid); + if (itr != _pointers.end()) { + return *itr; + } + return std::shared_ptr(); + }); } +QUuid PointerManager::addPointer(std::shared_ptr pointer) { + QUuid result; + if (!pointer->getRayUID().isNull()) { + result = QUuid::createUuid(); + withWriteLock([&] { _pointers[result] = pointer; }); + } + return result; +} + +void PointerManager::removePointer(const QUuid& uid) { + withWriteLock([&] { + _pointers.remove(uid); + }); +} + +void PointerManager::enablePointer(const QUuid& uid) const { + auto pointer = find(uid); + if (pointer) { + pointer->enable(); + } +} + +void PointerManager::disablePointer(const QUuid& uid) const { + auto pointer = find(uid); + if (pointer) { + pointer->disable(); + } +} + +void PointerManager::setRenderState(const QUuid& uid, const std::string& renderState) const { + auto pointer = find(uid); + if (pointer) { + pointer->setRenderState(renderState); + } +} + +void PointerManager::editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const { + auto pointer = find(uid); + if (pointer) { + pointer->editRenderState(state, startProps, pathProps, endProps); + } +} + +const QVariantMap PointerManager::getPrevRayPickResult(const QUuid& uid) const { + auto pointer = find(uid); + if (pointer) { + return pointer->getPrevPickResult(); + } + return QVariantMap(); +} + +void PointerManager::update() { + auto cachedPointers = resultWithReadLock>>([&] { + return _pointers.values(); + }); + + for (const auto& pointer : cachedPointers) { + pointer->update(); + } +} + +void PointerManager::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const { + auto pointer = find(uid); + if (pointer) { + pointer->setPrecisionPicking(precisionPicking); + } +} + +void PointerManager::setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const { + auto pointer = find(uid); + if (pointer) { + pointer->setIgnoreItems(ignoreEntities); + } +} + +void PointerManager::setIncludeItems(const QUuid& uid, const QVector& includeEntities) const { + auto pointer = find(uid); + if (pointer) { + pointer->setIncludeItems(includeEntities); + } +} + +void PointerManager::setLength(const QUuid& uid, const float length) const { + auto pointer = find(uid); + if (pointer) { + pointer->setLength(length); + } +} + +void PointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const { + auto pointer = find(uid); + if (pointer) { + pointer->setLockEndUUID(objectID, isOverlay); + } +} diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 16f854bff5..1841e66f7b 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -11,11 +11,39 @@ #include #include -class PointerManager : public QObject, public Dependency { +#include +#include + +#include + +#include "Pointer.h" + +class PointerManager : public QObject, public Dependency, protected ReadWriteLockable{ Q_OBJECT SINGLETON_DEPENDENCY public: - PointerManager(); + PointerManager() {} + + QUuid addPointer(std::shared_ptr pointer); + void removePointer(const QUuid& uid); + void enablePointer(const QUuid& uid) const; + void disablePointer(const QUuid& uid) const; + void setRenderState(const QUuid& uid, const std::string& renderState) const; + void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; + const QVariantMap getPrevRayPickResult(const QUuid& uid) const; + + void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const; + void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; + void setIncludeItems(const QUuid& uid, const QVector& includeEntities) const; + + void setLength(const QUuid& uid, const float length) const; + void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const; + + void update(); + +private: + std::shared_ptr find(const QUuid& uid) const; + QHash> _pointers; signals: void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent); From fb969964f3663131c88925a2571427a590d46fe4 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 20 Oct 2017 14:37:10 -0700 Subject: [PATCH 015/292] generalized scripting interfaces --- interface/src/Application.cpp | 12 +- .../LaserPointerScriptingInterface.cpp | 105 +------------ .../raypick/LaserPointerScriptingInterface.h | 7 +- .../src/raypick/PickScriptingInterface.cpp | 107 ++++++++++++++ .../src/raypick/PickScriptingInterface.h | 65 ++++++++ .../src/raypick/PointerScriptingInterface.cpp | 139 ++++++++++++++++++ .../src/raypick/PointerScriptingInterface.h | 46 ++++++ .../src/raypick/RayPickScriptingInterface.cpp | 50 +------ .../src/raypick/RayPickScriptingInterface.h | 31 +--- libraries/pointers/src/pointers/Pick.h | 7 + .../pointers/src/pointers/PickManager.cpp | 6 +- libraries/pointers/src/pointers/PickManager.h | 11 +- .../pointers/src/pointers/PointerManager.cpp | 2 +- .../pointers/src/pointers/PointerManager.h | 2 +- .../controllers/controllerDispatcher.js | 12 +- .../controllerModules/farActionGrabEntity.js | 8 +- .../controllerModules/farTrigger.js | 2 +- .../controllerModules/hudOverlayPointer.js | 2 +- .../controllerModules/inEditMode.js | 6 +- .../controllerModules/overlayLaserInput.js | 4 +- .../controllers/controllerModules/teleport.js | 10 +- .../controllerModules/webEntityLaserInput.js | 4 +- scripts/system/controllers/grab.js | 8 +- scripts/system/libraries/touchEventUtils.js | 2 +- 24 files changed, 417 insertions(+), 231 deletions(-) create mode 100644 interface/src/raypick/PickScriptingInterface.cpp create mode 100644 interface/src/raypick/PickScriptingInterface.h create mode 100644 interface/src/raypick/PointerScriptingInterface.cpp create mode 100644 interface/src/raypick/PointerScriptingInterface.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3476700904..26e659e118 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -197,6 +197,8 @@ #include #include #include +#include +#include #include #include @@ -696,6 +698,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); + DependencyManager::set(); return previousSessionCrashed; } @@ -1825,14 +1829,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get()->setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); // Setup the mouse ray pick and related operators - DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(RAY, std::make_shared( - PickFilter(RayPickScriptingInterface::PICK_ENTITIES() | RayPickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true))); + DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared( + PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true))); DependencyManager::get()->setMouseRayPickResultOperator([&](QUuid rayPickID) { RayToEntityIntersectionResult entityResult; entityResult.intersects = false; QVariantMap result = DependencyManager::get()->getPrevPickResult(rayPickID); if (result["type"].isValid()) { - entityResult.intersects = result["type"] != RayPickScriptingInterface::INTERSECTED_NONE(); + entityResult.intersects = result["type"] != PickScriptingInterface::INTERSECTED_NONE(); if (entityResult.intersects) { entityResult.intersection = vec3FromVariant(result["intersection"]); entityResult.distance = result["distance"].toFloat(); @@ -5798,6 +5802,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe scriptEngine->registerGlobalObject("RayPick", DependencyManager::get().data()); scriptEngine->registerGlobalObject("LaserPointers", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Picks", DependencyManager::get().data()); + scriptEngine->registerGlobalObject("Pointers", DependencyManager::get().data()); // Caches scriptEngine->registerGlobalObject("AnimationCache", DependencyManager::get().data()); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 779f9ff605..8f8f9d921a 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -15,6 +15,7 @@ #include +#include "PointerScriptingInterface.h" #include "Application.h" void LaserPointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { @@ -25,109 +26,9 @@ void LaserPointerScriptingInterface::setIncludeItems(const QUuid& uid, const QSc } QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) const { - QVariantMap propertyMap = properties.toMap(); - - bool faceAvatar = false; - if (propertyMap["faceAvatar"].isValid()) { - faceAvatar = propertyMap["faceAvatar"].toBool(); - } - - bool centerEndY = true; - if (propertyMap["centerEndY"].isValid()) { - centerEndY = propertyMap["centerEndY"].toBool(); - } - - bool lockEnd = false; - if (propertyMap["lockEnd"].isValid()) { - lockEnd = propertyMap["lockEnd"].toBool(); - } - - bool enabled = false; - if (propertyMap["enabled"].isValid()) { - enabled = propertyMap["enabled"].toBool(); - } - - LaserPointer::RenderStateMap renderStates; - if (propertyMap["renderStates"].isValid()) { - QList renderStateVariants = propertyMap["renderStates"].toList(); - for (QVariant& renderStateVariant : renderStateVariants) { - if (renderStateVariant.isValid()) { - QVariantMap renderStateMap = renderStateVariant.toMap(); - if (renderStateMap["name"].isValid()) { - std::string name = renderStateMap["name"].toString().toStdString(); - renderStates[name] = buildRenderState(renderStateMap); - } - } - } - } - - LaserPointer::DefaultRenderStateMap defaultRenderStates; - if (propertyMap["defaultRenderStates"].isValid()) { - QList renderStateVariants = propertyMap["defaultRenderStates"].toList(); - for (QVariant& renderStateVariant : renderStateVariants) { - if (renderStateVariant.isValid()) { - QVariantMap renderStateMap = renderStateVariant.toMap(); - if (renderStateMap["name"].isValid() && renderStateMap["distance"].isValid()) { - std::string name = renderStateMap["name"].toString().toStdString(); - float distance = renderStateMap["distance"].toFloat(); - defaultRenderStates[name] = std::pair(distance, buildRenderState(renderStateMap)); - } - } - } - } - - return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled)); + return DependencyManager::get()->createLaserPointer(properties); } void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { - QVariantMap propMap = properties.toMap(); - - QVariant startProps; - if (propMap["start"].isValid()) { - startProps = propMap["start"]; - } - - QVariant pathProps; - if (propMap["path"].isValid()) { - pathProps = propMap["path"]; - } - - QVariant endProps; - if (propMap["end"].isValid()) { - endProps = propMap["end"]; - } - - DependencyManager::get()->editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps); -} - -RenderState LaserPointerScriptingInterface::buildRenderState(const QVariantMap& propMap) { - QUuid startID; - if (propMap["start"].isValid()) { - QVariantMap startMap = propMap["start"].toMap(); - if (startMap["type"].isValid()) { - startMap.remove("visible"); - startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); - } - } - - QUuid pathID; - if (propMap["path"].isValid()) { - QVariantMap pathMap = propMap["path"].toMap(); - // right now paths must be line3ds - if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { - pathMap.remove("visible"); - pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); - } - } - - QUuid endID; - if (propMap["end"].isValid()) { - QVariantMap endMap = propMap["end"].toMap(); - if (endMap["type"].isValid()) { - endMap.remove("visible"); - endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); - } - } - - return RenderState(startID, pathID, endID); + DependencyManager::get()->editRenderState(uid, renderState, properties); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index b2e46f66d6..1116da1528 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -16,8 +16,6 @@ #include "DependencyManager.h" #include -#include "LaserPointer.h" - class LaserPointerScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY @@ -29,7 +27,7 @@ public slots: Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { DependencyManager::get()->removePointer(uid); } Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } - Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return DependencyManager::get()->getPrevRayPickResult(uid); } + Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return DependencyManager::get()->getPrevPickResult(uid); } Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } @@ -38,9 +36,6 @@ public slots: Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } -private: - static RenderState buildRenderState(const QVariantMap& propMap); - }; #endif // hifi_LaserPointerScriptingInterface_h diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp new file mode 100644 index 0000000000..99f7ac2515 --- /dev/null +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -0,0 +1,107 @@ +// +// Created by Sam Gondelman 10/20/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "PickScriptingInterface.h" + +#include +#include "GLMHelpers.h" + +#include + +#include "StaticRayPick.h" +#include "JointRayPick.h" +#include "MouseRayPick.h" + +QUuid PickScriptingInterface::createPick(const PickQuery::PickType type, const QVariant& properties) { + switch (type) { + case PickQuery::PickType::Ray: + return createRayPick(properties); + default: + return QUuid(); + } +} + +QUuid PickScriptingInterface::createRayPick(const QVariant& properties) { + QVariantMap propMap = properties.toMap(); + + bool enabled = false; + if (propMap["enabled"].isValid()) { + enabled = propMap["enabled"].toBool(); + } + + PickFilter filter = PickFilter(); + if (propMap["filter"].isValid()) { + filter = PickFilter(propMap["filter"].toUInt()); + } + + float maxDistance = 0.0f; + if (propMap["maxDistance"].isValid()) { + maxDistance = propMap["maxDistance"].toFloat(); + } + + if (propMap["joint"].isValid()) { + std::string jointName = propMap["joint"].toString().toStdString(); + + if (jointName != "Mouse") { + // x = upward, y = forward, z = lateral + glm::vec3 posOffset = Vectors::ZERO; + if (propMap["posOffset"].isValid()) { + posOffset = vec3FromVariant(propMap["posOffset"]); + } + + glm::vec3 dirOffset = Vectors::UP; + if (propMap["dirOffset"].isValid()) { + dirOffset = vec3FromVariant(propMap["dirOffset"]); + } + + return DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); + + } else { + return DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared(filter, maxDistance, enabled)); + } + } else if (propMap["position"].isValid()) { + glm::vec3 position = vec3FromVariant(propMap["position"]); + + glm::vec3 direction = -Vectors::UP; + if (propMap["direction"].isValid()) { + direction = vec3FromVariant(propMap["direction"]); + } + + return DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared(position, direction, filter, maxDistance, enabled)); + } + + return QUuid(); +} + +void PickScriptingInterface::enablePick(const QUuid& uid) { + DependencyManager::get()->enablePick(uid); +} + +void PickScriptingInterface::disablePick(const QUuid& uid) { + DependencyManager::get()->disablePick(uid); +} + +void PickScriptingInterface::removePick(const QUuid& uid) { + DependencyManager::get()->removePick(uid); +} + +QVariantMap PickScriptingInterface::getPrevPickResult(const QUuid& uid) { + return DependencyManager::get()->getPrevPickResult(uid); +} + +void PickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) { + DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); +} + +void PickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) { + DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); +} + +void PickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) { + DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); +} diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h new file mode 100644 index 0000000000..462b64dbd1 --- /dev/null +++ b/interface/src/raypick/PickScriptingInterface.h @@ -0,0 +1,65 @@ +// +// Created by Sam Gondelman 10/20/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_PickScriptingInterface_h +#define hifi_PickScriptingInterface_h + +#include + +#include +#include +#include + +class PickScriptingInterface : public QObject, public Dependency { + Q_OBJECT + Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) + Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT) + Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT) + Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT) + Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT) + Q_PROPERTY(unsigned int PICK_COARSE READ PICK_COARSE CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT) + Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT) + SINGLETON_DEPENDENCY + +public: + QUuid createRayPick(const QVariant& properties); + +public slots: + Q_INVOKABLE QUuid createPick(const PickQuery::PickType type, const QVariant& properties); + Q_INVOKABLE void enablePick(const QUuid& uid); + Q_INVOKABLE void disablePick(const QUuid& uid); + Q_INVOKABLE void removePick(const QUuid& uid); + Q_INVOKABLE QVariantMap getPrevPickResult(const QUuid& uid); + + Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, const bool precisionPicking); + Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities); + Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities); + + static constexpr unsigned int PICK_NOTHING() { return 0; } + static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } + static constexpr unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); } + static constexpr unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); } + static constexpr unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); } + static constexpr unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); } + static constexpr unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } + static constexpr unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } + static constexpr unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } + static constexpr unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } + static constexpr unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } + static constexpr unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } + static constexpr unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } + static constexpr unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } +}; + +#endif // hifi_PickScriptingInterface_h \ No newline at end of file diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp new file mode 100644 index 0000000000..4e5d5f414f --- /dev/null +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -0,0 +1,139 @@ +// +// Created by Sam Gondelman 10/20/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "PointerScriptingInterface.h" + +#include + +#include + +#include "Application.h" + +void PointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { + DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); +} +void PointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) const { + DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); +} + +QUuid PointerScriptingInterface::createPointer(const PickQuery::PickType type, const QVariant& properties) const { + switch (type) { + case PickQuery::PickType::Ray: + return createLaserPointer(properties); + default: + return QUuid(); + } +} + +QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) const { + QVariantMap propertyMap = properties.toMap(); + + bool faceAvatar = false; + if (propertyMap["faceAvatar"].isValid()) { + faceAvatar = propertyMap["faceAvatar"].toBool(); + } + + bool centerEndY = true; + if (propertyMap["centerEndY"].isValid()) { + centerEndY = propertyMap["centerEndY"].toBool(); + } + + bool lockEnd = false; + if (propertyMap["lockEnd"].isValid()) { + lockEnd = propertyMap["lockEnd"].toBool(); + } + + bool enabled = false; + if (propertyMap["enabled"].isValid()) { + enabled = propertyMap["enabled"].toBool(); + } + + LaserPointer::RenderStateMap renderStates; + if (propertyMap["renderStates"].isValid()) { + QList renderStateVariants = propertyMap["renderStates"].toList(); + for (QVariant& renderStateVariant : renderStateVariants) { + if (renderStateVariant.isValid()) { + QVariantMap renderStateMap = renderStateVariant.toMap(); + if (renderStateMap["name"].isValid()) { + std::string name = renderStateMap["name"].toString().toStdString(); + renderStates[name] = buildRenderState(renderStateMap); + } + } + } + } + + LaserPointer::DefaultRenderStateMap defaultRenderStates; + if (propertyMap["defaultRenderStates"].isValid()) { + QList renderStateVariants = propertyMap["defaultRenderStates"].toList(); + for (QVariant& renderStateVariant : renderStateVariants) { + if (renderStateVariant.isValid()) { + QVariantMap renderStateMap = renderStateVariant.toMap(); + if (renderStateMap["name"].isValid() && renderStateMap["distance"].isValid()) { + std::string name = renderStateMap["name"].toString().toStdString(); + float distance = renderStateMap["distance"].toFloat(); + defaultRenderStates[name] = std::pair(distance, buildRenderState(renderStateMap)); + } + } + } + } + + return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled)); +} + +void PointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { + QVariantMap propMap = properties.toMap(); + + QVariant startProps; + if (propMap["start"].isValid()) { + startProps = propMap["start"]; + } + + QVariant pathProps; + if (propMap["path"].isValid()) { + pathProps = propMap["path"]; + } + + QVariant endProps; + if (propMap["end"].isValid()) { + endProps = propMap["end"]; + } + + DependencyManager::get()->editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps); +} + +RenderState PointerScriptingInterface::buildRenderState(const QVariantMap& propMap) { + QUuid startID; + if (propMap["start"].isValid()) { + QVariantMap startMap = propMap["start"].toMap(); + if (startMap["type"].isValid()) { + startMap.remove("visible"); + startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); + } + } + + QUuid pathID; + if (propMap["path"].isValid()) { + QVariantMap pathMap = propMap["path"].toMap(); + // right now paths must be line3ds + if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { + pathMap.remove("visible"); + pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); + } + } + + QUuid endID; + if (propMap["end"].isValid()) { + QVariantMap endMap = propMap["end"].toMap(); + if (endMap["type"].isValid()) { + endMap.remove("visible"); + endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); + } + } + + return RenderState(startID, pathID, endID); +} \ No newline at end of file diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h new file mode 100644 index 0000000000..8a3a316d9e --- /dev/null +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -0,0 +1,46 @@ +// +// Created by Sam Gondelman 10/20/2017 +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_PointerScriptingInterface_h +#define hifi_PointerScriptingInterface_h + +#include + +#include "DependencyManager.h" +#include + +#include "LaserPointer.h" + +class PointerScriptingInterface : public QObject, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public: + QUuid createLaserPointer(const QVariant& properties) const; + +public slots: + Q_INVOKABLE QUuid createPointer(const PickQuery::PickType type, const QVariant& properties) const; + Q_INVOKABLE void enablePointer(const QUuid& uid) const { DependencyManager::get()->enablePointer(uid); } + Q_INVOKABLE void disablePointer(const QUuid& uid) const { DependencyManager::get()->disablePointer(uid); } + Q_INVOKABLE void removePointer(const QUuid& uid) const { DependencyManager::get()->removePointer(uid); } + Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; + Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } + Q_INVOKABLE QVariantMap getPrevPickResult(QUuid uid) const { return DependencyManager::get()->getPrevPickResult(uid); } + + Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } + Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } + Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const; + Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const; + + Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } + +private: + static RenderState buildRenderState(const QVariantMap& propMap); + +}; + +#endif // hifi_PointerScriptingInterface_h diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index 8913138c36..92bf3ec521 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -21,55 +21,7 @@ #include "MouseRayPick.h" QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { - QVariantMap propMap = properties.toMap(); - - bool enabled = false; - if (propMap["enabled"].isValid()) { - enabled = propMap["enabled"].toBool(); - } - - PickFilter filter = PickFilter(); - if (propMap["filter"].isValid()) { - filter = PickFilter(propMap["filter"].toUInt()); - } - - float maxDistance = 0.0f; - if (propMap["maxDistance"].isValid()) { - maxDistance = propMap["maxDistance"].toFloat(); - } - - if (propMap["joint"].isValid()) { - std::string jointName = propMap["joint"].toString().toStdString(); - - if (jointName != "Mouse") { - // x = upward, y = forward, z = lateral - glm::vec3 posOffset = Vectors::ZERO; - if (propMap["posOffset"].isValid()) { - posOffset = vec3FromVariant(propMap["posOffset"]); - } - - glm::vec3 dirOffset = Vectors::UP; - if (propMap["dirOffset"].isValid()) { - dirOffset = vec3FromVariant(propMap["dirOffset"]); - } - - return DependencyManager::get()->addPick(RAY, std::make_shared(jointName, posOffset, dirOffset, filter, maxDistance, enabled)); - - } else { - return DependencyManager::get()->addPick(RAY, std::make_shared(filter, maxDistance, enabled)); - } - } else if (propMap["position"].isValid()) { - glm::vec3 position = vec3FromVariant(propMap["position"]); - - glm::vec3 direction = -Vectors::UP; - if (propMap["direction"].isValid()) { - direction = vec3FromVariant(propMap["direction"]); - } - - return DependencyManager::get()->addPick(RAY, std::make_shared(position, direction, filter, maxDistance, enabled)); - } - - return QUuid(); + return DependencyManager::get()->createRayPick(properties); } void RayPickScriptingInterface::enableRayPick(const QUuid& uid) { diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index ebfc3fb9fe..ed837afe49 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -17,22 +17,10 @@ #include #include "RayPick.h" +#include "PickScriptingInterface.h" + class RayPickScriptingInterface : public QObject, public Dependency { Q_OBJECT - Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) - Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT) - Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT) - Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT) - Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT) - Q_PROPERTY(unsigned int PICK_COARSE READ PICK_COARSE CONSTANT) - Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT) - Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT) - Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT) - Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT) SINGLETON_DEPENDENCY public slots: @@ -45,21 +33,6 @@ public slots: Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, const bool precisionPicking); Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities); Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities); - - static constexpr unsigned int PICK_NOTHING() { return 0; } - static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } - static constexpr unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); } - static constexpr unsigned int PICK_AVATARS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_AVATARS); } - static constexpr unsigned int PICK_HUD() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_HUD); } - static constexpr unsigned int PICK_COARSE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_COARSE); } - static constexpr unsigned int PICK_INCLUDE_INVISIBLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_INVISIBLE); } - static constexpr unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_INCLUDE_NONCOLLIDABLE); } - static constexpr unsigned int PICK_ALL_INTERSECTIONS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ALL_INTERSECTIONS); } - static constexpr unsigned int INTERSECTED_NONE() { return IntersectionType::NONE; } - static constexpr unsigned int INTERSECTED_ENTITY() { return IntersectionType::ENTITY; } - static constexpr unsigned int INTERSECTED_OVERLAY() { return IntersectionType::OVERLAY; } - static constexpr unsigned int INTERSECTED_AVATAR() { return IntersectionType::AVATAR; } - static constexpr unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; } }; #endif // hifi_RayPickScriptingInterface_h diff --git a/libraries/pointers/src/pointers/Pick.h b/libraries/pointers/src/pointers/Pick.h index 6ac0d6781e..5dcaba2bb8 100644 --- a/libraries/pointers/src/pointers/Pick.h +++ b/libraries/pointers/src/pointers/Pick.h @@ -130,9 +130,16 @@ public: using PickResultPointer = std::shared_ptr; class PickQuery : protected ReadWriteLockable { + Q_GADGET public: PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled); + enum PickType { + Ray = 0, + Stylus + }; + Q_ENUM(PickType) + void enable(bool enabled = true); void disable() { enable(false); } diff --git a/libraries/pointers/src/pointers/PickManager.cpp b/libraries/pointers/src/pointers/PickManager.cpp index d6c2f44212..571f9f04cd 100644 --- a/libraries/pointers/src/pointers/PickManager.cpp +++ b/libraries/pointers/src/pointers/PickManager.cpp @@ -11,7 +11,7 @@ PickManager::PickManager() { setShouldPickHUDOperator([]() { return false; }); } -QUuid PickManager::addPick(PickType type, const std::shared_ptr pick) { +QUuid PickManager::addPick(PickQuery::PickType type, const std::shared_ptr pick) { QUuid id = QUuid::createUuid(); withWriteLock([&] { _picks[type][id] = pick; @@ -84,11 +84,11 @@ void PickManager::setIncludeItems(const QUuid& uid, const QVector& includ } void PickManager::update() { - QHash>> cachedPicks; + QHash>> cachedPicks; withReadLock([&] { cachedPicks = _picks; }); bool shouldPickHUD = _shouldPickHUDOperator(); - _rayPickCacheOptimizer.update(cachedPicks[RAY], shouldPickHUD); + _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], shouldPickHUD); } \ No newline at end of file diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index 07c8d914f3..f09f44621a 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -16,11 +16,6 @@ #include "Pick.h" #include "PickCacheOptimizer.h" -enum PickType { - RAY = 0, - STYLUS -}; - class PickManager : public Dependency, protected ReadWriteLockable { SINGLETON_DEPENDENCY @@ -29,7 +24,7 @@ public: void update(); - QUuid addPick(PickType type, const std::shared_ptr pick); + QUuid addPick(PickQuery::PickType type, const std::shared_ptr pick); void removePick(const QUuid& uid); void enablePick(const QUuid& uid) const; void disablePick(const QUuid& uid) const; @@ -46,8 +41,8 @@ protected: std::function _shouldPickHUDOperator; std::shared_ptr findPick(const QUuid& uid) const; - QHash>> _picks; - QHash _typeMap; + QHash>> _picks; + QHash _typeMap; PickCacheOptimizer _rayPickCacheOptimizer; }; diff --git a/libraries/pointers/src/pointers/PointerManager.cpp b/libraries/pointers/src/pointers/PointerManager.cpp index f2c2756d6f..a475ba4d83 100644 --- a/libraries/pointers/src/pointers/PointerManager.cpp +++ b/libraries/pointers/src/pointers/PointerManager.cpp @@ -61,7 +61,7 @@ void PointerManager::editRenderState(const QUuid& uid, const std::string& state, } } -const QVariantMap PointerManager::getPrevRayPickResult(const QUuid& uid) const { +const QVariantMap PointerManager::getPrevPickResult(const QUuid& uid) const { auto pointer = find(uid); if (pointer) { return pointer->getPrevPickResult(); diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 1841e66f7b..db08199949 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -30,7 +30,7 @@ public: void disablePointer(const QUuid& uid) const; void setRenderState(const QUuid& uid, const std::string& renderState) const; void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; - const QVariantMap getPrevRayPickResult(const QUuid& uid) const; + const QVariantMap getPrevPickResult(const QUuid& uid) const; void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const; void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 2deef5f9fa..3bc423450e 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -252,7 +252,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); length: 1000 }; - if (rayPicks[h].type === RayPick.INTERSECTED_ENTITY) { + if (rayPicks[h].type === Picks.INTERSECTED_ENTITY) { // XXX check to make sure this one isn't already in nearbyEntityProperties? if (rayPicks[h].distance < NEAR_GRAB_PICK_RADIUS * sensorScaleFactor) { var nearEntityID = rayPicks[h].objectID; @@ -390,35 +390,35 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.leftControllerRayPick = RayPick.createRayPick({ joint: "_CONTROLLER_LEFTHAND", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, enabled: true, maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true) }); this.leftControllerHudRayPick = RayPick.createRayPick({ joint: "_CONTROLLER_LEFTHAND", - filter: RayPick.PICK_HUD, + filter: Picks.PICK_HUD, enabled: true, maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true) }); this.rightControllerRayPick = RayPick.createRayPick({ joint: "_CONTROLLER_RIGHTHAND", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, enabled: true, maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true) }); this.rightControllerHudRayPick = RayPick.createRayPick({ joint: "_CONTROLLER_RIGHTHAND", - filter: RayPick.PICK_HUD, + filter: Picks.PICK_HUD, enabled: true, maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true) }); this.mouseRayPick = RayPick.createRayPick({ joint: "Mouse", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, enabled: true }); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 2ef7b1efeb..79a7b70bae 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -376,8 +376,8 @@ Script.include("/~/system/libraries/controllers.js"); var entityType = entityProperty.type; var hudRayPick = controllerData.hudRayPicks[this.hand]; var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); - if ((intersection.type === RayPick.INTERSECTED_ENTITY && entityType === "Web") || - intersection.type === RayPick.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) { + if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web") || + intersection.type === Picks.INTERSECTED_OVERLAY || Window.isPointOnDesktopWindow(point2d)) { return true; } return false; @@ -497,7 +497,7 @@ Script.include("/~/system/libraries/controllers.js"); } var rayPickInfo = controllerData.rayPicks[this.hand]; - if (rayPickInfo.type === RayPick.INTERSECTED_ENTITY) { + if (rayPickInfo.type === Picks.INTERSECTED_ENTITY) { if (controllerData.triggerClicks[this.hand]) { var entityID = rayPickInfo.objectID; var targetProps = Entities.getEntityProperties(entityID, [ @@ -581,7 +581,7 @@ Script.include("/~/system/libraries/controllers.js"); this.fullEnd = fullEnd; this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, maxDistance: PICK_MAX_DISTANCE, posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, diff --git a/scripts/system/controllers/controllerModules/farTrigger.js b/scripts/system/controllers/controllerModules/farTrigger.js index a683044e6e..7975889bc8 100644 --- a/scripts/system/controllers/controllerModules/farTrigger.js +++ b/scripts/system/controllers/controllerModules/farTrigger.js @@ -196,7 +196,7 @@ Script.include("/~/system/libraries/controllers.js"); this.fullEnd = fullEnd; this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, maxDistance: PICK_MAX_DISTANCE, posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, diff --git a/scripts/system/controllers/controllerModules/hudOverlayPointer.js b/scripts/system/controllers/controllerModules/hudOverlayPointer.js index fe1dedefb8..d579ce2611 100644 --- a/scripts/system/controllers/controllerModules/hudOverlayPointer.js +++ b/scripts/system/controllers/controllerModules/hudOverlayPointer.js @@ -216,7 +216,7 @@ this.fullEnd = fullEnd; this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: RayPick.PICK_HUD, + filter: Picks.PICK_HUD, maxDistance: PICK_MAX_DISTANCE, posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 5049185827..34247b1d9d 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -153,12 +153,12 @@ Script.include("/~/system/libraries/utils.js"); this.sendPickData = function(controllerData) { if (controllerData.triggerClicks[this.hand] && !this.triggerClicked) { var intersection = controllerData.rayPicks[this.hand]; - if (intersection.type === RayPick.INTERSECTED_ENTITY) { + if (intersection.type === Picks.INTERSECTED_ENTITY) { Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ method: "selectEntity", entityID: intersection.objectID })); - } else if (intersection.type === RayPick.INTERSECTED_OVERLAY) { + } else if (intersection.type === Picks.INTERSECTED_OVERLAY) { Messages.sendLocalMessage("entityToolUpdates", JSON.stringify({ method: "selectOverlay", overlayID: intersection.objectID @@ -243,7 +243,7 @@ Script.include("/~/system/libraries/utils.js"); this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS, + filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, maxDistance: PICK_MAX_DISTANCE, posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, diff --git a/scripts/system/controllers/controllerModules/overlayLaserInput.js b/scripts/system/controllers/controllerModules/overlayLaserInput.js index 7c86a01c5d..0747985c7b 100644 --- a/scripts/system/controllers/controllerModules/overlayLaserInput.js +++ b/scripts/system/controllers/controllerModules/overlayLaserInput.js @@ -301,7 +301,7 @@ Script.include("/~/system/libraries/controllers.js"); this.shouldExit = function(controllerData) { var intersection = controllerData.rayPicks[this.hand]; - var offOverlay = (intersection.type !== RayPick.INTERSECTED_OVERLAY); + var offOverlay = (intersection.type !== Picks.INTERSECTED_OVERLAY); var triggerOff = (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE); if (triggerOff) { this.deleteContextOverlay(); @@ -375,7 +375,7 @@ Script.include("/~/system/libraries/controllers.js"); this.fullEnd = fullEnd; this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: RayPick.PICK_OVERLAYS, + filter: Picks.PICK_OVERLAYS, maxDistance: PICK_MAX_DISTANCE, posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 86ad9c56ca..1fb867675e 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -149,7 +149,7 @@ Script.include("/~/system/libraries/controllers.js"); this.teleportRayHandVisible = LaserPointers.createLaserPointer({ joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand", - filter: RayPick.PICK_ENTITIES, + filter: Picks.PICK_ENTITIES, faceAvatar: true, centerEndY: false, renderStates: teleportRenderStates, @@ -157,14 +157,14 @@ Script.include("/~/system/libraries/controllers.js"); }); this.teleportRayHandInvisible = LaserPointers.createLaserPointer({ joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE, + filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, centerEndY: false, renderStates: teleportRenderStates }); this.teleportRayHeadVisible = LaserPointers.createLaserPointer({ joint: "Avatar", - filter: RayPick.PICK_ENTITIES, + filter: Picks.PICK_ENTITIES, faceAvatar: true, centerEndY: false, renderStates: teleportRenderStates, @@ -172,7 +172,7 @@ Script.include("/~/system/libraries/controllers.js"); }); this.teleportRayHeadInvisible = LaserPointers.createLaserPointer({ joint: "Avatar", - filter: RayPick.PICK_ENTITIES | RayPick.PICK_INCLUDE_INVISIBLE, + filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, centerEndY: false, renderStates: teleportRenderStates @@ -397,7 +397,7 @@ Script.include("/~/system/libraries/controllers.js"); // you can't teleport there. var MAX_ANGLE_FROM_UP_TO_TELEPORT = 70; function getTeleportTargetType(result) { - if (result.type === RayPick.INTERSECTED_NONE) { + if (result.type === Picks.INTERSECTED_NONE) { return TARGET.NONE; } diff --git a/scripts/system/controllers/controllerModules/webEntityLaserInput.js b/scripts/system/controllers/controllerModules/webEntityLaserInput.js index 339f248547..0076e1c865 100644 --- a/scripts/system/controllers/controllerModules/webEntityLaserInput.js +++ b/scripts/system/controllers/controllerModules/webEntityLaserInput.js @@ -386,7 +386,7 @@ Script.include("/~/system/libraries/controllers.js"); var entityProperty = Entities.getEntityProperties(intersection.objectID); var entityType = entityProperty.type; - if ((intersection.type === RayPick.INTERSECTED_ENTITY && entityType === "Web")) { + if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web")) { return true; } return false; @@ -454,7 +454,7 @@ Script.include("/~/system/libraries/controllers.js"); this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: RayPick.PICK_ENTITIES, + filter: Picks.PICK_ENTITIES, maxDistance: PICK_MAX_DISTANCE, posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index a1846e7ad7..7e575e38b0 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -260,14 +260,14 @@ function Grabber() { this.mouseRayOverlays = RayPick.createRayPick({ joint: "Mouse", - filter: RayPick.PICK_OVERLAYS, + filter: Picks.PICK_OVERLAYS, enabled: true }); RayPick.setIncludeItems(this.mouseRayOverlays, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); var renderStates = [{name: "grabbed", end: beacon}]; this.mouseRayEntities = LaserPointers.createLaserPointer({ joint: "Mouse", - filter: RayPick.PICK_ENTITIES, + filter: Picks.PICK_ENTITIES, faceAvatar: true, enabled: true, renderStates: renderStates @@ -321,12 +321,12 @@ Grabber.prototype.pressEvent = function(event) { } var overlayResult = RayPick.getPrevRayPickResult(this.mouseRayOverlays); - if (overlayResult.type != RayPick.INTERSECTED_NONE) { + if (overlayResult.type != Picks.INTERSECTED_NONE) { return; } var pickResults = LaserPointers.getPrevRayPickResult(this.mouseRayEntities); - if (pickResults.type == RayPick.INTERSECTED_NONE) { + if (pickResults.type == Picks.INTERSECTED_NONE) { LaserPointers.setRenderState(this.mouseRayEntities, ""); return; } diff --git a/scripts/system/libraries/touchEventUtils.js b/scripts/system/libraries/touchEventUtils.js index fbd56e16ae..7d19181c2a 100644 --- a/scripts/system/libraries/touchEventUtils.js +++ b/scripts/system/libraries/touchEventUtils.js @@ -130,7 +130,7 @@ function sendTouchMoveEventToTouchTarget(hand, touchTarget) { } function composeTouchTargetFromIntersection(intersection) { - var isEntity = (intersection.type === RayPick.INTERSECTED_ENTITY); + var isEntity = (intersection.type === Picks.INTERSECTED_ENTITY); var objectID = intersection.objectID; var worldPos = intersection.intersection; var props = null; From fd41299efc5e6ed42d2ec7f6336fc57dac2f86da Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 23 Oct 2017 22:34:22 +0200 Subject: [PATCH 016/292] Disable profile and custom user agent which broke nav bars --- interface/resources/qml/hifi/WebBrowser.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index 6a1d61de11..edd0523aa6 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -264,7 +264,7 @@ Rectangle { url: "http://www.highfidelity.com" - profile: HFWebEngineProfile; + //profile: HFWebEngineProfile; property string userScriptUrl: "" @@ -321,7 +321,7 @@ Rectangle { Component.onCompleted: { webChannel.registerObject("eventBridge", eventBridge); webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - webEngineView.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)"; + //webEngineView.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)"; } onFeaturePermissionRequested: { From 874b9149e7a204eff07d5c48c637d6793e27f812 Mon Sep 17 00:00:00 2001 From: vladest Date: Tue, 24 Oct 2017 22:04:25 +0200 Subject: [PATCH 017/292] Popupd support reworked --- interface/resources/qml/hifi/WebBrowser.qml | 255 ++++++++++++-------- 1 file changed, 159 insertions(+), 96 deletions(-) diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index edd0523aa6..c96d05d6a7 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -253,115 +253,178 @@ Rectangle { height: 2 } - HifiControls.BaseWebView { - id: webEngineView + Component { + id: webDialogComponent + Rectangle { + property alias webDialogView: webDialogView + color: "white" + HifiControls.BaseWebView { + id: webDialogView + anchors.fill: parent + + settings.autoLoadImages: true + settings.javascriptEnabled: true + settings.errorPageEnabled: true + settings.pluginsEnabled: true + settings.fullScreenSupportEnabled: true + settings.autoLoadIconsForPage: true + settings.touchIconsEnabled: true + + onWindowCloseRequested: { + webDialog.active = false + webDialog.request = null + } + } + } + } + + Item { width: parent.width; property real webViewHeight: root.height - loadProgressBar.height - 48 - 4 height: keyboardEnabled && keyboardRaised ? webViewHeight - keyboard.height : webViewHeight - focus: true - objectName: "tabletWebEngineView" + HifiControls.BaseWebView { + id: webEngineView + anchors.fill: parent - url: "http://www.highfidelity.com" + focus: true + objectName: "tabletWebEngineView" - //profile: HFWebEngineProfile; + url: "https://www.highfidelity.com" - property string userScriptUrl: "" + //profile: HFWebEngineProfile; - onLoadingChanged: { - if (!loading) { - suggestionRequestTimer.stop() - addressBar.popup.close() + property string userScriptUrl: "" + + onLoadingChanged: { + if (!loading) { + suggestionRequestTimer.stop() + addressBar.popup.close() + } + } + + onLinkHovered: { + //TODO: change cursor shape? + console.error("hoveredUrl:", hoveredUrl) + } + + // creates a global EventBridge object. + WebEngineScript { + id: createGlobalEventBridge + sourceCode: eventBridgeJavaScriptToInject + injectionPoint: WebEngineScript.DocumentCreation + worldId: WebEngineScript.MainWorld + } + + // detects when to raise and lower virtual keyboard + WebEngineScript { + id: raiseAndLowerKeyboard + injectionPoint: WebEngineScript.Deferred + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" + worldId: WebEngineScript.MainWorld + } + + // User script. + WebEngineScript { + id: userScript + sourceUrl: webEngineView.userScriptUrl + injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. + worldId: WebEngineScript.MainWorld + } + + userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] + + settings.autoLoadImages: true + settings.javascriptEnabled: true + settings.errorPageEnabled: true + settings.pluginsEnabled: true + settings.fullScreenSupportEnabled: true + settings.autoLoadIconsForPage: true + settings.touchIconsEnabled: true + + onCertificateError: { + error.defer(); + } + + Component.onCompleted: { + webChannel.registerObject("eventBridge", eventBridge); + webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); + //webEngineView.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)"; + } + + onFeaturePermissionRequested: { + grantFeaturePermission(securityOrigin, feature, true); + } + + onNewViewRequested: { + console.error("new view requested:", request.destination) + if (request.destination == WebEngineView.NewViewInDialog) { + webDialog.request = request + webDialog.active = true + } else { + request.openIn(webEngineView); + } + } + + onRenderProcessTerminated: { + var status = ""; + switch (terminationStatus) { + case WebEngineView.NormalTerminationStatus: + status = "(normal exit)"; + break; + case WebEngineView.AbnormalTerminationStatus: + status = "(abnormal exit)"; + break; + case WebEngineView.CrashedTerminationStatus: + status = "(crashed)"; + break; + case WebEngineView.KilledTerminationStatus: + status = "(killed)"; + break; + } + + console.error("Render process exited with code " + exitCode + " " + status); + reloadTimer.running = true; + } + + onFullScreenRequested: { + console.error("FS requested:", request.destination) + if (request.toggleOn) { + webEngineView.state = "FullScreen"; + } else { + webEngineView.state = ""; + } + request.accept(); + } + + onWindowCloseRequested: { + console.error("window close requested:", request.destination) + } + + Timer { + id: reloadTimer + interval: 0 + running: false + repeat: false + onTriggered: webEngineView.reload() } } - onLinkHovered: { - //TODO: change cursor shape? - console.error("hoveredUrl:", hoveredUrl) - } + Loader { + id: webDialog + property WebEngineNewViewRequest request: null + anchors.fill: parent + anchors.margins: 10 - // creates a global EventBridge object. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // detects when to raise and lower virtual keyboard - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - // User script. - WebEngineScript { - id: userScript - sourceUrl: webEngineView.userScriptUrl - injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] - - settings.autoLoadImages: true - settings.javascriptEnabled: true - settings.errorPageEnabled: true - settings.pluginsEnabled: true - settings.fullScreenSupportEnabled: true - settings.autoLoadIconsForPage: true - settings.touchIconsEnabled: true - - onCertificateError: { - error.defer(); - } - - Component.onCompleted: { - webChannel.registerObject("eventBridge", eventBridge); - webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - //webEngineView.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)"; - } - - onFeaturePermissionRequested: { - grantFeaturePermission(securityOrigin, feature, true); - } - - onNewViewRequested: { - request.openIn(webEngineView); - } - - onRenderProcessTerminated: { - var status = ""; - switch (terminationStatus) { - case WebEngineView.NormalTerminationStatus: - status = "(normal exit)"; - break; - case WebEngineView.AbnormalTerminationStatus: - status = "(abnormal exit)"; - break; - case WebEngineView.CrashedTerminationStatus: - status = "(crashed)"; - break; - case WebEngineView.KilledTerminationStatus: - status = "(killed)"; - break; + active: false + sourceComponent: webDialogComponent + onStatusChanged: { + if (Loader.Ready === status) { + focus = true + item.webDialogView.profile = webEngineView.profile + request.openIn(item.webDialogView) + } } - - print("Render process exited with code " + exitCode + " " + status); - reloadTimer.running = true; - } - - onWindowCloseRequested: { - } - - Timer { - id: reloadTimer - interval: 0 - running: false - repeat: false - onTriggered: webEngineView.reload() } } } From cf34fe334567c15114394047e2331eb0d2a094b8 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 25 Oct 2017 16:04:21 -0700 Subject: [PATCH 018/292] laserpointers generate pointerevents --- interface/src/Application.cpp | 2 + interface/src/raypick/LaserPointer.cpp | 114 ++++++++++++----- interface/src/raypick/LaserPointer.h | 19 ++- .../src/raypick/PickScriptingInterface.cpp | 22 ++++ .../src/raypick/PickScriptingInterface.h | 2 + .../src/raypick/PointerScriptingInterface.cpp | 27 +++- .../src/raypick/PointerScriptingInterface.h | 12 +- interface/src/ui/overlays/Overlays.cpp | 12 ++ interface/src/ui/overlays/Overlays.h | 2 +- .../src/controllers/UserInputMapper.h | 3 +- libraries/entities-renderer/CMakeLists.txt | 2 + .../src/EntityTreeRenderer.cpp | 10 ++ libraries/pointers/CMakeLists.txt | 2 +- libraries/pointers/src/pointers/Pick.cpp | 2 + libraries/pointers/src/pointers/Pick.h | 5 +- libraries/pointers/src/pointers/Pointer.cpp | 121 ++++++++++++++++++ libraries/pointers/src/pointers/Pointer.h | 49 ++++++- .../pointers/src/pointers/PointerManager.h | 18 ++- libraries/shared/src/PointerEvent.h | 5 +- scripts/defaultScripts.js | 2 +- 20 files changed, 375 insertions(+), 56 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 38e648ab72..1475eee59a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -5919,6 +5919,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); + DependencyManager::get()->registerMetaTypes(scriptEngine.data()); + // connect this script engines printedMessage signal to the global ScriptEngines these various messages connect(scriptEngine.data(), &ScriptEngine::printedMessage, DependencyManager::get().data(), &ScriptEngines::onPrintedMessage); diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 32c67be884..988f3023be 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -17,10 +17,10 @@ #include #include "PickScriptingInterface.h" -LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, +LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const PointerTriggers& triggers, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) : - Pointer(DependencyManager::get()->createRayPick(rayProps)), - _renderingEnabled(enabled), + Pointer(DependencyManager::get()->createRayPick(rayProps), enabled), + _triggers(triggers), _renderStates(renderStates), _defaultRenderStates(defaultRenderStates), _faceAvatar(faceAvatar), @@ -49,17 +49,9 @@ LaserPointer::~LaserPointer() { } } -void LaserPointer::enable() { - Pointer::enable(); - withWriteLock([&] { - _renderingEnabled = true; - }); -} - void LaserPointer::disable() { - Pointer::disable(); + Parent::disable(); withWriteLock([&] { - _renderingEnabled = false; if (!_currentRenderState.empty()) { if (_renderStates.find(_currentRenderState) != _renderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); @@ -199,26 +191,37 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { } } -void LaserPointer::update() { - // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts - withReadLock([&] { - QVariantMap prevRayPickResult = DependencyManager::get()->getPrevPickResult(_pickUID); - IntersectionType type = IntersectionType(prevRayPickResult["type"].toInt()); - PickRay pickRay = PickRay(prevRayPickResult["searchRay"].toMap()); - QUuid uid = prevRayPickResult["objectID"].toUuid(); - if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && - (type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { - float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult["distance"].toFloat(); - updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay, false); - disableRenderState(_defaultRenderStates[_currentRenderState].second); - } else if (_renderingEnabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { - disableRenderState(_renderStates[_currentRenderState]); - updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), pickRay, true); - } else if (!_currentRenderState.empty()) { - disableRenderState(_renderStates[_currentRenderState]); - disableRenderState(_defaultRenderStates[_currentRenderState].second); +void LaserPointer::updateVisuals(const QVariantMap& prevRayPickResult) { + IntersectionType type = IntersectionType(prevRayPickResult["type"].toInt()); + PickRay pickRay = PickRay(prevRayPickResult["searchRay"].toMap()); + QUuid uid = prevRayPickResult["objectID"].toUuid(); + if (_enabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && + (type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { + float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult["distance"].toFloat(); + updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay, false); + disableRenderState(_defaultRenderStates[_currentRenderState].second); + } else if (_enabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { + disableRenderState(_renderStates[_currentRenderState]); + updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), pickRay, true); + } else if (!_currentRenderState.empty()) { + disableRenderState(_renderStates[_currentRenderState]); + disableRenderState(_defaultRenderStates[_currentRenderState].second); + } +} + +Pointer::PickedObject LaserPointer::getHoveredObject(const QVariantMap& pickResult) { + return Pointer::PickedObject(pickResult["objectID"].toUuid(), IntersectionType(pickResult["type"].toUInt())); +} + +Pointer::Buttons LaserPointer::getPressedButtons() { + std::unordered_set toReturn; + for (const PointerTrigger& trigger : _triggers) { + // TODO: right now, LaserPointers don't support axes, only on/off buttons + if (trigger.getEndpoint()->peek() >= 1.0f) { + toReturn.insert(trigger.getButton()); } - }); + } + return toReturn; } void LaserPointer::setLength(const float length) { @@ -290,4 +293,53 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) { } return RenderState(startID, pathID, endID); +} + +PointerEvent LaserPointer::buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const { + uint32_t id = 0; + glm::vec3 intersection = vec3FromVariant(pickResult["intersection"]); + glm::vec3 surfaceNormal = vec3FromVariant(pickResult["surfaceNormal"]); + glm::vec3 direction = -surfaceNormal; + IntersectionType type = IntersectionType(pickResult["type"].toUInt()); + glm::vec2 pos2D; + if (type == ENTITY) { + pos2D = projectOntoEntityXYPlane(uid, intersection); + } else if (type == OVERLAY) { + pos2D = projectOntoOverlayXYPlane(uid, intersection); + } + return PointerEvent(PointerEvent::Move, id, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons); +} + +glm::vec2 LaserPointer::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const { + glm::quat invRot = glm::inverse(rotation); + glm::vec3 localPos = invRot * (worldPos - position); + glm::vec3 invDimensions = glm::vec3(1.0f / dimensions.x, 1.0f / dimensions.y, 1.0f / dimensions.z); + + glm::vec3 normalizedPos = (localPos * invDimensions) + registrationPoint; + return glm::vec2(normalizedPos.x * dimensions.x, (1.0f - normalizedPos.y) * dimensions.y); +} + +glm::vec2 LaserPointer::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos) const { + glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value); + glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value); + glm::vec3 dimensions; + + float dpi = qApp->getOverlays().getProperty(overlayID, "dpi").value.toFloat(); + if (dpi > 0) { + // Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property is used as a scale. + glm::vec3 resolution = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "resolution").value), 1); + glm::vec3 scale = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01f); + const float INCHES_TO_METERS = 1.0f / 39.3701f; + dimensions = (resolution * INCHES_TO_METERS / dpi) * scale; + } else { + dimensions = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01); + } + + const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); + return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT); +} + +glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entity, const glm::vec3& worldPos) const { + auto props = DependencyManager::get()->getEntityProperties(entity); + return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint()); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index dd1ee6de57..fbe293ea75 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -49,16 +49,15 @@ private: }; class LaserPointer : public Pointer { - + using Parent = Pointer; public: typedef std::unordered_map RenderStateMap; typedef std::unordered_map> DefaultRenderStateMap; - LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, + LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const PointerTriggers& triggers, const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled); ~LaserPointer(); - void enable() override; void disable() override; void setRenderState(const std::string& state) override; @@ -68,12 +67,18 @@ public: void setLength(const float length) override; void setLockEndUUID(QUuid objectID, const bool isOverlay) override; - void update() override; + void updateVisuals(const QVariantMap& prevRayPickResult) override; + + PickedObject getHoveredObject(const QVariantMap& pickResult) override; + Pointer::Buttons getPressedButtons() override; static RenderState buildRenderState(const QVariantMap& propMap); +protected: + PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const override; + private: - bool _renderingEnabled; + PointerTriggers _triggers; float _laserLength { 0.0f }; std::string _currentRenderState { "" }; RenderStateMap _renderStates; @@ -88,6 +93,10 @@ private: void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState); void disableRenderState(const RenderState& renderState); + glm::vec2 projectOntoEntityXYPlane(const QUuid& entity, const glm::vec3& worldPos) const; + glm::vec2 projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos) const; + glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const; + }; #endif // hifi_LaserPointer_h diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 99f7ac2515..40f898e65d 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -17,6 +17,9 @@ #include "JointRayPick.h" #include "MouseRayPick.h" +#include +#include + QUuid PickScriptingInterface::createPick(const PickQuery::PickType type, const QVariant& properties) { switch (type) { case PickQuery::PickType::Ray: @@ -105,3 +108,22 @@ void PickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue void PickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } + +QScriptValue pickTypesToScriptValue(QScriptEngine* engine, const PickQuery::PickType& pickType) { + return pickType; +} + +void pickTypesFromScriptValue(const QScriptValue& object, PickQuery::PickType& pickType) { + pickType = static_cast(object.toUInt16()); +} + +void PickScriptingInterface::registerMetaTypes(QScriptEngine* engine) { + QScriptValue pickTypes = engine->newObject(); + auto metaEnum = QMetaEnum::fromType(); + for (int i = 0; i < PickQuery::PickType::NUM_PICK_TYPES; ++i) { + pickTypes.setProperty(metaEnum.key(i), metaEnum.value(i)); + } + engine->globalObject().setProperty("PickType", pickTypes); + + qScriptRegisterMetaType(engine, pickTypesToScriptValue, pickTypesFromScriptValue); +} \ No newline at end of file diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 462b64dbd1..7c2eeb1ffc 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -35,6 +35,8 @@ class PickScriptingInterface : public QObject, public Dependency { public: QUuid createRayPick(const QVariant& properties); + void registerMetaTypes(QScriptEngine* engine); + public slots: Q_INVOKABLE QUuid createPick(const PickQuery::PickType type, const QVariant& properties); Q_INVOKABLE void enablePick(const QUuid& uid); diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 8a87721ad9..5ac209d295 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -21,7 +21,7 @@ void PointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptV DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } -QUuid PointerScriptingInterface::createPointer(const PickQuery::PickType type, const QVariant& properties) const { +QUuid PointerScriptingInterface::createPointer(const PickQuery::PickType& type, const QVariant& properties) const { switch (type) { case PickQuery::PickType::Ray: return createLaserPointer(properties); @@ -61,7 +61,7 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) LaserPointer::RenderStateMap renderStates; if (propertyMap["renderStates"].isValid()) { QList renderStateVariants = propertyMap["renderStates"].toList(); - for (QVariant& renderStateVariant : renderStateVariants) { + for (const QVariant& renderStateVariant : renderStateVariants) { if (renderStateVariant.isValid()) { QVariantMap renderStateMap = renderStateVariant.toMap(); if (renderStateMap["name"].isValid()) { @@ -75,7 +75,7 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) LaserPointer::DefaultRenderStateMap defaultRenderStates; if (propertyMap["defaultRenderStates"].isValid()) { QList renderStateVariants = propertyMap["defaultRenderStates"].toList(); - for (QVariant& renderStateVariant : renderStateVariants) { + for (const QVariant& renderStateVariant : renderStateVariants) { if (renderStateVariant.isValid()) { QVariantMap renderStateMap = renderStateVariant.toMap(); if (renderStateMap["name"].isValid() && renderStateMap["distance"].isValid()) { @@ -87,7 +87,26 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) } } - return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled)); + PointerTriggers triggers; + auto userInputMapper = DependencyManager::get(); + if (propertyMap["triggers"].isValid()) { + QList triggerVariants = propertyMap["triggers"].toList(); + for (const QVariant& triggerVariant : triggerVariants) { + if (triggerVariant.isValid()) { + QVariantMap triggerMap = triggerVariant.toMap(); + if (triggerMap["action"].isValid() && triggerMap["button"].isValid()) { + controller::Endpoint::Pointer endpoint = userInputMapper->endpointFor(controller::Input(triggerMap["action"].toUInt())); + if (endpoint) { + std::string button = triggerMap["button"].toString().toStdString(); + triggers.emplace_back(endpoint, button); + } + } + } + } + } + + return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, triggers, + faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled)); } void PointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index de45826d48..cc2ffbc3cc 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -22,13 +22,13 @@ public: QUuid createLaserPointer(const QVariant& properties) const; public slots: - Q_INVOKABLE QUuid createPointer(const PickQuery::PickType type, const QVariant& properties) const; + Q_INVOKABLE QUuid createPointer(const PickQuery::PickType& type, const QVariant& properties) const; Q_INVOKABLE void enablePointer(const QUuid& uid) const { DependencyManager::get()->enablePointer(uid); } Q_INVOKABLE void disablePointer(const QUuid& uid) const { DependencyManager::get()->disablePointer(uid); } Q_INVOKABLE void removePointer(const QUuid& uid) const { DependencyManager::get()->removePointer(uid); } Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } - Q_INVOKABLE QVariantMap getPrevPickResult(QUuid uid) const { return DependencyManager::get()->getPrevPickResult(uid); } + Q_INVOKABLE QVariantMap getPrevPickResult(const QUuid& uid) const { return DependencyManager::get()->getPrevPickResult(uid); } Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } @@ -37,6 +37,14 @@ public slots: Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } +signals: + void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent); + void triggerContinue(const QUuid& id, const PointerEvent& pointerEvent); + void triggerEnd(const QUuid& id, const PointerEvent& pointerEvent); + void hoverBegin(const QUuid& id, const PointerEvent& pointerEvent); + void hoverContinue(const QUuid& id, const PointerEvent& pointerEvent); + void hoverEnd(const QUuid& id, const PointerEvent& pointerEvent); + }; #endif // hifi_PointerScriptingInterface_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 5e5b9367a6..2645d3b061 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -37,10 +37,22 @@ #include "Web3DOverlay.h" #include +#include + Q_LOGGING_CATEGORY(trace_render_overlays, "trace.render.overlays") extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest = false); +Overlays::Overlays() { + auto pointerManager = DependencyManager::get(); + connect(pointerManager.data(), &PointerManager::hoverBeginOverlay, this, &Overlays::hoverEnterOverlay); + connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, this, &Overlays::hoverOverOverlay); + connect(pointerManager.data(), &PointerManager::hoverEndOverlay, this, &Overlays::hoverLeaveOverlay); + connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, this, &Overlays::mousePressOnOverlay); + connect(pointerManager.data(), &PointerManager::triggerContinueOverlay, this, &Overlays::mouseMoveOnOverlay); + connect(pointerManager.data(), &PointerManager::triggerEndOverlay, this, &Overlays::mouseReleaseOnOverlay); +} + void Overlays::cleanupAllOverlays() { QMap overlaysHUD; QMap overlaysWorld; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 732a437eae..67d2537640 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -85,7 +85,7 @@ class Overlays : public QObject { Q_PROPERTY(OverlayID keyboardFocusOverlay READ getKeyboardFocusOverlay WRITE setKeyboardFocusOverlay) public: - Overlays() {}; + Overlays(); void init(); void update(float deltatime); diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index 0c8bb51008..5fd21e6299 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -129,6 +129,8 @@ namespace controller { template void withLock(F&& f) { Locker locker(_lock); f(); } + EndpointPointer endpointFor(const Input& endpoint) const; + signals: void actionEvent(int action, float state); void inputEvent(int input, float state); @@ -161,7 +163,6 @@ namespace controller { void disableMapping(const MappingPointer& mapping); EndpointPointer endpointFor(const QJSValue& endpoint); EndpointPointer endpointFor(const QScriptValue& endpoint); - EndpointPointer endpointFor(const Input& endpoint) const; EndpointPointer compositeEndpointFor(EndpointPointer first, EndpointPointer second); ConditionalPointer conditionalFor(const QJSValue& endpoint); ConditionalPointer conditionalFor(const QScriptValue& endpoint); diff --git a/libraries/entities-renderer/CMakeLists.txt b/libraries/entities-renderer/CMakeLists.txt index 40111e257b..35301e93d6 100644 --- a/libraries/entities-renderer/CMakeLists.txt +++ b/libraries/entities-renderer/CMakeLists.txt @@ -12,6 +12,8 @@ include_hifi_library_headers(animation) include_hifi_library_headers(fbx) include_hifi_library_headers(entities) include_hifi_library_headers(avatars) +include_hifi_library_headers(pointers) +include_hifi_library_headers(controllers) target_bullet() diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4238eb4050..c63079b020 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -35,6 +35,8 @@ #include "EntitiesRendererLogging.h" #include "RenderableEntityItem.h" +#include + size_t std::hash::operator()(const EntityItemID& id) const { return qHash(id); } std::function EntityTreeRenderer::_entitiesShouldFadeFunction; @@ -55,6 +57,14 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf EntityRenderer::initEntityRenderers(); _currentHoverOverEntityID = UNKNOWN_ENTITY_ID; _currentClickingOnEntityID = UNKNOWN_ENTITY_ID; + + auto pointerManager = DependencyManager::get(); + connect(pointerManager.data(), &PointerManager::hoverBeginEntity, this, &EntityTreeRenderer::hoverEnterEntity); + connect(pointerManager.data(), &PointerManager::hoverContinueEntity, this, &EntityTreeRenderer::hoverOverEntity); + connect(pointerManager.data(), &PointerManager::hoverEndEntity, this, &EntityTreeRenderer::hoverLeaveEntity); + connect(pointerManager.data(), &PointerManager::triggerBeginEntity, this, &EntityTreeRenderer::mousePressOnEntity); + connect(pointerManager.data(), &PointerManager::triggerContinueEntity, this, &EntityTreeRenderer::mouseMoveOnEntity); + connect(pointerManager.data(), &PointerManager::triggerEndEntity, this, &EntityTreeRenderer::mouseReleaseOnEntity); } EntityTreeRenderer::~EntityTreeRenderer() { diff --git a/libraries/pointers/CMakeLists.txt b/libraries/pointers/CMakeLists.txt index 504484574c..e33c76e249 100644 --- a/libraries/pointers/CMakeLists.txt +++ b/libraries/pointers/CMakeLists.txt @@ -1,5 +1,5 @@ set(TARGET_NAME pointers) setup_hifi_library() GroupSources(src) -link_hifi_libraries(shared) +link_hifi_libraries(shared controllers) diff --git a/libraries/pointers/src/pointers/Pick.cpp b/libraries/pointers/src/pointers/Pick.cpp index 4e48bc906b..4315409bdb 100644 --- a/libraries/pointers/src/pointers/Pick.cpp +++ b/libraries/pointers/src/pointers/Pick.cpp @@ -9,6 +9,8 @@ const PickFilter PickFilter::NOTHING; +int pickTypeMetaTypeId = qRegisterMetaType("PickType"); + PickQuery::PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled) : _filter(filter), _maxDistance(maxDistance), diff --git a/libraries/pointers/src/pointers/Pick.h b/libraries/pointers/src/pointers/Pick.h index 5dcaba2bb8..9ab17f87d8 100644 --- a/libraries/pointers/src/pointers/Pick.h +++ b/libraries/pointers/src/pointers/Pick.h @@ -136,7 +136,9 @@ public: enum PickType { Ray = 0, - Stylus + Stylus, + + NUM_PICK_TYPES }; Q_ENUM(PickType) @@ -189,6 +191,7 @@ private: QVector _ignoreItems; QVector _includeItems; }; +Q_DECLARE_METATYPE(PickQuery::PickType) template class Pick : public PickQuery { diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 6ba8c6072c..1ee725645f 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -9,6 +9,7 @@ #include #include "PickManager.h" +#include "PointerManager.h" Pointer::~Pointer() { DependencyManager::get()->removePick(_pickUID); @@ -16,10 +17,16 @@ Pointer::~Pointer() { void Pointer::enable() { DependencyManager::get()->enablePick(_pickUID); + withWriteLock([&] { + _enabled = true; + }); } void Pointer::disable() { DependencyManager::get()->disablePick(_pickUID); + withWriteLock([&] { + _enabled = false; + }); } const QVariantMap Pointer::getPrevPickResult() { @@ -36,4 +43,118 @@ void Pointer::setIgnoreItems(const QVector& ignoreItems) const { void Pointer::setIncludeItems(const QVector& includeItems) const { DependencyManager::get()->setIncludeItems(_pickUID, includeItems); +} + +void Pointer::update() { + // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts + withReadLock([&] { + QVariantMap pickResult = getPrevPickResult(); + updateVisuals(pickResult); + generatePointerEvents(pickResult); + }); +} + +void Pointer::generatePointerEvents(const QVariantMap& pickResult) { + // TODO: avatars/HUD? + auto pointerManager = DependencyManager::get(); + + // Hover events + Pointer::PickedObject hoveredObject = getHoveredObject(pickResult); + PointerEvent hoveredEvent = buildPointerEvent(hoveredObject.objectID, pickResult); + hoveredEvent.setType(PointerEvent::Move); + hoveredEvent.setButton(PointerEvent::NoButtons); + if (_enabled) { + if (hoveredObject.type == OVERLAY) { + if (_prevHoveredObject.type == OVERLAY) { + if (hoveredObject.objectID == _prevHoveredObject.objectID) { + emit pointerManager->hoverContinueOverlay(hoveredObject.objectID, hoveredEvent); + } else { + PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject.objectID, pickResult); + emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, prevHoveredEvent); + emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); + } + } else { + emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); + if (_prevHoveredObject.type == ENTITY) { + emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); + } + } + } + + // TODO: this is basically repeated code. is there a way to clean it up? + if (hoveredObject.type == ENTITY) { + if (_prevHoveredObject.type == ENTITY) { + if (hoveredObject.objectID == _prevHoveredObject.objectID) { + emit pointerManager->hoverContinueEntity(hoveredObject.objectID, hoveredEvent); + } else { + PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject.objectID, pickResult); + emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, prevHoveredEvent); + emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); + } + } else { + emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); + if (_prevHoveredObject.type == OVERLAY) { + emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent); + } + } + } + } + + // Trigger events + Buttons buttons; + Buttons newButtons; + Buttons sameButtons; + // NOTE: After this loop: _prevButtons = buttons that were removed + // If !_enabled, release all buttons + if (_enabled) { + buttons = getPressedButtons(); + for (const std::string& button : buttons) { + if (_prevButtons.find(button) == _prevButtons.end()) { + newButtons.insert(button); + } else { + sameButtons.insert(button); + _prevButtons.erase(button); + } + } + } + + // Trigger begin + for (const std::string& button : newButtons) { + hoveredEvent.setType(PointerEvent::Press); + hoveredEvent.setButton(PointerEvent::PrimaryButton); + if (hoveredObject.type == ENTITY) { + emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent); + } else if (hoveredObject.type == OVERLAY) { + emit pointerManager->triggerBeginOverlay(hoveredObject.objectID, hoveredEvent); + } + _triggeredObjects[button] = hoveredObject; + } + + // Trigger continue + for (const std::string& button : sameButtons) { + PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button].objectID, pickResult); + triggeredEvent.setType(PointerEvent::Move); + triggeredEvent.setButton(PointerEvent::PrimaryButton); + if (_triggeredObjects[button].type == ENTITY) { + emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent); + } else if (_triggeredObjects[button].type == OVERLAY) { + emit pointerManager->triggerContinueOverlay(_triggeredObjects[button].objectID, triggeredEvent); + } + } + + // Trigger end + for (const std::string& button : _prevButtons) { + PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button].objectID, pickResult); + triggeredEvent.setType(PointerEvent::Release); + triggeredEvent.setButton(PointerEvent::PrimaryButton); + if (_triggeredObjects[button].type == ENTITY) { + emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent); + } else if (_triggeredObjects[button].type == OVERLAY) { + emit pointerManager->triggerEndOverlay(_triggeredObjects[button].objectID, triggeredEvent); + } + _triggeredObjects.erase(button); + } + + _prevHoveredObject = hoveredObject; + _prevButtons = buttons; } \ No newline at end of file diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index 4a105f8a92..4e965cd73c 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -8,15 +8,37 @@ #ifndef hifi_Pointer_h #define hifi_Pointer_h +#include +#include + #include #include #include #include +#include +#include "PointerEvent.h" + +#include "Pick.h" + +class PointerTrigger { +public: + PointerTrigger(controller::Endpoint::Pointer endpoint, const std::string& button) : _endpoint(endpoint), _button(button) {} + + controller::Endpoint::Pointer getEndpoint() const { return _endpoint; } + const std::string& getButton() const { return _button; } + +private: + controller::Endpoint::Pointer _endpoint; + std::string _button { "" }; +}; + +using PointerTriggers = std::vector; + class Pointer : protected ReadWriteLockable { public: - Pointer(const QUuid& uid) : _pickUID(uid) {} + Pointer(const QUuid& uid, bool enabled) : _pickUID(uid), _enabled(enabled) {} virtual ~Pointer(); @@ -35,12 +57,35 @@ public: virtual void setLength(const float length) {} virtual void setLockEndUUID(QUuid objectID, const bool isOverlay) {} - virtual void update() = 0; + void update(); + virtual void updateVisuals(const QVariantMap& pickResult) = 0; + void generatePointerEvents(const QVariantMap& pickResult); + + struct PickedObject { + PickedObject() {} + PickedObject(const QUuid& objectID, IntersectionType type) : objectID(objectID), type(type) {} + + QUuid objectID; + IntersectionType type; + } typedef PickedObject; + + using Buttons = std::unordered_set; + + virtual PickedObject getHoveredObject(const QVariantMap& pickResult) = 0; + virtual Buttons getPressedButtons() = 0; QUuid getRayUID() { return _pickUID; } protected: + bool _enabled; const QUuid _pickUID; + + virtual PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const = 0; + +private: + PickedObject _prevHoveredObject; + Buttons _prevButtons; + std::unordered_map _triggeredObjects; }; #endif // hifi_Pick_h diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 2ec5921e3c..6e13c09851 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -45,13 +45,19 @@ private: QHash> _pointers; signals: - void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent); - void triggerContinue(const QUuid& id, const PointerEvent& pointerEvent); - void triggerEnd(const QUuid& id, const PointerEvent& pointerEvent); + void triggerBeginOverlay(const QUuid& id, const PointerEvent& pointerEvent); + void triggerContinueOverlay(const QUuid& id, const PointerEvent& pointerEvent); + void triggerEndOverlay(const QUuid& id, const PointerEvent& pointerEvent); + void hoverBeginOverlay(const QUuid& id, const PointerEvent& pointerEvent); + void hoverContinueOverlay(const QUuid& id, const PointerEvent& pointerEvent); + void hoverEndOverlay(const QUuid& id, const PointerEvent& pointerEvent); - void hoverEnter(const QUuid& id, const PointerEvent& pointerEvent); - void hoverOver(const QUuid& id, const PointerEvent& pointerEvent); - void hoverLeave(const QUuid& id, const PointerEvent& pointerEvent); + void triggerBeginEntity(const QUuid& id, const PointerEvent& pointerEvent); + void triggerContinueEntity(const QUuid& id, const PointerEvent& pointerEvent); + void triggerEndEntity(const QUuid& id, const PointerEvent& pointerEvent); + void hoverBeginEntity(const QUuid& id, const PointerEvent& pointerEvent); + void hoverContinueEntity(const QUuid& id, const PointerEvent& pointerEvent); + void hoverEndEntity(const QUuid& id, const PointerEvent& pointerEvent); }; #endif // hifi_pointers_PointerManager_h diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index ab77328fc1..63c063cd01 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -39,7 +39,7 @@ public: PointerEvent(EventType type, uint32_t id, const glm::vec2& pos2D, const glm::vec3& pos3D, const glm::vec3& normal, const glm::vec3& direction, - Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers); + Button button, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::KeyboardModifier::NoModifier); static QScriptValue toScriptValue(QScriptEngine* engine, const PointerEvent& event); static void fromScriptValue(const QScriptValue& object, PointerEvent& event); @@ -56,6 +56,9 @@ public: uint32_t getButtons() const { return _buttons; } Qt::KeyboardModifiers getKeyboardModifiers() const { return _keyboardModifiers; } + void setType(EventType type) { _type = type; } + void setButton(Button button) { _button = button; } + private: EventType _type; uint32_t _id; // used to identify the pointer. (left vs right hand, for example) diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 61e520af21..1243ed28e2 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -32,7 +32,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/tablet-ui/tabletUI.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ - "system/controllers/controllerScripts.js" + //"system/controllers/controllerScripts.js" // "system/chat.js" ]; From 320ab2e68211fc5753de3e1e3b9b4d74cc502db4 Mon Sep 17 00:00:00 2001 From: vladest Date: Thu, 26 Oct 2017 21:14:44 +0200 Subject: [PATCH 019/292] Rework using StackView. Now backward takes in account popups as well --- interface/resources/qml/hifi/WebBrowser.qml | 356 ++++++++++---------- 1 file changed, 174 insertions(+), 182 deletions(-) diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index c96d05d6a7..79932dbcdd 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -13,6 +13,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 as QQControls import QtQuick.Layouts 1.3 +import QtGraphicalEffects 1.0 import QtWebEngine 1.5 import QtWebChannel 1.0 @@ -46,13 +47,13 @@ Rectangle { onSuggestions: { if (suggestions.length > 0) { suggestionsList = [] - suggestionsList.push(addressBarInput.text) //do not overwrite edit text + suggestionsList.push(addressBarInput.text); //do not overwrite edit text for(var i = 0; i < suggestions.length; i++) { - suggestionsList.push(suggestions[i]) + suggestionsList.push(suggestions[i]); } addressBar.model = suggestionsList if (!addressBar.popup.visible) { - addressBar.popup.open() + addressBar.popup.open(); } } } @@ -64,7 +65,7 @@ Rectangle { repeat: false onTriggered: { if (addressBar.editText !== "") { - searchEngine.requestSuggestions(addressBarInput.text) + searchEngine.requestSuggestions(addressBarInput.text); } } } @@ -83,9 +84,9 @@ Rectangle { } addressBar.model = [] - webEngineView.url = url - suggestionRequestTimer.stop() - addressBar.popup.close() + webStack.currentItem.webEngineView.url = url + suggestionRequestTimer.stop(); + addressBar.popup.close(); } Column { @@ -98,22 +99,26 @@ Rectangle { height: 48 HifiControls.WebGlyphButton { - enabled: webEngineView.canGoBack + enabled: webStack.currentItem.webEngineView.canGoBack || webStack.depth > 1 glyph: hifi.glyphs.backward; anchors.verticalCenter: parent.verticalCenter; size: 38; onClicked: { - webEngineView.goBack() + if (webStack.currentItem.webEngineView.canGoBack) { + webStack.currentItem.webEngineView.goBack(); + } else if (webStack.depth > 1) { + webStack.pop(); + } } } HifiControls.WebGlyphButton { - enabled: webEngineView.canGoForward + enabled: webStack.currentItem.webEngineView.canGoForward glyph: hifi.glyphs.forward; anchors.verticalCenter: parent.verticalCenter; size: 38; onClicked: { - webEngineView.goForward() + webStack.currentItem.webEngineView.goForward(); } } @@ -128,21 +133,21 @@ Rectangle { indicator: Item {} background: Item {} onActivated: { - goTo(textAt(index)) + goTo(textAt(index)); } - popup.height: webEngineView.height + popup.height: webStack.height onFocusChanged: { if (focus) { - addressBarInput.selectAll() + addressBarInput.selectAll(); } } contentItem: QQControls.TextField { id: addressBarInput leftPadding: 26 - rightPadding: hifi.dimensions.controlLineHeight + rightPadding: hifi.dimensions.controlLineHeight + 5 text: addressBar.editText placeholderText: qsTr("Enter URL") font: addressBar.font @@ -151,7 +156,7 @@ Rectangle { verticalAlignment: Text.AlignVCenter onFocusChanged: { if (focus) { - selectAll() + selectAll(); } } @@ -161,7 +166,7 @@ Rectangle { Keys.onPressed: { if (event.key === Qt.Key_Return) { - goTo(addressBarInput.text) + goTo(addressBarInput.text); event.accepted = true; } } @@ -173,58 +178,57 @@ Rectangle { id: faviconImage width: 16; height: 16 sourceSize: Qt.size(width, height) - source: webEngineView.icon - onSourceChanged: console.log("web icon", source) + source: webStack.currentItem.webEngineView.icon } HifiControls.WebGlyphButton { - glyph: webEngineView.loading ? hifi.glyphs.closeSmall : hifi.glyphs.reloadSmall; + glyph: webStack.currentItem.webEngineView.loading ? hifi.glyphs.closeSmall : hifi.glyphs.reloadSmall; anchors.verticalCenter: parent.verticalCenter; width: hifi.dimensions.controlLineHeight z: 2 x: addressBarInput.width - implicitWidth onClicked: { - if (webEngineView.loading) { - webEngineView.stop() + if (webStack.currentItem.webEngineView.loading) { + webStack.currentItem.webEngineView.stop(); } else { - reloadTimer.start() + webStack.currentItem.webEngineView.reloadTimer.start(); } } } } - Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i") + Component.onCompleted: ScriptDiscoveryService.scriptsModelFilter.filterRegExp = new RegExp("^.*$", "i"); Keys.onPressed: { if (event.key === Qt.Key_Return) { - goTo(addressBarInput.text) + goTo(addressBarInput.text); event.accepted = true; } } onEditTextChanged: { - if (addressBar.editText !== "" && addressBar.editText !== webEngineView.url.toString()) { + if (addressBar.editText !== "" && addressBar.editText !== webStack.currentItem.webEngineView.url.toString()) { suggestionRequestTimer.restart(); } else { addressBar.model = [] - addressBar.popup.close() + addressBar.popup.close(); } } Layout.fillWidth: true - editText: webEngineView.url - onAccepted: goTo(addressBarInput.text) + editText: webStack.currentItem.webEngineView.url + onAccepted: goTo(addressBarInput.text); } HifiControls.WebGlyphButton { checkable: true - checked: webEngineView.audioMuted + checked: webStack.currentItem.webEngineView.audioMuted glyph: checked ? hifi.glyphs.unmuted : hifi.glyphs.muted anchors.verticalCenter: parent.verticalCenter; width: hifi.dimensions.controlLineHeight onClicked: { - webEngineView.triggerWebAction(WebEngineView.ToggleMediaMute) + webStack.currentItem.webEngineView.triggerWebAction(WebEngineView.ToggleMediaMute); } } } @@ -249,18 +253,88 @@ Rectangle { width: parent.width; from: 0 to: 100 - value: webEngineView.loadProgress + value: webStack.currentItem.webEngineView.loadProgress height: 2 } Component { - id: webDialogComponent + id: webViewComponent Rectangle { - property alias webDialogView: webDialogView - color: "white" + property alias webEngineView: webEngineView + property WebEngineNewViewRequest request: null + + property bool isDialog: QQControls.StackView.index > 0 + property real margins: isDialog ? 10 : 0 + + color: "#d1d1d1" + + QQControls.StackView.onActivated: { + addressBar.editText = Qt.binding( function() { return webStack.currentItem.webEngineView.url; }); + } + + onRequestChanged: { + if (isDialog && request !== null && request !== undefined) {//is Dialog ? + request.openIn(webEngineView); + } + } + HifiControls.BaseWebView { - id: webDialogView + id: webEngineView anchors.fill: parent + anchors.margins: parent.margins + + layer.enabled: parent.isDialog + layer.effect: DropShadow { + verticalOffset: 8 + horizontalOffset: 8 + color: "#330066ff" + samples: 10 + spread: 0.5 + } + + focus: true + objectName: "tabletWebEngineView" + + //profile: HFWebEngineProfile; + + property string userScriptUrl: "" + + onLoadingChanged: { + if (!loading) { + suggestionRequestTimer.stop(); + addressBar.popup.close(); + } + } + + onLinkHovered: { + //TODO: change cursor shape? + } + + // creates a global EventBridge object. + WebEngineScript { + id: createGlobalEventBridge + sourceCode: eventBridgeJavaScriptToInject + injectionPoint: WebEngineScript.DocumentCreation + worldId: WebEngineScript.MainWorld + } + + // detects when to raise and lower virtual keyboard + WebEngineScript { + id: raiseAndLowerKeyboard + injectionPoint: WebEngineScript.Deferred + sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" + worldId: WebEngineScript.MainWorld + } + + // User script. + WebEngineScript { + id: userScript + sourceUrl: webEngineView.userScriptUrl + injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. + worldId: WebEngineScript.MainWorld + } + + userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] settings.autoLoadImages: true settings.javascriptEnabled: true @@ -270,162 +344,80 @@ Rectangle { settings.autoLoadIconsForPage: true settings.touchIconsEnabled: true + onCertificateError: { + error.defer(); + } + + Component.onCompleted: { + webChannel.registerObject("eventBridge", eventBridge); + webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); + //webEngineView.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)"; + } + + onFeaturePermissionRequested: { + grantFeaturePermission(securityOrigin, feature, true); + } + + onNewViewRequested: { + if (request.destination == WebEngineView.NewViewInDialog) { + webStack.push(webViewComponent, {"request": request}); + } else { + request.openIn(webEngineView); + } + } + + onRenderProcessTerminated: { + var status = ""; + switch (terminationStatus) { + case WebEngineView.NormalTerminationStatus: + status = "(normal exit)"; + break; + case WebEngineView.AbnormalTerminationStatus: + status = "(abnormal exit)"; + break; + case WebEngineView.CrashedTerminationStatus: + status = "(crashed)"; + break; + case WebEngineView.KilledTerminationStatus: + status = "(killed)"; + break; + } + + console.error("Render process exited with code " + exitCode + " " + status); + reloadTimer.running = true; + } + + onFullScreenRequested: { + if (request.toggleOn) { + webEngineView.state = "FullScreen"; + } else { + webEngineView.state = ""; + } + request.accept(); + } + onWindowCloseRequested: { - webDialog.active = false - webDialog.request = null + webStack.pop(); + } + + Timer { + id: reloadTimer + interval: 0 + running: false + repeat: false + onTriggered: webEngineView.reload() } } } } - Item { + QQControls.StackView { + id: webStack width: parent.width; property real webViewHeight: root.height - loadProgressBar.height - 48 - 4 height: keyboardEnabled && keyboardRaised ? webViewHeight - keyboard.height : webViewHeight - HifiControls.BaseWebView { - id: webEngineView - anchors.fill: parent - - focus: true - objectName: "tabletWebEngineView" - - url: "https://www.highfidelity.com" - - //profile: HFWebEngineProfile; - - property string userScriptUrl: "" - - onLoadingChanged: { - if (!loading) { - suggestionRequestTimer.stop() - addressBar.popup.close() - } - } - - onLinkHovered: { - //TODO: change cursor shape? - console.error("hoveredUrl:", hoveredUrl) - } - - // creates a global EventBridge object. - WebEngineScript { - id: createGlobalEventBridge - sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation - worldId: WebEngineScript.MainWorld - } - - // detects when to raise and lower virtual keyboard - WebEngineScript { - id: raiseAndLowerKeyboard - injectionPoint: WebEngineScript.Deferred - sourceUrl: resourceDirectoryUrl + "/html/raiseAndLowerKeyboard.js" - worldId: WebEngineScript.MainWorld - } - - // User script. - WebEngineScript { - id: userScript - sourceUrl: webEngineView.userScriptUrl - injectionPoint: WebEngineScript.DocumentReady // DOM ready but page load may not be finished. - worldId: WebEngineScript.MainWorld - } - - userScripts: [ createGlobalEventBridge, raiseAndLowerKeyboard, userScript ] - - settings.autoLoadImages: true - settings.javascriptEnabled: true - settings.errorPageEnabled: true - settings.pluginsEnabled: true - settings.fullScreenSupportEnabled: true - settings.autoLoadIconsForPage: true - settings.touchIconsEnabled: true - - onCertificateError: { - error.defer(); - } - - Component.onCompleted: { - webChannel.registerObject("eventBridge", eventBridge); - webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - //webEngineView.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)"; - } - - onFeaturePermissionRequested: { - grantFeaturePermission(securityOrigin, feature, true); - } - - onNewViewRequested: { - console.error("new view requested:", request.destination) - if (request.destination == WebEngineView.NewViewInDialog) { - webDialog.request = request - webDialog.active = true - } else { - request.openIn(webEngineView); - } - } - - onRenderProcessTerminated: { - var status = ""; - switch (terminationStatus) { - case WebEngineView.NormalTerminationStatus: - status = "(normal exit)"; - break; - case WebEngineView.AbnormalTerminationStatus: - status = "(abnormal exit)"; - break; - case WebEngineView.CrashedTerminationStatus: - status = "(crashed)"; - break; - case WebEngineView.KilledTerminationStatus: - status = "(killed)"; - break; - } - - console.error("Render process exited with code " + exitCode + " " + status); - reloadTimer.running = true; - } - - onFullScreenRequested: { - console.error("FS requested:", request.destination) - if (request.toggleOn) { - webEngineView.state = "FullScreen"; - } else { - webEngineView.state = ""; - } - request.accept(); - } - - onWindowCloseRequested: { - console.error("window close requested:", request.destination) - } - - Timer { - id: reloadTimer - interval: 0 - running: false - repeat: false - onTriggered: webEngineView.reload() - } - } - - Loader { - id: webDialog - property WebEngineNewViewRequest request: null - anchors.fill: parent - anchors.margins: 10 - - active: false - sourceComponent: webDialogComponent - onStatusChanged: { - if (Loader.Ready === status) { - focus = true - item.webDialogView.profile = webEngineView.profile - request.openIn(item.webDialogView) - } - } - } + Component.onCompleted: webStack.push(webViewComponent, {"webEngineView.url": "https://www.highfidelity.com"}); } } From 7951826e4961896274e2aa12d045eea1898be864 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 26 Oct 2017 16:10:27 -0700 Subject: [PATCH 020/292] more advanced laser focusing --- interface/src/Application.cpp | 14 +++++---- interface/src/raypick/LaserPointer.cpp | 14 --------- interface/src/raypick/LaserPointer.h | 2 -- .../src/raypick/RayPickScriptingInterface.cpp | 1 - .../src/raypick/RayPickScriptingInterface.h | 31 +++++++++++++++++++ interface/src/ui/overlays/Overlays.cpp | 8 +++-- libraries/pointers/src/pointers/Pointer.cpp | 2 ++ libraries/pointers/src/pointers/Pointer.h | 2 +- libraries/shared/src/PointerEvent.h | 4 +++ 9 files changed, 51 insertions(+), 27 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 991d9eaecd..0db422953f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1472,13 +1472,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // If the user clicks an an entity, we will check that it's an unlocked web entity, and if so, set the focus to it auto entityScriptingInterface = DependencyManager::get(); - connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, + connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, [this](const EntityItemID& entityItemID, const PointerEvent& event) { - if (getEntities()->wantsKeyboardFocus(entityItemID)) { - setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); - setKeyboardFocusEntity(entityItemID); - } else { - setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); + if (event.shouldFocus()) { + if (getEntities()->wantsKeyboardFocus(entityItemID)) { + setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); + setKeyboardFocusEntity(entityItemID); + } else { + setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); + } } }); diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 988f3023be..b8122a2388 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -49,20 +49,6 @@ LaserPointer::~LaserPointer() { } } -void LaserPointer::disable() { - Parent::disable(); - withWriteLock([&] { - if (!_currentRenderState.empty()) { - if (_renderStates.find(_currentRenderState) != _renderStates.end()) { - disableRenderState(_renderStates[_currentRenderState]); - } - if (_defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { - disableRenderState(_defaultRenderStates[_currentRenderState].second); - } - } - }); -} - void LaserPointer::setRenderState(const std::string& state) { withWriteLock([&] { if (!_currentRenderState.empty() && state != _currentRenderState) { diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index fbe293ea75..167de88385 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -58,8 +58,6 @@ public: const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled); ~LaserPointer(); - void disable() override; - void setRenderState(const std::string& state) override; // You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays. void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override; diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index b89f89aab5..92bf3ec521 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -14,7 +14,6 @@ #include #include "GLMHelpers.h" -#include "PickScriptingInterface.h" #include #include "StaticRayPick.h" diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index e7c5dfd5dd..b0d36f482c 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -16,8 +16,24 @@ #include "RegisteredMetaTypes.h" #include +#include "PickScriptingInterface.h" + class RayPickScriptingInterface : public QObject, public Dependency { Q_OBJECT + Q_PROPERTY(unsigned int PICK_NOTHING READ PICK_NOTHING CONSTANT) + Q_PROPERTY(unsigned int PICK_ENTITIES READ PICK_ENTITIES CONSTANT) + Q_PROPERTY(unsigned int PICK_OVERLAYS READ PICK_OVERLAYS CONSTANT) + Q_PROPERTY(unsigned int PICK_AVATARS READ PICK_AVATARS CONSTANT) + Q_PROPERTY(unsigned int PICK_HUD READ PICK_HUD CONSTANT) + Q_PROPERTY(unsigned int PICK_COARSE READ PICK_COARSE CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_INVISIBLE READ PICK_INCLUDE_INVISIBLE CONSTANT) + Q_PROPERTY(unsigned int PICK_INCLUDE_NONCOLLIDABLE READ PICK_INCLUDE_NONCOLLIDABLE CONSTANT) + Q_PROPERTY(unsigned int PICK_ALL_INTERSECTIONS READ PICK_ALL_INTERSECTIONS CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_NONE READ INTERSECTED_NONE CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_ENTITY READ INTERSECTED_ENTITY CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_OVERLAY READ INTERSECTED_OVERLAY CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_AVATAR READ INTERSECTED_AVATAR CONSTANT) + Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT) SINGLETON_DEPENDENCY public slots: @@ -30,6 +46,21 @@ public slots: Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, const bool precisionPicking); Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities); Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities); + + static unsigned int PICK_NOTHING() { return PickScriptingInterface::PICK_NOTHING(); } + static unsigned int PICK_ENTITIES() { return PickScriptingInterface::PICK_ENTITIES(); } + static unsigned int PICK_OVERLAYS() { return PickScriptingInterface::PICK_OVERLAYS(); } + static unsigned int PICK_AVATARS() { return PickScriptingInterface::PICK_AVATARS(); } + static unsigned int PICK_HUD() { return PickScriptingInterface::PICK_HUD(); } + static unsigned int PICK_COARSE() { return PickScriptingInterface::PICK_COARSE(); } + static unsigned int PICK_INCLUDE_INVISIBLE() { return PickScriptingInterface::PICK_INCLUDE_INVISIBLE(); } + static unsigned int PICK_INCLUDE_NONCOLLIDABLE() { return PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE(); } + static unsigned int PICK_ALL_INTERSECTIONS() { return PickScriptingInterface::PICK_ALL_INTERSECTIONS(); } + static unsigned int INTERSECTED_NONE() { return PickScriptingInterface::INTERSECTED_NONE(); } + static unsigned int INTERSECTED_ENTITY() { return PickScriptingInterface::INTERSECTED_ENTITY(); } + static unsigned int INTERSECTED_OVERLAY() { return PickScriptingInterface::INTERSECTED_OVERLAY(); } + static unsigned int INTERSECTED_AVATAR() { return PickScriptingInterface::INTERSECTED_AVATAR(); } + static unsigned int INTERSECTED_HUD() { return PickScriptingInterface::INTERSECTED_HUD(); } }; #endif // hifi_RayPickScriptingInterface_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 05dcc1148a..b37a376de3 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -908,9 +908,11 @@ void Overlays::mousePressPointerEvent(const OverlayID& overlayID, const PointerE thisOverlay = std::static_pointer_cast(getOverlay(overlayID)); } if (thisOverlay) { - // Focus keyboard on web overlays - DependencyManager::get()->setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); - setKeyboardFocusOverlay(overlayID); + if (event.shouldFocus()) { + // Focus keyboard on web overlays + DependencyManager::get()->setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); + setKeyboardFocusOverlay(overlayID); + } // Send to web overlay QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event)); diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 1ee725645f..0075762f02 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -119,9 +119,11 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { } // Trigger begin + const std::string SHOULD_FOCUS_BUTTON = "Focus"; for (const std::string& button : newButtons) { hoveredEvent.setType(PointerEvent::Press); hoveredEvent.setButton(PointerEvent::PrimaryButton); + hoveredEvent.setShouldFocus(button == SHOULD_FOCUS_BUTTON); if (hoveredObject.type == ENTITY) { emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent); } else if (hoveredObject.type == OVERLAY) { diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index 4e965cd73c..595daebc33 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -77,8 +77,8 @@ public: QUuid getRayUID() { return _pickUID; } protected: - bool _enabled; const QUuid _pickUID; + bool _enabled; virtual PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const = 0; diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index 63c063cd01..074e5ab79b 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -55,9 +55,11 @@ public: Button getButton() const { return _button; } uint32_t getButtons() const { return _buttons; } Qt::KeyboardModifiers getKeyboardModifiers() const { return _keyboardModifiers; } + bool shouldFocus() const { return _shouldFocus; } void setType(EventType type) { _type = type; } void setButton(Button button) { _button = button; } + void setShouldFocus(bool focus) { _shouldFocus = focus; } private: EventType _type; @@ -70,6 +72,8 @@ private: Button _button { NoButtons }; // button associated with this event, (if type is Press, this will be the button that is pressed) uint32_t _buttons { NoButtons }; // the current state of all the buttons. Qt::KeyboardModifiers _keyboardModifiers; // set of keys held when event was generated + + bool _shouldFocus { true }; }; QDebug& operator<<(QDebug& dbg, const PointerEvent& p); From e5becba4e959dbc789d5b83017ebd1c59cc3e754 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 26 Oct 2017 20:38:07 -0700 Subject: [PATCH 021/292] migrate away from updateXXX standardize on setXXX --- .../src/RenderablePolyVoxEntityItem.cpp | 4 +- .../src/RenderablePolyVoxEntityItem.h | 2 +- libraries/entities/src/EntityItem.cpp | 197 +++++------------- libraries/entities/src/EntityItem.h | 15 +- 4 files changed, 67 insertions(+), 151 deletions(-) diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index b11ab76c2f..e92bc636bd 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -641,10 +641,10 @@ ShapeType RenderablePolyVoxEntityItem::getShapeType() const { return SHAPE_TYPE_COMPOUND; } -void RenderablePolyVoxEntityItem::updateRegistrationPoint(const glm::vec3& value) { +void RenderablePolyVoxEntityItem::setRegistrationPoint(const glm::vec3& value) { if (value != _registrationPoint) { _meshDirty = true; - EntityItem::updateRegistrationPoint(value); + EntityItem::setRegistrationPoint(value); } } diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index fc12a2b5ee..6ac518f79b 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -98,7 +98,7 @@ public: std::shared_ptr getYPNeighbor(); std::shared_ptr getZPNeighbor(); - virtual void updateRegistrationPoint(const glm::vec3& value) override; + virtual void setRegistrationPoint(const glm::vec3& value) override; void setVoxelsFromData(QByteArray uncompressedData, quint16 voxelXSize, quint16 voxelYSize, quint16 voxelZSize); void forEachVoxelValue(const ivec3& voxelSize, std::function thunk); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 008ec9769f..41b5960667 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -737,7 +737,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto customUpdateRotationFromNetwork = [this, shouldUpdate, lastEdited](glm::quat value){ if (shouldUpdate(_lastUpdatedRotationTimestamp, value != _lastUpdatedRotationValue)) { - updateRotation(value); + setRotation(value); _lastUpdatedRotationTimestamp = lastEdited; _lastUpdatedRotationValue = value; } @@ -745,7 +745,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto customUpdateVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){ if (shouldUpdate(_lastUpdatedVelocityTimestamp, value != _lastUpdatedVelocityValue)) { - updateVelocity(value); + setVelocity(value); _lastUpdatedVelocityTimestamp = lastEdited; _lastUpdatedVelocityValue = value; } @@ -753,7 +753,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef auto customUpdateAngularVelocityFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){ if (shouldUpdate(_lastUpdatedAngularVelocityTimestamp, value != _lastUpdatedAngularVelocityValue)) { - updateAngularVelocity(value); + setAngularVelocity(value); _lastUpdatedAngularVelocityTimestamp = lastEdited; _lastUpdatedAngularVelocityValue = value; } @@ -775,13 +775,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); - READ_ENTITY_PROPERTY(PROP_DENSITY, float, updateDensity); - READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, updateGravity); + READ_ENTITY_PROPERTY(PROP_DENSITY, float, setDensity); + READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, setGravity); - READ_ENTITY_PROPERTY(PROP_DAMPING, float, updateDamping); - READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, updateRestitution); - READ_ENTITY_PROPERTY(PROP_FRICTION, float, updateFriction); - READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime); + READ_ENTITY_PROPERTY(PROP_DAMPING, float, setDamping); + READ_ENTITY_PROPERTY(PROP_RESTITUTION, float, setRestitution); + READ_ENTITY_PROPERTY(PROP_FRICTION, float, setFriction); + READ_ENTITY_PROPERTY(PROP_LIFETIME, float, setLifetime); READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript); READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp); @@ -797,13 +797,13 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_SERVER_SCRIPTS, QString, setServerScripts); } - READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, updateRegistrationPoint); + READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint); - READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping); + READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, setAngularDamping); READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible); - READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, updateCollisionless); - READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, updateCollisionMask); - READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, updateDynamic); + READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, setCollisionless); + READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, setCollisionMask); + READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, setDynamic); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, updateLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); @@ -827,7 +827,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef { // parentID and parentJointIndex are also protected by simulation ownership bool oldOverwrite = overwriteLocalData; overwriteLocalData = overwriteLocalData && !weOwnSimulation; - READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, updateParentID); + READ_ENTITY_PROPERTY(PROP_PARENT_ID, QUuid, setParentID); READ_ENTITY_PROPERTY(PROP_PARENT_JOINT_INDEX, quint16, setParentJointIndex); overwriteLocalData = oldOverwrite; } @@ -922,12 +922,6 @@ float EntityItem::computeMass() const { } void EntityItem::setDensity(float density) { - withWriteLock([&] { - _density = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); - }); -} - -void EntityItem::updateDensity(float density) { float clampedDensity = glm::max(glm::min(density, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); withWriteLock([&] { if (_density != clampedDensity) { @@ -1317,27 +1311,27 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { // these affect TerseUpdate properties SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, updateSimulationOwner); SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, updateRotation); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, updateVelocity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, updateAngularVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, setAngularVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration); // these (along with "position" above) affect tree structure SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensions); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, updateRegistrationPoint); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); // these (along with all properties above) affect the simulation - SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, updateDensity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, updateGravity); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, updateDamping); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, updateAngularDamping); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, updateRestitution); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionless, updateCollisionless); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionMask, updateCollisionMask); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dynamic, updateDynamic); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, setDensity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(gravity, setGravity); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(damping, setDamping); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularDamping, setAngularDamping); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(restitution, setRestitution); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, setFriction); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionless, setCollisionless); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionMask, setCollisionMask); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dynamic, setDynamic); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, setCreated); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, updateLocked); // non-simulation properties below @@ -1365,7 +1359,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(href, setHref); SET_ENTITY_PROPERTY_FROM_PROPERTIES(description, setDescription); SET_ENTITY_PROPERTY_FROM_PROPERTIES(actionData, setDynamicData); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, updateParentID); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentID, setParentID); SET_ENTITY_PROPERTY_FROM_PROPERTIES(parentJointIndex, setParentJointIndex); SET_ENTITY_PROPERTY_FROM_PROPERTIES(queryAACube, setQueryAACube); @@ -1702,9 +1696,12 @@ float EntityItem::getVolumeEstimate() const { return dimensions.x * dimensions.y * dimensions.z; } -void EntityItem::updateRegistrationPoint(const glm::vec3& value) { +void EntityItem::setRegistrationPoint(const glm::vec3& value) { if (value != _registrationPoint) { - setRegistrationPoint(value); + withWriteLock([&] { + _registrationPoint = glm::clamp(value, 0.0f, 1.0f); + }); + dimensionsChanged(); // Registration Point affects the bounding box markDirtyFlags(Simulation::DIRTY_SHAPE); } } @@ -1730,14 +1727,14 @@ void EntityItem::updatePosition(const glm::vec3& value) { } } -void EntityItem::updateParentID(const QUuid& value) { +void EntityItem::setParentID(const QUuid& value) { QUuid oldParentID = getParentID(); if (oldParentID != value) { EntityTreePointer tree = getTree(); if (!oldParentID.isNull()) { tree->removeFromChildrenOfAvatars(getThisPointer()); } - setParentID(value); + SpatiallyNestable::setParentID(value); // children are forced to be kinematic // may need to not collide with own avatar markDirtyFlags(Simulation::DIRTY_MOTION_TYPE | Simulation::DIRTY_COLLISION_GROUP); @@ -1758,7 +1755,7 @@ void EntityItem::updateDimensions(const glm::vec3& value) { } } -void EntityItem::updateRotation(const glm::quat& rotation) { +void EntityItem::setRotation(glm::quat rotation) { if (getLocalOrientation() != rotation) { setLocalOrientation(rotation); _dirtyFlags |= Simulation::DIRTY_ROTATION; @@ -1771,31 +1768,7 @@ void EntityItem::updateRotation(const glm::quat& rotation) { } } -void EntityItem::updateMass(float mass) { - // Setting the mass actually changes the _density (at fixed volume), however - // we must protect the density range to help maintain stability of physics simulation - // therefore this method might not accept the mass that is supplied. - - glm::vec3 dimensions = getDimensions(); - float volume = _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z; - - // compute new density - float newDensity = _density; - const float MIN_VOLUME = 1.0e-6f; // 0.001mm^3 - if (volume < 1.0e-6f) { - // avoid divide by zero - newDensity = glm::min(mass / MIN_VOLUME, ENTITY_ITEM_MAX_DENSITY); - } else { - newDensity = glm::max(glm::min(mass / volume, ENTITY_ITEM_MAX_DENSITY), ENTITY_ITEM_MIN_DENSITY); - } - - if (_density != newDensity) { - _density = newDensity; - _dirtyFlags |= Simulation::DIRTY_MASS; - } -} - -void EntityItem::updateVelocity(const glm::vec3& value) { +void EntityItem::setVelocity(const glm::vec3& value) { glm::vec3 velocity = getLocalVelocity(); if (velocity != value) { if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { @@ -1821,7 +1794,7 @@ void EntityItem::updateVelocity(const glm::vec3& value) { } } -void EntityItem::updateDamping(float value) { +void EntityItem::setDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); if (_damping != clampedDamping) { _damping = clampedDamping; @@ -1829,7 +1802,7 @@ void EntityItem::updateDamping(float value) { } } -void EntityItem::updateGravity(const glm::vec3& value) { +void EntityItem::setGravity(const glm::vec3& value) { if (_gravity != value) { if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { _gravity = Vectors::ZERO; @@ -1848,7 +1821,7 @@ void EntityItem::updateGravity(const glm::vec3& value) { } } -void EntityItem::updateAngularVelocity(const glm::vec3& value) { +void EntityItem::setAngularVelocity(const glm::vec3& value) { glm::vec3 angularVelocity = getLocalAngularVelocity(); if (angularVelocity != value) { if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { @@ -1872,7 +1845,7 @@ void EntityItem::updateAngularVelocity(const glm::vec3& value) { } } -void EntityItem::updateAngularDamping(float value) { +void EntityItem::setAngularDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); if (_angularDamping != clampedDamping) { _angularDamping = clampedDamping; @@ -1880,21 +1853,21 @@ void EntityItem::updateAngularDamping(float value) { } } -void EntityItem::updateCollisionless(bool value) { +void EntityItem::setCollisionless(bool value) { if (_collisionless != value) { _collisionless = value; _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; } } -void EntityItem::updateCollisionMask(uint8_t value) { +void EntityItem::setCollisionMask(uint8_t value) { if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) { _collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT); _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; } } -void EntityItem::updateDynamic(bool value) { +void EntityItem::setDynamic(bool value) { if (getDynamic() != value) { // dynamic and STATIC_MESH are incompatible so we check for that case if (value && getShapeType() == SHAPE_TYPE_STATIC_MESH) { @@ -1909,7 +1882,7 @@ void EntityItem::updateDynamic(bool value) { } } -void EntityItem::updateRestitution(float value) { +void EntityItem::setRestitution(float value) { float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_RESTITUTION, value), ENTITY_ITEM_MIN_RESTITUTION); if (_restitution != clampedValue) { _restitution = clampedValue; @@ -1917,7 +1890,7 @@ void EntityItem::updateRestitution(float value) { } } -void EntityItem::updateFriction(float value) { +void EntityItem::setFriction(float value) { float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_FRICTION, value), ENTITY_ITEM_MIN_FRICTION); withWriteLock([&] { if (_friction != clampedValue) { @@ -1927,28 +1900,14 @@ void EntityItem::updateFriction(float value) { }); } -void EntityItem::setRestitution(float value) { - float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_RESTITUTION, value), ENTITY_ITEM_MIN_RESTITUTION); - withWriteLock([&] { - _restitution = clampedValue; - }); -} - -void EntityItem::setFriction(float value) { - float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_FRICTION, value), ENTITY_ITEM_MIN_FRICTION); - withWriteLock([&] { - _friction = clampedValue; - }); -} - -void EntityItem::updateLifetime(float value) { +void EntityItem::setLifetime(float value) { if (_lifetime != value) { _lifetime = value; _dirtyFlags |= Simulation::DIRTY_LIFETIME; } } -void EntityItem::updateCreated(uint64_t value) { +void EntityItem::setCreated(uint64_t value) { if (_created != value) { _created = value; _dirtyFlags |= Simulation::DIRTY_LIFETIME; @@ -2618,12 +2577,6 @@ glm::vec3 EntityItem::getGravity() const { return result; } -void EntityItem::setGravity(const glm::vec3& value) { - withWriteLock([&] { - _gravity = value; - }); -} - glm::vec3 EntityItem::getAcceleration() const { glm::vec3 result; withReadLock([&] { @@ -2645,11 +2598,6 @@ float EntityItem::getDamping() const { }); return result; } -void EntityItem::setDamping(float value) { - withWriteLock([&] { - _damping = value; - }); -} float EntityItem::getRestitution() const { float result; @@ -2676,12 +2624,6 @@ float EntityItem::getLifetime() const { return result; } -void EntityItem::setLifetime(float value) { - withWriteLock([&] { - _lifetime = value; - }); -} - quint64 EntityItem::getCreated() const { quint64 result; withReadLock([&] { @@ -2690,12 +2632,6 @@ quint64 EntityItem::getCreated() const { return result; } -void EntityItem::setCreated(quint64 value) { - withWriteLock([&] { - _created = value; - }); -} - QString EntityItem::getScript() const { QString result; withReadLock([&] { @@ -2755,13 +2691,6 @@ glm::vec3 EntityItem::getRegistrationPoint() const { return result; } -void EntityItem::setRegistrationPoint(const glm::vec3& value) { - withWriteLock([&] { - _registrationPoint = glm::clamp(value, 0.0f, 1.0f); - }); - dimensionsChanged(); // Registration Point affects the bounding box -} - float EntityItem::getAngularDamping() const { float result; withReadLock([&] { @@ -2770,12 +2699,6 @@ float EntityItem::getAngularDamping() const { return result; } -void EntityItem::setAngularDamping(float value) { - withWriteLock([&] { - _angularDamping = value; - }); -} - QString EntityItem::getName() const { QString result; withReadLock([&] { @@ -2825,12 +2748,6 @@ bool EntityItem::getCollisionless() const { return result; } -void EntityItem::setCollisionless(bool value) { - withWriteLock([&] { - _collisionless = value; - }); -} - uint8_t EntityItem::getCollisionMask() const { uint8_t result; withReadLock([&] { @@ -2839,12 +2756,6 @@ uint8_t EntityItem::getCollisionMask() const { return result; } -void EntityItem::setCollisionMask(uint8_t value) { - withWriteLock([&] { - _collisionMask = value; - }); -} - bool EntityItem::getDynamic() const { if (SHAPE_TYPE_STATIC_MESH == getShapeType()) { return false; @@ -2856,12 +2767,6 @@ bool EntityItem::getDynamic() const { return result; } -void EntityItem::setDynamic(bool value) { - withWriteLock([&] { - _dynamic = value; - }); -} - bool EntityItem::getLocked() const { bool result; withReadLock([&] { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index ce4bf13896..a05b0d6137 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -262,6 +262,8 @@ public: bool hasAngularVelocity() const { return getAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } bool hasLocalAngularVelocity() const { return getLocalAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } + virtual void setAngularVelocity(const glm::vec3& angularVelocity); + float getAngularDamping() const; void setAngularDamping(float value); @@ -354,10 +356,17 @@ public: virtual void setCollisionShape(const btCollisionShape* shape) {} // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags - virtual void updateRegistrationPoint(const glm::vec3& value); + //virtual void setRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); - void updateParentID(const QUuid& value); + void updateDimensions(const glm::vec3& value); + + virtual void setParentID(const QUuid& parentID); + virtual void setRotation(glm::quat orientation); + virtual void setVelocity(const glm::vec3& velocity); + + /* + void updateParentID(const QUuid& value); void updateRotation(const glm::quat& rotation); void updateDensity(float value); void updateMass(float value); @@ -373,6 +382,8 @@ public: void updateDynamic(bool value); void updateLifetime(float value); void updateCreated(uint64_t value); + */ + virtual void setShapeType(ShapeType type) { /* do nothing */ } uint32_t getDirtyFlags() const; From 431ee585773fc3988e7b502ed8c99d3f33bd8a7d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 26 Oct 2017 21:30:59 -0700 Subject: [PATCH 022/292] more cleanup --- libraries/entities/src/EntityItem.cpp | 59 +++++++-------------------- libraries/entities/src/EntityItem.h | 32 --------------- 2 files changed, 14 insertions(+), 77 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 41b5960667..e6549160b8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -774,7 +774,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_ACCELERATION, glm::vec3, customSetAcceleration); } - READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, updateDimensions); + READ_ENTITY_PROPERTY(PROP_DIMENSIONS, glm::vec3, setDimensions); READ_ENTITY_PROPERTY(PROP_DENSITY, float, setDensity); READ_ENTITY_PROPERTY(PROP_GRAVITY, glm::vec3, setGravity); @@ -804,7 +804,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_COLLISIONLESS, bool, setCollisionless); READ_ENTITY_PROPERTY(PROP_COLLISION_MASK, uint8_t, setCollisionMask); READ_ENTITY_PROPERTY(PROP_DYNAMIC, bool, setDynamic); - READ_ENTITY_PROPERTY(PROP_LOCKED, bool, updateLocked); + READ_ENTITY_PROPERTY(PROP_LOCKED, bool, setLocked); READ_ENTITY_PROPERTY(PROP_USER_DATA, QString, setUserData); READ_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, QString, setMarketplaceID); @@ -1309,7 +1309,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; // these affect TerseUpdate properties - SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, updateSimulationOwner); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocity); @@ -1317,7 +1317,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(acceleration, setAcceleration); // these (along with "position" above) affect tree structure - SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensions); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, setDimensions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint); // these (along with all properties above) affect the simulation @@ -1332,7 +1332,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(dynamic, setDynamic); SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, setCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, setLifetime); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, updateLocked); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); // non-simulation properties below SET_ENTITY_PROPERTY_FROM_PROPERTIES(script, setScript); @@ -1424,17 +1424,6 @@ const Transform EntityItem::getTransformToCenter(bool& success) const { return result; } -void EntityItem::setDimensions(const glm::vec3& value) { - if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) { - return; - } - if (_dimensions != value) { - _dimensions = value; - locationChanged(); - dimensionsChanged(); - } -} - /// The maximum bounding cube for the entity, independent of it's rotation. /// This accounts for the registration point (upon which rotation occurs around). /// @@ -1536,25 +1525,6 @@ bool EntityItem::shouldPuffQueryAACube() const { return hasActions() || isChildOfMyAvatar() || isMovingRelativeToParent(); } -// NOTE: This should only be used in cases of old bitstreams which only contain radius data -// 0,0,0 --> maxDimension,maxDimension,maxDimension -// ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension) -// ... radius = cornerToCornerLength / 2.0f -// ... radius * 2.0f = cornerToCornerLength -// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2) -// ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2) -// ... radius * 2.0f = sqrt(3 x maxDimension ^ 2) -// ... (radius * 2.0f) ^2 = 3 x maxDimension ^ 2 -// ... ((radius * 2.0f) ^2) / 3 = maxDimension ^ 2 -// ... sqrt(((radius * 2.0f) ^2) / 3) = maxDimension -// ... sqrt((diameter ^2) / 3) = maxDimension -// -void EntityItem::setRadius(float value) { - float diameter = value * 2.0f; - float maxDimension = sqrt((diameter * diameter) / 3.0f); - setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); -} - // TODO: get rid of all users of this function... // ... radius = cornerToCornerLength / 2.0f // ... cornerToCornerLength = sqrt(3 x maxDimension ^ 2) @@ -1746,11 +1716,14 @@ void EntityItem::setParentID(const QUuid& value) { } } -void EntityItem::updateDimensions(const glm::vec3& value) { - if (getDimensions() != value) { - setDimensions(value); +void EntityItem::setDimensions(const glm::vec3& value) { + const float MIN_ENTITY_DIMENSION = 0.00001f; + glm::vec3 newDimensions = glm::max(value, glm::vec3(MIN_ENTITY_DIMENSION)); + if (getDimensions() != newDimensions) { + _dimensions = newDimensions; markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); _queryAACubeSet = false; + locationChanged(); dimensionsChanged(); } } @@ -1983,6 +1956,7 @@ void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) { _simulationOwner.set(id, priority); } +/* void EntityItem::setSimulationOwner(const SimulationOwner& owner) { if (wantTerseEditLogging() && _simulationOwner != owner) { qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << owner; @@ -1990,8 +1964,9 @@ void EntityItem::setSimulationOwner(const SimulationOwner& owner) { _simulationOwner.set(owner); } +*/ -void EntityItem::updateSimulationOwner(const SimulationOwner& owner) { +void EntityItem::setSimulationOwner(const SimulationOwner& owner) { // NOTE: this method only used by EntityServer. The Interface uses special code in readEntityDataFromBuffer(). if (wantTerseEditLogging() && _simulationOwner != owner) { qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << owner; @@ -2776,12 +2751,6 @@ bool EntityItem::getLocked() const { } void EntityItem::setLocked(bool value) { - withWriteLock([&] { - _locked = value; - }); -} - -void EntityItem::updateLocked(bool value) { bool changed { false }; withWriteLock([&] { if (_locked != value) { diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a05b0d6137..3b31acafad 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -293,7 +293,6 @@ public: bool getLocked() const; void setLocked(bool value); - void updateLocked(bool value); QString getUserData() const; virtual void setUserData(const QString& value); @@ -306,7 +305,6 @@ public: quint8 getSimulationPriority() const { return _simulationOwner.getPriority(); } QUuid getSimulatorID() const { return _simulationOwner.getID(); } - void updateSimulationOwner(const SimulationOwner& owner); void clearSimulationOwnership(); void setPendingOwnershipPriority(quint8 priority, const quint64& timestamp); uint8_t getPendingOwnershipPriority() const { return _simulationOwner.getPendingPriority(); } @@ -356,34 +354,10 @@ public: virtual void setCollisionShape(const btCollisionShape* shape) {} // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags - //virtual void setRegistrationPoint(const glm::vec3& value); void updatePosition(const glm::vec3& value); - - void updateDimensions(const glm::vec3& value); - virtual void setParentID(const QUuid& parentID); virtual void setRotation(glm::quat orientation); virtual void setVelocity(const glm::vec3& velocity); - - /* - void updateParentID(const QUuid& value); - void updateRotation(const glm::quat& rotation); - void updateDensity(float value); - void updateMass(float value); - void updateVelocity(const glm::vec3& value); - void updateDamping(float value); - void updateRestitution(float value); - void updateFriction(float value); - void updateGravity(const glm::vec3& value); - void updateAngularVelocity(const glm::vec3& value); - void updateAngularDamping(float value); - void updateCollisionless(bool value); - void updateCollisionMask(uint8_t value); - void updateDynamic(bool value); - void updateLifetime(float value); - void updateCreated(uint64_t value); - */ - virtual void setShapeType(ShapeType type) { /* do nothing */ } uint32_t getDirtyFlags() const; @@ -590,12 +564,6 @@ protected: // damping = 1 - exp(-1 / timescale) // - // NOTE: Radius support is obsolete, but these private helper functions are available for this class to - // parse old data streams - - /// set radius in domain scale units (0.0 - 1.0) this will also reset dimensions to be equal for each axis - void setRadius(float value); - // DirtyFlags are set whenever a property changes that the EntitySimulation needs to know about. uint32_t _dirtyFlags { 0 }; // things that have changed from EXTERNAL changes (via script or packet) but NOT from simulation From f32282afdd308859544924f0c8d9a05b61456af1 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 27 Oct 2017 11:03:02 -0700 Subject: [PATCH 023/292] Clean update bug 8027 --- .../resources/html/createGlobalEventBridge.js | 48 ++++++++++++ interface/resources/qml/Browser.qml | 12 ++- libraries/ui/CMakeLists.txt | 4 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 76 +++++++++++++++++++ libraries/ui/src/ui/OffscreenQmlSurface.h | 9 +++ plugins/hifiSixense/CMakeLists.txt | 3 + tests/controllers/CMakeLists.txt | 3 + tests/render-perf/CMakeLists.txt | 4 + 8 files changed, 153 insertions(+), 6 deletions(-) diff --git a/interface/resources/html/createGlobalEventBridge.js b/interface/resources/html/createGlobalEventBridge.js index 4a0de464c3..bccbdfaf7c 100644 --- a/interface/resources/html/createGlobalEventBridge.js +++ b/interface/resources/html/createGlobalEventBridge.js @@ -33,6 +33,54 @@ var EventBridge; // replace the TempEventBridge with the real one. var tempEventBridge = EventBridge; EventBridge = channel.objects.eventBridge; + EventBridge.audioOutputDeviceChanged.connect(function(deviceName) { + navigator.mediaDevices.getUserMedia({ audio: true, video: true }).then(function(mediaStream) { + navigator.mediaDevices.enumerateDevices().then(function(devices) { + devices.forEach(function(device) { + if (device.kind == "audiooutput") { + if (device.label == deviceName){ + console.log("Changing HTML audio output to device " + device.label); + var deviceId = device.deviceId; + var videos = document.getElementsByTagName("video"); + for (var i = 0; i < videos.length; i++){ + videos[i].setSinkId(deviceId); + } + var audios = document.getElementsByTagName("audio"); + for (var i = 0; i < audios.length; i++){ + audios[i].setSinkId(deviceId); + } + } + } + }); + + }).catch(function(err) { + console.log("Error getting media devices"+ err.name + ": " + err.message); + }); + }).catch(function(err) { + console.log("Error getting user media"+ err.name + ": " + err.message); + }); + }); + + // To be able to update the state of the output device selection for every element added to the DOM + // we need to listen to events that might precede the addition of this elements. + // A more robust hack will be to add a setInterval that look for DOM changes every 100-300 ms (low performance?) + + window.onload = function(){ + setTimeout(function() { + EventBridge.forceHtmlAudioOutputDeviceUpdate(); + }, 1200); + }; + document.onclick = function(){ + setTimeout(function() { + EventBridge.forceHtmlAudioOutputDeviceUpdate(); + }, 1200); + }; + document.onchange = function(){ + setTimeout(function() { + EventBridge.forceHtmlAudioOutputDeviceUpdate(); + }, 1200); + }; + tempEventBridge._callbacks.forEach(function (callback) { EventBridge.scriptEventReceived.connect(callback); }); diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 55927fda24..8a6674bc14 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -212,7 +212,7 @@ ScrollingWindow { WebEngineScript { id: createGlobalEventBridge sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation + injectionPoint: WebEngineScript.Deferred worldId: WebEngineScript.MainWorld } @@ -233,9 +233,13 @@ ScrollingWindow { anchors.right: parent.right onFeaturePermissionRequested: { - permissionsBar.securityOrigin = securityOrigin; - permissionsBar.feature = feature; - root.showPermissionsBar(); + if (feature == 2) { // QWebEnginePage::MediaAudioCapture + grantFeaturePermission(securityOrigin, feature, true); + } else { + permissionsBar.securityOrigin = securityOrigin; + permissionsBar.feature = feature; + root.showPermissionsBar(); + } } onLoadingChanged: { diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index f28157ff97..ae682a11ea 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,6 +1,6 @@ set(TARGET_NAME ui) -setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns) -link_hifi_libraries(shared networking gl audio) +setup_hifi_library(OpenGL Multimedia Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns) +link_hifi_libraries(shared networking gl audio audio-client plugins) # Required for some low level GL interaction in the OffscreenQMLSurface target_opengl() diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index ecd07a5874..6632b669e3 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -24,7 +24,11 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -595,6 +599,14 @@ void OffscreenQmlSurface::create() { // Find a way to flag older scripts using this mechanism and wanr that this is deprecated _qmlContext->setContextProperty("eventBridgeWrapper", new EventBridgeWrapper(this, _qmlContext)); _renderControl->initialize(_canvas->getContext()); + + // Connect with the audio client and listen for audio device changes + auto audioIO = DependencyManager::get(); + connect(audioIO.data(), &AudioClient::deviceChanged, this, [&](QAudio::Mode mode, const QAudioDeviceInfo& device) { + if (mode == QAudio::Mode::AudioOutput) { + QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::DirectConnection, Q_ARG(QString, device.deviceName())); + } + }); // When Quick says there is a need to render, we will not render immediately. Instead, // a timer with a small interval is used to get better performance. @@ -605,6 +617,68 @@ void OffscreenQmlSurface::create() { _updateTimer.start(); } +void OffscreenQmlSurface::changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate) { + if (_rootItem != nullptr && !isHtmlUpdate) { + QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::DirectConnection); + } + emit audioOutputDeviceChanged(deviceName); +} + +void OffscreenQmlSurface::forceHtmlAudioOutputDeviceUpdate() { + auto audioIO = DependencyManager::get(); + QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); + QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::DirectConnection, + Q_ARG(QString, deviceName), Q_ARG(bool, true)); +} + +void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() { + if (QThread::currentThread() != qApp->thread()) { + QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); + } + else { + int waitForAudioQmlMs = 500; + QTimer::singleShot(waitForAudioQmlMs, this, SLOT(updateQmlAudio())); + } +} + +void OffscreenQmlSurface::updateQmlAudio() { + auto audioIO = DependencyManager::get(); + QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); + for (auto player : _rootItem->findChildren()) { + auto mediaState = player->state(); + QMediaService *svc = player->service(); + if (nullptr == svc) { + return; + } + QAudioOutputSelectorControl *out = qobject_cast + (svc->requestControl(QAudioOutputSelectorControl_iid)); + if (nullptr == out) { + return; + } + QString deviceOuput; + auto outputs = out->availableOutputs(); + for (int i = 0; i < outputs.size(); i++) { + QString output = outputs[i]; + QString description = out->outputDescription(output); + if (description == deviceName) { + deviceOuput = output; + break; + } + } + out->setActiveOutput(deviceOuput); + svc->releaseControl(out); + // if multimedia was paused, it will start playing automatically after changing audio device + // this will reset it back to a paused state + if (mediaState == QMediaPlayer::State::PausedState) { + player->pause(); + } + else if (mediaState == QMediaPlayer::State::StoppedState) { + player->stop(); + } + } + qDebug() << "QML Audio changed to " << deviceName; +} + static uvec2 clampSize(const uvec2& size, uint32_t maxDimension) { return glm::clamp(size, glm::uvec2(1), glm::uvec2(maxDimension)); } @@ -798,6 +872,7 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext if (newItem) { newItem->setParentItem(_rootItem); } + QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); return; } @@ -817,6 +892,7 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext for (const auto& callback : callbacks) { callback(qmlContext, newObject); } + QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); } void OffscreenQmlSurface::updateQuick() { diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 12ee9e59a1..0d053b373d 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -103,6 +103,15 @@ public slots: void onAboutToQuit(); void focusDestroyed(QObject *obj); + // audio output device +public slots: + void changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate = false); + void forceHtmlAudioOutputDeviceUpdate(); + void forceQmlAudioOutputDeviceUpdate(); + void updateQmlAudio(); +signals: + void audioOutputDeviceChanged(const QString& deviceName); + // event bridge public slots: void emitScriptEvent(const QVariant& scriptMessage); diff --git a/plugins/hifiSixense/CMakeLists.txt b/plugins/hifiSixense/CMakeLists.txt index 55880584a8..a503fc5710 100644 --- a/plugins/hifiSixense/CMakeLists.txt +++ b/plugins/hifiSixense/CMakeLists.txt @@ -15,4 +15,7 @@ if (NOT ANDROID) setup_hifi_plugin(Script Qml Widgets) link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins) target_sixense() + if (WIN32) + target_link_libraries(${TARGET_NAME} Winmm.lib) + endif() endif () diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt index 3221070837..623ee7d20e 100644 --- a/tests/controllers/CMakeLists.txt +++ b/tests/controllers/CMakeLists.txt @@ -17,5 +17,8 @@ if (WIN32) target_include_directories(${TARGET_NAME} PRIVATE ${OPENVR_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES}) endif() +if (WIN32) + target_link_libraries(${TARGET_NAME} Winmm.lib) +endif() package_libraries_for_deployment() diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index 5b83ff313b..b7f13c88c5 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -14,6 +14,10 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") # link in the shared libraries link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl render model-networking networking render-utils entities entities-renderer animation audio avatars script-engine physics procedural midi ui) +if (WIN32) + target_link_libraries(${TARGET_NAME} Winmm.lib) +endif() + package_libraries_for_deployment() From 70b37f2e8a4dede381fdb64696be6c29f526862c Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 27 Oct 2017 11:32:44 -0700 Subject: [PATCH 024/292] Cleaning some old tabs --- interface/resources/qml/Browser.qml | 14 +++++++------- plugins/hifiSixense/CMakeLists.txt | 6 +++--- tests/controllers/CMakeLists.txt | 2 +- tests/render-perf/CMakeLists.txt | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 8a6674bc14..1dfc6875bb 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -233,13 +233,13 @@ ScrollingWindow { anchors.right: parent.right onFeaturePermissionRequested: { - if (feature == 2) { // QWebEnginePage::MediaAudioCapture - grantFeaturePermission(securityOrigin, feature, true); - } else { - permissionsBar.securityOrigin = securityOrigin; - permissionsBar.feature = feature; - root.showPermissionsBar(); - } + if (feature == 2) { // QWebEnginePage::MediaAudioCapture + grantFeaturePermission(securityOrigin, feature, true); + } else { + permissionsBar.securityOrigin = securityOrigin; + permissionsBar.feature = feature; + root.showPermissionsBar(); + } } onLoadingChanged: { diff --git a/plugins/hifiSixense/CMakeLists.txt b/plugins/hifiSixense/CMakeLists.txt index a503fc5710..6e642fce29 100644 --- a/plugins/hifiSixense/CMakeLists.txt +++ b/plugins/hifiSixense/CMakeLists.txt @@ -15,7 +15,7 @@ if (NOT ANDROID) setup_hifi_plugin(Script Qml Widgets) link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins) target_sixense() - if (WIN32) - target_link_libraries(${TARGET_NAME} Winmm.lib) - endif() + if (WIN32) + target_link_libraries(${TARGET_NAME} Winmm.lib) + endif() endif () diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt index 623ee7d20e..062d69ca03 100644 --- a/tests/controllers/CMakeLists.txt +++ b/tests/controllers/CMakeLists.txt @@ -18,7 +18,7 @@ if (WIN32) target_link_libraries(${TARGET_NAME} ${OPENVR_LIBRARIES}) endif() if (WIN32) - target_link_libraries(${TARGET_NAME} Winmm.lib) + target_link_libraries(${TARGET_NAME} Winmm.lib) endif() package_libraries_for_deployment() diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index b7f13c88c5..59e043cd64 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -15,7 +15,7 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl render model-networking networking render-utils entities entities-renderer animation audio avatars script-engine physics procedural midi ui) if (WIN32) - target_link_libraries(${TARGET_NAME} Winmm.lib) + target_link_libraries(${TARGET_NAME} Winmm.lib) endif() package_libraries_for_deployment() From a466cf71242795deb2fb18d653c5e3e36d486034 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 27 Oct 2017 11:51:19 -0700 Subject: [PATCH 025/292] make wasapi compile first --- tests/recording/CMakeLists.txt | 4 ++++ tests/render-perf/CMakeLists.txt | 1 + 2 files changed, 5 insertions(+) diff --git a/tests/recording/CMakeLists.txt b/tests/recording/CMakeLists.txt index b5b1e6a54e..b1977c85b1 100644 --- a/tests/recording/CMakeLists.txt +++ b/tests/recording/CMakeLists.txt @@ -4,6 +4,10 @@ setup_hifi_project(Test) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") setup_memory_debugger() link_hifi_libraries(shared recording) +if (WIN32) + target_link_libraries(${TARGET_NAME} Winmm.lib) + add_dependency_external_projects(wasapi) +endif() package_libraries_for_deployment() # FIXME convert to unit tests diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index 59e043cd64..09b2dc6a50 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -16,6 +16,7 @@ link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl r if (WIN32) target_link_libraries(${TARGET_NAME} Winmm.lib) + add_dependency_external_projects(wasapi) endif() package_libraries_for_deployment() From 76223aa06f56d4bf923b7c52c75e8be5cb453424 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 27 Oct 2017 13:07:16 -0700 Subject: [PATCH 026/292] Force wasapi to compile with domain-server (TEST) --- domain-server/CMakeLists.txt | 1 + tests/recording/CMakeLists.txt | 1 - tests/render-perf/CMakeLists.txt | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index c1e275e4d3..4004bee598 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -44,6 +44,7 @@ if (UNIX) endif () if (WIN32) + add_dependency_external_projects(wasapi) package_libraries_for_deployment() endif () diff --git a/tests/recording/CMakeLists.txt b/tests/recording/CMakeLists.txt index b1977c85b1..7ed4f5b1b0 100644 --- a/tests/recording/CMakeLists.txt +++ b/tests/recording/CMakeLists.txt @@ -6,7 +6,6 @@ setup_memory_debugger() link_hifi_libraries(shared recording) if (WIN32) target_link_libraries(${TARGET_NAME} Winmm.lib) - add_dependency_external_projects(wasapi) endif() package_libraries_for_deployment() diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index 09b2dc6a50..59e043cd64 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -16,7 +16,6 @@ link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl r if (WIN32) target_link_libraries(${TARGET_NAME} Winmm.lib) - add_dependency_external_projects(wasapi) endif() package_libraries_for_deployment() From bda63e38a996c21f20f9ccb7a14c87cd7a1b4884 Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Fri, 27 Oct 2017 13:38:13 -0700 Subject: [PATCH 027/292] Updating all wasapi dependencies --- domain-server/CMakeLists.txt | 1 - tests/controllers/CMakeLists.txt | 1 + tests/entities/CMakeLists.txt | 4 ++++ tests/gpu-test/CMakeLists.txt | 5 +++++ tests/qt59/CMakeLists.txt | 5 +++++ tests/recording/CMakeLists.txt | 3 ++- tests/render-perf/CMakeLists.txt | 1 + tests/render-texture-load/CMakeLists.txt | 3 ++- tests/render-utils/CMakeLists.txt | 4 ++++ tests/shaders/CMakeLists.txt | 4 ++++ 10 files changed, 28 insertions(+), 3 deletions(-) diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 4004bee598..c1e275e4d3 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -44,7 +44,6 @@ if (UNIX) endif () if (WIN32) - add_dependency_external_projects(wasapi) package_libraries_for_deployment() endif () diff --git a/tests/controllers/CMakeLists.txt b/tests/controllers/CMakeLists.txt index 062d69ca03..c3d25cfe2e 100644 --- a/tests/controllers/CMakeLists.txt +++ b/tests/controllers/CMakeLists.txt @@ -19,6 +19,7 @@ if (WIN32) endif() if (WIN32) target_link_libraries(${TARGET_NAME} Winmm.lib) + add_dependency_external_projects(wasapi) endif() package_libraries_for_deployment() diff --git a/tests/entities/CMakeLists.txt b/tests/entities/CMakeLists.txt index 080ae7cdd9..0c33eb8555 100644 --- a/tests/entities/CMakeLists.txt +++ b/tests/entities/CMakeLists.txt @@ -9,4 +9,8 @@ set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") # link in the shared libraries link_hifi_libraries(entities avatars shared octree gpu model fbx networking animation audio gl) +if (WIN32) + add_dependency_external_projects(wasapi) +endif () + package_libraries_for_deployment() diff --git a/tests/gpu-test/CMakeLists.txt b/tests/gpu-test/CMakeLists.txt index d73d7a111d..8e49d523b8 100644 --- a/tests/gpu-test/CMakeLists.txt +++ b/tests/gpu-test/CMakeLists.txt @@ -5,6 +5,11 @@ setup_hifi_project(Quick Gui OpenGL Script Widgets) setup_memory_debugger() set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") link_hifi_libraries(networking gl gpu gpu-gl procedural shared fbx model model-networking animation script-engine render render-utils octree image ktx) + +if (WIN32) + add_dependency_external_projects(wasapi) +endif () + package_libraries_for_deployment() target_nsight() diff --git a/tests/qt59/CMakeLists.txt b/tests/qt59/CMakeLists.txt index e0e8138a1e..e3450ae069 100644 --- a/tests/qt59/CMakeLists.txt +++ b/tests/qt59/CMakeLists.txt @@ -11,7 +11,12 @@ setup_memory_debugger() setup_hifi_project(Gui) set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/") + # link in the shared libraries link_hifi_libraries(shared networking) +if (WIN32) + add_dependency_external_projects(wasapi) +endif() + package_libraries_for_deployment() diff --git a/tests/recording/CMakeLists.txt b/tests/recording/CMakeLists.txt index 7ed4f5b1b0..dbb942a27a 100644 --- a/tests/recording/CMakeLists.txt +++ b/tests/recording/CMakeLists.txt @@ -6,6 +6,7 @@ setup_memory_debugger() link_hifi_libraries(shared recording) if (WIN32) target_link_libraries(${TARGET_NAME} Winmm.lib) + add_dependency_external_projects(wasapi) endif() package_libraries_for_deployment() @@ -17,4 +18,4 @@ package_libraries_for_deployment() # # package_libraries_for_deployment() #endmacro () -#setup_hifi_testcase() +#setup_hifi_testcase() \ No newline at end of file diff --git a/tests/render-perf/CMakeLists.txt b/tests/render-perf/CMakeLists.txt index 59e043cd64..09b2dc6a50 100644 --- a/tests/render-perf/CMakeLists.txt +++ b/tests/render-perf/CMakeLists.txt @@ -16,6 +16,7 @@ link_hifi_libraries(shared networking model fbx ktx image octree gl gpu gpu-gl r if (WIN32) target_link_libraries(${TARGET_NAME} Winmm.lib) + add_dependency_external_projects(wasapi) endif() package_libraries_for_deployment() diff --git a/tests/render-texture-load/CMakeLists.txt b/tests/render-texture-load/CMakeLists.txt index 30030914ab..432a1f00d6 100644 --- a/tests/render-texture-load/CMakeLists.txt +++ b/tests/render-texture-load/CMakeLists.txt @@ -26,7 +26,8 @@ target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${QUAZIP_INCLUDE_DIRS}) target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES}) if (WIN32) -add_paths_to_fixup_libs(${QUAZIP_DLL_PATH}) + add_paths_to_fixup_libs(${QUAZIP_DLL_PATH}) + add_dependency_external_projects(wasapi) endif () diff --git a/tests/render-utils/CMakeLists.txt b/tests/render-utils/CMakeLists.txt index 4944ad2cbc..4e67aef3be 100644 --- a/tests/render-utils/CMakeLists.txt +++ b/tests/render-utils/CMakeLists.txt @@ -11,4 +11,8 @@ setup_memory_debugger() link_hifi_libraries(render-utils gl gpu gpu-gl shared) target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) +if (WIN32) + add_dependency_external_projects(wasapi) +endif () + package_libraries_for_deployment() diff --git a/tests/shaders/CMakeLists.txt b/tests/shaders/CMakeLists.txt index bab1e0dcdc..ba4ca88127 100644 --- a/tests/shaders/CMakeLists.txt +++ b/tests/shaders/CMakeLists.txt @@ -17,4 +17,8 @@ include_directories("${PROJECT_BINARY_DIR}/../../libraries/render-utils/") include_directories("${PROJECT_BINARY_DIR}/../../libraries/entities-renderer/") include_directories("${PROJECT_BINARY_DIR}/../../libraries/model/") +if (WIN32) + add_dependency_external_projects(wasapi) +endif () + package_libraries_for_deployment() From 1000318dff63622d5074dc2982b632a586edfbc4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 27 Oct 2017 14:26:02 -0700 Subject: [PATCH 028/292] tweak min dimension to match current behavior --- libraries/entities/src/EntityItem.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e6549160b8..71e6990aaf 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1717,8 +1717,7 @@ void EntityItem::setParentID(const QUuid& value) { } void EntityItem::setDimensions(const glm::vec3& value) { - const float MIN_ENTITY_DIMENSION = 0.00001f; - glm::vec3 newDimensions = glm::max(value, glm::vec3(MIN_ENTITY_DIMENSION)); + glm::vec3 newDimensions = glm::max(value, glm::vec3(0.0f)); // can never have negative dimensions if (getDimensions() != newDimensions) { _dimensions = newDimensions; markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); From a7a0f03ede8c3afbee422ec8bfbd9e448521a0cd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 27 Oct 2017 18:39:17 -0700 Subject: [PATCH 029/292] rename SpatiallyNestable::getPosition() to SpatiallyNestable::getWorldPosition() --- assignment-client/src/Agent.cpp | 12 ++-- .../src/avatars/AvatarMixerClientData.h | 2 +- .../src/avatars/AvatarMixerSlave.cpp | 2 +- .../src/avatars/ScriptableAvatar.cpp | 2 +- interface/src/Application.cpp | 38 ++++++------- interface/src/avatar/AvatarActionHold.cpp | 2 +- interface/src/avatar/AvatarManager.cpp | 2 +- interface/src/avatar/AvatarManager.h | 2 +- interface/src/avatar/AvatarMotionState.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 56 +++++++++---------- interface/src/avatar/MyAvatar.h | 2 +- .../src/avatar/MyCharacterController.cpp | 2 +- interface/src/raypick/JointRayPick.cpp | 2 +- interface/src/ui/Stats.cpp | 2 +- interface/src/ui/overlays/Base3DOverlay.cpp | 4 +- interface/src/ui/overlays/Base3DOverlay.h | 2 +- interface/src/ui/overlays/Circle3DOverlay.cpp | 4 +- .../ui/overlays/ContextOverlayInterface.cpp | 2 +- interface/src/ui/overlays/Cube3DOverlay.cpp | 2 +- interface/src/ui/overlays/Grid3DOverlay.cpp | 2 +- interface/src/ui/overlays/Line3DOverlay.cpp | 4 +- interface/src/ui/overlays/ModelOverlay.cpp | 6 +- interface/src/ui/overlays/Overlays.cpp | 2 +- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- interface/src/ui/overlays/Planar3DOverlay.cpp | 2 +- .../src/ui/overlays/Rectangle3DOverlay.cpp | 2 +- interface/src/ui/overlays/Shape3DOverlay.cpp | 2 +- interface/src/ui/overlays/Volume3DOverlay.cpp | 2 +- interface/src/ui/overlays/Web3DOverlay.cpp | 6 +- .../src/avatars-renderer/Avatar.cpp | 42 +++++++------- libraries/avatars/src/AvatarData.cpp | 14 ++--- libraries/avatars/src/AvatarData.h | 2 +- libraries/avatars/src/AvatarHashMap.cpp | 4 +- libraries/avatars/src/HeadData.cpp | 4 +- libraries/avatars/src/ScriptAvatarData.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 2 +- .../src/RenderableLightEntityItem.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderablePolyLineEntityItem.cpp | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 6 +- .../src/RenderableShapeEntityItem.cpp | 2 +- .../src/RenderableWebEntityItem.cpp | 6 +- .../src/RenderableZoneEntityItem.cpp | 4 +- libraries/entities/src/EntityItem.cpp | 12 ++-- .../entities/src/EntityScriptingInterface.cpp | 4 +- libraries/entities/src/EntityTree.cpp | 4 +- libraries/entities/src/EntityTreeElement.cpp | 8 +-- libraries/entities/src/LineEntityItem.cpp | 2 +- libraries/entities/src/ModelEntityItem.cpp | 2 +- .../entities/src/ParticleEffectEntityItem.cpp | 2 +- libraries/entities/src/PolyLineEntityItem.cpp | 2 +- libraries/entities/src/PolyVoxEntityItem.cpp | 6 +- libraries/entities/src/ShapeEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/entities/src/ZoneEntityItem.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 4 +- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectActionTractor.cpp | 2 +- .../physics/src/PhysicalEntitySimulation.cpp | 2 +- libraries/shared/src/SpatiallyNestable.cpp | 24 ++++---- libraries/shared/src/SpatiallyNestable.h | 10 ++-- 62 files changed, 180 insertions(+), 180 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 4efc3343d1..f166a780ff 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -441,7 +441,7 @@ void Agent::executeScript() { Transform audioTransform; auto headOrientation = scriptedAvatar->getHeadOrientation(); - audioTransform.setTranslation(scriptedAvatar->getPosition()); + audioTransform.setTranslation(scriptedAvatar->getWorldPosition()); audioTransform.setRotation(headOrientation); QByteArray encodedBuffer; @@ -452,7 +452,7 @@ void Agent::executeScript() { } AbstractAudioInterface::emitAudioPacket(encodedBuffer.data(), encodedBuffer.size(), audioSequenceNumber, - audioTransform, scriptedAvatar->getPosition(), glm::vec3(0), + audioTransform, scriptedAvatar->getWorldPosition(), glm::vec3(0), packetType, _selectedCodecName); }); @@ -742,10 +742,10 @@ void Agent::processAgentAvatarAudio() { audioPacket->writePrimitive(numAvailableSamples); // use the orientation and position of this avatar for the source of this audio - audioPacket->writePrimitive(scriptedAvatar->getPosition()); + audioPacket->writePrimitive(scriptedAvatar->getWorldPosition()); glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); audioPacket->writePrimitive(headOrientation); - audioPacket->writePrimitive(scriptedAvatar->getPosition()); + audioPacket->writePrimitive(scriptedAvatar->getWorldPosition()); audioPacket->writePrimitive(glm::vec3(0)); // no matter what, the loudness should be set to 0 @@ -759,10 +759,10 @@ void Agent::processAgentAvatarAudio() { audioPacket->writePrimitive((quint8)0); // use the orientation and position of this avatar for the source of this audio - audioPacket->writePrimitive(scriptedAvatar->getPosition()); + audioPacket->writePrimitive(scriptedAvatar->getWorldPosition()); glm::quat headOrientation = scriptedAvatar->getHeadOrientation(); audioPacket->writePrimitive(headOrientation); - audioPacket->writePrimitive(scriptedAvatar->getPosition()); + audioPacket->writePrimitive(scriptedAvatar->getWorldPosition()); // HUH? why do we write this twice?? audioPacket->writePrimitive(glm::vec3(0)); QByteArray encodedBuffer; diff --git a/assignment-client/src/avatars/AvatarMixerClientData.h b/assignment-client/src/avatars/AvatarMixerClientData.h index 12b0286088..d5c7784da7 100644 --- a/assignment-client/src/avatars/AvatarMixerClientData.h +++ b/assignment-client/src/avatars/AvatarMixerClientData.h @@ -91,7 +91,7 @@ public: void loadJSONStats(QJsonObject& jsonObject) const; - glm::vec3 getPosition() const { return _avatar ? _avatar->getPosition() : glm::vec3(0); } + glm::vec3 getPosition() const { return _avatar ? _avatar->getWorldPosition() : glm::vec3(0); } glm::vec3 getGlobalBoundingBoxCorner() const { return _avatar ? _avatar->getGlobalBoundingBoxCorner() : glm::vec3(0); } bool isRadiusIgnoring(const QUuid& other) const { return _radiusIgnoredOthers.find(other) != _radiusIgnoredOthers.end(); } void addToRadiusIgnoringSet(const QUuid& other) { _radiusIgnoredOthers.insert(other); } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 5d36a6d261..dd045c24ea 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -209,7 +209,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map return nodeData->getLastBroadcastTime(avatarNode->getUUID()); }, [&](AvatarSharedPointer avatar)->float{ - glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner() * avatar->getSensorToWorldScale()); + glm::vec3 nodeBoxHalfScale = (avatar->getWorldPosition() - avatar->getGlobalBoundingBoxCorner() * avatar->getSensorToWorldScale()); return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z)); }, [&](AvatarSharedPointer avatar)->bool { if (avatar == thisAvatar) { diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 5060891284..c9ded2d6fb 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -20,7 +20,7 @@ QByteArray ScriptableAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) { - _globalPosition = getPosition(); + _globalPosition = getWorldPosition(); return AvatarData::toByteArrayStateful(dataDetail); } diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f2bb52ea47..b1f461f227 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -893,7 +893,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(audioIO.data(), &AudioClient::muteEnvironmentRequested, [](glm::vec3 position, float radius) { auto audioClient = DependencyManager::get(); auto audioScriptingInterface = DependencyManager::get(); - auto myAvatarPosition = DependencyManager::get()->getMyAvatar()->getPosition(); + auto myAvatarPosition = DependencyManager::get()->getMyAvatar()->getWorldPosition(); float distance = glm::distance(myAvatarPosition, position); bool shouldMute = !audioClient->isMuted() && (distance < radius); @@ -966,7 +966,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo auto addressManager = DependencyManager::get(); // use our MyAvatar position and quat for address manager path - addressManager->setPositionGetter([this]{ return getMyAvatar()->getPosition(); }); + addressManager->setPositionGetter([this]{ return getMyAvatar()->getWorldPosition(); }); addressManager->setOrientationGetter([this]{ return getMyAvatar()->getOrientation(); }); connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); @@ -1501,7 +1501,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo static const QString FAST_STATS_ARG = "--fast-heartbeat"; static int SEND_STATS_INTERVAL_MS = arguments().indexOf(FAST_STATS_ARG) != -1 ? 1000 : 10000; - static glm::vec3 lastAvatarPosition = myAvatar->getPosition(); + static glm::vec3 lastAvatarPosition = myAvatar->getWorldPosition(); static glm::mat4 lastHMDHeadPose = getHMDSensorPose(); static controller::Pose lastLeftHandPose = myAvatar->getLeftHandPose(); static controller::Pose lastRightHandPose = myAvatar->getRightHandPose(); @@ -1629,7 +1629,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo properties["bytes_downloaded"] = bytesDownloaded; auto myAvatar = getMyAvatar(); - glm::vec3 avatarPosition = myAvatar->getPosition(); + glm::vec3 avatarPosition = myAvatar->getWorldPosition(); properties["avatar_has_moved"] = lastAvatarPosition != avatarPosition; lastAvatarPosition = avatarPosition; @@ -1711,7 +1711,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS); // 10 seconds, Qt::CoarseTimer ok connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() { auto avatarManager = DependencyManager::get(); - int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(), + int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getWorldPosition(), NEARBY_AVATAR_RADIUS_METERS) - 1; if (nearbyAvatars != lastCountOfNearbyAvatars) { lastCountOfNearbyAvatars = nearbyAvatars; @@ -2455,11 +2455,11 @@ void Application::updateCamera(RenderArgs& renderArgs) { glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); _myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); - _myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset)); + _myCamera.setPosition(cameraEntity->getWorldPosition() + (hmdRotation * hmdOffset)); } else { _myCamera.setOrientation(cameraEntity->getRotation()); - _myCamera.setPosition(cameraEntity->getPosition()); + _myCamera.setPosition(cameraEntity->getWorldPosition()); } } } @@ -3871,7 +3871,7 @@ void Application::idle() { auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get()); if (entity && _keyboardFocusHighlight) { _keyboardFocusHighlight->setRotation(entity->getRotation()); - _keyboardFocusHighlight->setPosition(entity->getPosition()); + _keyboardFocusHighlight->setWorldPosition(entity->getWorldPosition()); } } else { // Only Web overlays can have focus. @@ -3879,7 +3879,7 @@ void Application::idle() { std::dynamic_pointer_cast(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); if (overlay && _keyboardFocusHighlight) { _keyboardFocusHighlight->setRotation(overlay->getRotation()); - _keyboardFocusHighlight->setPosition(overlay->getPosition()); + _keyboardFocusHighlight->setWorldPosition(overlay->getWorldPosition()); } } } @@ -4013,7 +4013,7 @@ bool Application::exportEntities(const QString& filename, !entityIDs.contains(parentID) || !entityTree->findEntityByEntityItemID(parentID))) { // If parent wasn't selected, we want absolute position, which isn't in properties. - auto position = entityItem->getPosition(); + auto position = entityItem->getWorldPosition(); root.x = glm::min(root.x, position.x); root.y = glm::min(root.y, position.y); root.z = glm::min(root.z, position.z); @@ -4216,7 +4216,7 @@ void Application::init() { return 0.0f; } - auto distance = glm::distance(getMyAvatar()->getPosition(), item.getPosition()); + auto distance = glm::distance(getMyAvatar()->getWorldPosition(), item.getWorldPosition()); return atan2(maxSize, distance); }); @@ -4520,7 +4520,7 @@ void Application::setKeyboardFocusHighlight(const glm::vec3& position, const glm // Position focus _keyboardFocusHighlight->setRotation(rotation); - _keyboardFocusHighlight->setPosition(position); + _keyboardFocusHighlight->setWorldPosition(position); _keyboardFocusHighlight->setDimensions(dimensions); _keyboardFocusHighlight->setVisible(true); } @@ -4557,7 +4557,7 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) { } _lastAcceptedKeyPress = usecTimestampNow(); - setKeyboardFocusHighlight(entity->getPosition(), entity->getRotation(), + setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getRotation(), entity->getDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); } } @@ -4594,7 +4594,7 @@ void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) { if (overlay->getProperty("showKeyboardFocusHighlight").toBool()) { auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR; const float OVERLAY_DEPTH = 0.0105f; - setKeyboardFocusHighlight(overlay->getPosition(), overlay->getRotation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH)); + setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getRotation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH)); } else if (_keyboardFocusHighlight) { _keyboardFocusHighlight->setVisible(false); } @@ -4686,7 +4686,7 @@ void Application::update(float deltaTime) { controller::InputCalibrationData calibrationData = { myAvatar->getSensorToWorldMatrix(), - createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()), + createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getWorldPosition()), myAvatar->getHMDSensorMatrix(), myAvatar->getCenterEyeCalibrationMat(), myAvatar->getHeadCalibrationMat(), @@ -4796,7 +4796,7 @@ void Application::update(float deltaTime) { }; // copy controller poses from userInputMapper to myAvatar. - glm::mat4 myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()); + glm::mat4 myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getWorldPosition()); glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar->getSensorToWorldMatrix()); glm::mat4 avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix; for (auto& action : avatarControllerActions) { @@ -5412,7 +5412,7 @@ std::shared_ptr Application::getMyAvatar() const { } glm::vec3 Application::getAvatarPosition() const { - return getMyAvatar()->getPosition(); + return getMyAvatar()->getWorldPosition(); } void Application::copyViewFrustum(ViewFrustum& viewOut) const { @@ -5624,7 +5624,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { // whose bounding boxes cannot be computed (it is too loose for our purposes here). Instead we manufacture // custom filters and use the general-purpose EntityTree::findEntities(filter, ...) QVector entities; - AABox avatarBox(getMyAvatar()->getPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE)); + AABox avatarBox(getMyAvatar()->getWorldPosition() - glm::vec3(PHYSICS_READY_RANGE), glm::vec3(2 * PHYSICS_READY_RANGE)); // create two functions that use avatarBox (entityScan and elementScan), the second calls the first std::function entityScan = [=](EntityItemPointer& entity) { if (entity->shouldBePhysical()) { @@ -6438,7 +6438,7 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar. properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions. glm::vec3 positionOffset = getMyAvatar()->getOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); - properties.setPosition(getMyAvatar()->getPosition() + positionOffset); + properties.setPosition(getMyAvatar()->getWorldPosition() + positionOffset); properties.setRotation(getMyAvatar()->getOrientation()); properties.setGravity(glm::vec3(0.0f, 0.0f, 0.0f)); auto entityID = DependencyManager::get()->addEntity(properties); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index a47bbbad1b..668994883d 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -529,7 +529,7 @@ void AvatarActionHold::lateAvatarUpdate(const AnimPose& prePhysicsRoomPose, cons rigidBody->setWorldTransform(worldTrans); bool positionSuccess; - ownerEntity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); + ownerEntity->setWorldPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); bool orientationSuccess; ownerEntity->setOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); } diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index e8b800db69..d9d56b76b1 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -435,7 +435,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents static const int MAX_INJECTOR_COUNT = 3; if (_collisionInjectors.size() < MAX_INJECTOR_COUNT) { auto injector = AudioInjector::playSound(collisionSound, energyFactorOfFull, AVATAR_STRETCH_FACTOR, - myAvatar->getPosition()); + myAvatar->getWorldPosition()); _collisionInjectors.emplace_back(injector); } myAvatar->collisionWithEntity(collision); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 39a4f7a4af..fc93bbbfe3 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -41,7 +41,7 @@ public: void init(); std::shared_ptr getMyAvatar() { return _myAvatar; } - glm::vec3 getMyAvatarPosition() const { return _myAvatar->getPosition(); } + glm::vec3 getMyAvatarPosition() const { return _myAvatar->getWorldPosition(); } // Null/Default-constructed QUuids will return MyAvatar Q_INVOKABLE virtual ScriptAvatarData* getAvatar(QUuid avatarID) override { return new ScriptAvatar(getAvatarBySessionID(avatarID)); } diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 91c83afcbd..01cfb93333 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -106,7 +106,7 @@ float AvatarMotionState::getObjectAngularDamping() const { // virtual glm::vec3 AvatarMotionState::getObjectPosition() const { - return _avatar->getPosition(); + return _avatar->getWorldPosition(); } // virtual diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3189ad3c77..9458789685 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -196,7 +196,7 @@ MyAvatar::MyAvatar(QThread* thread) : setDisplayName(dummyAvatar.getDisplayName()); } - setPosition(dummyAvatar.getPosition()); + setWorldPosition(dummyAvatar.getWorldPosition()); setOrientation(dummyAvatar.getOrientation()); if (!dummyAvatar.getAttachmentData().isEmpty()) { @@ -276,7 +276,7 @@ void MyAvatar::simulateAttachments(float deltaTime) { QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropFaceTracking) { CameraMode mode = qApp->getCamera().getMode(); - _globalPosition = getPosition(); + _globalPosition = getWorldPosition(); // This might not be right! Isn't the capsule local offset in avatar space, and don't we need to add the radius to the y as well? -HRS 5/26/17 _globalBoundingBoxDimensions.x = _characterController.getCapsuleRadius(); _globalBoundingBoxDimensions.y = _characterController.getCapsuleHalfHeight(); @@ -284,11 +284,11 @@ QByteArray MyAvatar::toByteArrayStateful(AvatarDataDetail dataDetail, bool dropF _globalBoundingBoxOffset = _characterController.getCapsuleLocalOffset(); if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { // fake the avatar position that is sent up to the AvatarMixer - glm::vec3 oldPosition = getPosition(); - setPosition(getSkeletonPosition()); + glm::vec3 oldPosition = getWorldPosition(); + setWorldPosition(getSkeletonPosition()); QByteArray array = AvatarData::toByteArrayStateful(dataDetail); // copy the correct position back - setPosition(oldPosition); + setWorldPosition(oldPosition); return array; } return AvatarData::toByteArrayStateful(dataDetail); @@ -321,14 +321,14 @@ void MyAvatar::centerBody() { if (_characterController.getState() == CharacterController::State::Ground) { // the avatar's physical aspect thinks it is standing on something // therefore need to be careful to not "center" the body below the floor - float downStep = glm::dot(worldBodyPos - getPosition(), _worldUpDirection); + float downStep = glm::dot(worldBodyPos - getWorldPosition(), _worldUpDirection); if (downStep < -0.5f * _characterController.getCapsuleHalfHeight() + _characterController.getCapsuleRadius()) { worldBodyPos -= downStep * _worldUpDirection; } } // this will become our new position. - setPosition(worldBodyPos); + setWorldPosition(worldBodyPos); setOrientation(worldBodyRot); // reset the body in sensor space @@ -372,7 +372,7 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { auto worldBodyRot = glmExtractRotation(worldBodyMatrix); // this will become our new position. - setPosition(worldBodyPos); + setWorldPosition(worldBodyPos); setOrientation(worldBodyRot); // now sample the new hmd orientation AFTER sensor reset, which should be identity. @@ -410,7 +410,7 @@ void MyAvatar::update(float deltaTime) { #endif if (_goToPending) { - setPosition(_goToPosition); + setWorldPosition(_goToPosition); setOrientation(_goToOrientation); _headControllerFacingMovingAverage = _headControllerFacing; // reset moving average _goToPending = false; @@ -444,7 +444,7 @@ void MyAvatar::update(float deltaTime) { // This might not be right! Isn't the capsule local offset in avatar space? -HRS 5/26/17 halfBoundingBoxDimensions += _characterController.getCapsuleLocalOffset(); QMetaObject::invokeMethod(audio.data(), "setAvatarBoundingBoxParameters", - Q_ARG(glm::vec3, (getPosition() - halfBoundingBoxDimensions)), + Q_ARG(glm::vec3, (getWorldPosition() - halfBoundingBoxDimensions)), Q_ARG(glm::vec3, (halfBoundingBoxDimensions*2.0f))); if (getIdentityDataChanged()) { @@ -537,7 +537,7 @@ void MyAvatar::simulate(float deltaTime) { if (!_skeletonModel->hasSkeleton()) { // All the simulation that can be done has been done - getHead()->setPosition(getPosition()); // so audio-position isn't 0,0,0 + getHead()->setPosition(getWorldPosition()); // so audio-position isn't 0,0,0 return; } @@ -555,7 +555,7 @@ void MyAvatar::simulate(float deltaTime) { Head* head = getHead(); glm::vec3 headPosition; if (!_skeletonModel->getHeadPosition(headPosition)) { - headPosition = getPosition(); + headPosition = getWorldPosition(); } head->setPosition(headPosition); head->setScale(getModelScale()); @@ -666,7 +666,7 @@ void MyAvatar::updateSensorToWorldMatrix() { // update the sensor mat so that the body position will end up in the desired // position when driven from the head. float sensorToWorldScale = getEyeHeight() / getUserEyeHeight(); - glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getOrientation(), getPosition()); + glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getOrientation(), getWorldPosition()); _sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix); lateUpdatePalms(); @@ -783,7 +783,7 @@ controller::Pose MyAvatar::getRightHandTipPose() const { } glm::vec3 MyAvatar::worldToJointPoint(const glm::vec3& position, const int jointIndex) const { - glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified + glm::vec3 jointPos = getWorldPosition();//default value if no or invalid joint specified glm::quat jointRot = getRotation();//default value if no or invalid joint specified if (jointIndex != -1) { if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { @@ -818,7 +818,7 @@ glm::quat MyAvatar::worldToJointRotation(const glm::quat& worldRot, const int jo } glm::vec3 MyAvatar::jointToWorldPoint(const glm::vec3& jointSpacePos, const int jointIndex) const { - glm::vec3 jointPos = getPosition();//default value if no or invalid joint specified + glm::vec3 jointPos = getWorldPosition();//default value if no or invalid joint specified glm::quat jointRot = getRotation();//default value if no or invalid joint specified if (jointIndex != -1) { @@ -1230,7 +1230,7 @@ void MyAvatar::updateLookAtTargetAvatar() { float angleTo = coneSphereAngle(getHead()->getEyePosition(), lookForward, avatar->getHead()->getEyePosition(), radius); if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { _lookAtTargetAvatar = avatarPointer; - _targetAvatarPosition = avatarPointer->getPosition(); + _targetAvatarPosition = avatarPointer->getWorldPosition(); } if (_lookAtSnappingEnabled && avatar->getLookAtSnappingEnabled() && isLookingAtMe(avatar)) { @@ -1301,7 +1301,7 @@ eyeContactTarget MyAvatar::getEyeContactTarget() { } glm::vec3 MyAvatar::getDefaultEyePosition() const { - return getPosition() + getOrientation() * Quaternions::Y_180 * _skeletonModel->getDefaultEyeModelPosition(); + return getWorldPosition() + getOrientation() * Quaternions::Y_180 * _skeletonModel->getDefaultEyeModelPosition(); } const float SCRIPT_PRIORITY = 1.0f + 1.0f; @@ -1460,9 +1460,9 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - return getPosition() + getOrientation() * FLIP * _skeletonOffset; + return getWorldPosition() + getOrientation() * FLIP * _skeletonOffset; } - return Avatar::getPosition(); + return Avatar::getWorldPosition(); } void MyAvatar::rebuildCollisionShape() { @@ -1508,7 +1508,7 @@ controller::Pose MyAvatar::getControllerPoseInWorldFrame(controller::Action acti controller::Pose MyAvatar::getControllerPoseInAvatarFrame(controller::Action action) const { auto pose = getControllerPoseInWorldFrame(action); if (pose.valid) { - glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition())); + glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getWorldPosition())); return pose.transform(invAvatarMatrix); } else { return controller::Pose(); // invalid pose @@ -1575,7 +1575,7 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setParentVelocity(parentVelocity); _characterController.setScaleFactor(getSensorToWorldScale()); - _characterController.setPositionAndOrientation(getPosition(), getOrientation()); + _characterController.setPositionAndOrientation(getWorldPosition(), getOrientation()); auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD); if (headPose.isValid()) { _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); @@ -1609,7 +1609,7 @@ void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { if (_characterController.isEnabledAndReady()) { _characterController.getPositionAndOrientation(position, orientation); } else { - position = getPosition(); + position = getWorldPosition(); orientation = getOrientation(); } nextAttitude(position, orientation); @@ -1619,7 +1619,7 @@ void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity()); if (_characterController.isStuck()) { _physicsSafetyPending = true; - _goToPosition = getPosition(); + _goToPosition = getWorldPosition(); } } else { setVelocity(getVelocity() + _characterController.getFollowVelocity()); @@ -1846,7 +1846,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { } } - DebugDraw::getInstance().updateMyAvatarPos(getPosition()); + DebugDraw::getInstance().updateMyAvatarPos(getWorldPosition()); DebugDraw::getInstance().updateMyAvatarRot(getOrientation()); AnimPose postUpdateRoomPose(_sensorToWorldMatrix); @@ -1854,7 +1854,7 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { updateHoldActions(_prePhysicsRoomPose, postUpdateRoomPose); if (_enableDebugDrawDetailedCollision) { - AnimPose rigToWorldPose(glm::vec3(1.0f), getRotation() * Quaternions::Y_180, getPosition()); + AnimPose rigToWorldPose(glm::vec3(1.0f), getRotation() * Quaternions::Y_180, getWorldPosition()); const int NUM_DEBUG_COLORS = 8; const glm::vec4 DEBUG_COLORS[NUM_DEBUG_COLORS] = { glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), @@ -2105,7 +2105,7 @@ void MyAvatar::updatePosition(float deltaTime) { if (_moving) { // scan for walkability - glm::vec3 position = getPosition(); + glm::vec3 position = getWorldPosition(); MyCharacterController::RayShotgunResult result; glm::vec3 step = deltaTime * (getRotation() * _actionMotorVelocity); _characterController.testRayShotgun(position, step, result); @@ -2916,7 +2916,7 @@ float MyAvatar::getAudioEnergy() { } bool MyAvatar::didTeleport() { - glm::vec3 pos = getPosition(); + glm::vec3 pos = getWorldPosition(); glm::vec3 changeInPosition = pos - lastPosition; lastPosition = pos; return (changeInPosition.length() > MAX_AVATAR_MOVEMENT_PER_FRAME); @@ -2960,7 +2960,7 @@ glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& c glm::mat4 controllerWorldMatrix = getSensorToWorldMatrix() * delta * controllerSensorMatrix; // transform controller into avatar space - glm::mat4 avatarMatrix = createMatFromQuatAndPos(getOrientation(), getPosition()); + glm::mat4 avatarMatrix = createMatFromQuatAndPos(getOrientation(), getWorldPosition()); return glm::inverse(avatarMatrix) * controllerWorldMatrix; } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 16ed9ea5b4..263a2f34c4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -114,7 +114,7 @@ class MyAvatar : public Avatar { // FIXME: `glm::vec3 position` is not accessible from QML, so this exposes position in a QML-native type Q_PROPERTY(QVector3D qmlPosition READ getQmlPosition) - QVector3D getQmlPosition() { auto p = getPosition(); return QVector3D(p.x, p.y, p.z); } + QVector3D getQmlPosition() { auto p = getWorldPosition(); return QVector3D(p.x, p.y, p.z); } Q_PROPERTY(bool shouldRenderLocally READ getShouldRenderLocally WRITE setShouldRenderLocally) Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity) diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index 761e2e5bff..57b5e96ee5 100755 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -65,7 +65,7 @@ void MyCharacterController::updateShapeIfNecessary() { _rigidBody->setSleepingThresholds(0.0f, 0.0f); _rigidBody->setAngularFactor(0.0f); _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()), - glmToBullet(_avatar->getPosition()))); + glmToBullet(_avatar->getWorldPosition()))); _rigidBody->setDamping(0.0f, 0.0f); if (_state == State::Hover) { _rigidBody->setGravity(btVector3(0.0f, 0.0f, 0.0f)); diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index cf3f380ca0..fc0ecf94e5 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -28,7 +28,7 @@ const PickRay JointRayPick::getPickRay(bool& valid) const { if (jointIndex != INVALID_JOINT || useAvatarHead) { glm::vec3 jointPos = useAvatarHead ? myAvatar->getHeadPosition() : myAvatar->getAbsoluteJointTranslationInObjectFrame(jointIndex); glm::quat jointRot = useAvatarHead ? myAvatar->getHeadOrientation() : myAvatar->getAbsoluteJointRotationInObjectFrame(jointIndex); - glm::vec3 avatarPos = myAvatar->getPosition(); + glm::vec3 avatarPos = myAvatar->getWorldPosition(); glm::quat avatarRot = myAvatar->getOrientation(); glm::vec3 pos = useAvatarHead ? jointPos : avatarPos + (avatarRot * jointPos); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index d4a300c337..4fa5e5726b 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -192,7 +192,7 @@ void Stats::updateStats(bool force) { // Third column, avatar stats auto myAvatar = avatarManager->getMyAvatar(); - glm::vec3 avatarPos = myAvatar->getPosition(); + glm::vec3 avatarPos = myAvatar->getWorldPosition(); STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z)); STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getVelocity()), 0.01f); STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f); diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 42425932df..457f06aaa2 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -114,7 +114,7 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { properties["parentJointIndex"] = getParentJointIndex(); } if (!properties["position"].isValid() && !properties["localPosition"].isValid()) { - properties["position"] = vec3toVariant(getPosition()); + properties["position"] = vec3toVariant(getWorldPosition()); } if (!properties["orientation"].isValid() && !properties["localOrientation"].isValid()) { properties["orientation"] = quatToVariant(getOrientation()); @@ -214,7 +214,7 @@ QVariant Base3DOverlay::getProperty(const QString& property) { return _name; } if (property == "position" || property == "start" || property == "p1" || property == "point") { - return vec3toVariant(getPosition()); + return vec3toVariant(getWorldPosition()); } if (property == "localPosition") { return vec3toVariant(getLocalPosition()); diff --git a/interface/src/ui/overlays/Base3DOverlay.h b/interface/src/ui/overlays/Base3DOverlay.h index 436cfbf97b..817e9b2acf 100644 --- a/interface/src/ui/overlays/Base3DOverlay.h +++ b/interface/src/ui/overlays/Base3DOverlay.h @@ -33,7 +33,7 @@ public: virtual bool is3D() const override { return true; } // TODO: consider implementing registration points in this class - glm::vec3 getCenter() const { return getPosition(); } + glm::vec3 getCenter() const { return getWorldPosition(); } float getLineWidth() const { return _lineWidth; } bool getIsSolid() const { return _isSolid; } diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 536b2c764f..88172950ee 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -415,11 +415,11 @@ bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve // Scale the dimensions by the diameter glm::vec2 dimensions = getOuterRadius() * 2.0f * getDimensions(); - bool intersects = findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), dimensions, distance); + bool intersects = findRayRectangleIntersection(origin, direction, getRotation(), getWorldPosition(), dimensions, distance); if (intersects) { glm::vec3 hitPosition = origin + (distance * direction); - glm::vec3 localHitPosition = glm::inverse(getRotation()) * (hitPosition - getPosition()); + glm::vec3 localHitPosition = glm::inverse(getRotation()) * (hitPosition - getWorldPosition()); localHitPosition.x /= getDimensions().x; localHitPosition.y /= getDimensions().y; float distanceToHit = glm::length(localHitPosition); diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index 70b75a0b17..ccbf9fb1b2 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -161,7 +161,7 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& _contextOverlay->setIsFacingAvatar(true); _contextOverlayID = qApp->getOverlays().addOverlay(_contextOverlay); } - _contextOverlay->setPosition(contextOverlayPosition); + _contextOverlay->setWorldPosition(contextOverlayPosition); _contextOverlay->setDimensions(contextOverlayDimensions); _contextOverlay->setRotation(entityProperties.getRotation()); _contextOverlay->setVisible(true); diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index b6df1dbc31..d95b8c7761 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -144,7 +144,7 @@ QVariant Cube3DOverlay::getProperty(const QString& property) { Transform Cube3DOverlay::evalRenderTransform() { // TODO: handle registration point?? - glm::vec3 position = getPosition(); + glm::vec3 position = getWorldPosition(); glm::vec3 dimensions = getDimensions(); glm::quat rotation = getRotation(); diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index ca275368cb..afce710d08 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -69,7 +69,7 @@ void Grid3DOverlay::render(RenderArgs* args) { auto minCorner = glm::vec2(-0.5f, -0.5f); auto maxCorner = glm::vec2(0.5f, 0.5f); - auto position = getPosition(); + auto position = getWorldPosition(); if (_followCamera) { // Get the camera position rounded to the nearest major grid line // This grid is for UI and should lie on worldlines diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index bdb35d4f49..8869817829 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -45,7 +45,7 @@ Line3DOverlay::~Line3DOverlay() { } glm::vec3 Line3DOverlay::getStart() const { - return getPosition(); + return getWorldPosition(); } glm::vec3 Line3DOverlay::getEnd() const { @@ -69,7 +69,7 @@ glm::vec3 Line3DOverlay::getEnd() const { } void Line3DOverlay::setStart(const glm::vec3& start) { - setPosition(start); + setWorldPosition(start); } void Line3DOverlay::setEnd(const glm::vec3& end) { diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 2a13249958..eedacd2d67 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -121,7 +121,7 @@ void ModelOverlay::setDrawHUDLayer(bool drawHUDLayer) { } void ModelOverlay::setProperties(const QVariantMap& properties) { - auto origPosition = getPosition(); + auto origPosition = getWorldPosition(); auto origRotation = getRotation(); auto origDimensions = getDimensions(); auto origScale = getSNScale(); @@ -143,7 +143,7 @@ void ModelOverlay::setProperties(const QVariantMap& properties) { _scaleToFit = false; } - if (origPosition != getPosition() || origRotation != getRotation() || origDimensions != getDimensions() || origScale != getSNScale()) { + if (origPosition != getWorldPosition() || origRotation != getRotation() || origDimensions != getDimensions() || origScale != getSNScale()) { _updateModel = true; } @@ -384,7 +384,7 @@ void ModelOverlay::locationChanged(bool tellPhysics) { // FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform() if (_model && _model->isActive()) { _model->setRotation(getRotation()); - _model->setTranslation(getPosition()); + _model->setTranslation(getWorldPosition()); } } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index fd5aae4027..ca79d0b663 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -827,7 +827,7 @@ PointerEvent Overlays::calculateOverlayPointerEvent(OverlayID overlayID, PickRay if (!overlay) { return PointerEvent(); } - glm::vec3 position = overlay->getPosition(); + glm::vec3 position = overlay->getWorldPosition(); glm::quat rotation = overlay->getRotation(); glm::vec2 dimensions = overlay->getSize(); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 194c530df0..40d70d5348 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -69,7 +69,7 @@ namespace render { auto batch = args->_batch; auto avatar = DependencyManager::get()->getMyAvatar(); glm::quat myAvatarRotation = avatar->getOrientation(); - glm::vec3 myAvatarPosition = avatar->getPosition(); + glm::vec3 myAvatarPosition = avatar->getWorldPosition(); float angle = glm::degrees(glm::angle(myAvatarRotation)); glm::vec3 axis = glm::axis(myAvatarRotation); float myAvatarScale = avatar->getModelScale(); diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index ac3fe66ddc..ae5e0f32d0 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -69,7 +69,7 @@ QVariant Planar3DOverlay::getProperty(const QString& property) { bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) { // FIXME - face and surfaceNormal not being returned - return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getDimensions(), distance); + return findRayRectangleIntersection(origin, direction, getRotation(), getWorldPosition(), getDimensions(), distance); } Transform Planar3DOverlay::evalRenderTransform() { diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.cpp b/interface/src/ui/overlays/Rectangle3DOverlay.cpp index 47d47b76a5..2010b00d4d 100644 --- a/interface/src/ui/overlays/Rectangle3DOverlay.cpp +++ b/interface/src/ui/overlays/Rectangle3DOverlay.cpp @@ -58,7 +58,7 @@ void Rectangle3DOverlay::render(RenderArgs* args) { const float MAX_COLOR = 255.0f; glm::vec4 rectangleColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha); - glm::vec3 position = getPosition(); + glm::vec3 position = getWorldPosition(); glm::vec2 dimensions = getDimensions(); glm::vec2 halfDimensions = dimensions * 0.5f; glm::quat rotation = getRotation(); diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp index a3b51d40bf..7e9f44ef1d 100644 --- a/interface/src/ui/overlays/Shape3DOverlay.cpp +++ b/interface/src/ui/overlays/Shape3DOverlay.cpp @@ -121,7 +121,7 @@ QVariant Shape3DOverlay::getProperty(const QString& property) { Transform Shape3DOverlay::evalRenderTransform() { // TODO: handle registration point?? - glm::vec3 position = getPosition(); + glm::vec3 position = getWorldPosition(); glm::vec3 dimensions = getDimensions(); glm::quat rotation = getRotation(); diff --git a/interface/src/ui/overlays/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp index 8aa8490937..4e685bed0e 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.cpp +++ b/interface/src/ui/overlays/Volume3DOverlay.cpp @@ -21,7 +21,7 @@ Volume3DOverlay::Volume3DOverlay(const Volume3DOverlay* volume3DOverlay) : AABox Volume3DOverlay::getBounds() const { auto extents = Extents{_localBoundingBox}; extents.rotate(getRotation()); - extents.shiftBy(getPosition()); + extents.shiftBy(getWorldPosition()); return AABox(extents); } diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 0c75803d35..5d8e433615 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -151,7 +151,7 @@ void Web3DOverlay::buildWebSurface() { _webSurface = DependencyManager::get()->acquire(_url); setupQmlSurface(); } - _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition())); + _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition())); _webSurface->resize(QSize(_resolution.x, _resolution.y)); _webSurface->resume(); }); @@ -171,7 +171,7 @@ void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) { void Web3DOverlay::update(float deltatime) { if (_webSurface) { // update globalPosition - _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition())); + _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getWorldPosition())); } Parent::update(deltatime); } @@ -615,7 +615,7 @@ bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& // Don't call applyTransformTo() or setTransform() here because this code runs too frequently. // Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale. - return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getSize(), distance); + return findRayRectangleIntersection(origin, direction, getRotation(), getWorldPosition(), getSize(), distance); } Web3DOverlay* Web3DOverlay::createClone() const { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index f674a2206e..67efeda90d 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -145,18 +145,18 @@ void Avatar::init() { glm::vec3 Avatar::getChestPosition() const { // for now, let's just assume that the "chest" is halfway between the root and the neck glm::vec3 neckPosition; - return _skeletonModel->getNeckPosition(neckPosition) ? (getPosition() + neckPosition) * 0.5f : getPosition(); + return _skeletonModel->getNeckPosition(neckPosition) ? (getWorldPosition() + neckPosition) * 0.5f : getWorldPosition(); } glm::vec3 Avatar::getNeckPosition() const { glm::vec3 neckPosition; - return _skeletonModel->getNeckPosition(neckPosition) ? neckPosition : getPosition(); + return _skeletonModel->getNeckPosition(neckPosition) ? neckPosition : getWorldPosition(); } AABox Avatar::getBounds() const { if (!_skeletonModel->isRenderable() || _skeletonModel->needsFixupInScene()) { // approximately 2m tall, scaled to user request. - return AABox(getPosition() - glm::vec3(getModelScale()), getModelScale() * 2.0f); + return AABox(getWorldPosition() - glm::vec3(getModelScale()), getModelScale() * 2.0f); } return _skeletonModel->getRenderableMeshBound(); } @@ -359,9 +359,9 @@ void Avatar::simulate(float deltaTime, bool inView) { locationChanged(); // joints changed, so if there are any children, update them. _hasNewJointData = false; - glm::vec3 headPosition = getPosition(); + glm::vec3 headPosition = getWorldPosition(); if (!_skeletonModel->getHeadPosition(headPosition)) { - headPosition = getPosition(); + headPosition = getWorldPosition(); } head->setPosition(headPosition); } @@ -427,7 +427,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { } void Avatar::slamPosition(const glm::vec3& newPosition) { - setPosition(newPosition); + setWorldPosition(newPosition); _positionDeltaAccumulator = glm::vec3(0.0f); setVelocity(glm::vec3(0.0f)); _lastVelocity = glm::vec3(0.0f); @@ -439,7 +439,7 @@ void Avatar::updateAttitude(const glm::quat& orientation) { } void Avatar::applyPositionDelta(const glm::vec3& delta) { - setPosition(getPosition() + delta); + setWorldPosition(getWorldPosition() + delta); _positionDeltaAccumulator += delta; } @@ -588,7 +588,7 @@ void Avatar::render(RenderArgs* renderArgs) { glm::vec3 viewPos = renderArgs->getViewFrustum().getPosition(); const float MAX_DISTANCE_SQUARED_FOR_SHOWING_POINTING_LASERS = 100.0f; // 10^2 - if (glm::distance2(viewPos, getPosition()) < MAX_DISTANCE_SQUARED_FOR_SHOWING_POINTING_LASERS) { + if (glm::distance2(viewPos, getWorldPosition()) < MAX_DISTANCE_SQUARED_FOR_SHOWING_POINTING_LASERS) { auto geometryCache = DependencyManager::get(); // render pointing lasers @@ -647,7 +647,7 @@ void Avatar::render(RenderArgs* renderArgs) { } ViewFrustum frustum = renderArgs->getViewFrustum(); - if (!frustum.sphereIntersectsFrustum(getPosition(), getBoundingRadius())) { + if (!frustum.sphereIntersectsFrustum(getWorldPosition(), getBoundingRadius())) { return; } @@ -658,7 +658,7 @@ void Avatar::render(RenderArgs* renderArgs) { } if (showReceiveStats || showNamesAboveHeads) { - glm::vec3 toTarget = frustum.getPosition() - getPosition(); + glm::vec3 toTarget = frustum.getPosition() - getWorldPosition(); float distanceToTarget = glm::length(toTarget); const float DISPLAYNAME_DISTANCE = 20.0f; updateDisplayNameAlpha(distanceToTarget < DISPLAYNAME_DISTANCE); @@ -721,7 +721,7 @@ void Avatar::simulateAttachments(float deltaTime) { glm::quat jointRotation; if (attachment.isSoft) { // soft attachments do not have transform offsets - model->setTranslation(getPosition()); + model->setTranslation(getWorldPosition()); model->setRotation(getOrientation() * Quaternions::Y_180); model->simulate(deltaTime); } else { @@ -775,9 +775,9 @@ glm::vec3 Avatar::getDisplayNamePosition() const { const float HEAD_PROPORTION = 0.75f; float size = getBoundingRadius(); - DEBUG_VALUE("_position =", getPosition()); + DEBUG_VALUE("_position =", getWorldPosition()); DEBUG_VALUE("size =", size); - namePosition = getPosition() + bodyUpDirection * (size * HEAD_PROPORTION); + namePosition = getWorldPosition() + bodyUpDirection * (size * HEAD_PROPORTION); } if (glm::any(glm::isnan(namePosition)) || glm::any(glm::isinf(namePosition))) { @@ -902,7 +902,7 @@ glm::vec3 Avatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - return getPosition() + getOrientation() * FLIP * _skeletonOffset; + return getWorldPosition() + getOrientation() * FLIP * _skeletonOffset; } QVector Avatar::getJointRotations() const { @@ -1166,7 +1166,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const { void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { //Scale a world space vector as if it was relative to the position - positionToScale = getPosition() + getModelScale() * (positionToScale - getPosition()); + positionToScale = getWorldPosition() + getModelScale() * (positionToScale - getWorldPosition()); } void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { @@ -1254,12 +1254,12 @@ int Avatar::parseDataFromBuffer(const QByteArray& buffer) { } // change in position implies movement - glm::vec3 oldPosition = getPosition(); + glm::vec3 oldPosition = getWorldPosition(); int bytesRead = AvatarData::parseDataFromBuffer(buffer); const float MOVE_DISTANCE_THRESHOLD = 0.001f; - _moving = glm::distance(oldPosition, getPosition()) > MOVE_DISTANCE_THRESHOLD; + _moving = glm::distance(oldPosition, getWorldPosition()) > MOVE_DISTANCE_THRESHOLD; if (_moving) { addPhysicsFlags(Simulation::DIRTY_POSITION); } @@ -1333,7 +1333,7 @@ float Avatar::getHeadHeight() const { Extents extents = _skeletonModel->getMeshExtents(); glm::vec3 neckPosition; if (!extents.isEmpty() && extents.isValid() && _skeletonModel->getNeckPosition(neckPosition)) { - return extents.maximum.y / 2.0f - neckPosition.y + getPosition().y; + return extents.maximum.y / 2.0f - neckPosition.y + getWorldPosition().y; } const float DEFAULT_HEAD_HEIGHT = 0.25f; @@ -1378,8 +1378,8 @@ void Avatar::getCapsule(glm::vec3& start, glm::vec3& end, float& radius) { ShapeInfo shapeInfo; computeShapeInfo(shapeInfo); glm::vec3 halfExtents = shapeInfo.getHalfExtents(); // x = radius, y = halfHeight - start = getPosition() - glm::vec3(0, halfExtents.y, 0) + shapeInfo.getOffset(); - end = getPosition() + glm::vec3(0, halfExtents.y, 0) + shapeInfo.getOffset(); + start = getWorldPosition() - glm::vec3(0, halfExtents.y, 0) + shapeInfo.getOffset(); + end = getWorldPosition() + glm::vec3(0, halfExtents.y, 0) + shapeInfo.getOffset(); radius = halfExtents.x; } @@ -1472,7 +1472,7 @@ glm::quat Avatar::getUncachedRightPalmRotation() const { } void Avatar::setPositionViaScript(const glm::vec3& position) { - setPosition(position); + setWorldPosition(position); updateAttitude(getOrientation()); } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 877bcd9353..2fe62a4ca2 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -118,12 +118,12 @@ void AvatarData::setTargetScale(float targetScale) { } glm::vec3 AvatarData::getHandPosition() const { - return getOrientation() * _handPosition + getPosition(); + return getOrientation() * _handPosition + getWorldPosition(); } void AvatarData::setHandPosition(const glm::vec3& handPosition) { // store relative to position/orientation - _handPosition = glm::inverse(getOrientation()) * (handPosition - getPosition()); + _handPosition = glm::inverse(getOrientation()) * (handPosition - getWorldPosition()); } void AvatarData::lazyInitHeadData() const { @@ -1901,7 +1901,7 @@ void AvatarData::setRecordingBasis(std::shared_ptr recordingBasis) { if (!recordingBasis) { recordingBasis = std::make_shared(); recordingBasis->setRotation(getOrientation()); - recordingBasis->setTranslation(getPosition()); + recordingBasis->setTranslation(getWorldPosition()); // TODO: find a different way to record/playback the Scale of the avatar //recordingBasis->setScale(getTargetScale()); } @@ -2059,11 +2059,11 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { auto relativeTransform = Transform::fromJson(json[JSON_AVATAR_RELATIVE]); auto worldTransform = currentBasis->worldTransform(relativeTransform); - setPosition(worldTransform.getTranslation()); + setWorldPosition(worldTransform.getTranslation()); orientation = worldTransform.getRotation(); } else { // We still set the position in the case that there is no movement. - setPosition(currentBasis->getTranslation()); + setWorldPosition(currentBasis->getTranslation()); orientation = currentBasis->getRotation(); } setOrientation(orientation); @@ -2186,7 +2186,7 @@ void AvatarData::setBodyRoll(float bodyRoll) { } void AvatarData::setPositionViaScript(const glm::vec3& position) { - SpatiallyNestable::setPosition(position); + SpatiallyNestable::setWorldPosition(position); } void AvatarData::setOrientationViaScript(const glm::quat& orientation) { @@ -2413,7 +2413,7 @@ void AvatarData::sortAvatars( // (a) apparentSize // (b) proximity to center of view // (c) time since last update - glm::vec3 avatarPosition = avatar->getPosition(); + glm::vec3 avatarPosition = avatar->getWorldPosition(); glm::vec3 offset = avatarPosition - frustumCenter; float distance = glm::length(offset) + 0.001f; // add 1mm to avoid divide by zero diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 89fe270af1..5ce4395baa 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -351,7 +351,7 @@ public: class AvatarData : public QObject, public SpatiallyNestable { Q_OBJECT - Q_PROPERTY(glm::vec3 position READ getPosition WRITE setPositionViaScript) + Q_PROPERTY(glm::vec3 position READ getWorldPosition WRITE setPositionViaScript) Q_PROPERTY(float scale READ getTargetScale WRITE setTargetScale) Q_PROPERTY(float density READ getDensity) Q_PROPERTY(glm::vec3 handPosition READ getHandPosition WRITE setHandPosition) diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index 3712080cdb..61b13d7749 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -33,7 +33,7 @@ QVector AvatarHashMap::getAvatarIdentifiers() { bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range) { auto hashCopy = getHashCopy(); foreach(const AvatarSharedPointer& sharedAvatar, hashCopy) { - glm::vec3 avatarPosition = sharedAvatar->getPosition(); + glm::vec3 avatarPosition = sharedAvatar->getWorldPosition(); float distance = glm::distance(avatarPosition, position); if (distance < range) { return true; @@ -47,7 +47,7 @@ int AvatarHashMap::numberOfAvatarsInRange(const glm::vec3& position, float range auto rangeMeters2 = rangeMeters * rangeMeters; int count = 0; for (const AvatarSharedPointer& sharedAvatar : hashCopy) { - glm::vec3 avatarPosition = sharedAvatar->getPosition(); + glm::vec3 avatarPosition = sharedAvatar->getWorldPosition(); auto distance2 = glm::distance2(avatarPosition, position); if (distance2 < rangeMeters2) { ++count; diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index 1fda984e78..6ff36331cf 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -155,7 +155,7 @@ QJsonObject HeadData::toJson() const { auto lookat = getLookAtPosition(); if (lookat != vec3()) { vec3 relativeLookAt = glm::inverse(_owningAvatar->getOrientation()) * - (getLookAtPosition() - _owningAvatar->getPosition()); + (getLookAtPosition() - _owningAvatar->getWorldPosition()); headJson[JSON_AVATAR_HEAD_LOOKAT] = toJsonValue(relativeLookAt); } return headJson; @@ -185,7 +185,7 @@ void HeadData::fromJson(const QJsonObject& json) { if (json.contains(JSON_AVATAR_HEAD_LOOKAT)) { auto relativeLookAt = vec3FromJsonValue(json[JSON_AVATAR_HEAD_LOOKAT]); if (glm::length2(relativeLookAt) > 0.01f) { - setLookAtPosition((_owningAvatar->getOrientation() * relativeLookAt) + _owningAvatar->getPosition()); + setLookAtPosition((_owningAvatar->getOrientation() * relativeLookAt) + _owningAvatar->getWorldPosition()); } } diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index d0643d28f8..cac3f600ca 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -24,7 +24,7 @@ ScriptAvatarData::ScriptAvatarData(AvatarSharedPointer avatarData) : // glm::vec3 ScriptAvatarData::getPosition() const { if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) { - return sharedAvatarData->getPosition(); + return sharedAvatarData->getWorldPosition(); } else { return glm::vec3(); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index bf17f34749..a9277ff19a 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -509,7 +509,7 @@ static glm::vec2 projectOntoEntityXYPlane(EntityItemPointer entity, const PickRa if (entity) { - glm::vec3 entityPosition = entity->getPosition(); + glm::vec3 entityPosition = entity->getWorldPosition(); glm::quat entityRotation = entity->getRotation(); glm::vec3 entityDimensions = entity->getDimensions(); glm::vec3 entityRegistrationPoint = entity->getRegistrationPoint(); diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index 738b1a253e..e00cd98e65 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -28,7 +28,7 @@ void LightEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint lightPayload.setVisible(_visible); auto light = lightPayload.editLight(); - light->setPosition(entity->getPosition()); + light->setPosition(entity->getWorldPosition()); light->setOrientation(entity->getRotation()); bool success; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 7db19704b4..67b7b175b7 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -124,7 +124,7 @@ void RenderableModelEntityItem::doInitialModelSimulation() { model->setScaleToFit(true, getDimensions()); model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); model->setRotation(getRotation()); - model->setTranslation(getPosition()); + model->setTranslation(getWorldPosition()); if (_needsInitialSimulation) { model->simulate(0.0f); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 3fd1d024c1..e4706fa15e 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -154,7 +154,7 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo entity->resetPolyLineChanged(); _polylineTransform = Transform(); - _polylineTransform.setTranslation(entity->getPosition()); + _polylineTransform.setTranslation(entity->getWorldPosition()); _polylineTransform.setRotation(entity->getRotation()); if (pointsChanged) { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index e92bc636bd..fd7407287d 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -232,7 +232,7 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const { glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units bool success; // TODO -- Does this actually have to happen in world space? glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes - glm::vec3 position = getPosition(success); + glm::vec3 position = getWorldPosition(success); glm::vec3 positionToCenter = center - position; positionToCenter -= dimensions * Vectors::HALF - getSurfacePositionAdjustment(); @@ -248,7 +248,7 @@ glm::mat4 RenderablePolyVoxEntityItem::localToVoxelMatrix() const { glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const { glm::mat4 rotation = glm::mat4_cast(getRotation()); - glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 translation = glm::translate(getWorldPosition()); return translation * rotation * voxelToLocalMatrix(); } @@ -579,7 +579,7 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o // the PolyVox ray intersection code requires a near and far point. // set ray cast length to long enough to cover all of the voxel space - float distanceToEntity = glm::distance(origin, getPosition()); + float distanceToEntity = glm::distance(origin, getWorldPosition()); glm::vec3 dimensions = getDimensions(); float largestDimension = glm::compMax(dimensions) * 2.0f; glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension); diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index 332d87f930..dffde3386b 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -81,7 +81,7 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _color = vec4(toGlm(entity->getXColor()), entity->getLocalRenderAlpha()); _shape = entity->getShape(); - _position = entity->getPosition(); + _position = entity->getWorldPosition(); _dimensions = entity->getDimensions(); _orientation = entity->getOrientation(); _renderTransform = getModelTransform(); diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index a2e574a829..231f9c35b6 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -69,7 +69,7 @@ void WebEntityRenderer::onRemoveFromSceneTyped(const TypedEntityPointer& entity) } bool WebEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPointer& entity) const { - if (_contextPosition != entity->getPosition()) { + if (_contextPosition != entity->getWorldPosition()) { return true; } @@ -127,9 +127,9 @@ void WebEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene buildWebSurface(entity); } - if (_contextPosition != entity->getPosition()) { + if (_contextPosition != entity->getWorldPosition()) { // update globalPosition - _contextPosition = entity->getPosition(); + _contextPosition = entity->getWorldPosition(); _webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(_contextPosition)); } diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index 0235f1b7a3..e56e692890 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -200,7 +200,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen bool hazeChanged = entity->hazePropertiesChanged(); entity->resetRenderingPropertiesChanged(); - _lastPosition = entity->getPosition(); + _lastPosition = entity->getWorldPosition(); _lastRotation = entity->getRotation(); _lastDimensions = entity->getDimensions(); @@ -271,7 +271,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint return true; } - if (entity->getPosition() != _lastPosition) { + if (entity->getWorldPosition() != _lastPosition) { return true; } if (entity->getDimensions() != _lastDimensions) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 71e6990aaf..e1ff932915 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -888,7 +888,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef } void EntityItem::debugDump() const { - auto position = getPosition(); + auto position = getWorldPosition(); qCDebug(entities) << "EntityItem id:" << getEntityItemID(); qCDebug(entities, " edited ago:%f", (double)getEditedAgo()); qCDebug(entities, " position:%f,%f,%f", (double)position.x, (double)position.y, (double)position.z); @@ -1168,7 +1168,7 @@ bool EntityItem::wantTerseEditLogging() const { } glm::mat4 EntityItem::getEntityToWorldMatrix() const { - glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 translation = glm::translate(getWorldPosition()); glm::mat4 rotation = glm::mat4_cast(getRotation()); glm::mat4 scale = glm::scale(getDimensions()); glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); @@ -1429,7 +1429,7 @@ const Transform EntityItem::getTransformToCenter(bool& success) const { /// AACube EntityItem::getMaximumAACube(bool& success) const { if (_recalcMaxAACube) { - glm::vec3 centerOfRotation = getPosition(success); // also where _registration point is + glm::vec3 centerOfRotation = getWorldPosition(success); // also where _registration point is if (success) { _recalcMaxAACube = false; // we want to compute the furthestExtent that an entity can extend out from its "position" @@ -1457,7 +1457,7 @@ AACube EntityItem::getMaximumAACube(bool& success) const { AACube EntityItem::getMinimumAACube(bool& success) const { if (_recalcMinAACube) { // position represents the position of the registration point. - glm::vec3 position = getPosition(success); + glm::vec3 position = getWorldPosition(success); if (success) { _recalcMinAACube = false; glm::vec3 dimensions = getDimensions(); @@ -1487,7 +1487,7 @@ AACube EntityItem::getMinimumAACube(bool& success) const { AABox EntityItem::getAABox(bool& success) const { if (_recalcAABox) { // position represents the position of the registration point. - glm::vec3 position = getPosition(success); + glm::vec3 position = getWorldPosition(success); if (success) { _recalcAABox = false; glm::vec3 dimensions = getDimensions(); @@ -2381,7 +2381,7 @@ void EntityItem::dimensionsChanged() { void EntityItem::globalizeProperties(EntityItemProperties& properties, const QString& messageTemplate, const glm::vec3& offset) const { // TODO -- combine this with convertLocationToScriptSemantics bool success; - auto globalPosition = getPosition(success); + auto globalPosition = getWorldPosition(success); if (success) { properties.setPosition(globalPosition + offset); properties.setRotation(getRotation()); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index ed7a1469b3..329a616609 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -385,7 +385,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties.setParentJointIndex(entity->getParentJointIndex()); } if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) { - properties.setPosition(entity->getPosition()); + properties.setPosition(entity->getWorldPosition()); } if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) { properties.setRotation(entity->getOrientation()); @@ -1797,7 +1797,7 @@ glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) { _entityTree->withReadLock([&] { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); if (entity) { - glm::mat4 translation = glm::translate(entity->getPosition()); + glm::mat4 translation = glm::translate(entity->getWorldPosition()); glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); result = translation * rotation; } diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index bde82d96a1..64fbc6aefb 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -681,7 +681,7 @@ bool EntityTree::findNearPointOperation(const OctreeElementPointer& element, voi // we may have gotten NULL back, meaning no entity was available if (thisClosestEntity) { - glm::vec3 entityPosition = thisClosestEntity->getPosition(); + glm::vec3 entityPosition = thisClosestEntity->getWorldPosition(); float distanceFromPointToEntity = glm::distance(entityPosition, args->position); // If we're within our target radius @@ -1054,7 +1054,7 @@ bool EntityTree::filterProperties(EntityItemPointer& existingEntity, EntityItemP bool accepted = true; auto entityEditFilters = DependencyManager::get(); if (entityEditFilters) { - auto position = existingEntity ? existingEntity->getPosition() : propertiesIn.getPosition(); + auto position = existingEntity ? existingEntity->getWorldPosition() : propertiesIn.getPosition(); auto entityID = existingEntity ? existingEntity->getEntityItemID() : EntityItemID(); accepted = entityEditFilters->filter(position, propertiesIn, propertiesOut, wasChanged, filterType, entityID); } diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 2696377028..4b588fc23c 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -663,7 +663,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con // extents is the entity relative, scaled, centered extents of the entity glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); - glm::mat4 translation = glm::translate(entity->getPosition()); + glm::mat4 translation = glm::translate(entity->getWorldPosition()); glm::mat4 entityToWorldMatrix = translation * rotation; glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); @@ -718,7 +718,7 @@ bool EntityTreeElement::findSpherePenetration(const glm::vec3& center, float rad bool result = false; withReadLock([&] { foreach(EntityItemPointer entity, _entityItems) { - glm::vec3 entityCenter = entity->getPosition(); + glm::vec3 entityCenter = entity->getWorldPosition(); float entityRadius = entity->getRadius(); // don't penetrate yourself @@ -743,7 +743,7 @@ EntityItemPointer EntityTreeElement::getClosestEntity(glm::vec3 position) const float closestEntityDistance = FLT_MAX; withReadLock([&] { foreach(EntityItemPointer entity, _entityItems) { - float distanceToEntity = glm::distance2(position, entity->getPosition()); + float distanceToEntity = glm::distance2(position, entity->getWorldPosition()); if (distanceToEntity < closestEntityDistance) { closestEntity = entity; } @@ -788,7 +788,7 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc // determine the worldToEntityMatrix that doesn't include scale because // we're going to use the registration aware aa box in the entity frame glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); - glm::mat4 translation = glm::translate(entity->getPosition()); + glm::mat4 translation = glm::translate(entity->getWorldPosition()); glm::mat4 entityToWorldMatrix = translation * rotation; glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 119236e32d..02d16f2537 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -156,7 +156,7 @@ void LineEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " LINE EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; - qCDebug(entities) << " position:" << debugTreeVector(getPosition()); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 26f063f7cc..313721ff54 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -189,7 +189,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit void ModelEntityItem::debugDump() const { qCDebug(entities) << "ModelEntityItem id:" << getEntityItemID(); qCDebug(entities) << " edited ago:" << getEditedAgo(); - qCDebug(entities) << " position:" << getPosition(); + qCDebug(entities) << " position:" << getWorldPosition(); qCDebug(entities) << " dimensions:" << getDimensions(); qCDebug(entities) << " model URL:" << getModelURL(); qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL(); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index b216144ded..05c0feca18 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -591,7 +591,7 @@ void ParticleEffectEntityItem::debugDump() const { _particleProperties.color.gradient.target.red << "," << _particleProperties.color.gradient.target.green << "," << _particleProperties.color.gradient.target.blue; - qCDebug(entities) << " position:" << debugTreeVector(getPosition()); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 7cd70fdb21..e69fb2e100 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -256,7 +256,7 @@ void PolyLineEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " QUAD EntityItem id:" << getEntityItemID() << "---------------------------------------------"; qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; - qCDebug(entities) << " position:" << debugTreeVector(getPosition()); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index e577a6c1a7..abcc075bcf 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -228,7 +228,7 @@ void PolyVoxEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeB void PolyVoxEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " POLYVOX EntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " position:" << debugTreeVector(getPosition()); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); } @@ -396,7 +396,7 @@ glm::mat4 PolyVoxEntityItem::voxelToLocalMatrix() const { glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units bool success; // TODO -- Does this actually have to happen in world space? glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes - glm::vec3 position = getPosition(success); + glm::vec3 position = getWorldPosition(success); glm::vec3 positionToCenter = center - position; positionToCenter -= dimensions * Vectors::HALF - getSurfacePositionAdjustment(); @@ -412,7 +412,7 @@ glm::mat4 PolyVoxEntityItem::localToVoxelMatrix() const { glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix() const { glm::mat4 rotation = glm::mat4_cast(getRotation()); - glm::mat4 translation = glm::translate(getPosition()); + glm::mat4 translation = glm::translate(getWorldPosition()); return translation * rotation * voxelToLocalMatrix(); } diff --git a/libraries/entities/src/ShapeEntityItem.cpp b/libraries/entities/src/ShapeEntityItem.cpp index 9a1a500a54..654fecb156 100644 --- a/libraries/entities/src/ShapeEntityItem.cpp +++ b/libraries/entities/src/ShapeEntityItem.cpp @@ -235,7 +235,7 @@ void ShapeEntityItem::debugDump() const { qCDebug(entities) << " shape:" << stringFromShape(_shape) << " (EnumId: " << _shape << " )"; qCDebug(entities) << " collisionShapeType:" << ShapeInfo::getNameForShapeType(getShapeType()); qCDebug(entities) << " color:" << _color[0] << "," << _color[1] << "," << _color[2]; - qCDebug(entities) << " position:" << debugTreeVector(getPosition()); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); qCDebug(entities) << "SHAPE EntityItem Ptr:" << this; diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 074691e1d4..0f113248f7 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -135,7 +135,7 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3 dimensions = getDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getRotation(); - glm::vec3 position = getPosition() + rotation * + glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); // FIXME - should set face and surfaceNormal diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index dd4bf518e0..91137431fe 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -112,7 +112,7 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g glm::vec3 dimensions = getDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); glm::quat rotation = getRotation(); - glm::vec3 position = getPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); + glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { surfaceNormal = rotation * Vectors::UNIT_Z; diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 588c1f9386..debe3eab61 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -241,7 +241,7 @@ void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBits void ZoneEntityItem::debugDump() const { quint64 now = usecTimestampNow(); qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------"; - qCDebug(entities) << " position:" << debugTreeVector(getPosition()); + qCDebug(entities) << " position:" << debugTreeVector(getWorldPosition()); qCDebug(entities) << " dimensions:" << debugTreeVector(getDimensions()); qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now); qCDebug(entities) << " _backgroundMode:" << EntityItemProperties::getBackgroundModeString(_backgroundMode); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 6884482074..be56bffb18 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -108,7 +108,7 @@ void EntityMotionState::handleDeactivation() { _entity->setLocalTransformAndVelocities(localTransform, ENTITY_ITEM_ZERO_VEC3, ENTITY_ITEM_ZERO_VEC3); // and also to RigidBody btTransform worldTrans; - worldTrans.setOrigin(glmToBullet(_entity->getPosition())); + worldTrans.setOrigin(glmToBullet(_entity->getWorldPosition())); worldTrans.setRotation(glmToBullet(_entity->getRotation())); _body->setWorldTransform(worldTrans); // no need to update velocities... should already be zero @@ -256,7 +256,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { assert(entityTreeIsLocked()); measureBodyAcceleration(); bool positionSuccess; - _entity->setPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); + _entity->setWorldPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); if (!positionSuccess) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform " diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 968f53700c..839309e60e 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -57,7 +57,7 @@ public: virtual float getObjectLinearDamping() const override { return _entity->getDamping(); } virtual float getObjectAngularDamping() const override { return _entity->getAngularDamping(); } - virtual glm::vec3 getObjectPosition() const override { return _entity->getPosition() - ObjectMotionState::getWorldOffset(); } + virtual glm::vec3 getObjectPosition() const override { return _entity->getWorldPosition() - ObjectMotionState::getWorldOffset(); } virtual glm::quat getObjectRotation() const override { return _entity->getRotation(); } virtual glm::vec3 getObjectLinearVelocity() const override { return _entity->getVelocity(); } virtual glm::vec3 getObjectAngularVelocity() const override { return _entity->getAngularVelocity(); } diff --git a/libraries/physics/src/ObjectActionTractor.cpp b/libraries/physics/src/ObjectActionTractor.cpp index 1a1790b0e0..6ab7daae7f 100644 --- a/libraries/physics/src/ObjectActionTractor.cpp +++ b/libraries/physics/src/ObjectActionTractor.cpp @@ -55,7 +55,7 @@ bool ObjectActionTractor::getTarget(float deltaTimeStep, glm::quat& rotation, gl if (!_otherID.isNull()) { if (other) { rotation = _desiredRotationalTarget * other->getRotation(); - position = other->getRotation() * _desiredPositionalTarget + other->getPosition(); + position = other->getRotation() * _desiredPositionalTarget + other->getWorldPosition(); } else { // we should have an "other" but can't find it, so disable the tractor. linearTimeScale = FLT_MAX; diff --git a/libraries/physics/src/PhysicalEntitySimulation.cpp b/libraries/physics/src/PhysicalEntitySimulation.cpp index b6f460cf39..3e87b9437d 100644 --- a/libraries/physics/src/PhysicalEntitySimulation.cpp +++ b/libraries/physics/src/PhysicalEntitySimulation.cpp @@ -223,7 +223,7 @@ void PhysicalEntitySimulation::getObjectsToAddToPhysics(VectorOfMotionStates& re if (numPoints > MAX_HULL_POINTS) { qWarning() << "convex hull with" << numPoints << "points for entity" << entity->getName() - << "at" << entity->getPosition() << " will be reduced"; + << "at" << entity->getWorldPosition() << " will be reduced"; } } btCollisionShape* shape = const_cast(ObjectMotionState::getShapeManager()->getShape(shapeInfo)); diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 8dbd2dd5e0..9713ce8a17 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -367,26 +367,26 @@ glm::vec3 SpatiallyNestable::localToWorldAngularVelocity(const glm::vec3& angula return parentTransform.getRotation() * angularVelocity; } -glm::vec3 SpatiallyNestable::getPosition(bool& success) const { +glm::vec3 SpatiallyNestable::getWorldPosition(bool& success) const { return getTransform(success).getTranslation(); } -glm::vec3 SpatiallyNestable::getPosition() const { +glm::vec3 SpatiallyNestable::getWorldPosition() const { bool success; - auto result = getPosition(success); + auto result = getWorldPosition(success); #ifdef WANT_DEBUG if (!success) { - qCDebug(shared) << "Warning -- getPosition failed" << getID(); + qCDebug(shared) << "Warning -- getWorldPosition failed" << getID(); } #endif return result; } -glm::vec3 SpatiallyNestable::getPosition(int jointIndex, bool& success) const { +glm::vec3 SpatiallyNestable::getWorldPosition(int jointIndex, bool& success) const { return getTransform(jointIndex, success).getTranslation(); } -void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success, bool tellPhysics) { +void SpatiallyNestable::setWorldPosition(const glm::vec3& position, bool& success, bool tellPhysics) { // guard against introducing NaN into the transform if (isNaN(position)) { success = false; @@ -410,12 +410,12 @@ void SpatiallyNestable::setPosition(const glm::vec3& position, bool& success, bo } } -void SpatiallyNestable::setPosition(const glm::vec3& position) { +void SpatiallyNestable::setWorldPosition(const glm::vec3& position) { bool success; - setPosition(position, success); + setWorldPosition(position, success); #ifdef WANT_DEBUG if (!success) { - qCDebug(shared) << "Warning -- setPosition failed" << getID(); + qCDebug(shared) << "Warning -- setWorldPosition failed" << getID(); } #endif } @@ -624,7 +624,7 @@ const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, i bool setPositionSuccess; AACube aaCube = getQueryAACube(setPositionSuccess); if (setPositionSuccess) { - _this->setPosition(aaCube.calcCenter()); + _this->setWorldPosition(aaCube.calcCenter()); } return jointInWorldFrame; } @@ -958,7 +958,7 @@ void SpatiallyNestable::locationChanged(bool tellPhysics) { } AACube SpatiallyNestable::getMaximumAACube(bool& success) const { - return AACube(getPosition(success) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize); + return AACube(getWorldPosition(success) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize); } const float PARENTED_EXPANSION_FACTOR = 3.0f; @@ -1044,7 +1044,7 @@ AACube SpatiallyNestable::getQueryAACube(bool& success) const { } success = false; bool getPositionSuccess; - return AACube(getPosition(getPositionSuccess) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize); + return AACube(getWorldPosition(getPositionSuccess) - glm::vec3(defaultAACubeSize / 2.0f), defaultAACubeSize); } AACube SpatiallyNestable::getQueryAACube() const { diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 37f6cfdfd9..6b082fed82 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -78,10 +78,10 @@ public: virtual Transform getParentTransform(bool& success, int depth = 0) const; - virtual glm::vec3 getPosition(bool& success) const; - virtual glm::vec3 getPosition() const; - virtual void setPosition(const glm::vec3& position, bool& success, bool tellPhysics = true); - virtual void setPosition(const glm::vec3& position); + virtual glm::vec3 getWorldPosition(bool& success) const; + virtual glm::vec3 getWorldPosition() const; + virtual void setWorldPosition(const glm::vec3& position, bool& success, bool tellPhysics = true); + virtual void setWorldPosition(const glm::vec3& position); virtual glm::quat getOrientation(bool& success) const; virtual glm::quat getOrientation() const; @@ -122,7 +122,7 @@ public: // get world-frame values for a specific joint virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const; - virtual glm::vec3 getPosition(int jointIndex, bool& success) const; + virtual glm::vec3 getWorldPosition(int jointIndex, bool& success) const; virtual glm::vec3 getSNScale(int jointIndex, bool& success) const; // object's parent's frame From f63db42c0e0da7953563d3f24be10293147e646e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sat, 28 Oct 2017 10:14:25 -0700 Subject: [PATCH 030/292] migrate SpatiallyNestable::getOrientation to getWorldOrientation, remove redundant getRotation --- interface/src/Application.cpp | 36 +++++------ interface/src/avatar/AvatarActionHold.cpp | 2 +- interface/src/avatar/AvatarMotionState.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 60 +++++++++---------- .../src/avatar/MyCharacterController.cpp | 2 +- interface/src/avatar/MyHead.cpp | 2 +- interface/src/raypick/JointRayPick.cpp | 2 +- interface/src/raypick/LaserPointer.cpp | 2 +- interface/src/ui/overlays/Base3DOverlay.cpp | 4 +- interface/src/ui/overlays/Billboardable.cpp | 2 +- interface/src/ui/overlays/Circle3DOverlay.cpp | 4 +- .../ui/overlays/ContextOverlayInterface.cpp | 2 +- interface/src/ui/overlays/Cube3DOverlay.cpp | 2 +- interface/src/ui/overlays/Grid3DOverlay.cpp | 2 +- interface/src/ui/overlays/ModelOverlay.cpp | 6 +- interface/src/ui/overlays/Overlays.cpp | 2 +- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- interface/src/ui/overlays/Planar3DOverlay.cpp | 2 +- .../src/ui/overlays/Rectangle3DOverlay.cpp | 2 +- interface/src/ui/overlays/Shape3DOverlay.cpp | 2 +- interface/src/ui/overlays/Volume3DOverlay.cpp | 2 +- interface/src/ui/overlays/Web3DOverlay.cpp | 2 +- .../src/avatars-renderer/Avatar.cpp | 12 ++-- .../src/avatars-renderer/Avatar.h | 4 +- .../src/avatars-renderer/Head.cpp | 2 +- .../src/avatars-renderer/SkeletonModel.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 28 ++++----- libraries/avatars/src/AvatarData.h | 2 +- libraries/avatars/src/HeadData.cpp | 12 ++-- libraries/avatars/src/ScriptAvatarData.cpp | 2 +- .../src/EntityTreeRenderer.cpp | 2 +- .../src/RenderableLightEntityItem.cpp | 2 +- .../src/RenderableModelEntityItem.cpp | 2 +- .../src/RenderablePolyLineEntityItem.cpp | 2 +- .../src/RenderablePolyVoxEntityItem.cpp | 2 +- .../src/RenderableShapeEntityItem.cpp | 2 +- .../src/RenderableZoneEntityItem.cpp | 4 +- libraries/entities/src/EntityItem.cpp | 8 +-- .../entities/src/EntityScriptingInterface.cpp | 4 +- libraries/entities/src/EntityTreeElement.cpp | 4 +- libraries/entities/src/PolyVoxEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.cpp | 2 +- libraries/entities/src/WebEntityItem.cpp | 2 +- libraries/physics/src/EntityMotionState.cpp | 6 +- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectActionTractor.cpp | 4 +- libraries/shared/src/SpatiallyNestable.cpp | 14 ++--- libraries/shared/src/SpatiallyNestable.h | 14 ++--- 48 files changed, 141 insertions(+), 145 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b1f461f227..41560d56f1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -967,7 +967,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // use our MyAvatar position and quat for address manager path addressManager->setPositionGetter([this]{ return getMyAvatar()->getWorldPosition(); }); - addressManager->setOrientationGetter([this]{ return getMyAvatar()->getOrientation(); }); + addressManager->setOrientationGetter([this]{ return getMyAvatar()->getWorldOrientation(); }); connect(addressManager.data(), &AddressManager::hostChanged, this, &Application::updateWindowTitle); connect(this, &QCoreApplication::aboutToQuit, addressManager.data(), &AddressManager::storeCurrentAddress); @@ -2400,7 +2400,7 @@ void Application::updateCamera(RenderArgs& renderArgs) { auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix(); _myCamera.setOrientation(glm::normalize(glmExtractRotation(hmdWorldMat))); _myCamera.setPosition(extractTranslation(hmdWorldMat) + - myAvatar->getOrientation() * boomOffset); + myAvatar->getWorldOrientation() * boomOffset); } else { _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); @@ -2410,13 +2410,13 @@ void Application::updateCamera(RenderArgs& renderArgs) { } else { _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + myAvatar->getOrientation() * boomOffset); + + myAvatar->getWorldOrientation() * boomOffset); } } } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { if (isHMDMode()) { - auto mirrorBodyOrientation = myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)); + auto mirrorBodyOrientation = myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)); glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); // Mirror HMD yaw and roll @@ -2439,11 +2439,11 @@ void Application::updateCamera(RenderArgs& renderArgs) { + mirrorBodyOrientation * hmdOffset); } else { - _myCamera.setOrientation(myAvatar->getOrientation() + _myCamera.setOrientation(myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() + glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0) - + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * + + (myAvatar->getWorldOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); } renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE; @@ -2453,12 +2453,12 @@ void Application::updateCamera(RenderArgs& renderArgs) { if (cameraEntity != nullptr) { if (isHMDMode()) { glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix()); - _myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation); + _myCamera.setOrientation(cameraEntity->getWorldOrientation() * hmdRotation); glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix()); _myCamera.setPosition(cameraEntity->getWorldPosition() + (hmdRotation * hmdOffset)); } else { - _myCamera.setOrientation(cameraEntity->getRotation()); + _myCamera.setOrientation(cameraEntity->getWorldOrientation()); _myCamera.setPosition(cameraEntity->getWorldPosition()); } } @@ -3870,7 +3870,7 @@ void Application::idle() { if (!_keyboardFocusedEntity.get().isInvalidID()) { auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get()); if (entity && _keyboardFocusHighlight) { - _keyboardFocusHighlight->setRotation(entity->getRotation()); + _keyboardFocusHighlight->setWorldOrientation(entity->getWorldOrientation()); _keyboardFocusHighlight->setWorldPosition(entity->getWorldPosition()); } } else { @@ -3878,7 +3878,7 @@ void Application::idle() { auto overlay = std::dynamic_pointer_cast(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); if (overlay && _keyboardFocusHighlight) { - _keyboardFocusHighlight->setRotation(overlay->getRotation()); + _keyboardFocusHighlight->setWorldOrientation(overlay->getWorldOrientation()); _keyboardFocusHighlight->setWorldPosition(overlay->getWorldPosition()); } } @@ -4293,7 +4293,7 @@ void Application::updateMyAvatarLookAtPosition() { // TODO -- this code is probably wrong, getHeadPose() returns something in sensor frame, not avatar glm::mat4 headPose = getActiveDisplayPlugin()->getHeadPose(); glm::quat hmdRotation = glm::quat_cast(headPose); - lookAtSpot = _myCamera.getPosition() + myAvatar->getOrientation() * (hmdRotation * lookAtPosition); + lookAtSpot = _myCamera.getPosition() + myAvatar->getWorldOrientation() * (hmdRotation * lookAtPosition); } else { lookAtSpot = myAvatar->getHead()->getEyePosition() + (myAvatar->getHead()->getFinalOrientationInWorldFrame() * lookAtPosition); @@ -4519,7 +4519,7 @@ void Application::setKeyboardFocusHighlight(const glm::vec3& position, const glm } // Position focus - _keyboardFocusHighlight->setRotation(rotation); + _keyboardFocusHighlight->setWorldOrientation(rotation); _keyboardFocusHighlight->setWorldPosition(position); _keyboardFocusHighlight->setDimensions(dimensions); _keyboardFocusHighlight->setVisible(true); @@ -4557,7 +4557,7 @@ void Application::setKeyboardFocusEntity(const EntityItemID& entityItemID) { } _lastAcceptedKeyPress = usecTimestampNow(); - setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getRotation(), + setKeyboardFocusHighlight(entity->getWorldPosition(), entity->getWorldOrientation(), entity->getDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR); } } @@ -4594,7 +4594,7 @@ void Application::setKeyboardFocusOverlay(const OverlayID& overlayID) { if (overlay->getProperty("showKeyboardFocusHighlight").toBool()) { auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR; const float OVERLAY_DEPTH = 0.0105f; - setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getRotation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH)); + setKeyboardFocusHighlight(overlay->getWorldPosition(), overlay->getWorldOrientation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH)); } else if (_keyboardFocusHighlight) { _keyboardFocusHighlight->setVisible(false); } @@ -4686,7 +4686,7 @@ void Application::update(float deltaTime) { controller::InputCalibrationData calibrationData = { myAvatar->getSensorToWorldMatrix(), - createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getWorldPosition()), + createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()), myAvatar->getHMDSensorMatrix(), myAvatar->getCenterEyeCalibrationMat(), myAvatar->getHeadCalibrationMat(), @@ -4796,7 +4796,7 @@ void Application::update(float deltaTime) { }; // copy controller poses from userInputMapper to myAvatar. - glm::mat4 myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getWorldPosition()); + glm::mat4 myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getWorldOrientation(), myAvatar->getWorldPosition()); glm::mat4 worldToSensorMatrix = glm::inverse(myAvatar->getSensorToWorldMatrix()); glm::mat4 avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix; for (auto& action : avatarControllerActions) { @@ -6437,9 +6437,9 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar. properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions. - glm::vec3 positionOffset = getMyAvatar()->getOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); + glm::vec3 positionOffset = getMyAvatar()->getWorldOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); properties.setPosition(getMyAvatar()->getWorldPosition() + positionOffset); - properties.setRotation(getMyAvatar()->getOrientation()); + properties.setRotation(getMyAvatar()->getWorldOrientation()); properties.setGravity(glm::vec3(0.0f, 0.0f, 0.0f)); auto entityID = DependencyManager::get()->addEntity(properties); diff --git a/interface/src/avatar/AvatarActionHold.cpp b/interface/src/avatar/AvatarActionHold.cpp index 668994883d..66184513da 100644 --- a/interface/src/avatar/AvatarActionHold.cpp +++ b/interface/src/avatar/AvatarActionHold.cpp @@ -531,5 +531,5 @@ void AvatarActionHold::lateAvatarUpdate(const AnimPose& prePhysicsRoomPose, cons bool positionSuccess; ownerEntity->setWorldPosition(bulletToGLM(worldTrans.getOrigin()) + ObjectMotionState::getWorldOffset(), positionSuccess, false); bool orientationSuccess; - ownerEntity->setOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); + ownerEntity->setWorldOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); } diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 01cfb93333..4f6f2b0b71 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -111,7 +111,7 @@ glm::vec3 AvatarMotionState::getObjectPosition() const { // virtual glm::quat AvatarMotionState::getObjectRotation() const { - return _avatar->getOrientation(); + return _avatar->getWorldOrientation(); } // virtual diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9458789685..c7af0fa77e 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -197,7 +197,7 @@ MyAvatar::MyAvatar(QThread* thread) : } setWorldPosition(dummyAvatar.getWorldPosition()); - setOrientation(dummyAvatar.getOrientation()); + setWorldOrientation(dummyAvatar.getWorldOrientation()); if (!dummyAvatar.getAttachmentData().isEmpty()) { setAttachmentData(dummyAvatar.getAttachmentData()); @@ -250,11 +250,11 @@ void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) { } void MyAvatar::setOrientationVar(const QVariant& newOrientationVar) { - Avatar::setOrientation(quatFromVariant(newOrientationVar)); + Avatar::setWorldOrientation(quatFromVariant(newOrientationVar)); } QVariant MyAvatar::getOrientationVar() const { - return quatToVariant(Avatar::getOrientation()); + return quatToVariant(Avatar::getWorldOrientation()); } glm::quat MyAvatar::getOrientationOutbound() const { @@ -329,7 +329,7 @@ void MyAvatar::centerBody() { // this will become our new position. setWorldPosition(worldBodyPos); - setOrientation(worldBodyRot); + setWorldOrientation(worldBodyRot); // reset the body in sensor space _bodySensorMatrix = newBodySensorMatrix; @@ -373,7 +373,7 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) { // this will become our new position. setWorldPosition(worldBodyPos); - setOrientation(worldBodyRot); + setWorldOrientation(worldBodyRot); // now sample the new hmd orientation AFTER sensor reset, which should be identity. glm::mat4 identity; @@ -411,7 +411,7 @@ void MyAvatar::update(float deltaTime) { if (_goToPending) { setWorldPosition(_goToPosition); - setOrientation(_goToOrientation); + setWorldOrientation(_goToOrientation); _headControllerFacingMovingAverage = _headControllerFacing; // reset moving average _goToPending = false; // updateFromHMDSensorMatrix (called from paintGL) expects that the sensorToWorldMatrix is updated for any position changes @@ -666,7 +666,7 @@ void MyAvatar::updateSensorToWorldMatrix() { // update the sensor mat so that the body position will end up in the desired // position when driven from the head. float sensorToWorldScale = getEyeHeight() / getUserEyeHeight(); - glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getOrientation(), getWorldPosition()); + glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getWorldOrientation(), getWorldPosition()); _sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix); lateUpdatePalms(); @@ -784,7 +784,7 @@ controller::Pose MyAvatar::getRightHandTipPose() const { glm::vec3 MyAvatar::worldToJointPoint(const glm::vec3& position, const int jointIndex) const { glm::vec3 jointPos = getWorldPosition();//default value if no or invalid joint specified - glm::quat jointRot = getRotation();//default value if no or invalid joint specified + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified if (jointIndex != -1) { if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { _skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot); @@ -799,7 +799,7 @@ glm::vec3 MyAvatar::worldToJointPoint(const glm::vec3& position, const int joint } glm::vec3 MyAvatar::worldToJointDirection(const glm::vec3& worldDir, const int jointIndex) const { - glm::quat jointRot = getRotation();//default value if no or invalid joint specified + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { qWarning() << "Invalid joint index specified: " << jointIndex; } @@ -809,7 +809,7 @@ glm::vec3 MyAvatar::worldToJointDirection(const glm::vec3& worldDir, const int j } glm::quat MyAvatar::worldToJointRotation(const glm::quat& worldRot, const int jointIndex) const { - glm::quat jointRot = getRotation();//default value if no or invalid joint specified + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { qWarning() << "Invalid joint index specified: " << jointIndex; } @@ -819,7 +819,7 @@ glm::quat MyAvatar::worldToJointRotation(const glm::quat& worldRot, const int jo glm::vec3 MyAvatar::jointToWorldPoint(const glm::vec3& jointSpacePos, const int jointIndex) const { glm::vec3 jointPos = getWorldPosition();//default value if no or invalid joint specified - glm::quat jointRot = getRotation();//default value if no or invalid joint specified + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified if (jointIndex != -1) { if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPos)) { @@ -836,7 +836,7 @@ glm::vec3 MyAvatar::jointToWorldPoint(const glm::vec3& jointSpacePos, const int } glm::vec3 MyAvatar::jointToWorldDirection(const glm::vec3& jointSpaceDir, const int jointIndex) const { - glm::quat jointRot = getRotation();//default value if no or invalid joint specified + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { qWarning() << "Invalid joint index specified: " << jointIndex; } @@ -845,7 +845,7 @@ glm::vec3 MyAvatar::jointToWorldDirection(const glm::vec3& jointSpaceDir, const } glm::quat MyAvatar::jointToWorldRotation(const glm::quat& jointSpaceRot, const int jointIndex) const { - glm::quat jointRot = getRotation();//default value if no or invalid joint specified + glm::quat jointRot = getWorldOrientation();//default value if no or invalid joint specified if ((jointIndex != -1) && (!_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRot))) { qWarning() << "Invalid joint index specified: " << jointIndex; } @@ -1301,7 +1301,7 @@ eyeContactTarget MyAvatar::getEyeContactTarget() { } glm::vec3 MyAvatar::getDefaultEyePosition() const { - return getWorldPosition() + getOrientation() * Quaternions::Y_180 * _skeletonModel->getDefaultEyeModelPosition(); + return getWorldPosition() + getWorldOrientation() * Quaternions::Y_180 * _skeletonModel->getDefaultEyeModelPosition(); } const float SCRIPT_PRIORITY = 1.0f + 1.0f; @@ -1460,7 +1460,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - return getWorldPosition() + getOrientation() * FLIP * _skeletonOffset; + return getWorldPosition() + getWorldOrientation() * FLIP * _skeletonOffset; } return Avatar::getWorldPosition(); } @@ -1508,7 +1508,7 @@ controller::Pose MyAvatar::getControllerPoseInWorldFrame(controller::Action acti controller::Pose MyAvatar::getControllerPoseInAvatarFrame(controller::Action action) const { auto pose = getControllerPoseInWorldFrame(action); if (pose.valid) { - glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getOrientation(), getWorldPosition())); + glm::mat4 invAvatarMatrix = glm::inverse(createMatFromQuatAndPos(getWorldOrientation(), getWorldPosition())); return pose.transform(invAvatarMatrix); } else { return controller::Pose(); // invalid pose @@ -1527,7 +1527,7 @@ void MyAvatar::updateMotors() { // we decompose camera's rotation and store the twist part in motorRotation // however, we need to perform the decomposition in the avatar-frame // using the local UP axis and then transform back into world-frame - glm::quat orientation = getOrientation(); + glm::quat orientation = getWorldOrientation(); glm::quat headOrientation = glm::inverse(orientation) * getMyHead()->getHeadOrientation(); // avatar-frame glm::quat liftRotation; swingTwistDecomposition(headOrientation, Vectors::UNIT_Y, liftRotation, motorRotation); @@ -1547,7 +1547,7 @@ void MyAvatar::updateMotors() { if (_scriptedMotorFrame == SCRIPTED_MOTOR_CAMERA_FRAME) { motorRotation = getMyHead()->getHeadOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y); } else if (_scriptedMotorFrame == SCRIPTED_MOTOR_AVATAR_FRAME) { - motorRotation = getOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y); + motorRotation = getWorldOrientation() * glm::angleAxis(PI, Vectors::UNIT_Y); } else { // world-frame motorRotation = glm::quat(); @@ -1575,7 +1575,7 @@ void MyAvatar::prepareForPhysicsSimulation() { _characterController.setParentVelocity(parentVelocity); _characterController.setScaleFactor(getSensorToWorldScale()); - _characterController.setPositionAndOrientation(getWorldPosition(), getOrientation()); + _characterController.setPositionAndOrientation(getWorldPosition(), getWorldOrientation()); auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD); if (headPose.isValid()) { _follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput()); @@ -1610,7 +1610,7 @@ void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { _characterController.getPositionAndOrientation(position, orientation); } else { position = getWorldPosition(); - orientation = getOrientation(); + orientation = getWorldOrientation(); } nextAttitude(position, orientation); _bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix); @@ -1847,14 +1847,14 @@ void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) { } DebugDraw::getInstance().updateMyAvatarPos(getWorldPosition()); - DebugDraw::getInstance().updateMyAvatarRot(getOrientation()); + DebugDraw::getInstance().updateMyAvatarRot(getWorldOrientation()); AnimPose postUpdateRoomPose(_sensorToWorldMatrix); updateHoldActions(_prePhysicsRoomPose, postUpdateRoomPose); if (_enableDebugDrawDetailedCollision) { - AnimPose rigToWorldPose(glm::vec3(1.0f), getRotation() * Quaternions::Y_180, getWorldPosition()); + AnimPose rigToWorldPose(glm::vec3(1.0f), getWorldOrientation() * Quaternions::Y_180, getWorldPosition()); const int NUM_DEBUG_COLORS = 8; const glm::vec4 DEBUG_COLORS[NUM_DEBUG_COLORS] = { glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), @@ -1972,7 +1972,7 @@ void MyAvatar::updateOrientation(float deltaTime) { speedFactor = glm::min(speed / _lastDrivenSpeed, 1.0f); } - float direction = glm::dot(getVelocity(), getRotation() * Vectors::UNIT_NEG_Z) > 0.0f ? 1.0f : -1.0f; + float direction = glm::dot(getVelocity(), getWorldOrientation() * Vectors::UNIT_NEG_Z) > 0.0f ? 1.0f : -1.0f; float rollAngle = glm::degrees(asinf(glm::dot(IDENTITY_UP, _hmdSensorOrientation * IDENTITY_RIGHT))); float rollSign = rollAngle < 0.0f ? -1.0f : 1.0f; @@ -1985,12 +1985,12 @@ void MyAvatar::updateOrientation(float deltaTime) { // update body orientation by movement inputs glm::quat initialOrientation = getOrientationOutbound(); - setOrientation(getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)))); + setWorldOrientation(getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, totalBodyYaw, 0.0f)))); if (snapTurn) { // Whether or not there is an existing smoothing going on, just reset the smoothing timer and set the starting position as the avatar's current position, then smooth to the new position. _smoothOrientationInitial = initialOrientation; - _smoothOrientationTarget = getOrientation(); + _smoothOrientationTarget = getWorldOrientation(); _smoothOrientationTimer = 0.0f; } @@ -2107,7 +2107,7 @@ void MyAvatar::updatePosition(float deltaTime) { // scan for walkability glm::vec3 position = getWorldPosition(); MyCharacterController::RayShotgunResult result; - glm::vec3 step = deltaTime * (getRotation() * _actionMotorVelocity); + glm::vec3 step = deltaTime * (getWorldOrientation() * _actionMotorVelocity); _characterController.testRayShotgun(position, step, result); _characterController.setStepUpEnabled(result.walkable); } @@ -2325,7 +2325,7 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition, _goToPending = true; _goToPosition = newPosition; - _goToOrientation = getOrientation(); + _goToOrientation = getWorldOrientation(); if (hasOrientation) { qCDebug(interfaceapp).nospace() << "MyAvatar goToLocation - new orientation is " << newOrientation.x << ", " << newOrientation.y << ", " << newOrientation.z << ", " << newOrientation.w; @@ -2394,7 +2394,7 @@ bool MyAvatar::requiresSafeLanding(const glm::vec3& positionIn, glm::vec3& bette return false; // no entity tree } // More utilities. - const auto offset = getOrientation() *_characterController.getCapsuleLocalOffset(); + const auto offset = getWorldOrientation() *_characterController.getCapsuleLocalOffset(); const auto capsuleCenter = positionIn + offset; const auto up = _worldUpDirection, down = -up; glm::vec3 upperIntersection, upperNormal, lowerIntersection, lowerNormal; @@ -2960,7 +2960,7 @@ glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& c glm::mat4 controllerWorldMatrix = getSensorToWorldMatrix() * delta * controllerSensorMatrix; // transform controller into avatar space - glm::mat4 avatarMatrix = createMatFromQuatAndPos(getOrientation(), getWorldPosition()); + glm::mat4 avatarMatrix = createMatFromQuatAndPos(getWorldOrientation(), getWorldPosition()); return glm::inverse(avatarMatrix) * controllerWorldMatrix; } @@ -3164,7 +3164,7 @@ bool MyAvatar::pinJoint(int index, const glm::vec3& position, const glm::quat& o } slamPosition(position); - setOrientation(orientation); + setWorldOrientation(orientation); _skeletonModel->getRig().setMaxHipsOffsetLength(0.05f); diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index 57b5e96ee5..7e38c7763a 100755 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -64,7 +64,7 @@ void MyCharacterController::updateShapeIfNecessary() { _rigidBody->setSleepingThresholds(0.0f, 0.0f); _rigidBody->setAngularFactor(0.0f); - _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getOrientation()), + _rigidBody->setWorldTransform(btTransform(glmToBullet(_avatar->getWorldOrientation()), glmToBullet(_avatar->getWorldPosition()))); _rigidBody->setDamping(0.0f, 0.0f); if (_state == State::Hover) { diff --git a/interface/src/avatar/MyHead.cpp b/interface/src/avatar/MyHead.cpp index 7fc1850bb2..cad2f9e5d0 100644 --- a/interface/src/avatar/MyHead.cpp +++ b/interface/src/avatar/MyHead.cpp @@ -39,7 +39,7 @@ glm::quat MyHead::getHeadOrientation() const { return headPose.rotation * Quaternions::Y_180; } - return myAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.0f, 0.0f))); + return myAvatar->getWorldOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.0f, 0.0f))); } void MyHead::simulate(float deltaTime) { diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index fc0ecf94e5..5cecc56ae3 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -29,7 +29,7 @@ const PickRay JointRayPick::getPickRay(bool& valid) const { glm::vec3 jointPos = useAvatarHead ? myAvatar->getHeadPosition() : myAvatar->getAbsoluteJointTranslationInObjectFrame(jointIndex); glm::quat jointRot = useAvatarHead ? myAvatar->getHeadOrientation() : myAvatar->getAbsoluteJointRotationInObjectFrame(jointIndex); glm::vec3 avatarPos = myAvatar->getWorldPosition(); - glm::quat avatarRot = myAvatar->getOrientation(); + glm::quat avatarRot = myAvatar->getWorldOrientation(); glm::vec3 pos = useAvatarHead ? jointPos : avatarPos + (avatarRot * jointPos); glm::quat rot = useAvatarHead ? jointRot * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT) : avatarRot * jointRot; diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 75b43a251b..f7da2de7f7 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -162,7 +162,7 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter } if (!renderState.getEndID().isNull()) { QVariantMap endProps; - glm::quat faceAvatarRotation = DependencyManager::get()->getMyAvatar()->getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f))); + glm::quat faceAvatarRotation = DependencyManager::get()->getMyAvatar()->getWorldOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f))); glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value); if (_distanceScaleEnd) { dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec) * DependencyManager::get()->getMyAvatar()->getSensorToWorldScale(); diff --git a/interface/src/ui/overlays/Base3DOverlay.cpp b/interface/src/ui/overlays/Base3DOverlay.cpp index 457f06aaa2..6bfd55736b 100644 --- a/interface/src/ui/overlays/Base3DOverlay.cpp +++ b/interface/src/ui/overlays/Base3DOverlay.cpp @@ -117,7 +117,7 @@ void Base3DOverlay::setProperties(const QVariantMap& originalProperties) { properties["position"] = vec3toVariant(getWorldPosition()); } if (!properties["orientation"].isValid() && !properties["localOrientation"].isValid()) { - properties["orientation"] = quatToVariant(getOrientation()); + properties["orientation"] = quatToVariant(getWorldOrientation()); } } @@ -220,7 +220,7 @@ QVariant Base3DOverlay::getProperty(const QString& property) { return vec3toVariant(getLocalPosition()); } if (property == "rotation" || property == "orientation") { - return quatToVariant(getOrientation()); + return quatToVariant(getWorldOrientation()); } if (property == "localRotation" || property == "localOrientation") { return quatToVariant(getLocalOrientation()); diff --git a/interface/src/ui/overlays/Billboardable.cpp b/interface/src/ui/overlays/Billboardable.cpp index 892a9d998d..4062abb48f 100644 --- a/interface/src/ui/overlays/Billboardable.cpp +++ b/interface/src/ui/overlays/Billboardable.cpp @@ -35,7 +35,7 @@ bool Billboardable::pointTransformAtCamera(Transform& transform, glm::quat offse glm::vec3 billboardPos = transform.getTranslation(); glm::vec3 cameraPos = qApp->getCamera().getPosition(); // use the referencial from the avatar, y isn't always up - glm::vec3 avatarUP = DependencyManager::get()->getMyAvatar()->getOrientation()*Vectors::UP; + glm::vec3 avatarUP = DependencyManager::get()->getMyAvatar()->getWorldOrientation()*Vectors::UP; glm::quat rotation(conjugate(toQuat(glm::lookAt(billboardPos, cameraPos, avatarUP)))); diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index 88172950ee..9ea402b084 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -415,11 +415,11 @@ bool Circle3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve // Scale the dimensions by the diameter glm::vec2 dimensions = getOuterRadius() * 2.0f * getDimensions(); - bool intersects = findRayRectangleIntersection(origin, direction, getRotation(), getWorldPosition(), dimensions, distance); + bool intersects = findRayRectangleIntersection(origin, direction, getWorldOrientation(), getWorldPosition(), dimensions, distance); if (intersects) { glm::vec3 hitPosition = origin + (distance * direction); - glm::vec3 localHitPosition = glm::inverse(getRotation()) * (hitPosition - getWorldPosition()); + glm::vec3 localHitPosition = glm::inverse(getWorldOrientation()) * (hitPosition - getWorldPosition()); localHitPosition.x /= getDimensions().x; localHitPosition.y /= getDimensions().y; float distanceToHit = glm::length(localHitPosition); diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index ccbf9fb1b2..1f3d582b78 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -163,7 +163,7 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& } _contextOverlay->setWorldPosition(contextOverlayPosition); _contextOverlay->setDimensions(contextOverlayDimensions); - _contextOverlay->setRotation(entityProperties.getRotation()); + _contextOverlay->setWorldOrientation(entityProperties.getRotation()); _contextOverlay->setVisible(true); return true; diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index d95b8c7761..92eebe5556 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -146,7 +146,7 @@ Transform Cube3DOverlay::evalRenderTransform() { // TODO: handle registration point?? glm::vec3 position = getWorldPosition(); glm::vec3 dimensions = getDimensions(); - glm::quat rotation = getRotation(); + glm::quat rotation = getWorldOrientation(); Transform transform; transform.setScale(dimensions); diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index afce710d08..dd0f055f3f 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -146,7 +146,7 @@ void Grid3DOverlay::updateGrid() { Transform Grid3DOverlay::evalRenderTransform() { Transform transform; - transform.setRotation(getRotation()); + transform.setRotation(getWorldOrientation()); transform.setScale(glm::vec3(getDimensions(), 1.0f)); return transform; } diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index eedacd2d67..17dbe9850e 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -122,7 +122,7 @@ void ModelOverlay::setDrawHUDLayer(bool drawHUDLayer) { void ModelOverlay::setProperties(const QVariantMap& properties) { auto origPosition = getWorldPosition(); - auto origRotation = getRotation(); + auto origRotation = getWorldOrientation(); auto origDimensions = getDimensions(); auto origScale = getSNScale(); @@ -143,7 +143,7 @@ void ModelOverlay::setProperties(const QVariantMap& properties) { _scaleToFit = false; } - if (origPosition != getWorldPosition() || origRotation != getRotation() || origDimensions != getDimensions() || origScale != getSNScale()) { + if (origPosition != getWorldPosition() || origRotation != getWorldOrientation() || origDimensions != getDimensions() || origScale != getSNScale()) { _updateModel = true; } @@ -383,7 +383,7 @@ void ModelOverlay::locationChanged(bool tellPhysics) { // FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform() if (_model && _model->isActive()) { - _model->setRotation(getRotation()); + _model->setRotation(getWorldOrientation()); _model->setTranslation(getWorldPosition()); } } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index ca79d0b663..a20bb1d1c1 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -828,7 +828,7 @@ PointerEvent Overlays::calculateOverlayPointerEvent(OverlayID overlayID, PickRay return PointerEvent(); } glm::vec3 position = overlay->getWorldPosition(); - glm::quat rotation = overlay->getRotation(); + glm::quat rotation = overlay->getWorldOrientation(); glm::vec2 dimensions = overlay->getSize(); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 40d70d5348..8d3e514a0f 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -68,7 +68,7 @@ namespace render { if (overlay->getAnchor() == Overlay::MY_AVATAR) { auto batch = args->_batch; auto avatar = DependencyManager::get()->getMyAvatar(); - glm::quat myAvatarRotation = avatar->getOrientation(); + glm::quat myAvatarRotation = avatar->getWorldOrientation(); glm::vec3 myAvatarPosition = avatar->getWorldPosition(); float angle = glm::degrees(glm::angle(myAvatarRotation)); glm::vec3 axis = glm::axis(myAvatarRotation); diff --git a/interface/src/ui/overlays/Planar3DOverlay.cpp b/interface/src/ui/overlays/Planar3DOverlay.cpp index ae5e0f32d0..2cbaf31ff1 100644 --- a/interface/src/ui/overlays/Planar3DOverlay.cpp +++ b/interface/src/ui/overlays/Planar3DOverlay.cpp @@ -69,7 +69,7 @@ QVariant Planar3DOverlay::getProperty(const QString& property) { bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face, glm::vec3& surfaceNormal) { // FIXME - face and surfaceNormal not being returned - return findRayRectangleIntersection(origin, direction, getRotation(), getWorldPosition(), getDimensions(), distance); + return findRayRectangleIntersection(origin, direction, getWorldOrientation(), getWorldPosition(), getDimensions(), distance); } Transform Planar3DOverlay::evalRenderTransform() { diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.cpp b/interface/src/ui/overlays/Rectangle3DOverlay.cpp index 2010b00d4d..8468670637 100644 --- a/interface/src/ui/overlays/Rectangle3DOverlay.cpp +++ b/interface/src/ui/overlays/Rectangle3DOverlay.cpp @@ -61,7 +61,7 @@ void Rectangle3DOverlay::render(RenderArgs* args) { glm::vec3 position = getWorldPosition(); glm::vec2 dimensions = getDimensions(); glm::vec2 halfDimensions = dimensions * 0.5f; - glm::quat rotation = getRotation(); + glm::quat rotation = getWorldOrientation(); auto batch = args->_batch; diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp index 7e9f44ef1d..73bb701ea7 100644 --- a/interface/src/ui/overlays/Shape3DOverlay.cpp +++ b/interface/src/ui/overlays/Shape3DOverlay.cpp @@ -123,7 +123,7 @@ Transform Shape3DOverlay::evalRenderTransform() { // TODO: handle registration point?? glm::vec3 position = getWorldPosition(); glm::vec3 dimensions = getDimensions(); - glm::quat rotation = getRotation(); + glm::quat rotation = getWorldOrientation(); Transform transform; transform.setScale(dimensions); diff --git a/interface/src/ui/overlays/Volume3DOverlay.cpp b/interface/src/ui/overlays/Volume3DOverlay.cpp index 4e685bed0e..2bbbda151f 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.cpp +++ b/interface/src/ui/overlays/Volume3DOverlay.cpp @@ -20,7 +20,7 @@ Volume3DOverlay::Volume3DOverlay(const Volume3DOverlay* volume3DOverlay) : AABox Volume3DOverlay::getBounds() const { auto extents = Extents{_localBoundingBox}; - extents.rotate(getRotation()); + extents.rotate(getWorldOrientation()); extents.shiftBy(getWorldPosition()); return AABox(extents); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 5d8e433615..6d87bc8994 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -615,7 +615,7 @@ bool Web3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3& // Don't call applyTransformTo() or setTransform() here because this code runs too frequently. // Produce the dimensions of the overlay based on the image's aspect ratio and the overlay's scale. - return findRayRectangleIntersection(origin, direction, getRotation(), getWorldPosition(), getSize(), distance); + return findRayRectangleIntersection(origin, direction, getWorldOrientation(), getWorldPosition(), getSize(), distance); } Web3DOverlay* Web3DOverlay::createClone() const { diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 67efeda90d..60c88d435a 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -456,11 +456,11 @@ void Avatar::measureMotionDerivatives(float deltaTime) { setVelocity(velocity); // angular - glm::quat orientation = getOrientation(); + glm::quat orientation = getWorldOrientation(); glm::quat delta = glm::inverse(_lastOrientation) * orientation; glm::vec3 angularVelocity = glm::axis(delta) * glm::angle(delta) * invDeltaTime; setAngularVelocity(angularVelocity); - _lastOrientation = getOrientation(); + _lastOrientation = getWorldOrientation(); } enum TextRendererType { @@ -722,7 +722,7 @@ void Avatar::simulateAttachments(float deltaTime) { if (attachment.isSoft) { // soft attachments do not have transform offsets model->setTranslation(getWorldPosition()); - model->setRotation(getOrientation() * Quaternions::Y_180); + model->setRotation(getWorldOrientation() * Quaternions::Y_180); model->simulate(deltaTime); } else { if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPosition) && @@ -902,7 +902,7 @@ glm::vec3 Avatar::getSkeletonPosition() const { // The avatar is rotated PI about the yAxis, so we have to correct for it // to get the skeleton offset contribution in the world-frame. const glm::quat FLIP = glm::angleAxis(PI, glm::vec3(0.0f, 1.0f, 0.0f)); - return getWorldPosition() + getOrientation() * FLIP * _skeletonOffset; + return getWorldPosition() + getWorldOrientation() * FLIP * _skeletonOffset; } QVector Avatar::getJointRotations() const { @@ -1473,11 +1473,11 @@ glm::quat Avatar::getUncachedRightPalmRotation() const { void Avatar::setPositionViaScript(const glm::vec3& position) { setWorldPosition(position); - updateAttitude(getOrientation()); + updateAttitude(getWorldOrientation()); } void Avatar::setOrientationViaScript(const glm::quat& orientation) { - setOrientation(orientation); + setWorldOrientation(orientation); updateAttitude(orientation); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index a5ec307c50..1bebcd5c71 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -318,8 +318,8 @@ protected: void fade(render::Transaction& transaction, render::Transition::Type type); - glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } - glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } + glm::vec3 getBodyRightDirection() const { return getWorldOrientation() * IDENTITY_RIGHT; } + glm::vec3 getBodyUpDirection() const { return getWorldOrientation() * IDENTITY_UP; } void measureMotionDerivatives(float deltaTime); float getSkeletonHeight() const; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Head.cpp b/libraries/avatars-renderer/src/avatars-renderer/Head.cpp index b8a559027b..256b3bf8a6 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Head.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Head.cpp @@ -253,7 +253,7 @@ void Head::setScale (float scale) { } glm::quat Head::getFinalOrientationInWorldFrame() const { - return _owningAvatar->getOrientation() * getFinalOrientationInLocalFrame(); + return _owningAvatar->getWorldOrientation() * getFinalOrientationInLocalFrame(); } glm::quat Head::getFinalOrientationInLocalFrame() const { diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp index eaa62ecb0a..04b865fa03 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp @@ -127,7 +127,7 @@ void SkeletonModel::updateAttitude(const glm::quat& orientation) { // Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed), // but just before head has been simulated. void SkeletonModel::simulate(float deltaTime, bool fullUpdate) { - updateAttitude(_owningAvatar->getOrientation()); + updateAttitude(_owningAvatar->getWorldOrientation()); if (fullUpdate) { setBlendshapeCoefficients(_owningAvatar->getHead()->getSummedBlendshapeCoefficients()); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 2fe62a4ca2..27c19d4a21 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -118,12 +118,12 @@ void AvatarData::setTargetScale(float targetScale) { } glm::vec3 AvatarData::getHandPosition() const { - return getOrientation() * _handPosition + getWorldPosition(); + return getWorldOrientation() * _handPosition + getWorldPosition(); } void AvatarData::setHandPosition(const glm::vec3& handPosition) { // store relative to position/orientation - _handPosition = glm::inverse(getOrientation()) * (handPosition - getWorldPosition()); + _handPosition = glm::inverse(getWorldOrientation()) * (handPosition - getWorldPosition()); } void AvatarData::lazyInitHeadData() const { @@ -1900,7 +1900,7 @@ void registerAvatarTypes(QScriptEngine* engine) { void AvatarData::setRecordingBasis(std::shared_ptr recordingBasis) { if (!recordingBasis) { recordingBasis = std::make_shared(); - recordingBasis->setRotation(getOrientation()); + recordingBasis->setRotation(getWorldOrientation()); recordingBasis->setTranslation(getWorldPosition()); // TODO: find a different way to record/playback the Scale of the avatar //recordingBasis->setScale(getTargetScale()); @@ -2066,7 +2066,7 @@ void AvatarData::fromJson(const QJsonObject& json, bool useFrameSkeleton) { setWorldPosition(currentBasis->getTranslation()); orientation = currentBasis->getRotation(); } - setOrientation(orientation); + setWorldOrientation(orientation); updateAttitude(orientation); // Do after avatar orientation because head look-at needs avatar orientation. @@ -2153,36 +2153,36 @@ void AvatarData::fromFrame(const QByteArray& frameData, AvatarData& result, bool } float AvatarData::getBodyYaw() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getWorldOrientation())); return eulerAngles.y; } void AvatarData::setBodyYaw(float bodyYaw) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getWorldOrientation())); eulerAngles.y = bodyYaw; - setOrientation(glm::quat(glm::radians(eulerAngles))); + setWorldOrientation(glm::quat(glm::radians(eulerAngles))); } float AvatarData::getBodyPitch() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getWorldOrientation())); return eulerAngles.x; } void AvatarData::setBodyPitch(float bodyPitch) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getWorldOrientation())); eulerAngles.x = bodyPitch; - setOrientation(glm::quat(glm::radians(eulerAngles))); + setWorldOrientation(glm::quat(glm::radians(eulerAngles))); } float AvatarData::getBodyRoll() const { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getWorldOrientation())); return eulerAngles.z; } void AvatarData::setBodyRoll(float bodyRoll) { - glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getOrientation())); + glm::vec3 eulerAngles = glm::degrees(safeEulerAngles(getWorldOrientation())); eulerAngles.z = bodyRoll; - setOrientation(glm::quat(glm::radians(eulerAngles))); + setWorldOrientation(glm::quat(glm::radians(eulerAngles))); } void AvatarData::setPositionViaScript(const glm::vec3& position) { @@ -2190,7 +2190,7 @@ void AvatarData::setPositionViaScript(const glm::vec3& position) { } void AvatarData::setOrientationViaScript(const glm::quat& orientation) { - SpatiallyNestable::setOrientation(orientation); + SpatiallyNestable::setWorldOrientation(orientation); } glm::quat AvatarData::getAbsoluteJointRotationInObjectFrame(int index) const { diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 5ce4395baa..61e27a482e 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -359,7 +359,7 @@ class AvatarData : public QObject, public SpatiallyNestable { Q_PROPERTY(float bodyPitch READ getBodyPitch WRITE setBodyPitch) Q_PROPERTY(float bodyRoll READ getBodyRoll WRITE setBodyRoll) - Q_PROPERTY(glm::quat orientation READ getOrientation WRITE setOrientationViaScript) + Q_PROPERTY(glm::quat orientation READ getWorldOrientation WRITE setOrientationViaScript) Q_PROPERTY(glm::quat headOrientation READ getHeadOrientation WRITE setHeadOrientation) Q_PROPERTY(float headPitch READ getHeadPitch WRITE setHeadPitch) Q_PROPERTY(float headYaw READ getHeadYaw WRITE setHeadYaw) diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index 6ff36331cf..4119d7a459 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -49,11 +49,11 @@ void HeadData::setRawOrientation(const glm::quat& q) { glm::quat HeadData::getOrientation() const { - return _owningAvatar->getOrientation() * getRawOrientation(); + return _owningAvatar->getWorldOrientation() * getRawOrientation(); } void HeadData::setHeadOrientation(const glm::quat& orientation) { - glm::quat bodyOrientation = _owningAvatar->getOrientation(); + glm::quat bodyOrientation = _owningAvatar->getWorldOrientation(); glm::vec3 eulers = glm::degrees(safeEulerAngles(glm::inverse(bodyOrientation) * orientation)); _basePitch = eulers.x; _baseYaw = eulers.y; @@ -62,10 +62,10 @@ void HeadData::setHeadOrientation(const glm::quat& orientation) { void HeadData::setOrientation(const glm::quat& orientation) { // rotate body about vertical axis - glm::quat bodyOrientation = _owningAvatar->getOrientation(); + glm::quat bodyOrientation = _owningAvatar->getWorldOrientation(); glm::vec3 newForward = glm::inverse(bodyOrientation) * (orientation * IDENTITY_FORWARD); bodyOrientation = bodyOrientation * glm::angleAxis(atan2f(-newForward.x, -newForward.z), glm::vec3(0.0f, 1.0f, 0.0f)); - _owningAvatar->setOrientation(bodyOrientation); + _owningAvatar->setWorldOrientation(bodyOrientation); // the rest goes to the head setHeadOrientation(orientation); @@ -154,7 +154,7 @@ QJsonObject HeadData::toJson() const { } auto lookat = getLookAtPosition(); if (lookat != vec3()) { - vec3 relativeLookAt = glm::inverse(_owningAvatar->getOrientation()) * + vec3 relativeLookAt = glm::inverse(_owningAvatar->getWorldOrientation()) * (getLookAtPosition() - _owningAvatar->getWorldPosition()); headJson[JSON_AVATAR_HEAD_LOOKAT] = toJsonValue(relativeLookAt); } @@ -185,7 +185,7 @@ void HeadData::fromJson(const QJsonObject& json) { if (json.contains(JSON_AVATAR_HEAD_LOOKAT)) { auto relativeLookAt = vec3FromJsonValue(json[JSON_AVATAR_HEAD_LOOKAT]); if (glm::length2(relativeLookAt) > 0.01f) { - setLookAtPosition((_owningAvatar->getOrientation() * relativeLookAt) + _owningAvatar->getWorldPosition()); + setLookAtPosition((_owningAvatar->getWorldOrientation() * relativeLookAt) + _owningAvatar->getWorldPosition()); } } diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index cac3f600ca..6a57bab0b7 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -66,7 +66,7 @@ float ScriptAvatarData::getBodyRoll() const { } glm::quat ScriptAvatarData::getOrientation() const { if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) { - return sharedAvatarData->getOrientation(); + return sharedAvatarData->getWorldOrientation(); } else { return glm::quat(); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index a9277ff19a..e381d2cc38 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -510,7 +510,7 @@ static glm::vec2 projectOntoEntityXYPlane(EntityItemPointer entity, const PickRa if (entity) { glm::vec3 entityPosition = entity->getWorldPosition(); - glm::quat entityRotation = entity->getRotation(); + glm::quat entityRotation = entity->getWorldOrientation(); glm::vec3 entityDimensions = entity->getDimensions(); glm::vec3 entityRegistrationPoint = entity->getRegistrationPoint(); diff --git a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp index e00cd98e65..696d7ab8db 100644 --- a/libraries/entities-renderer/src/RenderableLightEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableLightEntityItem.cpp @@ -29,7 +29,7 @@ void LightEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint auto light = lightPayload.editLight(); light->setPosition(entity->getWorldPosition()); - light->setOrientation(entity->getRotation()); + light->setOrientation(entity->getWorldOrientation()); bool success; lightPayload.editBound() = entity->getAABox(success); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 67b7b175b7..bcc4c27bfc 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -123,7 +123,7 @@ void RenderableModelEntityItem::doInitialModelSimulation() { // now recalculate the bounds and registration model->setScaleToFit(true, getDimensions()); model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); - model->setRotation(getRotation()); + model->setRotation(getWorldOrientation()); model->setTranslation(getWorldPosition()); if (_needsInitialSimulation) { diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index e4706fa15e..fbf85fa8c2 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -155,7 +155,7 @@ void PolyLineEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPo _polylineTransform = Transform(); _polylineTransform.setTranslation(entity->getWorldPosition()); - _polylineTransform.setRotation(entity->getRotation()); + _polylineTransform.setRotation(entity->getWorldOrientation()); if (pointsChanged) { _lastPoints = entity->getLinePoints(); diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp index fd7407287d..356bf3a69c 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.cpp @@ -247,7 +247,7 @@ glm::mat4 RenderablePolyVoxEntityItem::localToVoxelMatrix() const { } glm::mat4 RenderablePolyVoxEntityItem::voxelToWorldMatrix() const { - glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 rotation = glm::mat4_cast(getWorldOrientation()); glm::mat4 translation = glm::translate(getWorldPosition()); return translation * rotation * voxelToLocalMatrix(); } diff --git a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp index dffde3386b..3524709395 100644 --- a/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableShapeEntityItem.cpp @@ -83,7 +83,7 @@ void ShapeEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce _shape = entity->getShape(); _position = entity->getWorldPosition(); _dimensions = entity->getDimensions(); - _orientation = entity->getOrientation(); + _orientation = entity->getWorldOrientation(); _renderTransform = getModelTransform(); if (_shape == entity::Sphere) { diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp index e56e692890..a077307c61 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.cpp @@ -201,7 +201,7 @@ void ZoneEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scen entity->resetRenderingPropertiesChanged(); _lastPosition = entity->getWorldPosition(); - _lastRotation = entity->getRotation(); + _lastRotation = entity->getWorldOrientation(); _lastDimensions = entity->getDimensions(); _keyLightProperties = entity->getKeyLightProperties(); @@ -277,7 +277,7 @@ bool ZoneEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityPoint if (entity->getDimensions() != _lastDimensions) { return true; } - if (entity->getRotation() != _lastRotation) { + if (entity->getWorldOrientation() != _lastRotation) { return true; } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e1ff932915..2d90a08e1c 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1169,7 +1169,7 @@ bool EntityItem::wantTerseEditLogging() const { glm::mat4 EntityItem::getEntityToWorldMatrix() const { glm::mat4 translation = glm::translate(getWorldPosition()); - glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 rotation = glm::mat4_cast(getWorldOrientation()); glm::mat4 scale = glm::scale(getDimensions()); glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint()); return translation * rotation * scale * registration; @@ -1464,7 +1464,7 @@ AACube EntityItem::getMinimumAACube(bool& success) const { glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint); Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; - extents.rotate(getRotation()); + extents.rotate(getWorldOrientation()); // shift the extents to be relative to the position/registration point extents.shiftBy(position); @@ -1494,7 +1494,7 @@ AABox EntityItem::getAABox(bool& success) const { glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint); glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint); Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity }; - extents.rotate(getRotation()); + extents.rotate(getWorldOrientation()); // shift the extents to be relative to the position/registration point extents.shiftBy(position); @@ -2384,7 +2384,7 @@ void EntityItem::globalizeProperties(EntityItemProperties& properties, const QSt auto globalPosition = getWorldPosition(success); if (success) { properties.setPosition(globalPosition + offset); - properties.setRotation(getRotation()); + properties.setRotation(getWorldOrientation()); properties.setDimensions(getDimensions()); // Should we do velocities and accelerations, too? This could end up being quite involved, which is why the method exists. } else { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 329a616609..9d532052fd 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -388,7 +388,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties.setPosition(entity->getWorldPosition()); } if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) { - properties.setRotation(entity->getOrientation()); + properties.setRotation(entity->getWorldOrientation()); } } properties = convertLocationFromScriptSemantics(properties); @@ -1798,7 +1798,7 @@ glm::mat4 EntityScriptingInterface::getEntityTransform(const QUuid& entityID) { EntityItemPointer entity = _entityTree->findEntityByEntityItemID(EntityItemID(entityID)); if (entity) { glm::mat4 translation = glm::translate(entity->getWorldPosition()); - glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); + glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation()); result = translation * rotation; } }); diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 4b588fc23c..7e2958583d 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -662,7 +662,7 @@ bool EntityTreeElement::findDetailedRayIntersection(const glm::vec3& origin, con } // extents is the entity relative, scaled, centered extents of the entity - glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); + glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation()); glm::mat4 translation = glm::translate(entity->getWorldPosition()); glm::mat4 entityToWorldMatrix = translation * rotation; glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); @@ -787,7 +787,7 @@ void EntityTreeElement::getEntities(const glm::vec3& searchPosition, float searc } else { // determine the worldToEntityMatrix that doesn't include scale because // we're going to use the registration aware aa box in the entity frame - glm::mat4 rotation = glm::mat4_cast(entity->getRotation()); + glm::mat4 rotation = glm::mat4_cast(entity->getWorldOrientation()); glm::mat4 translation = glm::translate(entity->getWorldPosition()); glm::mat4 entityToWorldMatrix = translation * rotation; glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix); diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index abcc075bcf..b08d94ca7e 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -411,7 +411,7 @@ glm::mat4 PolyVoxEntityItem::localToVoxelMatrix() const { } glm::mat4 PolyVoxEntityItem::voxelToWorldMatrix() const { - glm::mat4 rotation = glm::mat4_cast(getRotation()); + glm::mat4 rotation = glm::mat4_cast(getWorldOrientation()); glm::mat4 translation = glm::translate(getWorldPosition()); return translation * rotation * voxelToLocalMatrix(); } diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 0f113248f7..67e83ab3fd 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -134,7 +134,7 @@ bool TextEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const void** intersectedObject, bool precisionPicking) const { glm::vec3 dimensions = getDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); - glm::quat rotation = getRotation(); + glm::quat rotation = getWorldOrientation(); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 91137431fe..5ee630d8ed 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -111,7 +111,7 @@ bool WebEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const g void** intersectedObject, bool precisionPicking) const { glm::vec3 dimensions = getDimensions(); glm::vec2 xyDimensions(dimensions.x, dimensions.y); - glm::quat rotation = getRotation(); + glm::quat rotation = getWorldOrientation(); glm::vec3 position = getWorldPosition() + rotation * (dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint())); if (findRayRectangleIntersection(origin, direction, rotation, position, xyDimensions, distance)) { diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index be56bffb18..da98e838b0 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -109,7 +109,7 @@ void EntityMotionState::handleDeactivation() { // and also to RigidBody btTransform worldTrans; worldTrans.setOrigin(glmToBullet(_entity->getWorldPosition())); - worldTrans.setRotation(glmToBullet(_entity->getRotation())); + worldTrans.setRotation(glmToBullet(_entity->getWorldOrientation())); _body->setWorldTransform(worldTrans); // no need to update velocities... should already be zero } @@ -246,7 +246,7 @@ void EntityMotionState::getWorldTransform(btTransform& worldTrans) const { _accelerationNearlyGravityCount = (uint8_t)(-1); } worldTrans.setOrigin(glmToBullet(getObjectPosition())); - worldTrans.setRotation(glmToBullet(_entity->getRotation())); + worldTrans.setRotation(glmToBullet(_entity->getWorldOrientation())); } // This callback is invoked by the physics simulation at the end of each simulation step... @@ -264,7 +264,7 @@ void EntityMotionState::setWorldTransform(const btTransform& worldTrans) { qCDebug(physics) << "EntityMotionState::setWorldTransform setPosition failed" << _entity->getID(); } bool orientationSuccess; - _entity->setOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); + _entity->setWorldOrientation(bulletToGLM(worldTrans.getRotation()), orientationSuccess, false); if (!orientationSuccess) { static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex("EntityMotionState::setWorldTransform " diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 839309e60e..2bb692da81 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -58,7 +58,7 @@ public: virtual float getObjectAngularDamping() const override { return _entity->getAngularDamping(); } virtual glm::vec3 getObjectPosition() const override { return _entity->getWorldPosition() - ObjectMotionState::getWorldOffset(); } - virtual glm::quat getObjectRotation() const override { return _entity->getRotation(); } + virtual glm::quat getObjectRotation() const override { return _entity->getWorldOrientation(); } virtual glm::vec3 getObjectLinearVelocity() const override { return _entity->getVelocity(); } virtual glm::vec3 getObjectAngularVelocity() const override { return _entity->getAngularVelocity(); } virtual glm::vec3 getObjectGravity() const override { return _entity->getGravity(); } diff --git a/libraries/physics/src/ObjectActionTractor.cpp b/libraries/physics/src/ObjectActionTractor.cpp index 6ab7daae7f..629d8baefe 100644 --- a/libraries/physics/src/ObjectActionTractor.cpp +++ b/libraries/physics/src/ObjectActionTractor.cpp @@ -54,8 +54,8 @@ bool ObjectActionTractor::getTarget(float deltaTimeStep, glm::quat& rotation, gl if (!_otherID.isNull()) { if (other) { - rotation = _desiredRotationalTarget * other->getRotation(); - position = other->getRotation() * _desiredPositionalTarget + other->getWorldPosition(); + rotation = _desiredRotationalTarget * other->getWorldOrientation(); + position = other->getWorldOrientation() * _desiredPositionalTarget + other->getWorldPosition(); } else { // we should have an "other" but can't find it, so disable the tractor. linearTimeScale = FLT_MAX; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index 9713ce8a17..a931a524fd 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -420,13 +420,13 @@ void SpatiallyNestable::setWorldPosition(const glm::vec3& position) { #endif } -glm::quat SpatiallyNestable::getOrientation(bool& success) const { +glm::quat SpatiallyNestable::getWorldOrientation(bool& success) const { return getTransform(success).getRotation(); } -glm::quat SpatiallyNestable::getOrientation() const { +glm::quat SpatiallyNestable::getWorldOrientation() const { bool success; - auto result = getOrientation(success); + auto result = getWorldOrientation(success); #ifdef WANT_DEBUG if (!success) { qCDebug(shared) << "Warning -- getOrientation failed" << getID(); @@ -435,11 +435,11 @@ glm::quat SpatiallyNestable::getOrientation() const { return result; } -glm::quat SpatiallyNestable::getOrientation(int jointIndex, bool& success) const { +glm::quat SpatiallyNestable::getWorldOrientation(int jointIndex, bool& success) const { return getTransform(jointIndex, success).getRotation(); } -void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& success, bool tellPhysics) { +void SpatiallyNestable::setWorldOrientation(const glm::quat& orientation, bool& success, bool tellPhysics) { // guard against introducing NaN into the transform if (isNaN(orientation)) { success = false; @@ -463,9 +463,9 @@ void SpatiallyNestable::setOrientation(const glm::quat& orientation, bool& succe } } -void SpatiallyNestable::setOrientation(const glm::quat& orientation) { +void SpatiallyNestable::setWorldOrientation(const glm::quat& orientation) { bool success; - setOrientation(orientation, success); + setWorldOrientation(orientation, success); #ifdef WANT_DEBUG if (!success) { qCDebug(shared) << "Warning -- setOrientation failed" << getID(); diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 6b082fed82..929c2d53f2 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -83,15 +83,11 @@ public: virtual void setWorldPosition(const glm::vec3& position, bool& success, bool tellPhysics = true); virtual void setWorldPosition(const glm::vec3& position); - virtual glm::quat getOrientation(bool& success) const; - virtual glm::quat getOrientation() const; - virtual glm::quat getOrientation(int jointIndex, bool& success) const; - virtual void setOrientation(const glm::quat& orientation, bool& success, bool tellPhysics = true); - virtual void setOrientation(const glm::quat& orientation); - - // these are here because some older code uses rotation rather than orientation - virtual const glm::quat getRotation() const { return getOrientation(); } - virtual void setRotation(glm::quat orientation) { setOrientation(orientation); } + virtual glm::quat getWorldOrientation(bool& success) const; + virtual glm::quat getWorldOrientation() const; + virtual glm::quat getWorldOrientation(int jointIndex, bool& success) const; + virtual void setWorldOrientation(const glm::quat& orientation, bool& success, bool tellPhysics = true); + virtual void setWorldOrientation(const glm::quat& orientation); virtual glm::vec3 getVelocity(bool& success) const; virtual glm::vec3 getVelocity() const; From 950ac3540ab0af9a10b6188e190f8ec9cd16fb1b Mon Sep 17 00:00:00 2001 From: vladest Date: Sun, 29 Oct 2017 14:05:47 +0100 Subject: [PATCH 031/292] Fix mute unmute. Scrolling thru suggestions popup now set popup's contains into url. Fixed reload timer --- interface/resources/qml/hifi/WebBrowser.qml | 30 +++++++++++++-------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index 79932dbcdd..ec5594e74d 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -85,6 +85,7 @@ Rectangle { addressBar.model = [] webStack.currentItem.webEngineView.url = url + addressBar.editText = webStack.currentItem.webEngineView.url suggestionRequestTimer.stop(); addressBar.popup.close(); } @@ -136,6 +137,12 @@ Rectangle { goTo(textAt(index)); } + onHighlightedIndexChanged: { + if (highlightedIndex >= 0) { + addressBar.editText = textAt(highlightedIndex) + } + } + popup.height: webStack.height onFocusChanged: { @@ -191,7 +198,7 @@ Rectangle { if (webStack.currentItem.webEngineView.loading) { webStack.currentItem.webEngineView.stop(); } else { - webStack.currentItem.webEngineView.reloadTimer.start(); + webStack.currentItem.reloadTimer.start(); } } } @@ -228,7 +235,7 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter; width: hifi.dimensions.controlLineHeight onClicked: { - webStack.currentItem.webEngineView.triggerWebAction(WebEngineView.ToggleMediaMute); + webStack.currentItem.webEngineView.audioMuted = !webStack.currentItem.webEngineView.audioMuted } } } @@ -261,6 +268,8 @@ Rectangle { id: webViewComponent Rectangle { property alias webEngineView: webEngineView + property alias reloadTimer: reloadTimer + property WebEngineNewViewRequest request: null property bool isDialog: QQControls.StackView.index > 0 @@ -314,7 +323,7 @@ Rectangle { WebEngineScript { id: createGlobalEventBridge sourceCode: eventBridgeJavaScriptToInject - injectionPoint: WebEngineScript.DocumentCreation + injectionPoint: WebEngineScript.Deferred worldId: WebEngineScript.MainWorld } @@ -399,14 +408,13 @@ Rectangle { onWindowCloseRequested: { webStack.pop(); } - - Timer { - id: reloadTimer - interval: 0 - running: false - repeat: false - onTriggered: webEngineView.reload() - } + } + Timer { + id: reloadTimer + interval: 0 + running: false + repeat: false + onTriggered: webEngineView.reload() } } } From 6ba2a83bbe0c94aa5efad2f7b25c5b6118e81666 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sun, 29 Oct 2017 10:47:56 -0700 Subject: [PATCH 032/292] Send and receive Avatar MASTER Gain packets, signaled using null nodeID. Packet protocol change is not needed (existing audio-mixer will ignore). --- .../src/audio/AudioMixerClientData.cpp | 10 ++++++++-- libraries/networking/src/NodeList.cpp | 13 +++++++++---- .../script-engine/src/UsersScriptingInterface.h | 4 ++-- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 9bba9c7f30..59bc878cba 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -189,8 +189,14 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const uint8_t packedGain; message.readPrimitive(&packedGain); float gain = unpackFloatGainFromByte(packedGain); - hrtfForStream(avatarUuid, QUuid()).setGainAdjustment(gain); - qDebug() << "Setting gain adjustment for hrtf[" << uuid << "][" << avatarUuid << "] to " << gain; + + if (avatarUuid.isNull()) { + // FIXME: change master gain, and reset hrtf gains for all active streams + qDebug() << "Setting MASTER avatar gain for [" << uuid << "] to " << gain; + } else { + hrtfForStream(avatarUuid, QUuid()).setGainAdjustment(gain); + qDebug() << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUuid << "] to " << gain; + } } void AudioMixerClientData::parseNodeIgnoreRequest(QSharedPointer message, const SharedNodePointer& node) { diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 71128c5ff0..04699d8ad1 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -979,8 +979,8 @@ void NodeList::maybeSendIgnoreSetToNode(SharedNodePointer newNode) { } void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { - // cannot set gain of yourself or nobody - if (!nodeID.isNull() && _sessionUUID != nodeID) { + // cannot set gain of yourself + if (_sessionUUID != nodeID) { auto audioMixer = soloNodeOfType(NodeType::AudioMixer); if (audioMixer) { // setup the packet @@ -988,10 +988,15 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { // write the node ID to the packet setAvatarGainPacket->write(nodeID.toRfc4122()); + // We need to convert the gain in dB (from the script) to an amplitude before packing it. setAvatarGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.0206f))); - qCDebug(networking) << "Sending Set Avatar Gain packet UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; + if (nodeID.isNull()) { + qCDebug(networking) << "Sending Set Avatar MASTER Gain packet with Gain:" << gain; + } else { + qCDebug(networking) << "Sending Set Avatar Gain packet with UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; + } sendPacket(std::move(setAvatarGainPacket), *audioMixer); QWriteLocker{ &_avatarGainMapLock }; @@ -1001,7 +1006,7 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { qWarning() << "Couldn't find audio mixer to send set gain request"; } } else { - qWarning() << "NodeList::setAvatarGain called with an invalid ID or an ID which matches the current session ID:" << nodeID; + qWarning() << "NodeList::setAvatarGain called with an ID which matches the current session ID:" << nodeID; } } diff --git a/libraries/script-engine/src/UsersScriptingInterface.h b/libraries/script-engine/src/UsersScriptingInterface.h index acaa92d9c8..2d33bbca14 100644 --- a/libraries/script-engine/src/UsersScriptingInterface.h +++ b/libraries/script-engine/src/UsersScriptingInterface.h @@ -65,7 +65,7 @@ public slots: * Sets an avatar's gain for you and you only. * Units are Decibels (dB) * @function Users.setAvatarGain - * @param {nodeID} nodeID The node or session ID of the user whose gain you want to modify. + * @param {nodeID} nodeID The node or session ID of the user whose gain you want to modify, or null to set the master gain. * @param {float} gain The gain of the avatar you'd like to set. Units are dB. */ void setAvatarGain(const QUuid& nodeID, float gain); @@ -73,7 +73,7 @@ public slots: /**jsdoc * Gets an avatar's gain for you and you only. * @function Users.getAvatarGain - * @param {nodeID} nodeID The node or session ID of the user whose gain you want to get. + * @param {nodeID} nodeID The node or session ID of the user whose gain you want to get, or null to get the master gain. * @return {float} gain (in dB) */ float getAvatarGain(const QUuid& nodeID); From a99b1ffa230ef426010dc5278c0db0cf2cdaebb8 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Sun, 29 Oct 2017 18:01:43 -0700 Subject: [PATCH 033/292] HRTF cleanup --- libraries/audio/src/AudioHRTF.cpp | 4 ++-- libraries/audio/src/avx512/AudioHRTF_avx512.cpp | 13 +------------ 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 1d5b074db7..f2f0235ccb 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -673,8 +673,8 @@ static void crossfade_4x2(float* src, float* dst, const float* win, int numFrame // linear interpolation with gain static void interpolate(float* dst, const float* src0, const float* src1, float frac, float gain) { - float f0 = HRTF_GAIN * gain * (1.0f - frac); - float f1 = HRTF_GAIN * gain * frac; + float f0 = gain * (1.0f - frac); + float f1 = gain * frac; for (int k = 0; k < HRTF_TAPS; k++) { dst[k] = f0 * src0[k] + f1 * src1[k]; diff --git a/libraries/audio/src/avx512/AudioHRTF_avx512.cpp b/libraries/audio/src/avx512/AudioHRTF_avx512.cpp index 682f5f2f77..a8bb62be35 100644 --- a/libraries/audio/src/avx512/AudioHRTF_avx512.cpp +++ b/libraries/audio/src/avx512/AudioHRTF_avx512.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#if defined(__AVX512F__) +#ifdef __AVX512F__ #include #include @@ -87,15 +87,4 @@ void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* ds _mm256_zeroupper(); } -// FIXME: this fallback can be removed, once we require VS2017 -#elif defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__x86_64__) - -#include "../AudioHRTF.h" - -void FIR_1x4_AVX2(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames); - -void FIR_1x4_AVX512(float* src, float* dst0, float* dst1, float* dst2, float* dst3, float coef[4][HRTF_TAPS], int numFrames) { - FIR_1x4_AVX2(src, dst0, dst1, dst2, dst3, coef, numFrames); -} - #endif From e6582a0370434761f0b4f29e50e9923ad8fabe0d Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 27 Oct 2017 10:39:37 -0700 Subject: [PATCH 034/292] control hovering, preset buttons for clicking, constness, scroll off surface --- interface/src/raypick/LaserPointer.cpp | 55 ++++++++++++++----- interface/src/raypick/LaserPointer.h | 18 +++--- .../src/raypick/PointerScriptingInterface.cpp | 7 ++- libraries/pointers/src/pointers/Pointer.cpp | 36 ++++++++---- libraries/pointers/src/pointers/Pointer.h | 14 +++-- .../pointers/src/pointers/PointerManager.cpp | 6 +- .../pointers/src/pointers/PointerManager.h | 6 +- 7 files changed, 100 insertions(+), 42 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index b8122a2388..389a558f94 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -17,9 +17,9 @@ #include #include "PickScriptingInterface.h" -LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const PointerTriggers& triggers, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) : - Pointer(DependencyManager::get()->createRayPick(rayProps), enabled), +LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, + const PointerTriggers& triggers, bool faceAvatar, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool enabled) : + Pointer(DependencyManager::get()->createRayPick(rayProps), enabled, hover), _triggers(triggers), _renderStates(renderStates), _defaultRenderStates(defaultRenderStates), @@ -83,7 +83,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& } } -void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) { +void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState) { if (!renderState.getStartID().isNull()) { QVariantMap startProps; startProps.insert("position", vec3toVariant(pickRay.origin)); @@ -210,13 +210,13 @@ Pointer::Buttons LaserPointer::getPressedButtons() { return toReturn; } -void LaserPointer::setLength(const float length) { +void LaserPointer::setLength(float length) { withWriteLock([&] { _laserLength = length; }); } -void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) { +void LaserPointer::setLockEndUUID(const QUuid& objectID, bool isOverlay) { withWriteLock([&] { _objectLockEnd = std::pair(objectID, isOverlay); }); @@ -281,21 +281,50 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) { return RenderState(startID, pathID, endID); } -PointerEvent LaserPointer::buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const { +PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const { uint32_t id = 0; glm::vec3 intersection = vec3FromVariant(pickResult["intersection"]); glm::vec3 surfaceNormal = vec3FromVariant(pickResult["surfaceNormal"]); glm::vec3 direction = -surfaceNormal; IntersectionType type = IntersectionType(pickResult["type"].toUInt()); + QUuid pickedID = pickResult["objectID"].toUuid(); glm::vec2 pos2D; - if (type == ENTITY) { - pos2D = projectOntoEntityXYPlane(uid, intersection); - } else if (type == OVERLAY) { - pos2D = projectOntoOverlayXYPlane(uid, intersection); + if (pickedID != target.objectID) { + QVariantMap searchRay = pickResult["searchRay"].toMap(); + glm::vec3 origin = vec3FromVariant(searchRay["origin"]); + glm::vec3 direction = vec3FromVariant(searchRay["direction"]); + if (target.type == ENTITY) { + intersection = intersectRayWithEntityXYPlane(target.objectID, origin, direction); + } else if (target.type == OVERLAY) { + intersection = intersectRayWithOverlayXYPlane(target.objectID, origin, direction); + } + } + if (target.type == ENTITY) { + pos2D = projectOntoEntityXYPlane(target.objectID, intersection); + } else if (target.type == OVERLAY) { + pos2D = projectOntoOverlayXYPlane(target.objectID, intersection); } return PointerEvent(PointerEvent::Move, id, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons); } +glm::vec3 LaserPointer::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const { + glm::vec3 n = rotation * Vectors::FRONT; + float t = glm::dot(n, point - origin) / glm::dot(n, direction); + return origin + t * direction; +} + +glm::vec3 LaserPointer::intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) const { + glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value); + glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value); + const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); + return intersectRayWithXYPlane(origin, direction, position, rotation, DEFAULT_REGISTRATION_POINT); +} + +glm::vec3 LaserPointer::intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) const { + auto props = DependencyManager::get()->getEntityProperties(entityID); + return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint()); +} + glm::vec2 LaserPointer::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const { glm::quat invRot = glm::inverse(rotation); glm::vec3 localPos = invRot * (worldPos - position); @@ -325,7 +354,7 @@ glm::vec2 LaserPointer::projectOntoOverlayXYPlane(const QUuid& overlayID, const return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT); } -glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entity, const glm::vec3& worldPos) const { - auto props = DependencyManager::get()->getEntityProperties(entity); +glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const { + auto props = DependencyManager::get()->getEntityProperties(entityID); return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint()); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 167de88385..bdd3f2ffa0 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -54,16 +54,16 @@ public: typedef std::unordered_map RenderStateMap; typedef std::unordered_map> DefaultRenderStateMap; - LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const PointerTriggers& triggers, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled); + LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, const PointerTriggers& triggers, + bool faceAvatar, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool enabled); ~LaserPointer(); void setRenderState(const std::string& state) override; // You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays. void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override; - void setLength(const float length) override; - void setLockEndUUID(QUuid objectID, const bool isOverlay) override; + void setLength(float length) override; + void setLockEndUUID(const QUuid& objectID, bool isOverlay) override; void updateVisuals(const QVariantMap& prevRayPickResult) override; @@ -73,7 +73,7 @@ public: static RenderState buildRenderState(const QVariantMap& propMap); protected: - PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const override; + PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const override; private: PointerTriggers _triggers; @@ -88,10 +88,14 @@ private: std::pair _objectLockEnd { std::pair(QUuid(), false)}; void updateRenderStateOverlay(const OverlayID& id, const QVariant& props); - void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState); + void updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState); void disableRenderState(const RenderState& renderState); - glm::vec2 projectOntoEntityXYPlane(const QUuid& entity, const glm::vec3& worldPos) const; + + glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) const; + glm::vec3 intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) const; + glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const; + glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const; glm::vec2 projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos) const; glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const; diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 5ac209d295..c3a4ac164a 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -87,6 +87,11 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) } } + bool hover = false; + if (propertyMap["hover"].isValid()) { + hover = propertyMap["hover"].toBool(); + } + PointerTriggers triggers; auto userInputMapper = DependencyManager::get(); if (propertyMap["triggers"].isValid()) { @@ -105,7 +110,7 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) } } - return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, triggers, + return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, hover, triggers, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled)); } diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 0075762f02..af560a45ab 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -33,7 +33,7 @@ const QVariantMap Pointer::getPrevPickResult() { return DependencyManager::get()->getPrevPickResult(_pickUID); } -void Pointer::setPrecisionPicking(const bool precisionPicking) { +void Pointer::setPrecisionPicking(bool precisionPicking) { DependencyManager::get()->setPrecisionPicking(_pickUID, precisionPicking); } @@ -60,16 +60,17 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { // Hover events Pointer::PickedObject hoveredObject = getHoveredObject(pickResult); - PointerEvent hoveredEvent = buildPointerEvent(hoveredObject.objectID, pickResult); + PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult); hoveredEvent.setType(PointerEvent::Move); + // TODO: set buttons on hover events hoveredEvent.setButton(PointerEvent::NoButtons); - if (_enabled) { + if (_enabled && _hover) { if (hoveredObject.type == OVERLAY) { if (_prevHoveredObject.type == OVERLAY) { if (hoveredObject.objectID == _prevHoveredObject.objectID) { emit pointerManager->hoverContinueOverlay(hoveredObject.objectID, hoveredEvent); } else { - PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject.objectID, pickResult); + PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult); emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, prevHoveredEvent); emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); } @@ -87,7 +88,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { if (hoveredObject.objectID == _prevHoveredObject.objectID) { emit pointerManager->hoverContinueEntity(hoveredObject.objectID, hoveredEvent); } else { - PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject.objectID, pickResult); + PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult); emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, prevHoveredEvent); emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); } @@ -122,7 +123,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { const std::string SHOULD_FOCUS_BUTTON = "Focus"; for (const std::string& button : newButtons) { hoveredEvent.setType(PointerEvent::Press); - hoveredEvent.setButton(PointerEvent::PrimaryButton); + hoveredEvent.setButton(chooseButton(button)); hoveredEvent.setShouldFocus(button == SHOULD_FOCUS_BUTTON); if (hoveredObject.type == ENTITY) { emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent); @@ -134,9 +135,9 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { // Trigger continue for (const std::string& button : sameButtons) { - PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button].objectID, pickResult); + PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); triggeredEvent.setType(PointerEvent::Move); - triggeredEvent.setButton(PointerEvent::PrimaryButton); + hoveredEvent.setButton(chooseButton(button)); if (_triggeredObjects[button].type == ENTITY) { emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { @@ -146,9 +147,9 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { // Trigger end for (const std::string& button : _prevButtons) { - PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button].objectID, pickResult); + PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); triggeredEvent.setType(PointerEvent::Release); - triggeredEvent.setButton(PointerEvent::PrimaryButton); + hoveredEvent.setButton(chooseButton(button)); if (_triggeredObjects[button].type == ENTITY) { emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { @@ -159,4 +160,19 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { _prevHoveredObject = hoveredObject; _prevButtons = buttons; +} + +PointerEvent::Button Pointer::chooseButton(const std::string& button) { + const std::string PRIMARY_BUTTON = "Primary"; + const std::string SECONDARY_BUTTON = "Secondary"; + const std::string TERTIARY_BUTTON = "Tertiary"; + if (button == PRIMARY_BUTTON) { + return PointerEvent::PrimaryButton; + } else if (button == SECONDARY_BUTTON) { + return PointerEvent::SecondaryButton; + } else if (button == TERTIARY_BUTTON) { + return PointerEvent::TertiaryButton; + } else { + return PointerEvent::NoButtons; + } } \ No newline at end of file diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index 595daebc33..ca35c38c7a 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -38,7 +38,7 @@ using PointerTriggers = std::vector; class Pointer : protected ReadWriteLockable { public: - Pointer(const QUuid& uid, bool enabled) : _pickUID(uid), _enabled(enabled) {} + Pointer(const QUuid& uid, bool enabled, bool hover) : _pickUID(uid), _enabled(enabled), _hover(hover) {} virtual ~Pointer(); @@ -49,13 +49,13 @@ public: virtual void setRenderState(const std::string& state) = 0; virtual void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) = 0; - virtual void setPrecisionPicking(const bool precisionPicking); + virtual void setPrecisionPicking(bool precisionPicking); virtual void setIgnoreItems(const QVector& ignoreItems) const; virtual void setIncludeItems(const QVector& includeItems) const; // Pointers can choose to implement these - virtual void setLength(const float length) {} - virtual void setLockEndUUID(QUuid objectID, const bool isOverlay) {} + virtual void setLength(float length) {} + virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay) {} void update(); virtual void updateVisuals(const QVariantMap& pickResult) = 0; @@ -79,13 +79,17 @@ public: protected: const QUuid _pickUID; bool _enabled; + bool _hover; - virtual PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const = 0; + virtual PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const = 0; private: PickedObject _prevHoveredObject; Buttons _prevButtons; std::unordered_map _triggeredObjects; + + PointerEvent::Button chooseButton(const std::string& button); + }; #endif // hifi_Pick_h diff --git a/libraries/pointers/src/pointers/PointerManager.cpp b/libraries/pointers/src/pointers/PointerManager.cpp index a475ba4d83..2d41543b6b 100644 --- a/libraries/pointers/src/pointers/PointerManager.cpp +++ b/libraries/pointers/src/pointers/PointerManager.cpp @@ -79,7 +79,7 @@ void PointerManager::update() { } } -void PointerManager::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const { +void PointerManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { auto pointer = find(uid); if (pointer) { pointer->setPrecisionPicking(precisionPicking); @@ -100,14 +100,14 @@ void PointerManager::setIncludeItems(const QUuid& uid, const QVector& inc } } -void PointerManager::setLength(const QUuid& uid, const float length) const { +void PointerManager::setLength(const QUuid& uid, float length) const { auto pointer = find(uid); if (pointer) { pointer->setLength(length); } } -void PointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const { +void PointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { auto pointer = find(uid); if (pointer) { pointer->setLockEndUUID(objectID, isOverlay); diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 6e13c09851..9f477d9eb2 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -31,12 +31,12 @@ public: void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; const QVariantMap getPrevPickResult(const QUuid& uid) const; - void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const; + void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; void setIncludeItems(const QUuid& uid, const QVector& includeEntities) const; - void setLength(const QUuid& uid, const float length) const; - void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const; + void setLength(const QUuid& uid, float length) const; + void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const; void update(); From 586dde7dd70e0846b2b6644a8abb0275f7503683 Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 30 Oct 2017 18:15:42 +0100 Subject: [PATCH 035/292] Removed GPL code. Added own implementation of suggestions engine. Fixed Google maps different issues --- interface/resources/qml/hifi/WebBrowser.qml | 24 +- interface/src/Application.cpp | 4 +- interface/src/opensearch/opensearchengine.cpp | 650 ------------------ interface/src/opensearch/opensearchengine.h | 128 ---- .../opensearch/opensearchenginedelegate.cpp | 43 -- .../src/opensearch/opensearchenginedelegate.h | 18 - .../webbrowsersuggestionsengine.cpp | 87 +++ .../webbrowser/webbrowsersuggestionsengine.h | 46 ++ 8 files changed, 147 insertions(+), 853 deletions(-) delete mode 100644 interface/src/opensearch/opensearchengine.cpp delete mode 100644 interface/src/opensearch/opensearchengine.h delete mode 100644 interface/src/opensearch/opensearchenginedelegate.cpp delete mode 100644 interface/src/opensearch/opensearchenginedelegate.h create mode 100644 interface/src/webbrowser/webbrowsersuggestionsengine.cpp create mode 100644 interface/src/webbrowser/webbrowsersuggestionsengine.h diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index ec5594e74d..ab93752d92 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -36,13 +36,11 @@ Rectangle { property bool keyboardRaised: false property bool punctuationMode: false property var suggestionsList: [] + readonly property string searchUrlTemplate: "https://www.google.com/search?client=hifibrowser&q="; - OpenSearchEngine { + + WebBrowserSuggestionsEngine { id: searchEngine - name: "Google"; - searchUrlTemplate: "https://www.google.com/search?client=hifibrowser&q={searchTerms}"; - suggestionsUrlTemplate: "https://suggestqueries.google.com/complete/search?output=firefox&q=%s"; - suggestionsUrl: "https://suggestqueries.google.com/complete/search?output=firefox&q=%s"; onSuggestions: { if (suggestions.length > 0) { @@ -65,7 +63,7 @@ Rectangle { repeat: false onTriggered: { if (addressBar.editText !== "") { - searchEngine.requestSuggestions(addressBarInput.text); + searchEngine.querySuggestions(addressBarInput.text); } } } @@ -74,18 +72,19 @@ Rectangle { function goTo(url) { //must be valid attempt to open an site with dot - + var urlNew = url if (url.indexOf(".") > 0) { if (url.indexOf("http") < 0) { - url = "http://" + url; + urlNew = "http://" + url; } } else { - url = searchEngine.searchUrl(url) + urlNew = searchUrlTemplate + url } addressBar.model = [] - webStack.currentItem.webEngineView.url = url - addressBar.editText = webStack.currentItem.webEngineView.url + //need to rebind if binfing was broken by selecting from suggestions + addressBar.editText = Qt.binding( function() { return webStack.currentItem.webEngineView.url; }); + webStack.currentItem.webEngineView.url = urlNew suggestionRequestTimer.stop(); addressBar.popup.close(); } @@ -305,11 +304,13 @@ Rectangle { objectName: "tabletWebEngineView" //profile: HFWebEngineProfile; + profile.httpUserAgent: "Mozilla/5.0 (Android; Mobile; rv:13.0) Gecko/13.0 Firefox/13.0" property string userScriptUrl: "" onLoadingChanged: { if (!loading) { + addressBarInput.cursorPosition = 0 //set input field cursot to beginning suggestionRequestTimer.stop(); addressBar.popup.close(); } @@ -360,7 +361,6 @@ Rectangle { Component.onCompleted: { webChannel.registerObject("eventBridge", eventBridge); webChannel.registerObject("eventBridgeWrapper", eventBridgeWrapper); - //webEngineView.profile.httpUserAgent = "Mozilla/5.0 Chrome (HighFidelityInterface)"; } onFeaturePermissionRequested: { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0b9e8833e4..bf2754917b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -203,7 +203,7 @@ #include "commerce/Wallet.h" #include "commerce/QmlCommerce.h" -#include "opensearch/opensearchengine.h" +#include "webbrowser/webbrowsersuggestionsengine.h" // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. @@ -2225,7 +2225,7 @@ void Application::initializeUi() { QmlCommerce::registerType(); qmlRegisterType("Hifi", 1, 0, "ResourceImageItem"); qmlRegisterType("Hifi", 1, 0, "Preference"); - qmlRegisterType("HifiWeb", 1, 0, "OpenSearchEngine"); + qmlRegisterType("HifiWeb", 1, 0, "WebBrowserSuggestionsEngine"); auto offscreenUi = DependencyManager::get(); offscreenUi->create(); diff --git a/interface/src/opensearch/opensearchengine.cpp b/interface/src/opensearch/opensearchengine.cpp deleted file mode 100644 index 28cacab256..0000000000 --- a/interface/src/opensearch/opensearchengine.cpp +++ /dev/null @@ -1,650 +0,0 @@ -#include "opensearchengine.h" -#include "qregexp.h" -#include "opensearchenginedelegate.h" - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - - -/*! - \class OpenSearchEngine - \brief A class representing a single search engine described in OpenSearch format - - OpenSearchEngine is a class that represents a single search engine based on - the OpenSearch format. - For more information about the format, see http://www.opensearch.org/. - - Instances of the class hold all the data associated with the corresponding search - engines, such as name(), description() and also URL templates that are used - to construct URLs, which can be used later to perform search queries. Search engine - can also have an image, even an external one, in this case it will be downloaded - automatically from the network. - - OpenSearchEngine instances can be constructed from scratch but also read from - external sources and written back to them. OpenSearchReader and OpenSearchWriter - are the classes provided for reading and writing OpenSearch descriptions. - - Default constructed engines need to be filled with the necessary information before - they can be used to peform search requests. First of all, a search engine should have - the metadata including the name and the description. - However, the most important are URL templates, which are the construction of URLs - but can also contain template parameters, that are replaced with corresponding values - at the time of constructing URLs. - - There are two types of URL templates: search URL template and suggestions URL template. - Search URL template is needed for constructing search URLs, which point directly to - search results. Suggestions URL template is necessary to construct suggestion queries - URLs, which are then used for requesting contextual suggestions, a popular service - offered along with search results that provides search terms related to what has been - supplied by the user. - - Both types of URLs are constructed by the class, by searchUrl() and suggestionsUrl() - functions respectively. However, search requests are supposed to be performed outside - the class, while suggestion queries can be executed using the requestSuggestions() - method. The class will take care of peforming the network request and parsing the - JSON response. - - Both the image request and suggestion queries need network access. The class can - perform network requests on its own, though the client application needs to provide - a network access manager, which then will to be used for network operations. - Without that, both images delivered from remote locations and contextual suggestions - will be disabled. - - \sa OpenSearchReader, OpenSearchWriter -*/ - -/*! - Constructs an engine with a given \a parent. -*/ -OpenSearchEngine::OpenSearchEngine(QObject* parent) - : QObject(parent) - , m_searchMethod(QLatin1String("get")) - , m_suggestionsMethod(QLatin1String("get")) - , m_suggestionsReply(0) - , m_delegate(0) -{ - m_requestMethods.insert(QLatin1String("get"), QNetworkAccessManager::GetOperation); - m_requestMethods.insert(QLatin1String("post"), QNetworkAccessManager::PostOperation); -} - -/*! - A destructor. -*/ -OpenSearchEngine::~OpenSearchEngine() -{ -} - -QString OpenSearchEngine::parseTemplate(const QString &searchTerm, const QString &searchTemplate) -{ - QString language = QLocale().name(); - // Simple conversion to RFC 3066. - language = language.replace(QLatin1Char('_'), QLatin1Char('-')); - - QString result = searchTemplate; - result.replace(QLatin1String("{count}"), QLatin1String("20")); - result.replace(QLatin1String("{startIndex}"), QLatin1String("0")); - result.replace(QLatin1String("{startPage}"), QLatin1String("0")); - result.replace(QLatin1String("{language}"), language); - result.replace(QLatin1String("{inputEncoding}"), QLatin1String("UTF-8")); - result.replace(QLatin1String("{outputEncoding}"), QLatin1String("UTF-8")); - result.replace(QRegExp(QLatin1String("\\{([^\\}]*:|)source\\??\\}")), QCoreApplication::applicationName()); - result.replace(QLatin1String("{searchTerms}"), QLatin1String(QUrl::toPercentEncoding(searchTerm))); - - return result; -} - -/*! - \property OpenSearchEngine::name - \brief the name of the engine - - \sa description() -*/ -QString OpenSearchEngine::name() const -{ - return m_name; -} - -void OpenSearchEngine::setName(const QString &name) -{ - m_name = name; -} - -/*! - \property OpenSearchEngine::description - \brief the description of the engine - - \sa name() -*/ -QString OpenSearchEngine::description() const -{ - return m_description; -} - -void OpenSearchEngine::setDescription(const QString &description) -{ - m_description = description; -} - -/*! - \property OpenSearchEngine::searchUrlTemplate - \brief the template of the search URL - - \sa searchUrl(), searchParameters(), suggestionsUrlTemplate() -*/ -QString OpenSearchEngine::searchUrlTemplate() const -{ - return m_searchUrlTemplate; -} - -void OpenSearchEngine::setSearchUrlTemplate(const QString &searchUrlTemplate) -{ - if (!searchUrlTemplate.startsWith(QLatin1String("http://")) && !searchUrlTemplate.startsWith(QLatin1String("https://"))) { - return; - } - - m_searchUrlTemplate = searchUrlTemplate; -} - -/*! - Constructs and returns a search URL with a given \a searchTerm. - - The URL template is processed according to the specification: - http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax - - A list of template parameters currently supported and what they are replaced with: - \table - \header \o parameter - \o value - \row \o "{count}" - \o "20" - \row \o "{startIndex}" - \o "0" - \row \o "{startPage}" - \o "0" - \row \o "{language}" - \o "the default language code (RFC 3066)" - \row \o "{inputEncoding}" - \o "UTF-8" - \row \o "{outputEncoding}" - \o "UTF-8" - \row \o "{*:source}" - \o "application name, QCoreApplication::applicationName()" - \row \o "{searchTerms}" - \o "the string supplied by the user" - \endtable - - \sa searchUrlTemplate(), searchParameters(), suggestionsUrl() -*/ -QUrl OpenSearchEngine::searchUrl(const QString &searchTerm) const -{ - if (m_searchUrlTemplate.isEmpty()) { - return QUrl(); - } - - QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_searchUrlTemplate).toUtf8()); - - QUrlQuery query(retVal); - if (m_searchMethod != QLatin1String("post")) { - Parameters::const_iterator end = m_searchParameters.constEnd(); - Parameters::const_iterator i = m_searchParameters.constBegin(); - for (; i != end; ++i) { - query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); - } - retVal.setQuery(query); - } - - return retVal; -} - -QByteArray OpenSearchEngine::getPostData(const QString &searchTerm) const -{ - if (m_searchMethod != QLatin1String("post")) { - return QByteArray(); - } - - QUrl retVal = QUrl("http://foo.bar"); - - QUrlQuery query(retVal); - Parameters::const_iterator end = m_searchParameters.constEnd(); - Parameters::const_iterator i = m_searchParameters.constBegin(); - for (; i != end; ++i) { - query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); - } - retVal.setQuery(query); - - QByteArray data = retVal.toEncoded(QUrl::RemoveScheme); - return data.contains('?') ? data.mid(data.lastIndexOf('?') + 1) : QByteArray(); -} - -/*! - \property providesSuggestions - \brief indicates whether the engine supports contextual suggestions -*/ -bool OpenSearchEngine::providesSuggestions() const -{ - return (!m_suggestionsUrlTemplate.isEmpty() || !m_preparedSuggestionsUrl.isEmpty()); -} - -/*! - \property OpenSearchEngine::suggestionsUrlTemplate - \brief the template of the suggestions URL - - \sa suggestionsUrl(), suggestionsParameters(), searchUrlTemplate() -*/ -QString OpenSearchEngine::suggestionsUrlTemplate() const -{ - return m_suggestionsUrlTemplate; -} - -void OpenSearchEngine::setSuggestionsUrlTemplate(const QString &suggestionsUrlTemplate) -{ - if (!suggestionsUrlTemplate.startsWith(QLatin1String("http://")) && !suggestionsUrlTemplate.startsWith(QLatin1String("https://"))) { - return; - } - - m_suggestionsUrlTemplate = suggestionsUrlTemplate; -} - -/*! - Constructs a suggestions URL with a given \a searchTerm. - - The URL template is processed according to the specification: - http://www.opensearch.org/Specifications/OpenSearch/1.1#OpenSearch_URL_template_syntax - - See searchUrl() for more information about processing template parameters. - - \sa suggestionsUrlTemplate(), suggestionsParameters(), searchUrl() -*/ -QUrl OpenSearchEngine::suggestionsUrl(const QString &searchTerm) const -{ - if (!m_preparedSuggestionsUrl.isEmpty()) { - QString s = m_preparedSuggestionsUrl; - s.replace(QLatin1String("%s"), searchTerm); - return QUrl(s); - } - - if (m_suggestionsUrlTemplate.isEmpty()) { - return QUrl(); - } - - QUrl retVal = QUrl::fromEncoded(parseTemplate(searchTerm, m_suggestionsUrlTemplate).toUtf8()); - - QUrlQuery query(retVal); - if (m_suggestionsMethod != QLatin1String("post")) { - Parameters::const_iterator end = m_suggestionsParameters.constEnd(); - Parameters::const_iterator i = m_suggestionsParameters.constBegin(); - for (; i != end; ++i) { - query.addQueryItem(i->first, parseTemplate(searchTerm, i->second)); - } - retVal.setQuery(query); - } - - return retVal; -} - -/*! - \property searchParameters - \brief additional parameters that will be included in the search URL - - For more information see: - http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0 -*/ -OpenSearchEngine::Parameters OpenSearchEngine::searchParameters() const -{ - return m_searchParameters; -} - -void OpenSearchEngine::setSearchParameters(const Parameters &searchParameters) -{ - m_searchParameters = searchParameters; -} - -/*! - \property suggestionsParameters - \brief additional parameters that will be included in the suggestions URL - - For more information see: - http://www.opensearch.org/Specifications/OpenSearch/Extensions/Parameter/1.0 -*/ -OpenSearchEngine::Parameters OpenSearchEngine::suggestionsParameters() const -{ - return m_suggestionsParameters; -} - -void OpenSearchEngine::setSuggestionsParameters(const Parameters &suggestionsParameters) -{ - m_suggestionsParameters = suggestionsParameters; -} - -/*! - \property searchMethod - \brief HTTP request method that will be used to perform search requests -*/ -QString OpenSearchEngine::searchMethod() const -{ - return m_searchMethod; -} - -void OpenSearchEngine::setSearchMethod(const QString &method) -{ - QString requestMethod = method.toLower(); - if (!m_requestMethods.contains(requestMethod)) { - return; - } - - m_searchMethod = requestMethod; -} - -/*! - \property suggestionsMethod - \brief HTTP request method that will be used to perform suggestions requests -*/ -QString OpenSearchEngine::suggestionsMethod() const -{ - return m_suggestionsMethod; -} - -void OpenSearchEngine::setSuggestionsMethod(const QString &method) -{ - QString requestMethod = method.toLower(); - if (!m_requestMethods.contains(requestMethod)) { - return; - } - - m_suggestionsMethod = requestMethod; -} - -/*! - \property imageUrl - \brief the image URL of the engine - - When setting a new image URL, it won't be loaded immediately. The first request will be - deferred until image() is called for the first time. - - \note To be able to request external images, you need to provide a network access manager, - which will be used for network operations. - - \sa image(), networkAccessManager() -*/ -QString OpenSearchEngine::imageUrl() const -{ - return m_imageUrl; -} - -void OpenSearchEngine::setImageUrl(const QString &imageUrl) -{ - m_imageUrl = imageUrl; -} - -void OpenSearchEngine::loadImage() const -{ - if (m_imageUrl.isEmpty()) { - return; - } - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - - QNetworkReply* reply = networkAccessManager.get(QNetworkRequest(QUrl::fromEncoded(m_imageUrl.toUtf8()))); - connect(reply, SIGNAL(finished()), this, SLOT(imageObtained())); -} - -void OpenSearchEngine::imageObtained() -{ - QNetworkReply* reply = qobject_cast(sender()); - - if (!reply) { - return; - } - - QByteArray response = reply->readAll(); - - reply->close(); - reply->deleteLater(); - - if (response.isEmpty()) { - return; - } - - m_image.loadFromData(response); - emit imageChanged(); -} - -/*! - \property image - \brief the image of the engine - - When no image URL has been set and an image will be set explicitly, a new data URL - will be constructed, holding the image data encoded with Base64. - - \sa imageUrl() -*/ -QImage OpenSearchEngine::image() const -{ - if (m_image.isNull()) { - loadImage(); - } - return m_image; -} - -void OpenSearchEngine::setImage(const QImage &image) -{ - if (m_imageUrl.isEmpty()) { - QBuffer imageBuffer; - imageBuffer.open(QBuffer::ReadWrite); - if (image.save(&imageBuffer, "PNG")) { - m_imageUrl = QString(QLatin1String("data:image/png;base64,%1")) - .arg(QLatin1String(imageBuffer.buffer().toBase64())); - } - } - - m_image = image; - emit imageChanged(); -} - -/*! - \property valid - \brief indicates whether the engine is valid i.e. the description was properly formed and included all necessary information -*/ -bool OpenSearchEngine::isValid() const -{ - return (!m_name.isEmpty() && !m_searchUrlTemplate.isEmpty()); -} - -bool OpenSearchEngine::operator==(const OpenSearchEngine &other) const -{ - return (m_name == other.m_name - && m_description == other.m_description - && m_imageUrl == other.m_imageUrl - && m_searchUrlTemplate == other.m_searchUrlTemplate - && m_suggestionsUrlTemplate == other.m_suggestionsUrlTemplate - && m_searchParameters == other.m_searchParameters - && m_suggestionsParameters == other.m_suggestionsParameters); -} - -bool OpenSearchEngine::operator<(const OpenSearchEngine &other) const -{ - return (m_name < other.m_name); -} - -/*! - Requests contextual suggestions on the search engine, for a given \a searchTerm. - - If succeeded, suggestions() signal will be emitted once the suggestions are received. - - \note To be able to request suggestions, you need to provide a network access manager, - which will be used for network operations. - - \sa requestSearchResults() -*/ - -void OpenSearchEngine::setSuggestionsParameters(const QByteArray ¶meters) -{ - m_preparedSuggestionsParameters = parameters; -} - -void OpenSearchEngine::setSuggestionsUrl(const QString &string) -{ - m_preparedSuggestionsUrl = string; -} - -QString OpenSearchEngine::getSuggestionsUrl() -{ - return suggestionsUrl("searchstring").toString().replace(QLatin1String("searchstring"), QLatin1String("%s")); -} - -QByteArray OpenSearchEngine::getSuggestionsParameters() -{ - QStringList parameters; - Parameters::const_iterator end = m_suggestionsParameters.constEnd(); - Parameters::const_iterator i = m_suggestionsParameters.constBegin(); - for (; i != end; ++i) { - parameters.append(i->first + QLatin1String("=") + i->second); - } - - QByteArray data = parameters.join(QLatin1String("&")).toUtf8(); - - return data; -} - -void OpenSearchEngine::requestSuggestions(const QString &searchTerm) -{ - if (searchTerm.isEmpty() || !providesSuggestions()) { - return; - } - - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - - if (m_suggestionsReply) { - m_suggestionsReply->disconnect(this); - m_suggestionsReply->abort(); - m_suggestionsReply->deleteLater(); - m_suggestionsReply = 0; - } - - Q_ASSERT(m_requestMethods.contains(m_suggestionsMethod)); - if (m_suggestionsMethod == QLatin1String("get")) { - m_suggestionsReply = networkAccessManager.get(QNetworkRequest(suggestionsUrl(searchTerm))); - } - else { - QStringList parameters; - Parameters::const_iterator end = m_suggestionsParameters.constEnd(); - Parameters::const_iterator i = m_suggestionsParameters.constBegin(); - for (; i != end; ++i) { - parameters.append(i->first + QLatin1String("=") + i->second); - } - - QByteArray data = parameters.join(QLatin1String("&")).toUtf8(); - m_suggestionsReply = networkAccessManager.post(QNetworkRequest(suggestionsUrl(searchTerm)), data); - } - - connect(m_suggestionsReply, SIGNAL(finished()), this, SLOT(suggestionsObtained())); -} - -/*! - Requests search results on the search engine, for a given \a searchTerm. - - The default implementation does nothing, to supply your own you need to create your own - OpenSearchEngineDelegate subclass and supply it to the engine. Then the function will call - the performSearchRequest() method of the delegate, which can then handle the request - in a custom way. - - \sa requestSuggestions(), delegate() -*/ -void OpenSearchEngine::requestSearchResults(const QString &searchTerm) -{ - if (!m_delegate || searchTerm.isEmpty()) { - return; - } - - Q_ASSERT(m_requestMethods.contains(m_searchMethod)); - - QNetworkRequest request(QUrl(searchUrl(searchTerm))); - QByteArray data; - QNetworkAccessManager::Operation operation = m_requestMethods.value(m_searchMethod); - - if (operation == QNetworkAccessManager::PostOperation) { - QStringList parameters; - Parameters::const_iterator end = m_searchParameters.constEnd(); - Parameters::const_iterator i = m_searchParameters.constBegin(); - for (; i != end; ++i) { - parameters.append(i->first + QLatin1String("=") + i->second); - } - - data = parameters.join(QLatin1String("&")).toUtf8(); - } - - m_delegate->performSearchRequest(request, operation, data); -} - -void OpenSearchEngine::suggestionsObtained() -{ - const QByteArray response = m_suggestionsReply->readAll(); - - m_suggestionsReply->close(); - m_suggestionsReply->deleteLater(); - m_suggestionsReply = 0; - - QJsonParseError err; - QJsonDocument json = QJsonDocument::fromJson(response, &err); - const QVariant res = json.toVariant(); - - if (err.error != QJsonParseError::NoError || res.type() != QVariant::List) - return; - - const QVariantList list = res.toList(); - - if (list.size() < 2) - return; - - QStringList out; - - foreach (const QVariant &v, list.at(1).toList()) - out.append(v.toString()); - - emit suggestions(out); -} - - -/*! - \property delegate - \brief the delegate that is used to perform specific tasks. - - It can be currently supplied to provide a custom behaviour ofthe requetSearchResults() method. - The default implementation does nothing. -*/ -OpenSearchEngineDelegate* OpenSearchEngine::delegate() const -{ - return m_delegate; -} - -void OpenSearchEngine::setDelegate(OpenSearchEngineDelegate* delegate) -{ - m_delegate = delegate; -} - -/*! - \fn void OpenSearchEngine::imageChanged() - - This signal is emitted whenever the image of the engine changes. - - \sa image(), imageUrl() -*/ - -/*! - \fn void OpenSearchEngine::suggestions(const QStringList &suggestions) - - This signal is emitted whenever new contextual suggestions have been provided - by the search engine. To request suggestions, use requestSuggestions(). - The suggestion set is specified by \a suggestions. - - \sa requestSuggestions() -*/ diff --git a/interface/src/opensearch/opensearchengine.h b/interface/src/opensearch/opensearchengine.h deleted file mode 100644 index fa714b85d3..0000000000 --- a/interface/src/opensearch/opensearchengine.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef OPENSEARCHENGINE_H -#define OPENSEARCHENGINE_H - -#include -#include -#include -#include -#include -#include - -class QNetworkReply; - -class OpenSearchEngineDelegate; -class OpenSearchEngine : public QObject -{ - Q_OBJECT - -signals: - void imageChanged(); - void suggestions(const QStringList &suggestions); - -public: - typedef QPair Parameter; - typedef QList Parameters; - - Q_PROPERTY(QString name READ name WRITE setName) - Q_PROPERTY(QString description READ description WRITE setDescription) - Q_PROPERTY(QString searchUrlTemplate READ searchUrlTemplate WRITE setSearchUrlTemplate) - Q_PROPERTY(Parameters searchParameters READ searchParameters WRITE setSearchParameters) - Q_PROPERTY(QString searchMethod READ searchMethod WRITE setSearchMethod) - Q_PROPERTY(QString suggestionsUrlTemplate READ suggestionsUrlTemplate WRITE setSuggestionsUrlTemplate) - Q_PROPERTY(QString suggestionsUrl READ getSuggestionsUrl WRITE setSuggestionsUrl) - Q_PROPERTY(Parameters suggestionsParameters READ suggestionsParameters WRITE setSuggestionsParameters) - Q_PROPERTY(QString suggestionsMethod READ suggestionsMethod WRITE setSuggestionsMethod) - Q_PROPERTY(bool providesSuggestions READ providesSuggestions) - Q_PROPERTY(QString imageUrl READ imageUrl WRITE setImageUrl) - Q_PROPERTY(bool valid READ isValid) - - OpenSearchEngine(QObject* parent = 0); - ~OpenSearchEngine(); - - QString name() const; - void setName(const QString &name); - - QString description() const; - void setDescription(const QString &description); - - QString searchUrlTemplate() const; - void setSearchUrlTemplate(const QString &searchUrl); - - QByteArray getPostData(const QString &searchTerm) const; - - bool providesSuggestions() const; - - QString suggestionsUrlTemplate() const; - void setSuggestionsUrlTemplate(const QString &suggestionsUrl); - QUrl suggestionsUrl(const QString &searchTerm) const; - - Parameters searchParameters() const; - void setSearchParameters(const Parameters &searchParameters); - - Parameters suggestionsParameters() const; - void setSuggestionsParameters(const Parameters &suggestionsParameters); - - QString searchMethod() const; - void setSearchMethod(const QString &method); - - QString suggestionsMethod() const; - void setSuggestionsMethod(const QString &method); - - QString imageUrl() const; - void setImageUrl(const QString &url); - - QImage image() const; - void setImage(const QImage &image); - - bool isValid() const; - - void setSuggestionsUrl(const QString &string); - void setSuggestionsParameters(const QByteArray ¶meters); - QString getSuggestionsUrl(); - QByteArray getSuggestionsParameters(); - - OpenSearchEngineDelegate* delegate() const; - void setDelegate(OpenSearchEngineDelegate* delegate); - - bool operator==(const OpenSearchEngine &other) const; - bool operator<(const OpenSearchEngine &other) const; - -public slots: - QUrl searchUrl(const QString &searchTerm) const; - void requestSuggestions(const QString &searchTerm); - void requestSearchResults(const QString &searchTerm); - -protected: - static QString parseTemplate(const QString &searchTerm, const QString &searchTemplate); - void loadImage() const; - -private slots: - void imageObtained(); - void suggestionsObtained(); - -private: - QString m_name; - QString m_description; - - QString m_imageUrl; - QImage m_image; - - QString m_searchUrlTemplate; - QString m_suggestionsUrlTemplate; - Parameters m_searchParameters; - Parameters m_suggestionsParameters; - QString m_searchMethod; - QString m_suggestionsMethod; - - QByteArray m_preparedSuggestionsParameters; - QString m_preparedSuggestionsUrl; - - QMap m_requestMethods; - - QNetworkReply* m_suggestionsReply; - - OpenSearchEngineDelegate* m_delegate; -}; - -#endif // OPENSEARCHENGINE_H - diff --git a/interface/src/opensearch/opensearchenginedelegate.cpp b/interface/src/opensearch/opensearchenginedelegate.cpp deleted file mode 100644 index 2c9c18ece0..0000000000 --- a/interface/src/opensearch/opensearchenginedelegate.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include "opensearchenginedelegate.h" - -/*! - \class OpenSearchEngineDelegate - \brief An abstract class providing custom processing of specific activities. - - OpenSearchEngineDelegate is an abstract class that can be subclassed and set on - an OpenSearchEngine. It allows to customize some parts of the default implementation - or even extend it with missing bits. - - Currently subclasses can only provide a custom way of handling search requests by - reimplementing the performSearchRequest() method. - - \sa OpenSearchEngine -*/ - -/*! - Constructs the delegate. -*/ -OpenSearchEngineDelegate::OpenSearchEngineDelegate() -{ -} - -/*! - Destructs the delegate. -*/ -OpenSearchEngineDelegate::~OpenSearchEngineDelegate() -{ -} - -/*! - \fn void performSearchRequest(const QNetworkRequest &request, - QNetworkAccessManager::Operation operation, const QByteArray &data) = 0 - - This method will be used after OpenSearchEngine::requestResults() is called. - - For example, a console application that uses the OpenSearchEngine class to generate - a search URL for a search term supplied by the user would reimplement the function - and forward the request to e.g. a web browser. - - Likewise, a web browser that uses the OpenSearchEngine class to support multiple search - engines e.g. in a toolbar would perform the request and navigate to the search results site. -*/ diff --git a/interface/src/opensearch/opensearchenginedelegate.h b/interface/src/opensearch/opensearchenginedelegate.h deleted file mode 100644 index ae7b5ef876..0000000000 --- a/interface/src/opensearch/opensearchenginedelegate.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef OPENSEARCHENGINEDELEGATE_H -#define OPENSEARCHENGINEDELEGATE_H - -#include -#include - -class OpenSearchEngineDelegate -{ -public: - OpenSearchEngineDelegate(); - virtual ~OpenSearchEngineDelegate(); - - virtual void performSearchRequest(const QNetworkRequest &request, - QNetworkAccessManager::Operation operation, - const QByteArray &data) = 0; -}; - -#endif // OPENSEARCHENGINEDELEGATE_H diff --git a/interface/src/webbrowser/webbrowsersuggestionsengine.cpp b/interface/src/webbrowser/webbrowsersuggestionsengine.cpp new file mode 100644 index 0000000000..546d9c68b0 --- /dev/null +++ b/interface/src/webbrowser/webbrowsersuggestionsengine.cpp @@ -0,0 +1,87 @@ +// +// webbrowsersuggestionsengine.cpp +// interface/src/webbrowser +// +// Created by Vlad Stelmahovsky Kapolka on 30/10/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "webbrowsersuggestionsengine.h" +#include "qregexp.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +const QString GoogleSuggestionsUrl = "https://suggestqueries.google.com/complete/search?output=firefox&q=%1"; + +WebBrowserSuggestionsEngine::WebBrowserSuggestionsEngine(QObject* parent) + : QObject(parent) + , _suggestionsReply(0) { + _currentNAM = &NetworkAccessManager::getInstance(); + connect(_currentNAM, &QNetworkAccessManager::finished, this, &WebBrowserSuggestionsEngine::suggestionsFinished); +} + + +WebBrowserSuggestionsEngine::~WebBrowserSuggestionsEngine() { + disconnect(_currentNAM, &QNetworkAccessManager::finished, this, &WebBrowserSuggestionsEngine::suggestionsFinished); +} + +void WebBrowserSuggestionsEngine::querySuggestions(const QString &searchString) { + if (_suggestionsReply) { + _suggestionsReply->disconnect(this); + _suggestionsReply->abort(); + _suggestionsReply->deleteLater(); + _suggestionsReply = 0; + } + QString url = QString(GoogleSuggestionsUrl).arg(searchString); + _suggestionsReply = _currentNAM->get(QNetworkRequest(url)); +} + +void WebBrowserSuggestionsEngine::suggestionsFinished(QNetworkReply *reply) { + + if (reply != _suggestionsReply) { + return; //invalid reply. ignore + } + + const QByteArray response = _suggestionsReply->readAll(); + + _suggestionsReply->close(); + _suggestionsReply->deleteLater(); + _suggestionsReply = 0; + + QJsonParseError err; + QJsonDocument json = QJsonDocument::fromJson(response, &err); + const QVariant res = json.toVariant(); + + if (err.error != QJsonParseError::NoError || res.type() != QVariant::List) { + return; + } + + const QVariantList list = res.toList(); + + if (list.size() < 2) { + return; + } + + QStringList out; + const QVariantList& suggList = list.at(1).toList(); + + foreach (const QVariant &v, suggList) { + out.append(v.toString()); + } + + emit suggestions(out); +} diff --git a/interface/src/webbrowser/webbrowsersuggestionsengine.h b/interface/src/webbrowser/webbrowsersuggestionsengine.h new file mode 100644 index 0000000000..fa0f7f8e2e --- /dev/null +++ b/interface/src/webbrowser/webbrowsersuggestionsengine.h @@ -0,0 +1,46 @@ +#ifndef WEBBROWSERSUGGESTIONSENGINE_H +#define WEBBROWSERSUGGESTIONSENGINE_H + +#include +#include +#include +// +// webbrowsersuggestionsengine.h +// interface/src/webbrowser +// +// Created by Vlad Stelmahovsky Kapolka on 30/10/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include + +class QNetworkReply; + +class WebBrowserSuggestionsEngine : public QObject +{ + Q_OBJECT + +public: + WebBrowserSuggestionsEngine(QObject* parent = 0); + virtual ~WebBrowserSuggestionsEngine(); + +public slots: + void querySuggestions(const QString& searchString); + +signals: + void suggestions(const QStringList& suggestions); + +private slots: + void suggestionsFinished(QNetworkReply *reply); +private: + QNetworkReply* _suggestionsReply; + QNetworkAccessManager* _currentNAM; +}; + +#endif // WEBBROWSERSUGGESTIONSENGINE_H + From e9a5acda06373ac98a8a7c70c53f67df29b222c0 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 27 Oct 2017 10:39:37 -0700 Subject: [PATCH 036/292] control hovering, preset buttons for clicking, constness, scroll off surface --- interface/src/raypick/LaserPointer.cpp | 56 ++++++++++++++----- interface/src/raypick/LaserPointer.h | 18 +++--- .../src/raypick/PointerScriptingInterface.cpp | 7 ++- libraries/pointers/src/pointers/Pointer.cpp | 36 ++++++++---- libraries/pointers/src/pointers/Pointer.h | 14 +++-- .../pointers/src/pointers/PointerManager.cpp | 6 +- .../pointers/src/pointers/PointerManager.h | 6 +- 7 files changed, 100 insertions(+), 43 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index b8122a2388..92a404e765 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -17,9 +17,9 @@ #include #include "PickScriptingInterface.h" -LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const PointerTriggers& triggers, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) : - Pointer(DependencyManager::get()->createRayPick(rayProps), enabled), +LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, + const PointerTriggers& triggers, bool faceAvatar, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool enabled) : + Pointer(DependencyManager::get()->createRayPick(rayProps), enabled, hover), _triggers(triggers), _renderStates(renderStates), _defaultRenderStates(defaultRenderStates), @@ -83,7 +83,7 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant& } } -void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) { +void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState) { if (!renderState.getStartID().isNull()) { QVariantMap startProps; startProps.insert("position", vec3toVariant(pickRay.origin)); @@ -210,13 +210,13 @@ Pointer::Buttons LaserPointer::getPressedButtons() { return toReturn; } -void LaserPointer::setLength(const float length) { +void LaserPointer::setLength(float length) { withWriteLock([&] { _laserLength = length; }); } -void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) { +void LaserPointer::setLockEndUUID(const QUuid& objectID, bool isOverlay) { withWriteLock([&] { _objectLockEnd = std::pair(objectID, isOverlay); }); @@ -281,21 +281,49 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) { return RenderState(startID, pathID, endID); } -PointerEvent LaserPointer::buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const { +PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const { uint32_t id = 0; glm::vec3 intersection = vec3FromVariant(pickResult["intersection"]); glm::vec3 surfaceNormal = vec3FromVariant(pickResult["surfaceNormal"]); glm::vec3 direction = -surfaceNormal; - IntersectionType type = IntersectionType(pickResult["type"].toUInt()); + QUuid pickedID = pickResult["objectID"].toUuid(); glm::vec2 pos2D; - if (type == ENTITY) { - pos2D = projectOntoEntityXYPlane(uid, intersection); - } else if (type == OVERLAY) { - pos2D = projectOntoOverlayXYPlane(uid, intersection); + if (pickedID != target.objectID) { + QVariantMap searchRay = pickResult["searchRay"].toMap(); + glm::vec3 origin = vec3FromVariant(searchRay["origin"]); + glm::vec3 direction = vec3FromVariant(searchRay["direction"]); + if (target.type == ENTITY) { + intersection = intersectRayWithEntityXYPlane(target.objectID, origin, direction); + } else if (target.type == OVERLAY) { + intersection = intersectRayWithOverlayXYPlane(target.objectID, origin, direction); + } + } + if (target.type == ENTITY) { + pos2D = projectOntoEntityXYPlane(target.objectID, intersection); + } else if (target.type == OVERLAY) { + pos2D = projectOntoOverlayXYPlane(target.objectID, intersection); } return PointerEvent(PointerEvent::Move, id, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons); } +glm::vec3 LaserPointer::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const { + glm::vec3 n = rotation * Vectors::FRONT; + float t = glm::dot(n, point - origin) / glm::dot(n, direction); + return origin + t * direction; +} + +glm::vec3 LaserPointer::intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) const { + glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value); + glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value); + const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); + return intersectRayWithXYPlane(origin, direction, position, rotation, DEFAULT_REGISTRATION_POINT); +} + +glm::vec3 LaserPointer::intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) const { + auto props = DependencyManager::get()->getEntityProperties(entityID); + return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint()); +} + glm::vec2 LaserPointer::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const { glm::quat invRot = glm::inverse(rotation); glm::vec3 localPos = invRot * (worldPos - position); @@ -325,7 +353,7 @@ glm::vec2 LaserPointer::projectOntoOverlayXYPlane(const QUuid& overlayID, const return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT); } -glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entity, const glm::vec3& worldPos) const { - auto props = DependencyManager::get()->getEntityProperties(entity); +glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const { + auto props = DependencyManager::get()->getEntityProperties(entityID); return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint()); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 167de88385..bdd3f2ffa0 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -54,16 +54,16 @@ public: typedef std::unordered_map RenderStateMap; typedef std::unordered_map> DefaultRenderStateMap; - LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, const PointerTriggers& triggers, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled); + LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, const PointerTriggers& triggers, + bool faceAvatar, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool enabled); ~LaserPointer(); void setRenderState(const std::string& state) override; // You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays. void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override; - void setLength(const float length) override; - void setLockEndUUID(QUuid objectID, const bool isOverlay) override; + void setLength(float length) override; + void setLockEndUUID(const QUuid& objectID, bool isOverlay) override; void updateVisuals(const QVariantMap& prevRayPickResult) override; @@ -73,7 +73,7 @@ public: static RenderState buildRenderState(const QVariantMap& propMap); protected: - PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const override; + PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const override; private: PointerTriggers _triggers; @@ -88,10 +88,14 @@ private: std::pair _objectLockEnd { std::pair(QUuid(), false)}; void updateRenderStateOverlay(const OverlayID& id, const QVariant& props); - void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState); + void updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState); void disableRenderState(const RenderState& renderState); - glm::vec2 projectOntoEntityXYPlane(const QUuid& entity, const glm::vec3& worldPos) const; + + glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) const; + glm::vec3 intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) const; + glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const; + glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const; glm::vec2 projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos) const; glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const; diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 5ac209d295..c3a4ac164a 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -87,6 +87,11 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) } } + bool hover = false; + if (propertyMap["hover"].isValid()) { + hover = propertyMap["hover"].toBool(); + } + PointerTriggers triggers; auto userInputMapper = DependencyManager::get(); if (propertyMap["triggers"].isValid()) { @@ -105,7 +110,7 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) } } - return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, triggers, + return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, hover, triggers, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled)); } diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 0075762f02..af560a45ab 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -33,7 +33,7 @@ const QVariantMap Pointer::getPrevPickResult() { return DependencyManager::get()->getPrevPickResult(_pickUID); } -void Pointer::setPrecisionPicking(const bool precisionPicking) { +void Pointer::setPrecisionPicking(bool precisionPicking) { DependencyManager::get()->setPrecisionPicking(_pickUID, precisionPicking); } @@ -60,16 +60,17 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { // Hover events Pointer::PickedObject hoveredObject = getHoveredObject(pickResult); - PointerEvent hoveredEvent = buildPointerEvent(hoveredObject.objectID, pickResult); + PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult); hoveredEvent.setType(PointerEvent::Move); + // TODO: set buttons on hover events hoveredEvent.setButton(PointerEvent::NoButtons); - if (_enabled) { + if (_enabled && _hover) { if (hoveredObject.type == OVERLAY) { if (_prevHoveredObject.type == OVERLAY) { if (hoveredObject.objectID == _prevHoveredObject.objectID) { emit pointerManager->hoverContinueOverlay(hoveredObject.objectID, hoveredEvent); } else { - PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject.objectID, pickResult); + PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult); emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, prevHoveredEvent); emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); } @@ -87,7 +88,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { if (hoveredObject.objectID == _prevHoveredObject.objectID) { emit pointerManager->hoverContinueEntity(hoveredObject.objectID, hoveredEvent); } else { - PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject.objectID, pickResult); + PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult); emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, prevHoveredEvent); emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); } @@ -122,7 +123,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { const std::string SHOULD_FOCUS_BUTTON = "Focus"; for (const std::string& button : newButtons) { hoveredEvent.setType(PointerEvent::Press); - hoveredEvent.setButton(PointerEvent::PrimaryButton); + hoveredEvent.setButton(chooseButton(button)); hoveredEvent.setShouldFocus(button == SHOULD_FOCUS_BUTTON); if (hoveredObject.type == ENTITY) { emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent); @@ -134,9 +135,9 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { // Trigger continue for (const std::string& button : sameButtons) { - PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button].objectID, pickResult); + PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); triggeredEvent.setType(PointerEvent::Move); - triggeredEvent.setButton(PointerEvent::PrimaryButton); + hoveredEvent.setButton(chooseButton(button)); if (_triggeredObjects[button].type == ENTITY) { emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { @@ -146,9 +147,9 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { // Trigger end for (const std::string& button : _prevButtons) { - PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button].objectID, pickResult); + PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); triggeredEvent.setType(PointerEvent::Release); - triggeredEvent.setButton(PointerEvent::PrimaryButton); + hoveredEvent.setButton(chooseButton(button)); if (_triggeredObjects[button].type == ENTITY) { emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { @@ -159,4 +160,19 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { _prevHoveredObject = hoveredObject; _prevButtons = buttons; +} + +PointerEvent::Button Pointer::chooseButton(const std::string& button) { + const std::string PRIMARY_BUTTON = "Primary"; + const std::string SECONDARY_BUTTON = "Secondary"; + const std::string TERTIARY_BUTTON = "Tertiary"; + if (button == PRIMARY_BUTTON) { + return PointerEvent::PrimaryButton; + } else if (button == SECONDARY_BUTTON) { + return PointerEvent::SecondaryButton; + } else if (button == TERTIARY_BUTTON) { + return PointerEvent::TertiaryButton; + } else { + return PointerEvent::NoButtons; + } } \ No newline at end of file diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index 595daebc33..ca35c38c7a 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -38,7 +38,7 @@ using PointerTriggers = std::vector; class Pointer : protected ReadWriteLockable { public: - Pointer(const QUuid& uid, bool enabled) : _pickUID(uid), _enabled(enabled) {} + Pointer(const QUuid& uid, bool enabled, bool hover) : _pickUID(uid), _enabled(enabled), _hover(hover) {} virtual ~Pointer(); @@ -49,13 +49,13 @@ public: virtual void setRenderState(const std::string& state) = 0; virtual void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) = 0; - virtual void setPrecisionPicking(const bool precisionPicking); + virtual void setPrecisionPicking(bool precisionPicking); virtual void setIgnoreItems(const QVector& ignoreItems) const; virtual void setIncludeItems(const QVector& includeItems) const; // Pointers can choose to implement these - virtual void setLength(const float length) {} - virtual void setLockEndUUID(QUuid objectID, const bool isOverlay) {} + virtual void setLength(float length) {} + virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay) {} void update(); virtual void updateVisuals(const QVariantMap& pickResult) = 0; @@ -79,13 +79,17 @@ public: protected: const QUuid _pickUID; bool _enabled; + bool _hover; - virtual PointerEvent buildPointerEvent(const QUuid& uid, const QVariantMap& pickResult) const = 0; + virtual PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const = 0; private: PickedObject _prevHoveredObject; Buttons _prevButtons; std::unordered_map _triggeredObjects; + + PointerEvent::Button chooseButton(const std::string& button); + }; #endif // hifi_Pick_h diff --git a/libraries/pointers/src/pointers/PointerManager.cpp b/libraries/pointers/src/pointers/PointerManager.cpp index a475ba4d83..2d41543b6b 100644 --- a/libraries/pointers/src/pointers/PointerManager.cpp +++ b/libraries/pointers/src/pointers/PointerManager.cpp @@ -79,7 +79,7 @@ void PointerManager::update() { } } -void PointerManager::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const { +void PointerManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { auto pointer = find(uid); if (pointer) { pointer->setPrecisionPicking(precisionPicking); @@ -100,14 +100,14 @@ void PointerManager::setIncludeItems(const QUuid& uid, const QVector& inc } } -void PointerManager::setLength(const QUuid& uid, const float length) const { +void PointerManager::setLength(const QUuid& uid, float length) const { auto pointer = find(uid); if (pointer) { pointer->setLength(length); } } -void PointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const { +void PointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { auto pointer = find(uid); if (pointer) { pointer->setLockEndUUID(objectID, isOverlay); diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 6e13c09851..9f477d9eb2 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -31,12 +31,12 @@ public: void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; const QVariantMap getPrevPickResult(const QUuid& uid) const; - void setPrecisionPicking(const QUuid& uid, const bool precisionPicking) const; + void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; void setIncludeItems(const QUuid& uid, const QVector& includeEntities) const; - void setLength(const QUuid& uid, const float length) const; - void setLockEndUUID(const QUuid& uid, const QUuid& objectID, const bool isOverlay) const; + void setLength(const QUuid& uid, float length) const; + void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const; void update(); From 3a2780bdf689af2540fc01e0dc756512a967b0d6 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Mon, 30 Oct 2017 10:42:26 -0700 Subject: [PATCH 037/292] Enable gain slider in PAL menu to control Avatar MASTER Gain --- interface/resources/qml/hifi/NameCard.qml | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index fcfff02b72..0adcde3ad9 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -441,7 +441,7 @@ Item { Rectangle { id: nameCardVUMeter // Size - width: isMyCard ? myDisplayName.width - 20 : ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * (gainSlider.width); + width: ((gainSlider.value - gainSlider.minimumValue)/(gainSlider.maximumValue - gainSlider.minimumValue)) * (gainSlider.width); height: 8 // Anchors anchors.bottom: isMyCard ? avatarImage.bottom : parent.bottom; @@ -525,16 +525,14 @@ Item { anchors.verticalCenter: nameCardVUMeter.verticalCenter; anchors.left: nameCardVUMeter.left; // Properties - visible: !isMyCard && selected && pal.activeTab == "nearbyTab" && isPresent; + visible: (isMyCard || (selected && pal.activeTab == "nearbyTab")) && isPresent; value: Users.getAvatarGain(uuid) minimumValue: -60.0 maximumValue: 20.0 stepSize: 5 updateValueWhileDragging: true onValueChanged: { - if (uuid !== "") { - updateGainFromQML(uuid, value, false); - } + updateGainFromQML(uuid, value, false); } onPressedChanged: { if (!pressed) { @@ -574,7 +572,19 @@ Item { implicitHeight: 16 } } - } + RalewayRegular { + // The slider for my card is special, it controls the master gain + id: gainSliderText; + visible: isMyCard; + text: "master gain"; + size: hifi.fontSizes.tabularData; + anchors.left: parent.right; + anchors.leftMargin: 8; + color: hifi.colors.baseGrayHighlight; + horizontalAlignment: Text.AlignLeft; + verticalAlignment: Text.AlignTop; + } + } function updateGainFromQML(avatarUuid, sliderValue, isReleased) { Users.setAvatarGain(avatarUuid, sliderValue); From d9c6f17e42b3dc4d23e0bbf81594665f68b8a83d Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 30 Oct 2017 20:06:17 +0100 Subject: [PATCH 038/292] Coding standards --- interface/src/Application.cpp | 2 +- ...ggestionsengine.cpp => WebBrowserSuggestionsEngine.cpp} | 7 ++++--- ...ersuggestionsengine.h => WebBrowserSuggestionsEngine.h} | 0 3 files changed, 5 insertions(+), 4 deletions(-) rename interface/src/webbrowser/{webbrowsersuggestionsengine.cpp => WebBrowserSuggestionsEngine.cpp} (92%) rename interface/src/webbrowser/{webbrowsersuggestionsengine.h => WebBrowserSuggestionsEngine.h} (100%) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bf2754917b..ab1884f67a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -203,7 +203,7 @@ #include "commerce/Wallet.h" #include "commerce/QmlCommerce.h" -#include "webbrowser/webbrowsersuggestionsengine.h" +#include "webbrowser/WebBrowserSuggestionsEngine.h" // On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. diff --git a/interface/src/webbrowser/webbrowsersuggestionsengine.cpp b/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp similarity index 92% rename from interface/src/webbrowser/webbrowsersuggestionsengine.cpp rename to interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp index 546d9c68b0..40af21753b 100644 --- a/interface/src/webbrowser/webbrowsersuggestionsengine.cpp +++ b/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp @@ -9,7 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "webbrowsersuggestionsengine.h" +#include "WebBrowserSuggestionsEngine.h" #include "qregexp.h" #include @@ -26,6 +26,7 @@ #include const QString GoogleSuggestionsUrl = "https://suggestqueries.google.com/complete/search?output=firefox&q=%1"; +const int SUGGESTIONS_LIST_INDEX = 2; WebBrowserSuggestionsEngine::WebBrowserSuggestionsEngine(QObject* parent) : QObject(parent) @@ -72,12 +73,12 @@ void WebBrowserSuggestionsEngine::suggestionsFinished(QNetworkReply *reply) { const QVariantList list = res.toList(); - if (list.size() < 2) { + if (list.size() <= SUGGESTIONS_LIST_INDEX) { return; } QStringList out; - const QVariantList& suggList = list.at(1).toList(); + const QVariantList& suggList = list.at(SUGGESTIONS_LIST_INDEX).toList(); foreach (const QVariant &v, suggList) { out.append(v.toString()); diff --git a/interface/src/webbrowser/webbrowsersuggestionsengine.h b/interface/src/webbrowser/WebBrowserSuggestionsEngine.h similarity index 100% rename from interface/src/webbrowser/webbrowsersuggestionsengine.h rename to interface/src/webbrowser/WebBrowserSuggestionsEngine.h From 7b57fe1a5da214b6b621b17fc5b49d3128f96b04 Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 30 Oct 2017 20:21:34 +0100 Subject: [PATCH 039/292] type fixed --- interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp b/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp index 40af21753b..a21badb0a8 100644 --- a/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp +++ b/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp @@ -25,8 +25,8 @@ #include -const QString GoogleSuggestionsUrl = "https://suggestqueries.google.com/complete/search?output=firefox&q=%1"; -const int SUGGESTIONS_LIST_INDEX = 2; +static const QString GoogleSuggestionsUrl = "https://suggestqueries.google.com/complete/search?output=firefox&q=%1"; +static const int SUGGESTIONS_LIST_INDEX = 1; WebBrowserSuggestionsEngine::WebBrowserSuggestionsEngine(QObject* parent) : QObject(parent) From ea55b5407ea66541f435e193d7a8c4d4ec524b7b Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 30 Oct 2017 20:22:47 +0100 Subject: [PATCH 040/292] bracket fix --- interface/src/webbrowser/WebBrowserSuggestionsEngine.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/webbrowser/WebBrowserSuggestionsEngine.h b/interface/src/webbrowser/WebBrowserSuggestionsEngine.h index fa0f7f8e2e..0a94ea75c4 100644 --- a/interface/src/webbrowser/WebBrowserSuggestionsEngine.h +++ b/interface/src/webbrowser/WebBrowserSuggestionsEngine.h @@ -21,8 +21,7 @@ class QNetworkReply; -class WebBrowserSuggestionsEngine : public QObject -{ +class WebBrowserSuggestionsEngine : public QObject { Q_OBJECT public: From aa9ae6c8381829f598d8b8231d286fa756022564 Mon Sep 17 00:00:00 2001 From: vladest Date: Mon, 30 Oct 2017 20:29:44 +0100 Subject: [PATCH 041/292] License header fix --- .../WebBrowserSuggestionsEngine.cpp | 4 ++-- .../webbrowser/WebBrowserSuggestionsEngine.h | 21 ++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp b/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp index a21badb0a8..4e7b135cdf 100644 --- a/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp +++ b/interface/src/webbrowser/WebBrowserSuggestionsEngine.cpp @@ -1,8 +1,8 @@ // -// webbrowsersuggestionsengine.cpp +// WebBrowserSuggestionsEngine.cpp // interface/src/webbrowser // -// Created by Vlad Stelmahovsky Kapolka on 30/10/17. +// Created by Vlad Stelmahovsky on 30/10/17. // Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. diff --git a/interface/src/webbrowser/WebBrowserSuggestionsEngine.h b/interface/src/webbrowser/WebBrowserSuggestionsEngine.h index 0a94ea75c4..976631f109 100644 --- a/interface/src/webbrowser/WebBrowserSuggestionsEngine.h +++ b/interface/src/webbrowser/WebBrowserSuggestionsEngine.h @@ -1,19 +1,20 @@ +// +// WebBrowserSuggestionsEngine.h +// interface/src/webbrowser +// +// Created by Vlad Stelmahovsky on 30/10/17. +// Copyright 2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + #ifndef WEBBROWSERSUGGESTIONSENGINE_H #define WEBBROWSERSUGGESTIONSENGINE_H #include #include #include -// -// webbrowsersuggestionsengine.h -// interface/src/webbrowser -// -// Created by Vlad Stelmahovsky Kapolka on 30/10/17. -// Copyright 2017 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// #include #include From 76eb4c656ee8a51a4812faa1a5eb45a1b62464f1 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 30 Oct 2017 16:34:02 -0700 Subject: [PATCH 042/292] fix multi-touch and keyboard on web entities --- interface/src/raypick/LaserPointer.cpp | 5 +- interface/src/ui/overlays/Web3DOverlay.cpp | 32 ++-- .../src/RenderableWebEntityItem.cpp | 140 +++++++++++------- .../src/RenderableWebEntityItem.h | 7 +- libraries/pointers/src/pointers/Pointer.cpp | 3 +- 5 files changed, 104 insertions(+), 83 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 92a404e765..83e3757514 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -285,13 +285,12 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const Q uint32_t id = 0; glm::vec3 intersection = vec3FromVariant(pickResult["intersection"]); glm::vec3 surfaceNormal = vec3FromVariant(pickResult["surfaceNormal"]); - glm::vec3 direction = -surfaceNormal; + QVariantMap searchRay = pickResult["searchRay"].toMap(); + glm::vec3 direction = vec3FromVariant(searchRay["direction"]); QUuid pickedID = pickResult["objectID"].toUuid(); glm::vec2 pos2D; if (pickedID != target.objectID) { - QVariantMap searchRay = pickResult["searchRay"].toMap(); glm::vec3 origin = vec3FromVariant(searchRay["origin"]); - glm::vec3 direction = vec3FromVariant(searchRay["direction"]); if (target.type == ENTITY) { intersection = intersectRayWithEntityXYPlane(target.objectID, origin, direction); } else if (target.type == OVERLAY) { diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 0c75803d35..e32246b666 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -66,7 +66,7 @@ const QString Web3DOverlay::QML = "Web3DOverlay.qml"; Web3DOverlay::Web3DOverlay() : _dpi(DPI) { _touchDevice.setCapabilities(QTouchDevice::Position); _touchDevice.setType(QTouchDevice::TouchScreen); - _touchDevice.setName("RenderableWebEntityItemTouchDevice"); + _touchDevice.setName("Web3DOverlayTouchDevice"); _touchDevice.setMaximumTouchPoints(4); _geometryId = DependencyManager::get()->allocateID(); @@ -332,6 +332,12 @@ void Web3DOverlay::setProxyWindow(QWindow* proxyWindow) { } void Web3DOverlay::handlePointerEvent(const PointerEvent& event) { + if (event.getType() == PointerEvent::Press) { + _pressed = true; + } else if (event.getType() == PointerEvent::Release) { + _pressed = false; + } + if (_inputMode == Touch) { handlePointerEventAsTouch(event); } else { @@ -344,19 +350,8 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) { return; } - //do not send secondary button events to tablet - if (event.getButton() == PointerEvent::SecondaryButton || - //do not block composed events - event.getButtons() == PointerEvent::SecondaryButton) { - return; - } - - - QPointF windowPoint; - { - glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi); - windowPoint = QPointF(windowPos.x, windowPos.y); - } + glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi); + QPointF windowPoint(windowPos.x, windowPos.y); Qt::TouchPointState state = Qt::TouchPointStationary; if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) { @@ -395,14 +390,13 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) { } touchEvent.setWindow(_webSurface->getWindow()); + touchEvent.setDevice(&_touchDevice); touchEvent.setTarget(_webSurface->getRootItem()); touchEvent.setTouchPoints(touchPoints); touchEvent.setTouchPointStates(touchPointStates); } // Send mouse events to the Web surface so that HTML dialog elements work with mouse press and hover. - // FIXME: Scroll bar dragging is a bit unstable in the tablet (content can jump up and down at times). - // This may be improved in Qt 5.8. Release notes: "Cleaned up touch and mouse event delivery". // // In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will // receive mouse events @@ -449,12 +443,6 @@ void Web3DOverlay::handlePointerEventAsMouse(const PointerEvent& event) { glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi); QPointF windowPoint(windowPos.x, windowPos.y); - if (event.getType() == PointerEvent::Press) { - this->_pressed = true; - } else if (event.getType() == PointerEvent::Release) { - this->_pressed = false; - } - Qt::MouseButtons buttons = Qt::NoButton; if (event.getButtons() & PointerEvent::PrimaryButton) { buttons |= Qt::LeftButton; diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index a2e574a829..ad4230c55b 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -227,6 +227,8 @@ bool WebEntityRenderer::buildWebSurface(const TypedEntityPointer& entity) { _webSurface->setMaxFps(DEFAULT_MAX_FPS); // FIXME - Keyboard HMD only: Possibly add "HMDinfo" object to context for WebView.qml. _webSurface->getSurfaceContext()->setContextProperty("desktop", QVariant()); + // Let us interact with the keyboard + _webSurface->getSurfaceContext()->setContextProperty("tabletInterface", DependencyManager::get().data()); _fadeStartTime = usecTimestampNow(); loadSourceURL(); _webSurface->resume(); @@ -315,21 +317,9 @@ void WebEntityRenderer::loadSourceURL() { void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) { if (!_lastLocked && _webSurface && _pressed) { // If the user mouses off the entity while the button is down, simulate a touch end. - QTouchEvent::TouchPoint point; - point.setId(event.getID()); - point.setState(Qt::TouchPointReleased); - glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI); - QPointF windowPoint(windowPos.x, windowPos.y); - point.setScenePos(windowPoint); - point.setPos(windowPoint); - QList touchPoints; - touchPoints.push_back(point); - QTouchEvent* touchEvent = new QTouchEvent(QEvent::TouchEnd, nullptr, - Qt::NoModifier, Qt::TouchPointReleased, touchPoints); - touchEvent->setWindow(_webSurface->getWindow()); - touchEvent->setDevice(&_touchDevice); - touchEvent->setTarget(_webSurface->getRootItem()); - QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent); + PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), + event.getButton(), event.getButtons(), event.getKeyboardModifiers()); + handlePointerEvent(endEvent); } } @@ -339,57 +329,95 @@ void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) { return; } + if (event.getType() == PointerEvent::Press) { + _pressed = true; + } else if (event.getType() == PointerEvent::Release) { + _pressed = false; + } + glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI); QPointF windowPoint(windowPos.x, windowPos.y); - if (event.getType() == PointerEvent::Move) { - // Forward a mouse move event to webSurface - QMouseEvent* mouseEvent = new QMouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, Qt::NoButton, Qt::NoButton, Qt::NoModifier); - QCoreApplication::postEvent(_webSurface->getWindow(), mouseEvent); + + Qt::TouchPointState state = Qt::TouchPointStationary; + if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) { + state = Qt::TouchPointPressed; + } else if (event.getType() == PointerEvent::Release) { + state = Qt::TouchPointReleased; + } else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].pos()) { + state = Qt::TouchPointMoved; + } + + QEvent::Type touchType = QEvent::TouchUpdate; + if (_activeTouchPoints.empty()) { + // If the first active touch point is being created, send a begin + touchType = QEvent::TouchBegin; + } if (state == Qt::TouchPointReleased && _activeTouchPoints.size() == 1 && _activeTouchPoints.count(event.getID())) { + // If the last active touch point is being released, send an end + touchType = QEvent::TouchEnd; } { - // Forward a touch update event to webSurface - if (event.getType() == PointerEvent::Press) { - this->_pressed = true; - } else if (event.getType() == PointerEvent::Release) { - this->_pressed = false; - } - - QEvent::Type type; - Qt::TouchPointState touchPointState; - switch (event.getType()) { - case PointerEvent::Press: - type = QEvent::TouchBegin; - touchPointState = Qt::TouchPointPressed; - break; - case PointerEvent::Release: - type = QEvent::TouchEnd; - touchPointState = Qt::TouchPointReleased; - break; - case PointerEvent::Move: - default: - type = QEvent::TouchUpdate; - touchPointState = Qt::TouchPointMoved; - break; - } - QTouchEvent::TouchPoint point; point.setId(event.getID()); - point.setState(touchPointState); + point.setState(state); point.setPos(windowPoint); point.setScreenPos(windowPoint); - QList touchPoints; - touchPoints.push_back(point); - - QTouchEvent* touchEvent = new QTouchEvent(type); - touchEvent->setWindow(_webSurface->getWindow()); - touchEvent->setDevice(&_touchDevice); - touchEvent->setTarget(_webSurface->getRootItem()); - touchEvent->setTouchPoints(touchPoints); - touchEvent->setTouchPointStates(touchPointState); - - QCoreApplication::postEvent(_webSurface->getWindow(), touchEvent); + _activeTouchPoints[event.getID()] = point; } + + QTouchEvent touchEvent(touchType, &_touchDevice, event.getKeyboardModifiers()); + { + QList touchPoints; + Qt::TouchPointStates touchPointStates; + for (const auto& entry : _activeTouchPoints) { + touchPointStates |= entry.second.state(); + touchPoints.push_back(entry.second); + } + + touchEvent.setWindow(_webSurface->getWindow()); + touchEvent.setDevice(&_touchDevice); + touchEvent.setTarget(_webSurface->getRootItem()); + touchEvent.setTouchPoints(touchPoints); + touchEvent.setTouchPointStates(touchPointStates); + } + + // Send mouse events to the Web surface so that HTML dialog elements work with mouse press and hover. + // + // In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will + // receive mouse events + Qt::MouseButton button = Qt::NoButton; + Qt::MouseButtons buttons = Qt::NoButton; + if (event.getButton() == PointerEvent::PrimaryButton) { + button = Qt::LeftButton; + } + if (event.getButtons() & PointerEvent::PrimaryButton) { + buttons |= Qt::LeftButton; + } + +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + if (event.getType() == PointerEvent::Move) { + QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier); + QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); + } +#endif + + if (touchType == QEvent::TouchBegin) { + _touchBeginAccepted = QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent); + } else if (_touchBeginAccepted) { + QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent); + } + + // If this was a release event, remove the point from the active touch points + if (state == Qt::TouchPointReleased) { + _activeTouchPoints.erase(event.getID()); + } + +#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) + if (event.getType() == PointerEvent::Move) { + QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier); + QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); + } +#endif } void WebEntityRenderer::setProxyWindow(QWindow* proxyWindow) { diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 2d162e57fe..8adbc17a75 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -12,6 +12,8 @@ #include #include "RenderableEntityItem.h" +#include + class OffscreenQmlSurface; class PointerEvent; @@ -58,13 +60,16 @@ private: QSharedPointer _webSurface; glm::vec3 _contextPosition; gpu::TexturePointer _texture; - bool _pressed{ false }; QString _lastSourceUrl; uint16_t _lastDPI; bool _lastLocked; QTimer _timer; uint64_t _lastRenderTime { 0 }; Transform _renderTransform; + + bool _pressed{ false }; + bool _touchBeginAccepted{ false }; + std::map _activeTouchPoints; }; } } // namespace diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index af560a45ab..8796b1e47d 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -23,10 +23,11 @@ void Pointer::enable() { } void Pointer::disable() { - DependencyManager::get()->disablePick(_pickUID); + // Disable the pointer first, then the pick, so someone can't try to use it while it's in a bad state withWriteLock([&] { _enabled = false; }); + DependencyManager::get()->disablePick(_pickUID); } const QVariantMap Pointer::getPrevPickResult() { From 8d5c95b1d6212957677d72a2cc23950a72da810a Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Mon, 30 Oct 2017 16:47:59 -0700 Subject: [PATCH 043/292] Various corrections --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 6632b669e3..b7f717db04 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -24,9 +24,9 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include @@ -634,10 +634,11 @@ void OffscreenQmlSurface::forceHtmlAudioOutputDeviceUpdate() { void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() { if (QThread::currentThread() != qApp->thread()) { QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); - } - else { + } else { int waitForAudioQmlMs = 500; - QTimer::singleShot(waitForAudioQmlMs, this, SLOT(updateQmlAudio())); + QTimer::singleShot(waitForAudioQmlMs, this, [this] { + updateQmlAudio(); + }); } } From e5600e4f1e017bd0fa0558357261896ed7951e5b Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 30 Oct 2017 16:58:14 -0700 Subject: [PATCH 044/292] one universal controller pointer for all modules --- scripts/defaultScripts.js | 4 +- .../controllers/controllerDispatcher.js | 178 ++++++++++++++++-- .../controllerModules/farActionGrabEntity.js | 130 +------------ .../libraries/controllerDispatcherUtils.js | 19 +- 4 files changed, 186 insertions(+), 145 deletions(-) diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 1243ed28e2..89d4c75ae4 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -32,8 +32,8 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/tablet-ui/tabletUI.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ - //"system/controllers/controllerScripts.js" - // "system/chat.js" + "system/controllers/controllerScripts.js" + //"system/chat.js" ]; // add a menu item for debugging diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 12bc16b319..e2be817ae5 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -33,6 +33,77 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); PROFILE = true; } + var SEARCH_SPHERE_SIZE = 0.0132; + var dim = {x: SEARCH_SPHERE_SIZE, y: SEARCH_SPHERE_SIZE, z: SEARCH_SPHERE_SIZE}; + var halfPath = { + type: "line3d", + color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + parentID: MyAvatar.SELF_ID + }; + var halfEnd = { + type: "sphere", + dimensions: dim, + solid: true, + color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, + alpha: 0.9, + ignoreRayIntersection: true, + drawInFront: true, // Even when burried inside of something, show it. + visible: true + }; + var fullPath = { + type: "line3d", + color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + parentID: MyAvatar.SELF_ID + }; + var fullEnd = { + type: "sphere", + dimensions: dim, + solid: true, + color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, + alpha: 0.9, + ignoreRayIntersection: true, + drawInFront: true, // Even when burried inside of something, show it. + visible: true + }; + var holdPath = { + type: "line3d", + color: COLORS_GRAB_DISTANCE_HOLD, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + parentID: MyAvatar.SELF_ID + }; + + var renderStates = [ + {name: "half", path: halfPath, end: halfEnd}, + {name: "full", path: fullPath, end: fullEnd}, + {name: "hold", path: holdPath} + ]; + + var defaultRenderStates = [ + {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, + {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, + {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} + ]; + function ControllerDispatcher() { var _this = this; this.lastInterval = Date.now(); @@ -57,6 +128,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); mouse: false }; + this.laserVisibleStatus = [false, false]; + this.laserLockStatus = [false, false]; + this.slotsAreAvailableForPlugin = function (plugin) { for (var i = 0; i < plugin.parameters.activitySlots.length; i++) { if (_this.activitySlots[plugin.parameters.activitySlots[i]]) { @@ -72,6 +146,39 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } }; + this.enableLaserForPlugin = function(plugin) { + var handLaser = plugin.parameters.handLaser; + if (handLaser !== undefined) { + _this.laserVisibleStatus[handLaser] = true; + } + }; + + this.disableLaserForPlugin = function(plugin) { + var handLaser = plugin.parameters.handLaser; + if (handLaser !== undefined) { + _this.laserVisibleStatus[handLaser] = false; + _this.laserLockStatus[handLaser] = false; + } + }; + + this.lockLaserToTarget = function(laserLockInfo, plugin) { + if (laserLockInfo !== undefined) { + var hand = laserLockInfo.hand; + if (_this.laserVisibleStatus[laserLockInfo.hand]) { + var pointer = (hand === RIGHT_HAND) ? _this.rightControllerPointer : _this.leftControllerPointer; + var targetID = laserLockInfo.targetID; + var targetIsOverlay = laserLockInfo.isOverlay; + Pointers.setLockEndUUID(pointer, targetID, targetIsOverlay); + _this.laserLockStatus[hand] = targetID; + } + } else { + var handLaser = plugin.parameters.handLaser; + if (handLaser !== undefined) { + _this.laserLockStatus[handLaser] = false; + } + } + }; + this.unmarkSlotsForPluginName = function (runningPluginName) { // this is used to free activity-slots when a plugin is deactivated while it's running. for (var activitySlot in _this.activitySlots) { @@ -108,7 +215,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); _this.rightSecondaryValue = value; }; - this.dataGatherers = {}; this.dataGatherers.leftControllerLocation = function () { return getControllerWorldLocation(Controller.Standard.LeftHand, true); @@ -148,6 +254,37 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } }; + this.updateRenderStateForVisibleLasers = function() { + // update left hand laser + if (_this.laserVisibleStatus[LEFT_HAND]) { + var laserLocked = _this.laserLockStatus[LEFT_HAND]; + _this.updateLaserRenderState(_this.leftControllerPointer,_this.leftTriggerClicked, laserLocked); + } else { + Pointers.setRenderState(_this.leftControllerPointer, ""); + } + + //update right hand laser + if (_this.laserVisibleStatus[RIGHT_HAND]) { + var laserLocked = _this.laserLockStatus[RIGHT_HAND]; + _this.updateLaserRenderState(_this.rightControllerPointer, _this.rightTriggerClicked, laserLocked); + } else { + Pointers.setRenderState(_this.rightControllerPointer, ""); + } + }; + + this.updateLaserRenderState = function(laser, triggerClicked, laserLocked) { + var mode = "hold"; + if (!laserLocked) { + if (triggerClicked) { + mode = "full"; + } else { + mode = "half"; + } + } + + Pointers.setRenderState(laser, mode); + }; + this.update = function () { if (PROFILE) { Script.beginProfileRange("dispatch.pre"); @@ -234,8 +371,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); // raypick for each controller var rayPicks = [ - RayPick.getPrevRayPickResult(_this.leftControllerRayPick), - RayPick.getPrevRayPickResult(_this.rightControllerRayPick) + Pointers.getPrevPickResult(_this.leftControllerPointer), + Pointers.getPrevPickResult(_this.rightControllerPointer) ]; var hudRayPicks = [ RayPick.getPrevRayPickResult(_this.leftControllerHudRayPick), @@ -319,6 +456,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); // activity-slots which this plugin consumes as "in use" _this.runningPluginNames[orderedPluginName] = true; _this.markSlots(candidatePlugin, orderedPluginName); + _this.enableLaserForPlugin(candidatePlugin); if (DEBUG) { print("controllerDispatcher running " + orderedPluginName); } @@ -354,16 +492,19 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); // of running plugins and mark its activity-slots as "not in use" delete _this.runningPluginNames[runningPluginName]; _this.markSlots(plugin, false); + _this.disableLaserForPlugin(plugin); if (DEBUG) { print("controllerDispatcher stopping " + runningPluginName); } } + _this.lockLaserToTarget(runningness.laserLockInfo, plugin); if (PROFILE) { Script.endProfileRange("dispatch.run." + runningPluginName); } } } } + _this.updateRenderStateForVisibleLasers(); if (PROFILE) { Script.endProfileRange("dispatch.run"); } @@ -388,12 +529,13 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Controller.enableMapping(MAPPING_NAME); - this.leftControllerRayPick = RayPick.createRayPick({ - joint: "_CONTROLLER_LEFTHAND", - filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, - enabled: true, - maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, - posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true) + this.leftControllerPointer = Pointers.createPointer(PickType.Ray, { + joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", + filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES, + renderStates: renderStates, + defaultRenderStates: defaultRenderStates, + triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], + hover: true }); this.leftControllerHudRayPick = RayPick.createRayPick({ joint: "_CONTROLLER_LEFTHAND", @@ -402,12 +544,13 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true) }); - this.rightControllerRayPick = RayPick.createRayPick({ - joint: "_CONTROLLER_RIGHTHAND", - filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, - enabled: true, - maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, - posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true) + this.rightControllerPointer = Pointers.createPointer(PickType.Ray, { + joint: "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", + filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES, + renderStates: renderStates, + defaultRenderStates: defaultRenderStates, + triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], + hover: true }); this.rightControllerHudRayPick = RayPick.createRayPick({ joint: "_CONTROLLER_RIGHTHAND", @@ -422,6 +565,11 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); enabled: true }); + Pointers.setRenderState(this.leftControllerPointer, ""); + Pointers.setRenderState(this.rightControllerPointer, ""); + Pointers.enablePointer(this.leftControllerPointer); + Pointers.enablePointer(this.rightControllerPointer); + this.handleHandMessage = function(channel, message, sender) { var data; if (sender === MyAvatar.sessionUUID) { diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index de5bdf701b..f67f4de814 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -22,78 +22,6 @@ Script.include("/~/system/libraries/controllers.js"); (function() { var PICK_WITH_HAND_RAY = true; - - var SEARCH_SPHERE_SIZE = 0.0132; - var dim = {x: SEARCH_SPHERE_SIZE, y: SEARCH_SPHERE_SIZE, z: SEARCH_SPHERE_SIZE}; - var halfPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var halfEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var fullPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var fullEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var holdPath = { - type: "line3d", - color: COLORS_GRAB_DISTANCE_HOLD, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - - var renderStates = [ - {name: "half", path: halfPath, end: halfEnd}, - {name: "full", path: fullPath, end: fullEnd}, - {name: "hold", path: holdPath} - ]; - - var defaultRenderStates = [ - {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, - {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, - {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} - ]; - var GRABBABLE_PROPERTIES = [ "position", "registrationPoint", @@ -137,37 +65,8 @@ Script.include("/~/system/libraries/controllers.js"); 550, this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], [], - 100); - - this.updateLaserPointer = function(controllerData) { - var mode = "hold"; - if (!this.distanceHolding && !this.distanceRotating) { - if (controllerData.triggerClicks[this.hand]) { - mode = "full"; - } else { - mode = "half"; - } - } - - var laserPointerID = PICK_WITH_HAND_RAY ? this.laserPointer : this.headLaserPointer; - if (mode === "full") { - this.contextOverlayTimer = false; - this.destroyContextOverlay(); - } - - LaserPointers.enableLaserPointer(laserPointerID); - LaserPointers.setRenderState(laserPointerID, mode); - if (this.distanceHolding || this.distanceRotating) { - LaserPointers.setLockEndUUID(laserPointerID, this.grabbedThingID, this.grabbedIsOverlay); - } else { - LaserPointers.setLockEndUUID(laserPointerID, null, false); - } - }; - - this.laserPointerOff = function() { - LaserPointers.disableLaserPointer(this.laserPointer); - LaserPointers.disableLaserPointer(this.headLaserPointer); - }; + 100, + this.hand); this.handToController = function() { @@ -307,9 +206,6 @@ Script.include("/~/system/libraries/controllers.js"); // XXX // this.maybeScale(grabbedProperties); - // visualizations - this.updateLaserPointer(controllerData); - var distanceToObject = Vec3.length(Vec3.subtract(MyAvatar.position, this.currentObjectPosition)); this.linearTimeScale = (this.linearTimeScale / 2); @@ -445,11 +341,9 @@ Script.include("/~/system/libraries/controllers.js"); if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.notPointingAtEntity(controllerData)) { this.endNearGrabAction(); - this.laserPointerOff(); return makeRunningValues(false, [], []); } this.intersectionDistance = controllerData.rayPicks[this.hand].distance; - this.updateLaserPointer(controllerData); var otherModuleName =this.hand === RIGHT_HAND ? "LeftFarActionGrabEntity" : "RightFarActionGrabEntity"; var otherFarGrabModule = getEnabledModuleByName(otherModuleName); @@ -475,7 +369,6 @@ Script.include("/~/system/libraries/controllers.js"); // stop the far-grab so the near-grab or equip can take over. for (var k = 0; k < nearGrabReadiness.length; k++) { if (nearGrabReadiness[k].active && nearGrabReadiness[k].targets[0] === this.grabbedThingID) { - this.laserPointerOff(); this.endNearGrabAction(); return makeRunningValues(false, [], []); } @@ -563,29 +456,18 @@ Script.include("/~/system/libraries/controllers.js"); var disableModule = getEnabledModuleByName(moduleName); if (disableModule) { if (disableModule.disableModules) { - this.laserPointerOff(); this.endNearGrabAction(); return makeRunningValues(false, [], []); } } - return makeRunningValues(true, [], []); + var grabbedThing = (this.distanceHolding || this.distanceRotating) ? this.grabbedThingID : null; + var grabbedIsOverlay = (this.distanceHolding || this.distanceRotating) ? this.grabbedIsOverlay : false; + var laserLockInfo = makeLaserLockInfo(grabbedThing, grabbedIsOverlay, this.hand); + return makeRunningValues(true, [], [], laserLockInfo); }; this.cleanup = function () { - LaserPointers.disableLaserPointer(this.laserPointer); - LaserPointers.removeLaserPointer(this.laserPointer); }; - - this.laserPointer = LaserPointers.createLaserPointer({ - joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, - maxDistance: PICK_MAX_DISTANCE, - posOffset: getGrabPointSphereOffset(this.handToController(), true), - renderStates: renderStates, - faceAvatar: true, - distanceScaleEnd: true, - defaultRenderStates: defaultRenderStates - }); } var leftFarActionGrabEntity = new FarActionGrabEntity(LEFT_HAND); diff --git a/scripts/system/libraries/controllerDispatcherUtils.js b/scripts/system/libraries/controllerDispatcherUtils.js index cd3f1a711f..30f2e1a8d0 100644 --- a/scripts/system/libraries/controllerDispatcherUtils.js +++ b/scripts/system/libraries/controllerDispatcherUtils.js @@ -37,6 +37,7 @@ projectOntoXYPlane:true, projectOntoEntityXYPlane:true, projectOntoOverlayXYPlane:true, + makeLaserLockInfo:true, entityHasActions:true, ensureDynamic:true, findGroupParent:true, @@ -107,20 +108,30 @@ DISPATCHER_PROPERTIES = [ // activitySlots -- indicates which "slots" must not yet be in use for this module to start // requiredDataForReady -- which "situation" parts this module looks at to decide if it will start // sleepMSBetweenRuns -- how long to wait between calls to this module's "run" method -makeDispatcherModuleParameters = function (priority, activitySlots, requiredDataForReady, sleepMSBetweenRuns) { +makeDispatcherModuleParameters = function (priority, activitySlots, requiredDataForReady, sleepMSBetweenRuns, enableLaserForHand) { return { priority: priority, activitySlots: activitySlots, requiredDataForReady: requiredDataForReady, - sleepMSBetweenRuns: sleepMSBetweenRuns + sleepMSBetweenRuns: sleepMSBetweenRuns, + handLaser: enableLaserForHand }; }; -makeRunningValues = function (active, targets, requiredDataForRun) { +makeLaserLockInfo = function(targetID, isOverlay, hand) { + return { + targetID: targetID, + isOverlay: isOverlay, + hand: hand + }; +}; + +makeRunningValues = function (active, targets, requiredDataForRun, laserLockInfo) { return { active: active, targets: targets, - requiredDataForRun: requiredDataForRun + requiredDataForRun: requiredDataForRun, + laserLockInfo: laserLockInfo }; }; From cfba6ae819cbcdb64dcbd5583dbe0334ed09e6c6 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Tue, 31 Oct 2017 11:18:03 -0700 Subject: [PATCH 045/292] Implement master avatar gain in the audio-mixer --- .../src/audio/AudioMixerClientData.cpp | 6 ++++-- .../src/audio/AudioMixerClientData.h | 5 +++++ assignment-client/src/audio/AudioMixerSlave.cpp | 15 ++++++++++----- libraries/networking/src/NodeList.cpp | 4 ++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 59bc878cba..3b3d6549ee 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -191,9 +191,11 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const float gain = unpackFloatGainFromByte(packedGain); if (avatarUuid.isNull()) { - // FIXME: change master gain, and reset hrtf gains for all active streams - qDebug() << "Setting MASTER avatar gain for [" << uuid << "] to " << gain; + // set the MASTER avatar gain + setMasterAvatarGain(gain); + qDebug() << "Setting MASTER avatar gain for " << uuid << " to " << gain; } else { + // set the per-source avatar gain hrtfForStream(avatarUuid, QUuid()).setGainAdjustment(gain); qDebug() << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUuid << "] to " << gain; } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 7a8690d8cc..c3a31715ea 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -83,6 +83,9 @@ public: // uses randomization to have the AudioMixer send a stats packet to this node around every second bool shouldSendStats(int frameNumber); + float getMasterAvatarGain() const { return _masterAvatarGain; } + void setMasterAvatarGain(float gain) { _masterAvatarGain = gain; } + AudioLimiter audioLimiter; void setupCodec(CodecPluginPointer codec, const QString& codecName); @@ -175,6 +178,8 @@ private: int _frameToSendStats { 0 }; + float _masterAvatarGain { 1.0f }; // per-listener mixing gain, applied only to avatars + CodecPluginPointer _codec; QString _selectedCodecName; Encoder* _encoder{ nullptr }; // for outbound mixed stream diff --git a/assignment-client/src/audio/AudioMixerSlave.cpp b/assignment-client/src/audio/AudioMixerSlave.cpp index a131e266d2..86e6d21d66 100644 --- a/assignment-client/src/audio/AudioMixerSlave.cpp +++ b/assignment-client/src/audio/AudioMixerSlave.cpp @@ -48,8 +48,8 @@ void sendEnvironmentPacket(const SharedNodePointer& node, AudioMixerClientData& // mix helpers inline float approximateGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); -inline float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, - const glm::vec3& relativePosition, bool isEcho); +inline float computeGain(AudioMixerClientData& listenerNodeData, const AvatarAudioStream& listeningNodeStream, + const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, bool isEcho); inline float computeAzimuth(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition); @@ -266,7 +266,7 @@ void AudioMixerSlave::addStream(AudioMixerClientData& listenerNodeData, const QU glm::vec3 relativePosition = streamToAdd.getPosition() - listeningNodeStream.getPosition(); float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = computeGain(listeningNodeStream, streamToAdd, relativePosition, isEcho); + float gain = computeGain(listenerNodeData, listeningNodeStream, streamToAdd, relativePosition, isEcho); float azimuth = isEcho ? 0.0f : computeAzimuth(listeningNodeStream, listeningNodeStream, relativePosition); const int HRTF_DATASET_INDEX = 1; @@ -484,10 +484,12 @@ float approximateGain(const AvatarAudioStream& listeningNodeStream, const Positi // when throttling, as close streams are expected to be heard by a user float distance = glm::length(relativePosition); return gain / distance; + + // avatar: skip master gain - it is constant for all streams } -float computeGain(const AvatarAudioStream& listeningNodeStream, const PositionalAudioStream& streamToAdd, - const glm::vec3& relativePosition, bool isEcho) { +float computeGain(AudioMixerClientData& listenerNodeData, const AvatarAudioStream& listeningNodeStream, + const PositionalAudioStream& streamToAdd, const glm::vec3& relativePosition, bool isEcho) { float gain = 1.0f; // injector: apply attenuation @@ -507,6 +509,9 @@ float computeGain(const AvatarAudioStream& listeningNodeStream, const Positional float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + (angleOfDelivery * (OFF_AXIS_ATTENUATION_STEP / PI_OVER_TWO)); gain *= offAxisCoefficient; + + // apply master gain, only to avatars + gain *= listenerNodeData.getMasterAvatarGain(); } auto& audioZones = AudioMixer::getAudioZones(); diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 04699d8ad1..63ec460de8 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -990,10 +990,10 @@ void NodeList::setAvatarGain(const QUuid& nodeID, float gain) { setAvatarGainPacket->write(nodeID.toRfc4122()); // We need to convert the gain in dB (from the script) to an amplitude before packing it. - setAvatarGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.0206f))); + setAvatarGainPacket->writePrimitive(packFloatGainToByte(fastExp2f(gain / 6.02059991f))); if (nodeID.isNull()) { - qCDebug(networking) << "Sending Set Avatar MASTER Gain packet with Gain:" << gain; + qCDebug(networking) << "Sending Set MASTER Avatar Gain packet with Gain:" << gain; } else { qCDebug(networking) << "Sending Set Avatar Gain packet with UUID: " << uuidStringWithoutCurlyBraces(nodeID) << "Gain:" << gain; } From df237eae54065b016931850a2f03ea07cdb78a71 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 31 Oct 2017 13:26:43 -0700 Subject: [PATCH 046/292] HUD events WIP, fix entity/overlay hover --- interface/src/Application.cpp | 6 ++ interface/src/raypick/LaserPointer.cpp | 2 + interface/src/ui/overlays/Overlays.cpp | 21 ++++++- interface/src/ui/overlays/Overlays.h | 1 + .../src/EntityTreeRenderer.cpp | 1 + .../pointers/src/pointers/PickManager.cpp | 1 + libraries/pointers/src/pointers/PickManager.h | 3 + libraries/pointers/src/pointers/Pointer.cpp | 26 ++++++++- .../pointers/src/pointers/PointerManager.h | 7 +++ libraries/shared/src/PointerEvent.cpp | 5 ++ libraries/shared/src/PointerEvent.h | 2 +- libraries/ui/CMakeLists.txt | 3 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 56 ++++++++++++++++--- libraries/ui/src/ui/OffscreenQmlSurface.h | 5 ++ 14 files changed, 125 insertions(+), 14 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0db422953f..6038ff6c9a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1811,6 +1811,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); DependencyManager::get()->setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); + DependencyManager::get()->setCalculatePos2DFromHUDOperator([&](const glm::vec3& intersection) { + const glm::vec2 MARGIN(25.0f); + glm::vec2 maxPos = _controllerScriptingInterface->getViewportDimensions() - MARGIN; + glm::vec2 pos2D = DependencyManager::get()->overlayFromWorldPoint(intersection); + return glm::max(MARGIN, glm::min(pos2D, maxPos)); + }); // Setup the mouse ray pick and related operators DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared( diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 83e3757514..d2d829e579 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -301,6 +301,8 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const Q pos2D = projectOntoEntityXYPlane(target.objectID, intersection); } else if (target.type == OVERLAY) { pos2D = projectOntoOverlayXYPlane(target.objectID, intersection); + } else if (target.type == HUD) { + pos2D = DependencyManager::get()->calculatePos2DFromHUD(intersection); } return PointerEvent(PointerEvent::Move, id, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons); } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index b37a376de3..5a7b1bd76c 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -46,7 +46,7 @@ extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest Overlays::Overlays() { auto pointerManager = DependencyManager::get(); connect(pointerManager.data(), &PointerManager::hoverBeginOverlay, this, &Overlays::hoverEnterOverlay); - connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, this, &Overlays::hoverOverOverlay); + connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, this, &Overlays::hoverOverPointerEvent); connect(pointerManager.data(), &PointerManager::hoverEndOverlay, this, &Overlays::hoverLeavePointerEvent); connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, this, &Overlays::mousePressPointerEvent); connect(pointerManager.data(), &PointerManager::triggerContinueOverlay, this, &Overlays::mouseMovePointerEvent); @@ -745,7 +745,7 @@ void Overlays::sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEv } void Overlays::sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event) { - emit hoverOverOverlay(overlayID, event); + hoverOverPointerEvent(overlayID, event); } void Overlays::sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event) { @@ -940,6 +940,21 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { return false; } +void Overlays::hoverOverPointerEvent(const OverlayID& overlayID, const PointerEvent& event) { + // TODO: generalize this to allow any overlay to recieve events + std::shared_ptr thisOverlay; + if (getOverlayType(overlayID) == "web3d") { + thisOverlay = std::static_pointer_cast(getOverlay(overlayID)); + } + if (thisOverlay) { + // Send to web overlay + QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event)); + } + + // emit to scripts + emit hoverOverOverlay(overlayID, event); +} + void Overlays::hoverLeavePointerEvent(const OverlayID& overlayID, const PointerEvent& event) { // TODO: generalize this to allow any overlay to recieve events std::shared_ptr thisOverlay; @@ -1005,7 +1020,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { } // Hover over current overlay. - emit hoverOverOverlay(rayPickResult.overlayID, pointerEvent); + hoverOverPointerEvent(rayPickResult.overlayID, pointerEvent); _currentHoverOverOverlayID = rayPickResult.overlayID; } else { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 8bcfa99aba..a5ad013246 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -308,6 +308,7 @@ public slots: void mousePressPointerEvent(const OverlayID& overlayID, const PointerEvent& event); void mouseMovePointerEvent(const OverlayID& overlayID, const PointerEvent& event); void mouseReleasePointerEvent(const OverlayID& overlayID, const PointerEvent& event); + void hoverOverPointerEvent(const OverlayID& overlayID, const PointerEvent& event); void hoverLeavePointerEvent(const OverlayID& overlayID, const PointerEvent& event); signals: diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index ef056b88ac..4dc5729c03 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -83,6 +83,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent); connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent); connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, this, handlePointerEvent); connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const EntityItemID& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); diff --git a/libraries/pointers/src/pointers/PickManager.cpp b/libraries/pointers/src/pointers/PickManager.cpp index 571f9f04cd..1c5025250a 100644 --- a/libraries/pointers/src/pointers/PickManager.cpp +++ b/libraries/pointers/src/pointers/PickManager.cpp @@ -9,6 +9,7 @@ PickManager::PickManager() { setShouldPickHUDOperator([]() { return false; }); + setCalculatePos2DFromHUDOperator([](const glm::vec3& intersection) { return glm::vec2(NAN); }); } QUuid PickManager::addPick(PickQuery::PickType type, const std::shared_ptr pick) { diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index b8abb077c7..e3b1d03080 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -34,9 +34,12 @@ public: void setIncludeItems(const QUuid& uid, const QVector& include) const; void setShouldPickHUDOperator(std::function shouldPickHUDOperator) { _shouldPickHUDOperator = shouldPickHUDOperator; } + void setCalculatePos2DFromHUDOperator(std::function calculatePos2DFromHUDOperator) { _calculatePos2DFromHUDOperator = calculatePos2DFromHUDOperator; } + glm::vec2 calculatePos2DFromHUD(const glm::vec3& intersection) { return _calculatePos2DFromHUDOperator(intersection); } protected: std::function _shouldPickHUDOperator; + std::function _calculatePos2DFromHUDOperator; std::shared_ptr findPick(const QUuid& uid) const; QHash>> _picks; diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 8796b1e47d..2f92664da0 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -56,7 +56,7 @@ void Pointer::update() { } void Pointer::generatePointerEvents(const QVariantMap& pickResult) { - // TODO: avatars/HUD? + // TODO: avatars? auto pointerManager = DependencyManager::get(); // Hover events @@ -79,6 +79,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); if (_prevHoveredObject.type == ENTITY) { emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); + } else if (_prevHoveredObject.type == HUD) { + emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent); } } } @@ -97,6 +99,22 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); if (_prevHoveredObject.type == OVERLAY) { emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent); + } else if (_prevHoveredObject.type == HUD) { + emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent); + } + } + } + + if (hoveredObject.type == HUD) { + if (_prevHoveredObject.type == HUD) { + // There's only one HUD + emit pointerManager->hoverContinueHUD(hoveredObject.objectID, hoveredEvent); + } else { + emit pointerManager->hoverBeginHUD(hoveredObject.objectID, hoveredEvent); + if (_prevHoveredObject.type == ENTITY) { + emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); + } else if (_prevHoveredObject.type == OVERLAY) { + emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent); } } } @@ -130,6 +148,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent); } else if (hoveredObject.type == OVERLAY) { emit pointerManager->triggerBeginOverlay(hoveredObject.objectID, hoveredEvent); + } else if (hoveredObject.type == HUD) { + emit pointerManager->triggerBeginHUD(hoveredObject.objectID, hoveredEvent); } _triggeredObjects[button] = hoveredObject; } @@ -143,6 +163,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { emit pointerManager->triggerContinueOverlay(_triggeredObjects[button].objectID, triggeredEvent); + } else if (_triggeredObjects[button].type == HUD) { + emit pointerManager->triggerContinueHUD(_triggeredObjects[button].objectID, triggeredEvent); } } @@ -155,6 +177,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { emit pointerManager->triggerEndOverlay(_triggeredObjects[button].objectID, triggeredEvent); + } else if (_triggeredObjects[button].type == HUD) { + emit pointerManager->triggerEndHUD(_triggeredObjects[button].objectID, triggeredEvent); } _triggeredObjects.erase(button); } diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 9f477d9eb2..574be8320a 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -58,6 +58,13 @@ signals: void hoverBeginEntity(const QUuid& id, const PointerEvent& pointerEvent); void hoverContinueEntity(const QUuid& id, const PointerEvent& pointerEvent); void hoverEndEntity(const QUuid& id, const PointerEvent& pointerEvent); + + void triggerBeginHUD(const QUuid& id, const PointerEvent& pointerEvent); + void triggerContinueHUD(const QUuid& id, const PointerEvent& pointerEvent); + void triggerEndHUD(const QUuid& id, const PointerEvent& pointerEvent); + void hoverBeginHUD(const QUuid& id, const PointerEvent& pointerEvent); + void hoverContinueHUD(const QUuid& id, const PointerEvent& pointerEvent); + void hoverEndHUD(const QUuid& id, const PointerEvent& pointerEvent); }; #endif // hifi_pointers_PointerManager_h diff --git a/libraries/shared/src/PointerEvent.cpp b/libraries/shared/src/PointerEvent.cpp index e35832391d..183b7c332a 100644 --- a/libraries/shared/src/PointerEvent.cpp +++ b/libraries/shared/src/PointerEvent.cpp @@ -41,6 +41,11 @@ PointerEvent::PointerEvent(EventType type, uint32_t id, ; } +void PointerEvent::setButton(Button button) { + _button = button; + _buttons |= button; +} + QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEvent& event) { QScriptValue obj = engine->newObject(); diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index 074e5ab79b..d3b72f072c 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -58,7 +58,7 @@ public: bool shouldFocus() const { return _shouldFocus; } void setType(EventType type) { _type = type; } - void setButton(Button button) { _button = button; } + void setButton(Button button); void setShouldFocus(bool focus) { _shouldFocus = focus; } private: diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index f28157ff97..334cce97e5 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME ui) setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns) -link_hifi_libraries(shared networking gl audio) +link_hifi_libraries(shared networking gl audio pointers) +include_hifi_library_headers(controllers) # Required for some low level GL interaction in the OffscreenQMLSurface target_opengl() diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index ecd07a5874..7c3a159177 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -49,6 +49,8 @@ #include "Logging.h" +#include + Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml") Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl") Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus") @@ -529,6 +531,13 @@ bool OffscreenQmlSurface::allowNewFrame(uint8_t fps) { } OffscreenQmlSurface::OffscreenQmlSurface() { + auto pointerManager = DependencyManager::get(); + connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &OffscreenQmlSurface::handlePointerEvent); } OffscreenQmlSurface::~OffscreenQmlSurface() { @@ -932,14 +941,8 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even transformedPos, mouseEvent->screenPos(), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); - if (event->type() == QEvent::MouseMove) { - // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install - // need to investigate into why this crash is happening. - //_qmlContext->setContextProperty("lastMousePosition", transformedPos); - } - mappedEvent.ignore(); - if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) { - return mappedEvent.isAccepted(); + if (sendMouseEvent(mappedEvent)) { + return true; } break; } @@ -951,6 +954,43 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even return false; } +void OffscreenQmlSurface::handlePointerEvent(const QUuid& id, const PointerEvent& event) { + if (_paused) { + return; + } + + QEvent::Type type; + switch (event.getType()) { + case PointerEvent::Press: + qDebug() << event.getPos2D().x << event.getPos2D().y << event.getButton() << Qt::MouseButton(event.getButton()) << Qt::MouseButtons(event.getButtons()); + type = QEvent::Type::MouseButtonPress; + break; + case PointerEvent::DoublePress: + type = QEvent::Type::MouseButtonDblClick; + break; + case PointerEvent::Release: + type = QEvent::Type::MouseButtonRelease; + break; + case PointerEvent::Move: + type = QEvent::Type::MouseMove; + break; + } + QMouseEvent mouseEvent(type, QPointF(event.getPos2D().x, event.getPos2D().y), Qt::MouseButton(event.getButton()), Qt::MouseButtons(event.getButtons()), event.getKeyboardModifiers()); + qDebug() << sendMouseEvent(mouseEvent); +} + +bool OffscreenQmlSurface::sendMouseEvent(QMouseEvent& mouseEvent) { + if (mouseEvent.type() == QEvent::MouseMove) { + // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install + // need to investigate into why this crash is happening. + //_qmlContext->setContextProperty("lastMousePosition", mouseEvent.localPos()); + } + mouseEvent.ignore(); + if (QCoreApplication::sendEvent(_quickWindow, &mouseEvent)) { + return mouseEvent.isAccepted(); + } +} + void OffscreenQmlSurface::pause() { _paused = true; } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 12ee9e59a1..3deab07411 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -30,6 +30,8 @@ class QQmlContext; class QQmlComponent; class QQuickWindow; class QQuickItem; +class QMouseEvent; +class PointerEvent; // GPU resources are typically buffered for one copy being used by the renderer, // one copy in flight, and one copy being used by the receiver @@ -135,6 +137,7 @@ private: private slots: void updateQuick(); void onFocusObjectChanged(QObject* newFocus); + void handlePointerEvent(const QUuid& id, const PointerEvent& event); private: QQuickWindow* _quickWindow { nullptr }; @@ -161,6 +164,8 @@ private: QWindow* _proxyWindow { nullptr }; QQuickItem* _currentFocusItem { nullptr }; + + bool sendMouseEvent(QMouseEvent& mouseEvent); }; #endif From 30332c3d003683bb3c080a0d688cd2c346b3baaa Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 31 Oct 2017 14:13:42 -0700 Subject: [PATCH 047/292] removing more laserPointers --- .../controllers/controllerDispatcher.js | 8 +- .../controllerModules/farActionGrabEntity.js | 1 - .../controllerModules/farTrigger.js | 123 +----- .../controllerModules/inEditMode.js | 132 +----- .../controllerModules/overlayLaserInput.js | 307 +------------ .../controllerModules/webEntityLaserInput.js | 413 +----------------- 6 files changed, 22 insertions(+), 962 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index e2be817ae5..1773e013e1 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -249,8 +249,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.setIgnoreTablet = function() { if (HMD.tabletID !== this.tabletID) { this.tabletID = HMD.tabletID; - RayPick.setIgnoreItems(_this.leftControllerRayPick, _this.blacklist.concat([HMD.tabletID])); - RayPick.setIgnoreItems(_this.rightControllerRayPick, _this.blacklist.concat([HMD.tabletID])); + Pointers.setIgnoreItems(_this.leftControllerPointer, _this.blacklist.concat([HMD.tabletID])); + Pointers.setIgnoreItems(_this.rightControllerPointer, _this.blacklist.concat([HMD.tabletID])); } }; @@ -534,7 +534,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES, renderStates: renderStates, defaultRenderStates: defaultRenderStates, - triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], + triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}], + posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true), hover: true }); this.leftControllerHudRayPick = RayPick.createRayPick({ @@ -550,6 +551,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); renderStates: renderStates, defaultRenderStates: defaultRenderStates, triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], + posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true), hover: true }); this.rightControllerHudRayPick = RayPick.createRayPick({ diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index f67f4de814..6f818b8b1e 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -380,7 +380,6 @@ Script.include("/~/system/libraries/controllers.js"); // where it could near-grab something, stop searching. for (var j = 0; j < nearGrabReadiness.length; j++) { if (nearGrabReadiness[j].active) { - this.laserPointerOff(); this.endNearGrabAction(); return makeRunningValues(false, [], []); } diff --git a/scripts/system/controllers/controllerModules/farTrigger.js b/scripts/system/controllers/controllerModules/farTrigger.js index f641b34415..4a4c83a9d2 100644 --- a/scripts/system/controllers/controllerModules/farTrigger.js +++ b/scripts/system/controllers/controllerModules/farTrigger.js @@ -16,77 +16,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { - var SEARCH_SPHERE_SIZE = 0.0132; - var dim = {x: SEARCH_SPHERE_SIZE, y: SEARCH_SPHERE_SIZE, z: SEARCH_SPHERE_SIZE}; - var halfPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var halfEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var fullPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var fullEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var holdPath = { - type: "line3d", - color: COLORS_GRAB_DISTANCE_HOLD, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - - var renderStates = [ - {name: "half", path: halfPath, end: halfEnd}, - {name: "full", path: fullPath, end: fullEnd}, - {name: "hold", path: holdPath} - ]; - - var defaultRenderStates = [ - {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, - {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, - {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} - ]; - function entityWantsNearTrigger(props) { var grabbableData = getGrabbableData(props); return grabbableData.triggerable || grabbableData.wantsTrigger; @@ -104,27 +33,8 @@ Script.include("/~/system/libraries/controllers.js"); 520, this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], [], - 100); - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.updateLaserPointer = function(controllerData) { - var mode = "none"; - if (controllerData.triggerClicks[this.hand]) { - mode = "full"; - } else { - mode = "half"; - } - - LaserPointers.enableLaserPointer(this.laserPointer); - LaserPointers.setRenderState(this.laserPointer, mode); - }; - - this.laserPointerOff = function() { - LaserPointers.disableLaserPointer(this.laserPointer); - }; + 100, + this.hand); this.getTargetProps = function (controllerData) { // nearbyEntityProperties is already sorted by length from controller @@ -151,7 +61,6 @@ Script.include("/~/system/libraries/controllers.js"); this.endFarTrigger = function (controllerData) { var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID]; Entities.callEntityMethod(this.targetEntityID, "stopFarTrigger", args); - this.laserPointerOff(); }; this.isReady = function (controllerData) { @@ -176,31 +85,9 @@ Script.include("/~/system/libraries/controllers.js"); this.endFarTrigger(controllerData); return makeRunningValues(false, [], []); } - - this.updateLaserPointer(controllerData); this.continueFarTrigger(controllerData); return makeRunningValues(true, [this.targetEntityID], []); }; - - this.laserPointer = LaserPointers.createLaserPointer({ - joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, - maxDistance: PICK_MAX_DISTANCE, - posOffset: getGrabPointSphereOffset(this.handToController(), true), - renderStates: renderStates, - faceAvatar: true, - distanceScaleEnd: true, - defaultRenderStates: defaultRenderStates - }); - - this.cleanup = function () { - if (this.targetEntityID) { - this.endFarTrigger(); - } - - LaserPointers.disableLaserPointer(this.laserPointer); - LaserPointers.removeLaserPointer(this.laserPointer); - }; } var leftFarTriggerEntity = new FarTriggerEntity(LEFT_HAND); @@ -209,11 +96,9 @@ Script.include("/~/system/libraries/controllers.js"); enableDispatcherModule("LeftFarTriggerEntity", leftFarTriggerEntity); enableDispatcherModule("RightFarTriggerEntity", rightFarTriggerEntity); - this.cleanup = function () { - leftFarTriggerEntity.cleanup(); - rightFarTriggerEntity.cleanup(); + function cleanup() { disableDispatcherModule("LeftFarTriggerEntity"); disableDispatcherModule("RightFarTriggerEntity"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 7941ec8d4c..cfa1f0a9e3 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -18,81 +18,9 @@ Script.include("/~/system/libraries/controllers.js"); Script.include("/~/system/libraries/utils.js"); (function () { - var END_RADIUS = 0.005; - var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS }; - var halfPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var halfEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var fullPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var fullEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var holdPath = { - type: "line3d", - color: COLORS_GRAB_DISTANCE_HOLD, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - - var renderStates = [ - {name: "half", path: halfPath, end: halfEnd}, - {name: "full", path: fullPath, end: fullEnd}, - {name: "hold", path: holdPath} - ]; - - var defaultRenderStates = [ - {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, - {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, - {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} - ]; - function InEditMode(hand) { this.hand = hand; this.triggerClicked = false; - this.mode = "none"; this.parameters = makeDispatcherModuleParameters( 160, @@ -113,29 +41,6 @@ Script.include("/~/system/libraries/utils.js"); return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; }; - - this.processControllerTriggers = function(controllerData) { - if (controllerData.triggerClicks[this.hand]) { - this.mode = "full"; - } else if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { - this.mode = "half"; - } else { - this.mode = "none"; - } - }; - - this.updateLaserPointer = function(controllerData) { - LaserPointers.enableLaserPointer(this.laserPointer); - LaserPointers.setRenderState(this.laserPointer, this.mode); - - if (HMD.tabletID !== this.tabletID || HMD.tabletButtonID !== this.tabletButtonID || HMD.tabletScreenID !== this.tabletScreenID) { - this.tabletID = HMD.tabletID; - this.tabletButtonID = HMD.tabletButtonID; - this.tabletScreenID = HMD.tabletScreenID; - LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.tabletButtonID, HMD.tabletScreenID]); - } - }; - this.pointingAtTablet = function(objectID) { if (objectID === HMD.tabletScreenID || objectID === HMD.tabletButtonID) { return true; @@ -164,21 +69,12 @@ Script.include("/~/system/libraries/utils.js"); } }; - this.exitModule = function() { - this.disableLasers(); - return makeRunningValues(false, [], []); - }; - - this.disableLasers = function() { - LaserPointers.disableLaserPointer(this.laserPointer); - }; - this.isReady = function(controllerData) { if (isInEditMode()) { this.triggerClicked = false; return makeRunningValues(true, [], []); } - return this.exitModule(); + return makeRunningValues(false, [], []); }; this.run = function(controllerData) { @@ -216,31 +112,9 @@ Script.include("/~/system/libraries/utils.js"); return this.exitModule(); } } - - this.processControllerTriggers(controllerData); - this.updateLaserPointer(controllerData); this.sendPickData(controllerData); - - return this.isReady(controllerData); }; - - this.cleanup = function() { - LaserPointers.disableLaserPointer(this.laserPointer); - LaserPointers.removeLaserPointer(this.laserPointer); - }; - - this.laserPointer = LaserPointers.createLaserPointer({ - joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, - maxDistance: PICK_MAX_DISTANCE, - posOffset: getGrabPointSphereOffset(this.handToController(), true), - renderStates: renderStates, - faceAvatar: true, - defaultRenderStates: defaultRenderStates - }); - - LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.tabletButtonID, HMD.tabletScreenID]); } var leftHandInEditMode = new InEditMode(LEFT_HAND); @@ -249,12 +123,12 @@ Script.include("/~/system/libraries/utils.js"); enableDispatcherModule("LeftHandInEditMode", leftHandInEditMode); enableDispatcherModule("RightHandInEditMode", rightHandInEditMode); - this.cleanup = function() { + function cleanup() { leftHandInEditMode.cleanup(); rightHandInEditMode.cleanup(); disableDispatcherModule("LeftHandInEditMode"); disableDispatcherModule("RightHandInEditMode"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/overlayLaserInput.js b/scripts/system/controllers/controllerModules/overlayLaserInput.js index 9cec64b6b6..6c9258ead7 100644 --- a/scripts/system/controllers/controllerModules/overlayLaserInput.js +++ b/scripts/system/controllers/controllerModules/overlayLaserInput.js @@ -9,268 +9,27 @@ makeRunningValues, Messages, Quat, Vec3, makeDispatcherModuleParameters, Overlays, ZERO_VEC, HMD, INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, - TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE, LaserPointers, RayPick, ContextOverlay + TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE, LaserPointers, RayPick, ContextOverlay, Picks */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { - var TouchEventUtils = Script.require("/~/system/libraries/touchEventUtils.js"); - var END_RADIUS = 0.005; - var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS }; - var halfPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var halfEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var fullPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var fullEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var holdPath = { - type: "line3d", - color: COLORS_GRAB_DISTANCE_HOLD, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - - var renderStates = [ - {name: "half", path: halfPath, end: halfEnd}, - {name: "full", path: fullPath, end: fullEnd}, - {name: "hold", path: holdPath} - ]; - - var defaultRenderStates = [ - {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, - {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, - {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} - ]; - - - // triggered when stylus presses a web overlay/entity - var HAPTIC_STYLUS_STRENGTH = 1.0; - var HAPTIC_STYLUS_DURATION = 20.0; - - function distance2D(a, b) { - var dx = (a.x - b.x); - var dy = (a.y - b.y); - return Math.sqrt(dx * dx + dy * dy); - } - function OverlayLaserInput(hand) { this.hand = hand; - this.active = false; - this.previousLaserClickedTarget = false; - this.laserPressingTarget = false; - this.mode = "none"; - this.laserTarget = null; - this.pressEnterLaserTarget = null; - this.parameters = makeDispatcherModuleParameters( 120, this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], [], - 100); - - this.getOtherHandController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.LeftHand : Controller.Standard.RightHand; - }; - - this.getOtherModule = function() { - return (this.hand === RIGHT_HAND) ? leftOverlayLaserInput : rightOverlayLaserInput; - }; - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.hasTouchFocus = function(laserTarget) { - return (laserTarget.overlayID === this.hoverOverlay); - }; - - this.requestTouchFocus = function(laserTarget) { - if (laserTarget.overlayID && - laserTarget.overlayID !== this.hoverOverlay) { - this.hoverOverlay = laserTarget.overlayID; - TouchEventUtils.sendHoverEnterEventToTouchTarget(this.hand, laserTarget); - } - }; - - this.relinquishTouchFocus = function() { - // send hover leave event. - if (this.hoverOverlay) { - var pointerEvent = { type: "Move", id: this.hand + 1 }; - Overlays.sendMouseMoveOnOverlay(this.hoverOverlay, pointerEvent); - Overlays.sendHoverOverOverlay(this.hoverOverlay, pointerEvent); - Overlays.sendHoverLeaveOverlay(this.hoverOverlay, pointerEvent); - this.hoverOverlay = null; - } - }; - - this.relinquishStylusTargetTouchFocus = function(laserTarget) { - var stylusModuleNames = ["LeftTabletStylusInput", "RightTabletStylusError"]; - for (var i = 0; i < stylusModuleNames.length; i++) { - var stylusModule = getEnabledModuleByName(stylusModuleNames[i]); - if (stylusModule) { - if (stylusModule.hoverOverlay === laserTarget.overlayID) { - stylusModule.relinquishTouchFocus(); - } - } - } - }; - - this.stealTouchFocus = function(laserTarget) { - if (laserTarget.overlayID === this.getOtherModule().hoverOverlay) { - this.getOtherModule().relinquishTouchFocus(); - } - - // If the focus target we want to request is the same of one of the stylus - // tell the stylus to relinquish it focus on our target - this.relinquishStylusTargetTouchFocus(laserTarget); - - this.requestTouchFocus(laserTarget); - }; - - this.updateLaserPointer = function(controllerData) { - LaserPointers.enableLaserPointer(this.laserPointer); - LaserPointers.setRenderState(this.laserPointer, this.mode); - - if (HMD.tabletID !== this.tabletID) { - this.tabletID = HMD.tabletID; - LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID]); - } - }; - - this.processControllerTriggers = function(controllerData) { - if (controllerData.triggerClicks[this.hand]) { - this.mode = "full"; - } else if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { - this.mode = "half"; - } else { - this.mode = "none"; - } - }; - - this.laserPressEnter = function () { - this.stealTouchFocus(this.laserTarget); - TouchEventUtils.sendTouchStartEventToTouchTarget(this.hand, this.laserTarget); - Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand); - - this.touchingEnterTimer = 0; - this.pressEnterLaserTarget = this.laserTarget; - this.deadspotExpired = false; - - var LASER_PRESS_TO_MOVE_DEADSPOT = 0.094; - this.deadspotRadius = Math.tan(LASER_PRESS_TO_MOVE_DEADSPOT) * this.laserTarget.distance; - }; - - this.laserPressExit = function () { - if (this.laserTarget === null) { - return; - } - - // special case to handle home button. - if (this.laserTarget.overlayID === HMD.homeButtonID) { - Messages.sendLocalMessage("home", this.laserTarget.overlayID); - } - - // send press event - if (this.deadspotExpired) { - TouchEventUtils.sendTouchEndEventToTouchTarget(this.hand, this.laserTarget); - } else { - TouchEventUtils.sendTouchEndEventToTouchTarget(this.hand, this.pressEnterLaserTarget); - } - }; - - this.laserPressing = function (controllerData, dt) { - this.touchingEnterTimer += dt; - - if (this.laserTarget) { - if (controllerData.triggerClicks[this.hand]) { - var POINTER_PRESS_TO_MOVE_DELAY = 0.33; // seconds - if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY || - distance2D(this.laserTarget.position2D, - this.pressEnterLaserTarget.position2D) > this.deadspotRadius) { - TouchEventUtils.sendTouchMoveEventToTouchTarget(this.hand, this.laserTarget); - this.deadspotExpired = true; - } - } else { - this.laserPressingTarget = false; - } - } else { - this.laserPressingTarget = false; - } - }; + 100, + this.hand); this.processLaser = function(controllerData) { - if (this.shouldExit(controllerData) || this.getOtherModule().active) { - this.exitModule(); + if (this.shouldExit(controllerData)) { return false; } - var intersection = controllerData.rayPicks[this.hand]; - var laserTarget = TouchEventUtils.composeTouchTargetFromIntersection(intersection); - - if (controllerData.triggerClicks[this.hand]) { - this.laserTarget = laserTarget; - this.laserPressingTarget = true; - } else { - this.requestTouchFocus(laserTarget); - - if (!TouchEventUtils.touchTargetHasKeyboardFocus(laserTarget)) { - TouchEventUtils.setKeyboardFocusOnTouchTarget(laserTarget); - } - - if (this.hasTouchFocus(laserTarget) && !this.laserPressingTarget) { - TouchEventUtils.sendHoverOverEventToTouchTarget(this.hand, laserTarget); - } - } - - this.processControllerTriggers(controllerData); - this.updateLaserPointer(controllerData); - this.active = true; return true; }; @@ -303,23 +62,6 @@ Script.include("/~/system/libraries/controllers.js"); return offOverlay || grabbingOverlay || triggerOff; }; - this.exitModule = function() { - if (this.laserPressingTarget) { - this.deadspotExpired = true; - this.laserPressExit(); - this.laserPressingTarget = false; - } - this.relinquishTouchFocus(); - this.reset(); - this.updateLaserPointer(); - LaserPointers.disableLaserPointer(this.laserPointer); - }; - - this.reset = function() { - this.mode = "none"; - this.active = false; - }; - this.deleteContextOverlay = function() { var farGrabModule = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity"); if (farGrabModule) { @@ -340,41 +82,8 @@ Script.include("/~/system/libraries/controllers.js"); }; this.run = function (controllerData, deltaTime) { - if (!this.previousLaserClickedTarget && this.laserPressingTarget) { - this.laserPressEnter(); - } - if (this.previousLaserClickedTarget && !this.laserPressingTarget) { - this.laserPressExit(); - } - this.previousLaserClickedTarget = this.laserPressingTarget; - - if (this.laserPressingTarget) { - this.laserPressing(controllerData, deltaTime); - } - - if (this.processLaser(controllerData)) { - return makeRunningValues(true, [], []); - } else { - return makeRunningValues(false, [], []); - } + return this.isReady(controllerData); }; - - this.cleanup = function () { - LaserPointers.disableLaserPointer(this.laserPointer); - LaserPointers.removeLaserPointer(this.laserPointer); - }; - - this.laserPointer = LaserPointers.createLaserPointer({ - joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: Picks.PICK_OVERLAYS, - maxDistance: PICK_MAX_DISTANCE, - posOffset: getGrabPointSphereOffset(this.handToController(), true), - renderStates: renderStates, - faceAvatar: true, - defaultRenderStates: defaultRenderStates - }); - - LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID]); } var leftOverlayLaserInput = new OverlayLaserInput(LEFT_HAND); @@ -383,11 +92,9 @@ Script.include("/~/system/libraries/controllers.js"); enableDispatcherModule("LeftOverlayLaserInput", leftOverlayLaserInput); enableDispatcherModule("RightOverlayLaserInput", rightOverlayLaserInput); - this.cleanup = function () { - leftOverlayLaserInput.cleanup(); - rightOverlayLaserInput.cleanup(); + function cleanup() { disableDispatcherModule("LeftOverlayLaserInput"); disableDispatcherModule("RightOverlayLaserInput"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/webEntityLaserInput.js b/scripts/system/controllers/controllerModules/webEntityLaserInput.js index 0ade79f46e..1bd683856e 100644 --- a/scripts/system/controllers/controllerModules/webEntityLaserInput.js +++ b/scripts/system/controllers/controllerModules/webEntityLaserInput.js @@ -10,370 +10,21 @@ /* global Script, Controller, LaserPointers, RayPick, RIGHT_HAND, LEFT_HAND, Vec3, Quat, getGrabPointSphereOffset, makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters, PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, - DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, ZERO_VEC, Overlays + DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, ZERO_VEC, Overlays, Picks */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { - var END_RADIUS = 0.005; - var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS }; - var halfPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var halfEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var fullPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var fullEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var holdPath = { - type: "line3d", - color: COLORS_GRAB_DISTANCE_HOLD, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - - var renderStates = [ - {name: "half", path: halfPath, end: halfEnd}, - {name: "full", path: fullPath, end: fullEnd}, - {name: "hold", path: holdPath} - ]; - - var defaultRenderStates = [ - {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, - {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, - {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} - ]; - - - // triggered when stylus presses a web overlay/entity - var HAPTIC_STYLUS_STRENGTH = 1.0; - var HAPTIC_STYLUS_DURATION = 20.0; - - function laserTargetHasKeyboardFocus(laserTarget) { - if (laserTarget && laserTarget !== Uuid.NULL) { - return Entities.keyboardFocusOverlay === laserTarget; - } - } - - function setKeyboardFocusOnLaserTarget(laserTarget) { - if (laserTarget && laserTarget !== Uuid.NULL) { - Entities.wantsHandControllerPointerEvents(laserTarget); - Overlays.keyboardFocusOverlay = Uuid.NULL; - Entities.keyboardFocusEntity = laserTarget; - } - } - - function sendHoverEnterEventToLaserTarget(hand, laserTarget) { - if (!laserTarget) { - return; - } - var pointerEvent = { - type: "Move", - id: hand + 1, // 0 is reserved for hardware mouse - pos2D: laserTarget.position2D, - pos3D: laserTarget.position, - normal: laserTarget.normal, - direction: Vec3.subtract(ZERO_VEC, laserTarget.normal), - button: "None" - }; - - if (laserTarget.entityID && laserTarget.entityID !== Uuid.NULL) { - Entities.sendHoverEnterEntity(laserTarget.entityID, pointerEvent); - } - } - - function sendHoverOverEventToLaserTarget(hand, laserTarget) { - - if (!laserTarget) { - return; - } - var pointerEvent = { - type: "Move", - id: hand + 1, // 0 is reserved for hardware mouse - pos2D: laserTarget.position2D, - pos3D: laserTarget.position, - normal: laserTarget.normal, - direction: Vec3.subtract(ZERO_VEC, laserTarget.normal), - button: "None" - }; - - if (laserTarget.entityID && laserTarget.entityID !== Uuid.NULL) { - Entities.sendMouseMoveOnEntity(laserTarget.entityID, pointerEvent); - Entities.sendHoverOverEntity(laserTarget.entityID, pointerEvent); - } - } - - - function sendTouchStartEventToLaserTarget(hand, laserTarget) { - var pointerEvent = { - type: "Press", - id: hand + 1, // 0 is reserved for hardware mouse - pos2D: laserTarget.position2D, - pos3D: laserTarget.position, - normal: laserTarget.normal, - direction: Vec3.subtract(ZERO_VEC, laserTarget.normal), - button: "Primary", - isPrimaryHeld: true - }; - - if (laserTarget.entityID && laserTarget.entityID !== Uuid.NULL) { - Entities.sendMousePressOnEntity(laserTarget.entityID, pointerEvent); - Entities.sendClickDownOnEntity(laserTarget.entityID, pointerEvent); - } - } - - function sendTouchEndEventToLaserTarget(hand, laserTarget) { - var pointerEvent = { - type: "Release", - id: hand + 1, // 0 is reserved for hardware mouse - pos2D: laserTarget.position2D, - pos3D: laserTarget.position, - normal: laserTarget.normal, - direction: Vec3.subtract(ZERO_VEC, laserTarget.normal), - button: "Primary" - }; - - if (laserTarget.entityID && laserTarget.entityID !== Uuid.NULL) { - Entities.sendMouseReleaseOnEntity(laserTarget.entityID, pointerEvent); - Entities.sendClickReleaseOnEntity(laserTarget.entityID, pointerEvent); - Entities.sendHoverLeaveEntity(laserTarget.entityID, pointerEvent); - } - } - - function sendTouchMoveEventToLaserTarget(hand, laserTarget) { - var pointerEvent = { - type: "Move", - id: hand + 1, // 0 is reserved for hardware mouse - pos2D: laserTarget.position2D, - pos3D: laserTarget.position, - normal: laserTarget.normal, - direction: Vec3.subtract(ZERO_VEC, laserTarget.normal), - button: "Primary", - isPrimaryHeld: true - }; - - if (laserTarget.entityID && laserTarget.entityID !== Uuid.NULL) { - Entities.sendMouseMoveOnEntity(laserTarget.entityID, pointerEvent); - Entities.sendHoldingClickOnEntity(laserTarget.entityID, pointerEvent); - } - } - - function calculateTargetFromEntity(intersection, props) { - if (props.rotation === undefined) { - // if rotation is missing from props object, then this entity has probably been deleted. - return null; - } - - // project stylus tip onto entity plane. - var normal = Vec3.multiplyQbyV(props.rotation, {x: 0, y: 0, z: 1}); - Vec3.multiplyQbyV(props.rotation, {x: 0, y: 1, z: 0}); - var distance = Vec3.dot(Vec3.subtract(intersection, props.position), normal); - var position = Vec3.subtract(intersection, Vec3.multiply(normal, distance)); - - // generate normalized coordinates - var invRot = Quat.inverse(props.rotation); - var localPos = Vec3.multiplyQbyV(invRot, Vec3.subtract(position, props.position)); - var invDimensions = { x: 1 / props.dimensions.x, y: 1 / props.dimensions.y, z: 1 / props.dimensions.z }; - var normalizedPosition = Vec3.sum(Vec3.multiplyVbyV(localPos, invDimensions), props.registrationPoint); - - // 2D position on entity plane in meters, relative to the bounding box upper-left hand corner. - var position2D = { - x: normalizedPosition.x * props.dimensions.x, - y: (1 - normalizedPosition.y) * props.dimensions.y // flip y-axis - }; - - return { - entityID: props.id, - entityProps: props, - overlayID: null, - distance: distance, - position: position, - position2D: position2D, - normal: normal, - normalizedPosition: normalizedPosition, - dimensions: props.dimensions, - valid: true - }; - } - - function distance2D(a, b) { - var dx = (a.x - b.x); - var dy = (a.y - b.y); - return Math.sqrt(dx * dx + dy * dy); - } - function WebEntityLaserInput(hand) { this.hand = hand; - this.active = false; - this.previousLaserClickedTarget = false; - this.laserPressingTarget = false; - this.hover = false; - this.mode = "none"; - this.pressEnterLaserTarget = null; - this.laserTarget = null; - this.laserTargetID = null; - this.lastValidTargetID = null; - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.getOtherModule = function() { - return (this.hand === RIGHT_HAND) ? leftWebEntityLaserInput : rightWebEntityLaserInput; - }; - this.parameters = makeDispatcherModuleParameters( 550, this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], [], 100); - this.requestTouchFocus = function(laserTarget) { - if (laserTarget !== null || laserTarget !== undefined) { - sendHoverEnterEventToLaserTarget(this.hand, this.laserTarget); - this.lastValidTargetID = laserTarget; - } - }; - - this.relinquishTouchFocus = function() { - // send hover leave event. - var pointerEvent = { type: "Move", id: this.hand + 1 }; - Entities.sendMouseMoveOnEntity(this.lastValidTargetID, pointerEvent); - Entities.sendHoverOverEntity(this.lastValidTargetID, pointerEvent); - Entities.sendHoverLeaveEntity(this.lastValidID, pointerEvent); - }; - - this.updateLaserTargets = function(controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - this.laserTargetID = intersection.objectID; - var props = Entities.getEntityProperties(intersection.objectID); - this.laserTarget = calculateTargetFromEntity(intersection.intersection, props); - }; - - this.processControllerTriggers = function(controllerData) { - if (controllerData.triggerClicks[this.hand]) { - this.mode = "full"; - this.laserPressingTarget = true; - this.hover = false; - } else if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { - this.mode = "half"; - this.laserPressingTarget = false; - this.hover = true; - this.requestTouchFocus(this.laserTargetID); - } else { - this.mode = "none"; - this.laserPressingTarget = false; - this.hover = false; - this.relinquishTouchFocus(); - - } - }; - - this.hovering = function() { - if (!laserTargetHasKeyboardFocus(this.laserTagetID)) { - setKeyboardFocusOnLaserTarget(this.laserTargetID); - } - sendHoverOverEventToLaserTarget(this.hand, this.laserTarget); - }; - - this.laserPressEnter = function () { - sendTouchStartEventToLaserTarget(this.hand, this.laserTarget); - Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand); - - this.touchingEnterTimer = 0; - this.pressEnterLaserTarget = this.laserTarget; - this.deadspotExpired = false; - - var LASER_PRESS_TO_MOVE_DEADSPOT = 0.026; - this.deadspotRadius = Math.tan(LASER_PRESS_TO_MOVE_DEADSPOT) * this.laserTarget.distance; - }; - - this.laserPressExit = function () { - if (this.laserTarget === null) { - return; - } - - // send press event - if (this.deadspotExpired) { - sendTouchEndEventToLaserTarget(this.hand, this.laserTarget); - } else { - sendTouchEndEventToLaserTarget(this.hand, this.pressEnterLaserTarget); - } - }; - - this.laserPressing = function (controllerData, dt) { - this.touchingEnterTimer += dt; - - if (this.laserTarget) { - var POINTER_PRESS_TO_MOVE_DELAY = 0.33; // seconds - if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY || - distance2D(this.laserTarget.position2D, - this.pressEnterLaserTarget.position2D) > this.deadspotRadius) { - sendTouchMoveEventToLaserTarget(this.hand, this.laserTarget); - this.deadspotExpired = true; - } - } else { - this.laserPressingTarget = false; - } - }; - - this.releaseTouchEvent = function() { - if (this.pressEnterLaserTarget === null) { - return; - } - - sendTouchEndEventToLaserTarget(this.hand, this.pressEnterLaserTarget); - }; - - this.updateLaserPointer = function(controllerData) { - LaserPointers.enableLaserPointer(this.laserPointer); - LaserPointers.setRenderState(this.laserPointer, this.mode); - }; - this.isPointingAtWebEntity = function(controllerData) { var intersection = controllerData.rayPicks[this.hand]; var entityProperty = Entities.getEntityProperties(intersection.objectID); @@ -385,90 +36,32 @@ Script.include("/~/system/libraries/controllers.js"); return false; }; - this.exitModule = function() { - this.releaseTouchEvent(); - this.relinquishTouchFocus(); - this.reset(); - this.updateLaserPointer(); - LaserPointers.disableLaserPointer(this.laserPointer); - }; - - this.reset = function() { - this.pressEnterLaserTarget = null; - this.laserTarget = null; - this.laserTargetID = null; - this.laserPressingTarget = false; - this.previousLaserClickedTarget = null; - this.mode = "none"; - this.active = false; - }; - this.isReady = function(controllerData) { var otherModule = this.getOtherModule(); if (this.isPointingAtWebEntity(controllerData) && !otherModule.active) { return makeRunningValues(true, [], []); } - return makeRunningValues(false, [], []); }; this.run = function(controllerData, deltaTime) { if (!this.isPointingAtWebEntity(controllerData)) { - this.exitModule(); return makeRunningValues(false, [], []); } - - this.updateLaserTargets(controllerData); - this.processControllerTriggers(controllerData); - this.updateLaserPointer(controllerData); - - if (!this.previousLaserClickedTarget && this.laserPressingTarget) { - this.laserPressEnter(); - } - if (this.previousLaserClickedTarget && !this.laserPressingTarget) { - this.laserPressExit(); - } - this.previousLaserClickedTarget = this.laserPressingTarget; - - if (this.laserPressingTarget) { - this.laserPressing(controllerData, deltaTime); - } - - if (this.hover) { - this.hovering(); - } return makeRunningValues(true, [], []); }; - - this.cleanup = function() { - LaserPointers.disableLaserPointer(this.laserPointer); - LaserPointers.removeLaserPointer(this.laserPointer); - }; - - this.laserPointer = LaserPointers.createLaserPointer({ - joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: Picks.PICK_ENTITIES, - maxDistance: PICK_MAX_DISTANCE, - posOffset: getGrabPointSphereOffset(this.handToController(), true), - renderStates: renderStates, - faceAvatar: true, - defaultRenderStates: defaultRenderStates - }); } - var leftWebEntityLaserInput = new WebEntityLaserInput(LEFT_HAND); var rightWebEntityLaserInput = new WebEntityLaserInput(RIGHT_HAND); enableDispatcherModule("LeftWebEntityLaserInput", leftWebEntityLaserInput); enableDispatcherModule("RightWebEntityLaserInput", rightWebEntityLaserInput); - this.cleanup = function() { - leftWebEntityLaserInput.cleanup(); - rightWebEntityLaserInput.cleanup(); + function cleanup() { disableDispatcherModule("LeftWebEntityLaserInput"); disableDispatcherModule("RightWebEntityLaserInput"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); From 3c779f1528cd0eeccd2e04d2ffbecaa88629eca8 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 31 Oct 2017 13:26:43 -0700 Subject: [PATCH 048/292] HUD events WIP, fix entity/overlay hover, no hover for empty renderState --- interface/src/Application.cpp | 6 ++ interface/src/raypick/LaserPointer.cpp | 2 + interface/src/raypick/LaserPointer.h | 3 + interface/src/ui/overlays/Overlays.cpp | 21 ++++++- interface/src/ui/overlays/Overlays.h | 1 + .../src/EntityTreeRenderer.cpp | 1 + .../pointers/src/pointers/PickManager.cpp | 1 + libraries/pointers/src/pointers/PickManager.h | 3 + libraries/pointers/src/pointers/Pointer.cpp | 32 +++++++++-- libraries/pointers/src/pointers/Pointer.h | 9 ++- .../pointers/src/pointers/PointerManager.h | 7 +++ libraries/shared/src/PointerEvent.cpp | 5 ++ libraries/shared/src/PointerEvent.h | 2 +- libraries/ui/CMakeLists.txt | 3 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 57 ++++++++++++++++--- libraries/ui/src/ui/OffscreenQmlSurface.h | 5 ++ 16 files changed, 138 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0db422953f..6038ff6c9a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1811,6 +1811,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); DependencyManager::get()->setShouldPickHUDOperator([&]() { return DependencyManager::get()->isHMDMode(); }); + DependencyManager::get()->setCalculatePos2DFromHUDOperator([&](const glm::vec3& intersection) { + const glm::vec2 MARGIN(25.0f); + glm::vec2 maxPos = _controllerScriptingInterface->getViewportDimensions() - MARGIN; + glm::vec2 pos2D = DependencyManager::get()->overlayFromWorldPoint(intersection); + return glm::max(MARGIN, glm::min(pos2D, maxPos)); + }); // Setup the mouse ray pick and related operators DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared( diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 83e3757514..d2d829e579 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -301,6 +301,8 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const Q pos2D = projectOntoEntityXYPlane(target.objectID, intersection); } else if (target.type == OVERLAY) { pos2D = projectOntoOverlayXYPlane(target.objectID, intersection); + } else if (target.type == HUD) { + pos2D = DependencyManager::get()->calculatePos2DFromHUD(intersection); } return PointerEvent(PointerEvent::Move, id, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons); } diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index bdd3f2ffa0..14b95d34d3 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -75,6 +75,9 @@ public: protected: PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const override; + bool shouldHover() override { return _currentRenderState != ""; } + bool shouldTrigger() override { return _currentRenderState != ""; } + private: PointerTriggers _triggers; float _laserLength { 0.0f }; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index b37a376de3..5a7b1bd76c 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -46,7 +46,7 @@ extern void initOverlay3DPipelines(render::ShapePlumber& plumber, bool depthTest Overlays::Overlays() { auto pointerManager = DependencyManager::get(); connect(pointerManager.data(), &PointerManager::hoverBeginOverlay, this, &Overlays::hoverEnterOverlay); - connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, this, &Overlays::hoverOverOverlay); + connect(pointerManager.data(), &PointerManager::hoverContinueOverlay, this, &Overlays::hoverOverPointerEvent); connect(pointerManager.data(), &PointerManager::hoverEndOverlay, this, &Overlays::hoverLeavePointerEvent); connect(pointerManager.data(), &PointerManager::triggerBeginOverlay, this, &Overlays::mousePressPointerEvent); connect(pointerManager.data(), &PointerManager::triggerContinueOverlay, this, &Overlays::mouseMovePointerEvent); @@ -745,7 +745,7 @@ void Overlays::sendHoverEnterOverlay(const OverlayID& overlayID, const PointerEv } void Overlays::sendHoverOverOverlay(const OverlayID& overlayID, const PointerEvent& event) { - emit hoverOverOverlay(overlayID, event); + hoverOverPointerEvent(overlayID, event); } void Overlays::sendHoverLeaveOverlay(const OverlayID& overlayID, const PointerEvent& event) { @@ -940,6 +940,21 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { return false; } +void Overlays::hoverOverPointerEvent(const OverlayID& overlayID, const PointerEvent& event) { + // TODO: generalize this to allow any overlay to recieve events + std::shared_ptr thisOverlay; + if (getOverlayType(overlayID) == "web3d") { + thisOverlay = std::static_pointer_cast(getOverlay(overlayID)); + } + if (thisOverlay) { + // Send to web overlay + QMetaObject::invokeMethod(thisOverlay.get(), "handlePointerEvent", Q_ARG(PointerEvent, event)); + } + + // emit to scripts + emit hoverOverOverlay(overlayID, event); +} + void Overlays::hoverLeavePointerEvent(const OverlayID& overlayID, const PointerEvent& event) { // TODO: generalize this to allow any overlay to recieve events std::shared_ptr thisOverlay; @@ -1005,7 +1020,7 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { } // Hover over current overlay. - emit hoverOverOverlay(rayPickResult.overlayID, pointerEvent); + hoverOverPointerEvent(rayPickResult.overlayID, pointerEvent); _currentHoverOverOverlayID = rayPickResult.overlayID; } else { diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 8bcfa99aba..a5ad013246 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -308,6 +308,7 @@ public slots: void mousePressPointerEvent(const OverlayID& overlayID, const PointerEvent& event); void mouseMovePointerEvent(const OverlayID& overlayID, const PointerEvent& event); void mouseReleasePointerEvent(const OverlayID& overlayID, const PointerEvent& event); + void hoverOverPointerEvent(const OverlayID& overlayID, const PointerEvent& event); void hoverLeavePointerEvent(const OverlayID& overlayID, const PointerEvent& event); signals: diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index ef056b88ac..4dc5729c03 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -83,6 +83,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf connect(entityScriptingInterface.data(), &EntityScriptingInterface::mousePressOnEntity, this, handlePointerEvent); connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseReleaseOnEntity, this, handlePointerEvent); connect(entityScriptingInterface.data(), &EntityScriptingInterface::mouseMoveOnEntity, this, handlePointerEvent); + connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverOverEntity, this, handlePointerEvent); connect(entityScriptingInterface.data(), &EntityScriptingInterface::hoverLeaveEntity, this, [&](const EntityItemID& entityID, const PointerEvent& event) { std::shared_ptr thisEntity; auto entity = getEntity(entityID); diff --git a/libraries/pointers/src/pointers/PickManager.cpp b/libraries/pointers/src/pointers/PickManager.cpp index 571f9f04cd..1c5025250a 100644 --- a/libraries/pointers/src/pointers/PickManager.cpp +++ b/libraries/pointers/src/pointers/PickManager.cpp @@ -9,6 +9,7 @@ PickManager::PickManager() { setShouldPickHUDOperator([]() { return false; }); + setCalculatePos2DFromHUDOperator([](const glm::vec3& intersection) { return glm::vec2(NAN); }); } QUuid PickManager::addPick(PickQuery::PickType type, const std::shared_ptr pick) { diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index b8abb077c7..e3b1d03080 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -34,9 +34,12 @@ public: void setIncludeItems(const QUuid& uid, const QVector& include) const; void setShouldPickHUDOperator(std::function shouldPickHUDOperator) { _shouldPickHUDOperator = shouldPickHUDOperator; } + void setCalculatePos2DFromHUDOperator(std::function calculatePos2DFromHUDOperator) { _calculatePos2DFromHUDOperator = calculatePos2DFromHUDOperator; } + glm::vec2 calculatePos2DFromHUD(const glm::vec3& intersection) { return _calculatePos2DFromHUDOperator(intersection); } protected: std::function _shouldPickHUDOperator; + std::function _calculatePos2DFromHUDOperator; std::shared_ptr findPick(const QUuid& uid) const; QHash>> _picks; diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 8796b1e47d..90518ed965 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -56,7 +56,7 @@ void Pointer::update() { } void Pointer::generatePointerEvents(const QVariantMap& pickResult) { - // TODO: avatars/HUD? + // TODO: avatars? auto pointerManager = DependencyManager::get(); // Hover events @@ -65,7 +65,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { hoveredEvent.setType(PointerEvent::Move); // TODO: set buttons on hover events hoveredEvent.setButton(PointerEvent::NoButtons); - if (_enabled && _hover) { + if (_enabled && _hover && shouldHover()) { if (hoveredObject.type == OVERLAY) { if (_prevHoveredObject.type == OVERLAY) { if (hoveredObject.objectID == _prevHoveredObject.objectID) { @@ -79,6 +79,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); if (_prevHoveredObject.type == ENTITY) { emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); + } else if (_prevHoveredObject.type == HUD) { + emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent); } } } @@ -97,6 +99,22 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); if (_prevHoveredObject.type == OVERLAY) { emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent); + } else if (_prevHoveredObject.type == HUD) { + emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent); + } + } + } + + if (hoveredObject.type == HUD) { + if (_prevHoveredObject.type == HUD) { + // There's only one HUD + emit pointerManager->hoverContinueHUD(hoveredObject.objectID, hoveredEvent); + } else { + emit pointerManager->hoverBeginHUD(hoveredObject.objectID, hoveredEvent); + if (_prevHoveredObject.type == ENTITY) { + emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); + } else if (_prevHoveredObject.type == OVERLAY) { + emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent); } } } @@ -107,8 +125,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { Buttons newButtons; Buttons sameButtons; // NOTE: After this loop: _prevButtons = buttons that were removed - // If !_enabled, release all buttons - if (_enabled) { + // If switching to disabled or should stop triggering, release all buttons + if (_enabled && shouldTrigger()) { buttons = getPressedButtons(); for (const std::string& button : buttons) { if (_prevButtons.find(button) == _prevButtons.end()) { @@ -130,6 +148,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->triggerBeginEntity(hoveredObject.objectID, hoveredEvent); } else if (hoveredObject.type == OVERLAY) { emit pointerManager->triggerBeginOverlay(hoveredObject.objectID, hoveredEvent); + } else if (hoveredObject.type == HUD) { + emit pointerManager->triggerBeginHUD(hoveredObject.objectID, hoveredEvent); } _triggeredObjects[button] = hoveredObject; } @@ -143,6 +163,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { emit pointerManager->triggerContinueOverlay(_triggeredObjects[button].objectID, triggeredEvent); + } else if (_triggeredObjects[button].type == HUD) { + emit pointerManager->triggerContinueHUD(_triggeredObjects[button].objectID, triggeredEvent); } } @@ -155,6 +177,8 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { emit pointerManager->triggerEndOverlay(_triggeredObjects[button].objectID, triggeredEvent); + } else if (_triggeredObjects[button].type == HUD) { + emit pointerManager->triggerEndHUD(_triggeredObjects[button].objectID, triggeredEvent); } _triggeredObjects.erase(button); } diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index ca35c38c7a..b8294cd2f6 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -71,9 +71,6 @@ public: using Buttons = std::unordered_set; - virtual PickedObject getHoveredObject(const QVariantMap& pickResult) = 0; - virtual Buttons getPressedButtons() = 0; - QUuid getRayUID() { return _pickUID; } protected: @@ -83,6 +80,12 @@ protected: virtual PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const = 0; + virtual PickedObject getHoveredObject(const QVariantMap& pickResult) = 0; + virtual Buttons getPressedButtons() = 0; + + virtual bool shouldHover() = 0; + virtual bool shouldTrigger() = 0; + private: PickedObject _prevHoveredObject; Buttons _prevButtons; diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 9f477d9eb2..574be8320a 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -58,6 +58,13 @@ signals: void hoverBeginEntity(const QUuid& id, const PointerEvent& pointerEvent); void hoverContinueEntity(const QUuid& id, const PointerEvent& pointerEvent); void hoverEndEntity(const QUuid& id, const PointerEvent& pointerEvent); + + void triggerBeginHUD(const QUuid& id, const PointerEvent& pointerEvent); + void triggerContinueHUD(const QUuid& id, const PointerEvent& pointerEvent); + void triggerEndHUD(const QUuid& id, const PointerEvent& pointerEvent); + void hoverBeginHUD(const QUuid& id, const PointerEvent& pointerEvent); + void hoverContinueHUD(const QUuid& id, const PointerEvent& pointerEvent); + void hoverEndHUD(const QUuid& id, const PointerEvent& pointerEvent); }; #endif // hifi_pointers_PointerManager_h diff --git a/libraries/shared/src/PointerEvent.cpp b/libraries/shared/src/PointerEvent.cpp index e35832391d..183b7c332a 100644 --- a/libraries/shared/src/PointerEvent.cpp +++ b/libraries/shared/src/PointerEvent.cpp @@ -41,6 +41,11 @@ PointerEvent::PointerEvent(EventType type, uint32_t id, ; } +void PointerEvent::setButton(Button button) { + _button = button; + _buttons |= button; +} + QScriptValue PointerEvent::toScriptValue(QScriptEngine* engine, const PointerEvent& event) { QScriptValue obj = engine->newObject(); diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index 074e5ab79b..d3b72f072c 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -58,7 +58,7 @@ public: bool shouldFocus() const { return _shouldFocus; } void setType(EventType type) { _type = type; } - void setButton(Button button) { _button = button; } + void setButton(Button button); void setShouldFocus(bool focus) { _shouldFocus = focus; } private: diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index f28157ff97..334cce97e5 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME ui) setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns) -link_hifi_libraries(shared networking gl audio) +link_hifi_libraries(shared networking gl audio pointers) +include_hifi_library_headers(controllers) # Required for some low level GL interaction in the OffscreenQMLSurface target_opengl() diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index ecd07a5874..3363a47092 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -49,6 +49,8 @@ #include "Logging.h" +#include + Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml") Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl") Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus") @@ -529,6 +531,13 @@ bool OffscreenQmlSurface::allowNewFrame(uint8_t fps) { } OffscreenQmlSurface::OffscreenQmlSurface() { + auto pointerManager = DependencyManager::get(); + connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &OffscreenQmlSurface::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &OffscreenQmlSurface::handlePointerEvent); } OffscreenQmlSurface::~OffscreenQmlSurface() { @@ -932,14 +941,8 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even transformedPos, mouseEvent->screenPos(), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); - if (event->type() == QEvent::MouseMove) { - // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install - // need to investigate into why this crash is happening. - //_qmlContext->setContextProperty("lastMousePosition", transformedPos); - } - mappedEvent.ignore(); - if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) { - return mappedEvent.isAccepted(); + if (sendMouseEvent(mappedEvent)) { + return true; } break; } @@ -951,6 +954,44 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even return false; } +void OffscreenQmlSurface::handlePointerEvent(const QUuid& id, const PointerEvent& event) { + if (_paused) { + return; + } + + QEvent::Type type; + switch (event.getType()) { + case PointerEvent::Press: + type = QEvent::Type::MouseButtonPress; + break; + case PointerEvent::DoublePress: + type = QEvent::Type::MouseButtonDblClick; + break; + case PointerEvent::Release: + type = QEvent::Type::MouseButtonRelease; + break; + case PointerEvent::Move: + type = QEvent::Type::MouseMove; + break; + } + QPointF screenPos(event.getPos2D().x, event.getPos2D().y); + QMouseEvent mouseEvent(type, screenPos, Qt::MouseButton(event.getButton()), Qt::MouseButtons(event.getButtons()), event.getKeyboardModifiers()); + sendMouseEvent(mouseEvent); +} + +bool OffscreenQmlSurface::sendMouseEvent(QMouseEvent& mouseEvent) { + if (mouseEvent.type() == QEvent::MouseMove) { + // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install + // need to investigate into why this crash is happening. + //_qmlContext->setContextProperty("lastMousePosition", mouseEvent.localPos()); + } + mouseEvent.ignore(); + if (QCoreApplication::sendEvent(_quickWindow, &mouseEvent)) { + return mouseEvent.isAccepted(); + } + return false; +} + void OffscreenQmlSurface::pause() { _paused = true; } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 12ee9e59a1..3deab07411 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -30,6 +30,8 @@ class QQmlContext; class QQmlComponent; class QQuickWindow; class QQuickItem; +class QMouseEvent; +class PointerEvent; // GPU resources are typically buffered for one copy being used by the renderer, // one copy in flight, and one copy being used by the receiver @@ -135,6 +137,7 @@ private: private slots: void updateQuick(); void onFocusObjectChanged(QObject* newFocus); + void handlePointerEvent(const QUuid& id, const PointerEvent& event); private: QQuickWindow* _quickWindow { nullptr }; @@ -161,6 +164,8 @@ private: QWindow* _proxyWindow { nullptr }; QQuickItem* _currentFocusItem { nullptr }; + + bool sendMouseEvent(QMouseEvent& mouseEvent); }; #endif From f44025a8b1687ae727459a5578d75b24186db9e1 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Tue, 31 Oct 2017 15:57:57 -0700 Subject: [PATCH 049/292] completely removed non-need laserPointers --- .../controllers/controllerDispatcher.js | 52 ++++++-- .../controllerModules/hudOverlayPointer.js | 120 +----------------- .../controllerModules/webEntityLaserInput.js | 3 +- .../system/controllers/controllerScripts.js | 2 +- 4 files changed, 43 insertions(+), 134 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 1773e013e1..6f68edad07 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -128,8 +128,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); mouse: false }; - this.laserVisibleStatus = [false, false]; - this.laserLockStatus = [false, false]; + this.laserVisibleStatus = [false, false, false, false]; + this.laserLockStatus = [false, false, false, false]; this.slotsAreAvailableForPlugin = function (plugin) { for (var i = 0; i < plugin.parameters.activitySlots.length; i++) { @@ -256,6 +256,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.updateRenderStateForVisibleLasers = function() { // update left hand laser + + var HUD_LASER_OFFSET = 2; if (_this.laserVisibleStatus[LEFT_HAND]) { var laserLocked = _this.laserLockStatus[LEFT_HAND]; _this.updateLaserRenderState(_this.leftControllerPointer,_this.leftTriggerClicked, laserLocked); @@ -270,6 +272,18 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } else { Pointers.setRenderState(_this.rightControllerPointer, ""); } + + if (_this.laserVisibleStatus[LEFT_HAND + HUD_LASER_OFFSET]) { + _this.updateLaserRenderState(_this.leftControllerHudRayPick, _this.leftTriggerClicked, false); + } else { + Pointers.setRenderState(_this.leftControllerHudRayPick, ""); + } + + if (_this.laserVisibleStatus[RIGHT_HAND + HUD_LASER_OFFSET]) { + _this.updateLaserRenderState(_this.rightControllerHudRayPick, _this.rightTriggerClicked, false); + } else { + Pointers.setRenderState(_this.rightControllerHudRayPick, ""); + } }; this.updateLaserRenderState = function(laser, triggerClicked, laserLocked) { @@ -375,8 +389,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Pointers.getPrevPickResult(_this.rightControllerPointer) ]; var hudRayPicks = [ - RayPick.getPrevRayPickResult(_this.leftControllerHudRayPick), - RayPick.getPrevRayPickResult(_this.rightControllerHudRayPick) + Pointers.getPrevPickResult(_this.leftControllerHudRayPick), + Pointers.getPrevPickResult(_this.rightControllerHudRayPick) ]; var mouseRayPick = RayPick.getPrevRayPickResult(_this.mouseRayPick); // if the pickray hit something very nearby, put it into the nearby entities list @@ -538,12 +552,15 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true), hover: true }); - this.leftControllerHudRayPick = RayPick.createRayPick({ + this.leftControllerHudRayPick = Pointers.createPointer(PickType.Ray, { joint: "_CONTROLLER_LEFTHAND", filter: Picks.PICK_HUD, - enabled: true, maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, - posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true) + renderStates: renderStates, + defaultRenderStates: defaultRenderStates, + posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true), + triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}], + hover: true }); this.rightControllerPointer = Pointers.createPointer(PickType.Ray, { joint: "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", @@ -554,12 +571,15 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true), hover: true }); - this.rightControllerHudRayPick = RayPick.createRayPick({ + this.rightControllerHudRayPick = Pointers.createPointer(PickType.Ray, { joint: "_CONTROLLER_RIGHTHAND", filter: Picks.PICK_HUD, - enabled: true, maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, - posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true) + renderStates: renderStates, + defaultRenderStates: defaultRenderStates, + posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true), + triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], + hover: true }); this.mouseRayPick = RayPick.createRayPick({ joint: "Mouse", @@ -568,9 +588,13 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }); Pointers.setRenderState(this.leftControllerPointer, ""); + Pointers.setRenderState(this.leftControllerHudRayPick, ""); Pointers.setRenderState(this.rightControllerPointer, ""); + Pointers.setRenderState(this.rightControllerHudRayPick, ""); Pointers.enablePointer(this.leftControllerPointer); + Pointers.enablePointer(this.leftControllerHudRayPick); Pointers.enablePointer(this.rightControllerPointer); + Pointers.enablePointer(this.rightControllerHudRayPick); this.handleHandMessage = function(channel, message, sender) { var data; @@ -604,10 +628,10 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.cleanup = function () { Script.update.disconnect(_this.update); Controller.disableMapping(MAPPING_NAME); - RayPick.removeRayPick(_this.leftControllerRayPick); - RayPick.removeRayPick(_this.rightControllerRayPick); - RayPick.removeRayPick(_this.rightControllerHudRayPick); - RayPick.removeRayPick(_this.leftControllerHudRayPick); + Pointers.removePointer(_this.leftControllerPointer); + Pointers.removePointer(_this.rightControllerPointer); + Pointers.removePointer(_this.rightControllerHudRayPick); + Pointers.removePointer(_this.leftControllerHudRayPick); }; } diff --git a/scripts/system/controllers/controllerModules/hudOverlayPointer.js b/scripts/system/controllers/controllerModules/hudOverlayPointer.js index 191f7ed86f..b276bde027 100644 --- a/scripts/system/controllers/controllerModules/hudOverlayPointer.js +++ b/scripts/system/controllers/controllerModules/hudOverlayPointer.js @@ -22,79 +22,8 @@ (function() { Script.include("/~/system/libraries/controllers.js"); var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); - var END_RADIUS = 0.005; - var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS }; - var halfPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawHUDLayer: true, - parentID: MyAvatar.SELF_ID - }; - var halfEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawHUDLayer: true, - visible: true - }; - var fullPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawHUDLayer: true, - parentID: MyAvatar.SELF_ID - }; - var fullEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawHUDLayer: true, - visible: true - }; - var holdPath = { - type: "line3d", - color: COLORS_GRAB_DISTANCE_HOLD, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawHUDLayer: true, - parentID: MyAvatar.SELF_ID - }; - - var renderStates = [ - {name: "half", path: halfPath, end: halfEnd}, - {name: "full", path: fullPath, end: fullEnd}, - {name: "hold", path: holdPath} - ]; - - var defaultRenderStates = [ - {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, - {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, - {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} - ]; - var MARGIN = 25; - + var HUD_LASER_OFFSET = 2; function HudOverlayPointer(hand) { var _this = this; this.hand = hand; @@ -102,14 +31,12 @@ this.reticleMaxX; this.reticleMinY = MARGIN; this.reticleMaxY; - this.clicked = false; - this.triggerClicked = 0; - this.movedAway = false; this.parameters = ControllerDispatcherUtils.makeDispatcherModuleParameters( 540, this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], [], - 100); + 100, + (this.hand + HUD_LASER_OFFSET)); this.getOtherHandController = function() { return (this.hand === RIGHT_HAND) ? Controller.Standard.LeftHand : Controller.Standard.RightHand; @@ -129,22 +56,6 @@ this.reticleMaxY = dims.y - MARGIN; }; - this.updateLaserPointer = function(controllerData) { - LaserPointers.enableLaserPointer(this.laserPointer); - LaserPointers.setRenderState(this.laserPointer, this.mode); - }; - - this.processControllerTriggers = function(controllerData) { - if (controllerData.triggerClicks[this.hand]) { - this.mode = "full"; - } else if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { - this.clicked = false; - this.mode = "half"; - } else { - this.mode = "none"; - } - }; - this.calculateNewReticlePosition = function(intersection) { this.updateRecommendedArea(); var point2d = HMD.overlayFromWorldPoint(intersection); @@ -166,28 +77,18 @@ var controllerLocation = controllerData.controllerLocations[this.hand]; if ((controllerData.triggerValues[this.hand] < ControllerDispatcherUtils.TRIGGER_ON_VALUE || !controllerLocation.valid) || this.pointingAtTablet(controllerData)) { - this.exitModule(); return false; } var hudRayPick = controllerData.hudRayPicks[this.hand]; var point2d = this.calculateNewReticlePosition(hudRayPick.intersection); if (!Window.isPointOnDesktopWindow(point2d) && !this.triggerClicked) { - this.exitModule(); return false; } - this.setReticlePosition(point2d); Reticle.visible = false; - this.movedAway = false; this.triggerClicked = controllerData.triggerClicks[this.hand]; - this.processControllerTriggers(controllerData); - this.updateLaserPointer(controllerData); return true; }; - this.exitModule = function() { - LaserPointers.disableLaserPointer(this.laserPointer); - }; - this.isReady = function (controllerData) { if (this.processLaser(controllerData)) { return ControllerDispatcherUtils.makeRunningValues(true, [], []); @@ -199,21 +100,6 @@ this.run = function (controllerData, deltaTime) { return this.isReady(controllerData); }; - - this.cleanup = function () { - LaserPointers.disableLaserPointer(this.laserPointer); - LaserPointers.removeLaserPointer(this.laserPointer); - }; - - this.laserPointer = LaserPointers.createLaserPointer({ - joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: Picks.PICK_HUD, - maxDistance: PICK_MAX_DISTANCE, - posOffset: getGrabPointSphereOffset(this.handToController(), true), - renderStates: renderStates, - enabled: true, - defaultRenderStates: defaultRenderStates - }); } diff --git a/scripts/system/controllers/controllerModules/webEntityLaserInput.js b/scripts/system/controllers/controllerModules/webEntityLaserInput.js index 1bd683856e..20bd272542 100644 --- a/scripts/system/controllers/controllerModules/webEntityLaserInput.js +++ b/scripts/system/controllers/controllerModules/webEntityLaserInput.js @@ -37,8 +37,7 @@ Script.include("/~/system/libraries/controllers.js"); }; this.isReady = function(controllerData) { - var otherModule = this.getOtherModule(); - if (this.isPointingAtWebEntity(controllerData) && !otherModule.active) { + if (this.isPointingAtWebEntity(controllerData)) { return makeRunningValues(true, [], []); } return makeRunningValues(false, [], []); diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index 83576bd9a4..09602b33eb 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -19,7 +19,7 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/nearParentGrabOverlay.js", "controllerModules/nearActionGrabEntity.js", "controllerModules/farActionGrabEntity.js", - "controllerModules/tabletStylusInput.js", + //"controllerModules/tabletStylusInput.js", "controllerModules/equipEntity.js", "controllerModules/nearTrigger.js", "controllerModules/overlayLaserInput.js", From 64665c87b2886b36926ba8384d2988f32083f8aa Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Tue, 31 Oct 2017 17:07:48 -0700 Subject: [PATCH 050/292] replace ids with unsigned ints --- interface/src/Application.cpp | 4 +- interface/src/raypick/LaserPointer.cpp | 3 +- .../LaserPointerScriptingInterface.cpp | 8 ++-- .../raypick/LaserPointerScriptingInterface.h | 24 +++++----- .../src/raypick/PickScriptingInterface.cpp | 22 ++++----- .../src/raypick/PickScriptingInterface.h | 18 +++---- .../src/raypick/PointerScriptingInterface.cpp | 12 ++--- .../src/raypick/PointerScriptingInterface.h | 26 +++++----- .../src/raypick/RayPickScriptingInterface.cpp | 16 +++---- .../src/raypick/RayPickScriptingInterface.h | 16 +++---- .../src/EntityTreeRenderer.cpp | 4 +- .../src/EntityTreeRenderer.h | 12 ++--- .../src/pointers/PickCacheOptimizer.h | 4 +- .../pointers/src/pointers/PickManager.cpp | 30 +++++++----- libraries/pointers/src/pointers/PickManager.h | 25 +++++----- libraries/pointers/src/pointers/Pointer.cpp | 13 +++-- libraries/pointers/src/pointers/Pointer.h | 10 ++-- .../pointers/src/pointers/PointerManager.cpp | 47 ++++++++++--------- .../pointers/src/pointers/PointerManager.h | 30 ++++++------ libraries/shared/src/PointerEvent.h | 1 + libraries/ui/src/ui/OffscreenQmlSurface.cpp | 4 +- 21 files changed, 176 insertions(+), 153 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6038ff6c9a..8fe58ddc7c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1821,7 +1821,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo // Setup the mouse ray pick and related operators DependencyManager::get()->setMouseRayPickID(DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared( PickFilter(PickScriptingInterface::PICK_ENTITIES() | PickScriptingInterface::PICK_INCLUDE_NONCOLLIDABLE()), 0.0f, true))); - DependencyManager::get()->setMouseRayPickResultOperator([&](QUuid rayPickID) { + DependencyManager::get()->setMouseRayPickResultOperator([&](unsigned int rayPickID) { RayToEntityIntersectionResult entityResult; entityResult.intersects = false; QVariantMap result = DependencyManager::get()->getPrevPickResult(rayPickID); @@ -1837,7 +1837,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo } return entityResult; }); - DependencyManager::get()->setSetPrecisionPickingOperator([&](QUuid rayPickID, bool value) { + DependencyManager::get()->setSetPrecisionPickingOperator([&](unsigned int rayPickID, bool value) { DependencyManager::get()->setPrecisionPicking(rayPickID, value); }); diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index d2d829e579..2506c6222d 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -282,7 +282,6 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) { } PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const { - uint32_t id = 0; glm::vec3 intersection = vec3FromVariant(pickResult["intersection"]); glm::vec3 surfaceNormal = vec3FromVariant(pickResult["surfaceNormal"]); QVariantMap searchRay = pickResult["searchRay"].toMap(); @@ -304,7 +303,7 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const Q } else if (target.type == HUD) { pos2D = DependencyManager::get()->calculatePos2DFromHUD(intersection); } - return PointerEvent(PointerEvent::Move, id, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons); + return PointerEvent(PointerEvent::Move, 0, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons); } glm::vec3 LaserPointer::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const { diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 533dffafb9..53ddd71969 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -14,17 +14,17 @@ #include "RegisteredMetaTypes.h" #include "PointerScriptingInterface.h" -void LaserPointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { +void LaserPointerScriptingInterface::setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void LaserPointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) const { +void LaserPointerScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValue& includeItems) const { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } -QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) const { +unsigned int LaserPointerScriptingInterface::createLaserPointer(const QVariant& properties) const { return DependencyManager::get()->createLaserPointer(properties); } -void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { +void LaserPointerScriptingInterface::editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) const { DependencyManager::get()->editRenderState(uid, renderState, properties); } \ No newline at end of file diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 1116da1528..da62f4eb12 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -21,20 +21,20 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public slots: - Q_INVOKABLE QUuid createLaserPointer(const QVariant& properties) const; - Q_INVOKABLE void enableLaserPointer(const QUuid& uid) const { DependencyManager::get()->enablePointer(uid); } - Q_INVOKABLE void disableLaserPointer(const QUuid& uid) const { DependencyManager::get()->disablePointer(uid); } - Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { DependencyManager::get()->removePointer(uid); } - Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; - Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } - Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return DependencyManager::get()->getPrevPickResult(uid); } + Q_INVOKABLE unsigned int createLaserPointer(const QVariant& properties) const; + Q_INVOKABLE void enableLaserPointer(unsigned int uid) const { DependencyManager::get()->enablePointer(uid); } + Q_INVOKABLE void disableLaserPointer(unsigned int uid) const { DependencyManager::get()->disablePointer(uid); } + Q_INVOKABLE void removeLaserPointer(unsigned int uid) const { DependencyManager::get()->removePointer(uid); } + Q_INVOKABLE void editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) const; + Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } + Q_INVOKABLE QVariantMap getPrevRayPickResult(unsigned int uid) const { return DependencyManager::get()->getPrevPickResult(uid); } - Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } - Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } - Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const; - Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const; + Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } + Q_INVOKABLE void setLaserLength(unsigned int uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const; + Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const; - Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } + Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } }; diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 40f898e65d..a59e96ccbf 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -20,16 +20,16 @@ #include #include -QUuid PickScriptingInterface::createPick(const PickQuery::PickType type, const QVariant& properties) { +unsigned int PickScriptingInterface::createPick(const PickQuery::PickType type, const QVariant& properties) { switch (type) { case PickQuery::PickType::Ray: return createRayPick(properties); default: - return QUuid(); + return 0; } } -QUuid PickScriptingInterface::createRayPick(const QVariant& properties) { +unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) { QVariantMap propMap = properties.toMap(); bool enabled = false; @@ -78,34 +78,34 @@ QUuid PickScriptingInterface::createRayPick(const QVariant& properties) { return DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared(position, direction, filter, maxDistance, enabled)); } - return QUuid(); + return 0; } -void PickScriptingInterface::enablePick(const QUuid& uid) { +void PickScriptingInterface::enablePick(unsigned int uid) { DependencyManager::get()->enablePick(uid); } -void PickScriptingInterface::disablePick(const QUuid& uid) { +void PickScriptingInterface::disablePick(unsigned int uid) { DependencyManager::get()->disablePick(uid); } -void PickScriptingInterface::removePick(const QUuid& uid) { +void PickScriptingInterface::removePick(unsigned int uid) { DependencyManager::get()->removePick(uid); } -QVariantMap PickScriptingInterface::getPrevPickResult(const QUuid& uid) { +QVariantMap PickScriptingInterface::getPrevPickResult(unsigned int uid) { return DependencyManager::get()->getPrevPickResult(uid); } -void PickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) { +void PickScriptingInterface::setPrecisionPicking(unsigned int uid, const bool precisionPicking) { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } -void PickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) { +void PickScriptingInterface::setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems) { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void PickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) { +void PickScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValue& includeItems) { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 7c2eeb1ffc..900fa2ef40 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -33,20 +33,20 @@ class PickScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public: - QUuid createRayPick(const QVariant& properties); + unsigned int createRayPick(const QVariant& properties); void registerMetaTypes(QScriptEngine* engine); public slots: - Q_INVOKABLE QUuid createPick(const PickQuery::PickType type, const QVariant& properties); - Q_INVOKABLE void enablePick(const QUuid& uid); - Q_INVOKABLE void disablePick(const QUuid& uid); - Q_INVOKABLE void removePick(const QUuid& uid); - Q_INVOKABLE QVariantMap getPrevPickResult(const QUuid& uid); + Q_INVOKABLE unsigned int createPick(const PickQuery::PickType type, const QVariant& properties); + Q_INVOKABLE void enablePick(unsigned int uid); + Q_INVOKABLE void disablePick(unsigned int uid); + Q_INVOKABLE void removePick(unsigned int uid); + Q_INVOKABLE QVariantMap getPrevPickResult(unsigned int uid); - Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, const bool precisionPicking); - Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities); - Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities); + Q_INVOKABLE void setPrecisionPicking(unsigned int uid, const bool precisionPicking); + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities); + Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities); static constexpr unsigned int PICK_NOTHING() { return 0; } static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index c3a4ac164a..b7211830a8 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -14,23 +14,23 @@ #include "Application.h" #include "LaserPointer.h" -void PointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { +void PointerScriptingInterface::setIgnoreItems(unsigned int uid, const QScriptValue& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void PointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) const { +void PointerScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValue& includeItems) const { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } -QUuid PointerScriptingInterface::createPointer(const PickQuery::PickType& type, const QVariant& properties) const { +unsigned int PointerScriptingInterface::createPointer(const PickQuery::PickType& type, const QVariant& properties) const { switch (type) { case PickQuery::PickType::Ray: return createLaserPointer(properties); default: - return QUuid(); + return 0; } } -QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) const { +unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& properties) const { QVariantMap propertyMap = properties.toMap(); bool faceAvatar = false; @@ -114,7 +114,7 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled)); } -void PointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { +void PointerScriptingInterface::editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) const { QVariantMap propMap = properties.toMap(); QVariant startProps; diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index cc2ffbc3cc..722ba8cec5 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -19,23 +19,23 @@ class PointerScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public: - QUuid createLaserPointer(const QVariant& properties) const; + unsigned int createLaserPointer(const QVariant& properties) const; public slots: - Q_INVOKABLE QUuid createPointer(const PickQuery::PickType& type, const QVariant& properties) const; - Q_INVOKABLE void enablePointer(const QUuid& uid) const { DependencyManager::get()->enablePointer(uid); } - Q_INVOKABLE void disablePointer(const QUuid& uid) const { DependencyManager::get()->disablePointer(uid); } - Q_INVOKABLE void removePointer(const QUuid& uid) const { DependencyManager::get()->removePointer(uid); } - Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; - Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } - Q_INVOKABLE QVariantMap getPrevPickResult(const QUuid& uid) const { return DependencyManager::get()->getPrevPickResult(uid); } + Q_INVOKABLE unsigned int createPointer(const PickQuery::PickType& type, const QVariant& properties) const; + Q_INVOKABLE void enablePointer(unsigned int uid) const { DependencyManager::get()->enablePointer(uid); } + Q_INVOKABLE void disablePointer(unsigned int uid) const { DependencyManager::get()->disablePointer(uid); } + Q_INVOKABLE void removePointer(unsigned int uid) const { DependencyManager::get()->removePointer(uid); } + Q_INVOKABLE void editRenderState(unsigned int uid, const QString& renderState, const QVariant& properties) const; + Q_INVOKABLE void setRenderState(unsigned int uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } + Q_INVOKABLE QVariantMap getPrevPickResult(unsigned int uid) const { return DependencyManager::get()->getPrevPickResult(uid); } - Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } - Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } - Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities) const; - Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities) const; + Q_INVOKABLE void setPrecisionPicking(unsigned int uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } + Q_INVOKABLE void setLaserLength(unsigned int uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const; + Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const; - Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } + Q_INVOKABLE void setLockEndUid(unsigned int uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } signals: void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent); diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index 92bf3ec521..f9774dda31 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -20,34 +20,34 @@ #include "JointRayPick.h" #include "MouseRayPick.h" -QUuid RayPickScriptingInterface::createRayPick(const QVariant& properties) { +uint32_t RayPickScriptingInterface::createRayPick(const QVariant& properties) { return DependencyManager::get()->createRayPick(properties); } -void RayPickScriptingInterface::enableRayPick(const QUuid& uid) { +void RayPickScriptingInterface::enableRayPick(uint32_t uid) { DependencyManager::get()->enablePick(uid); } -void RayPickScriptingInterface::disableRayPick(const QUuid& uid) { +void RayPickScriptingInterface::disableRayPick(uint32_t uid) { DependencyManager::get()->disablePick(uid); } -void RayPickScriptingInterface::removeRayPick(const QUuid& uid) { +void RayPickScriptingInterface::removeRayPick(uint32_t uid) { DependencyManager::get()->removePick(uid); } -QVariantMap RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) { +QVariantMap RayPickScriptingInterface::getPrevRayPickResult(uint32_t uid) { return DependencyManager::get()->getPrevPickResult(uid); } -void RayPickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) { +void RayPickScriptingInterface::setPrecisionPicking(uint32_t uid, const bool precisionPicking) { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } -void RayPickScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) { +void RayPickScriptingInterface::setIgnoreItems(uint32_t uid, const QScriptValue& ignoreItems) { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); } -void RayPickScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptValue& includeItems) { +void RayPickScriptingInterface::setIncludeItems(uint32_t uid, const QScriptValue& includeItems) { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index b0d36f482c..844add9012 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -37,15 +37,15 @@ class RayPickScriptingInterface : public QObject, public Dependency { SINGLETON_DEPENDENCY public slots: - Q_INVOKABLE QUuid createRayPick(const QVariant& properties); - Q_INVOKABLE void enableRayPick(const QUuid& uid); - Q_INVOKABLE void disableRayPick(const QUuid& uid); - Q_INVOKABLE void removeRayPick(const QUuid& uid); - Q_INVOKABLE QVariantMap getPrevRayPickResult(const QUuid& uid); + Q_INVOKABLE unsigned int createRayPick(const QVariant& properties); + Q_INVOKABLE void enableRayPick(unsigned int uid); + Q_INVOKABLE void disableRayPick(unsigned int uid); + Q_INVOKABLE void removeRayPick(unsigned int uid); + Q_INVOKABLE QVariantMap getPrevRayPickResult(unsigned int uid); - Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, const bool precisionPicking); - Q_INVOKABLE void setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreEntities); - Q_INVOKABLE void setIncludeItems(const QUuid& uid, const QScriptValue& includeEntities); + Q_INVOKABLE void setPrecisionPicking(unsigned int uid, const bool precisionPicking); + Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities); + Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities); static unsigned int PICK_NOTHING() { return PickScriptingInterface::PICK_NOTHING(); } static unsigned int PICK_ENTITIES() { return PickScriptingInterface::PICK_ENTITIES(); } diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 4dc5729c03..3cccc31145 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -51,11 +51,11 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf _displayModelBounds(false), _layeredZones(this) { - setMouseRayPickResultOperator([](QUuid rayPickID) { + setMouseRayPickResultOperator([](unsigned int rayPickID) { RayToEntityIntersectionResult entityResult; return entityResult; }); - setSetPrecisionPickingOperator([](QUuid rayPickID, bool value) {}); + setSetPrecisionPickingOperator([](unsigned int rayPickID, bool value) {}); EntityRenderer::initEntityRenderers(); _currentHoverOverEntityID = UNKNOWN_ENTITY_ID; _currentClickingOnEntityID = UNKNOWN_ENTITY_ID; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 1eb44f996a..52876fa90e 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -74,9 +74,9 @@ public: static float getEntityLoadingPriority(const EntityItem& item) { return _calculateEntityLoadingPriorityFunc(item); } static void setEntityLoadingPriorityFunction(CalculateEntityLoadingPriority fn) { _calculateEntityLoadingPriorityFunc = fn; } - void setMouseRayPickID(QUuid rayPickID) { _mouseRayPickID = rayPickID; } - void setMouseRayPickResultOperator(std::function getPrevRayPickResultOperator) { _getPrevRayPickResultOperator = getPrevRayPickResultOperator; } - void setSetPrecisionPickingOperator(std::function setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; } + void setMouseRayPickID(unsigned int rayPickID) { _mouseRayPickID = rayPickID; } + void setMouseRayPickResultOperator(std::function getPrevRayPickResultOperator) { _getPrevRayPickResultOperator = getPrevRayPickResultOperator; } + void setSetPrecisionPickingOperator(std::function setPrecisionPickingOperator) { _setPrecisionPickingOperator = setPrecisionPickingOperator; } void shutdown(); void update(bool simulate); @@ -182,9 +182,9 @@ private: QMultiMap _waitingOnPreload; - QUuid _mouseRayPickID; - std::function _getPrevRayPickResultOperator; - std::function _setPrecisionPickingOperator; + unsigned int _mouseRayPickID; + std::function _getPrevRayPickResultOperator; + std::function _setPrecisionPickingOperator; class LayeredZone { public: diff --git a/libraries/pointers/src/pointers/PickCacheOptimizer.h b/libraries/pointers/src/pointers/PickCacheOptimizer.h index c4bf96ab51..f3bdbb87b0 100644 --- a/libraries/pointers/src/pointers/PickCacheOptimizer.h +++ b/libraries/pointers/src/pointers/PickCacheOptimizer.h @@ -37,7 +37,7 @@ template class PickCacheOptimizer { public: - void update(QHash>& picks, bool shouldPickHUD); + void update(QHash>& picks, bool shouldPickHUD); protected: typedef std::unordered_map> PickCache; @@ -67,7 +67,7 @@ void PickCacheOptimizer::cacheResult(const bool intersects, const PickResultP } template -void PickCacheOptimizer::update(QHash>& picks, bool shouldPickHUD) { +void PickCacheOptimizer::update(QHash>& picks, bool shouldPickHUD) { PickCache results; for (const auto& uid : picks.keys()) { std::shared_ptr> pick = std::static_pointer_cast>(picks[uid]); diff --git a/libraries/pointers/src/pointers/PickManager.cpp b/libraries/pointers/src/pointers/PickManager.cpp index 1c5025250a..903113d79d 100644 --- a/libraries/pointers/src/pointers/PickManager.cpp +++ b/libraries/pointers/src/pointers/PickManager.cpp @@ -12,16 +12,20 @@ PickManager::PickManager() { setCalculatePos2DFromHUDOperator([](const glm::vec3& intersection) { return glm::vec2(NAN); }); } -QUuid PickManager::addPick(PickQuery::PickType type, const std::shared_ptr pick) { - QUuid id = QUuid::createUuid(); +unsigned int PickManager::addPick(PickQuery::PickType type, const std::shared_ptr pick) { + unsigned int id = 0; withWriteLock([&] { - _picks[type][id] = pick; - _typeMap[id] = type; + // Don't let the pick IDs overflow + if (_nextPickID < UINT32_MAX) { + id = _nextPickID++; + _picks[type][id] = pick; + _typeMap[id] = type; + } }); return id; } -std::shared_ptr PickManager::findPick(const QUuid& uid) const { +std::shared_ptr PickManager::findPick(unsigned int uid) const { return resultWithReadLock>([&] { auto type = _typeMap.find(uid); if (type != _typeMap.end()) { @@ -31,7 +35,7 @@ std::shared_ptr PickManager::findPick(const QUuid& uid) const { }); } -void PickManager::removePick(const QUuid& uid) { +void PickManager::removePick(unsigned int uid) { withWriteLock([&] { auto type = _typeMap.find(uid); if (type != _typeMap.end()) { @@ -41,7 +45,7 @@ void PickManager::removePick(const QUuid& uid) { }); } -QVariantMap PickManager::getPrevPickResult(const QUuid& uid) const { +QVariantMap PickManager::getPrevPickResult(unsigned int uid) const { auto pick = findPick(uid); if (pick && pick->getPrevPickResult()) { return pick->getPrevPickResult()->toVariantMap(); @@ -49,35 +53,35 @@ QVariantMap PickManager::getPrevPickResult(const QUuid& uid) const { return QVariantMap(); } -void PickManager::enablePick(const QUuid& uid) const { +void PickManager::enablePick(unsigned int uid) const { auto pick = findPick(uid); if (pick) { pick->enable(); } } -void PickManager::disablePick(const QUuid& uid) const { +void PickManager::disablePick(unsigned int uid) const { auto pick = findPick(uid); if (pick) { pick->disable(); } } -void PickManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { +void PickManager::setPrecisionPicking(unsigned int uid, bool precisionPicking) const { auto pick = findPick(uid); if (pick) { pick->setPrecisionPicking(precisionPicking); } } -void PickManager::setIgnoreItems(const QUuid& uid, const QVector& ignore) const { +void PickManager::setIgnoreItems(unsigned int uid, const QVector& ignore) const { auto pick = findPick(uid); if (pick) { pick->setIgnoreItems(ignore); } } -void PickManager::setIncludeItems(const QUuid& uid, const QVector& include) const { +void PickManager::setIncludeItems(unsigned int uid, const QVector& include) const { auto pick = findPick(uid); if (pick) { pick->setIncludeItems(include); @@ -85,7 +89,7 @@ void PickManager::setIncludeItems(const QUuid& uid, const QVector& includ } void PickManager::update() { - QHash>> cachedPicks; + QHash>> cachedPicks; withReadLock([&] { cachedPicks = _picks; }); diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index e3b1d03080..7ff4fcc941 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -22,16 +22,16 @@ public: void update(); - QUuid addPick(PickQuery::PickType type, const std::shared_ptr pick); - void removePick(const QUuid& uid); - void enablePick(const QUuid& uid) const; - void disablePick(const QUuid& uid) const; + unsigned int addPick(PickQuery::PickType type, const std::shared_ptr pick); + void removePick(unsigned int uid); + void enablePick(unsigned int uid) const; + void disablePick(unsigned int uid) const; - QVariantMap getPrevPickResult(const QUuid& uid) const; + QVariantMap getPrevPickResult(unsigned int uid) const; - void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; - void setIgnoreItems(const QUuid& uid, const QVector& ignore) const; - void setIncludeItems(const QUuid& uid, const QVector& include) const; + void setPrecisionPicking(unsigned int uid, bool precisionPicking) const; + void setIgnoreItems(unsigned int uid, const QVector& ignore) const; + void setIncludeItems(unsigned int uid, const QVector& include) const; void setShouldPickHUDOperator(std::function shouldPickHUDOperator) { _shouldPickHUDOperator = shouldPickHUDOperator; } void setCalculatePos2DFromHUDOperator(std::function calculatePos2DFromHUDOperator) { _calculatePos2DFromHUDOperator = calculatePos2DFromHUDOperator; } @@ -41,9 +41,12 @@ protected: std::function _shouldPickHUDOperator; std::function _calculatePos2DFromHUDOperator; - std::shared_ptr findPick(const QUuid& uid) const; - QHash>> _picks; - QHash _typeMap; + std::shared_ptr findPick(unsigned int uid) const; + QHash>> _picks; + QHash _typeMap; + // 0 = invalid + const unsigned int FIRST_PICK_ID { 1 }; + unsigned int _nextPickID { FIRST_PICK_ID }; PickCacheOptimizer _rayPickCacheOptimizer; }; diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 90518ed965..f57bded5ad 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -46,16 +46,16 @@ void Pointer::setIncludeItems(const QVector& includeItems) const { DependencyManager::get()->setIncludeItems(_pickUID, includeItems); } -void Pointer::update() { +void Pointer::update(unsigned int pointerID) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { QVariantMap pickResult = getPrevPickResult(); updateVisuals(pickResult); - generatePointerEvents(pickResult); + generatePointerEvents(pointerID, pickResult); }); } -void Pointer::generatePointerEvents(const QVariantMap& pickResult) { +void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& pickResult) { // TODO: avatars? auto pointerManager = DependencyManager::get(); @@ -63,6 +63,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { Pointer::PickedObject hoveredObject = getHoveredObject(pickResult); PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult); hoveredEvent.setType(PointerEvent::Move); + hoveredEvent.setID(pointerID); // TODO: set buttons on hover events hoveredEvent.setButton(PointerEvent::NoButtons); if (_enabled && _hover && shouldHover()) { @@ -72,6 +73,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->hoverContinueOverlay(hoveredObject.objectID, hoveredEvent); } else { PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult); + prevHoveredEvent.setID(pointerID); emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, prevHoveredEvent); emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); } @@ -92,6 +94,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { emit pointerManager->hoverContinueEntity(hoveredObject.objectID, hoveredEvent); } else { PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult); + prevHoveredEvent.setID(pointerID); emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, prevHoveredEvent); emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); } @@ -153,10 +156,13 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { } _triggeredObjects[button] = hoveredObject; } + // We still want other trigger events for Focus buttons, but they only set focus on triggerBegin + hoveredEvent.setShouldFocus(false); // Trigger continue for (const std::string& button : sameButtons) { PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); + triggeredEvent.setID(pointerID); triggeredEvent.setType(PointerEvent::Move); hoveredEvent.setButton(chooseButton(button)); if (_triggeredObjects[button].type == ENTITY) { @@ -171,6 +177,7 @@ void Pointer::generatePointerEvents(const QVariantMap& pickResult) { // Trigger end for (const std::string& button : _prevButtons) { PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); + triggeredEvent.setID(pointerID); triggeredEvent.setType(PointerEvent::Release); hoveredEvent.setButton(chooseButton(button)); if (_triggeredObjects[button].type == ENTITY) { diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index b8294cd2f6..fc43e121f0 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -38,7 +38,7 @@ using PointerTriggers = std::vector; class Pointer : protected ReadWriteLockable { public: - Pointer(const QUuid& uid, bool enabled, bool hover) : _pickUID(uid), _enabled(enabled), _hover(hover) {} + Pointer(unsigned int uid, bool enabled, bool hover) : _pickUID(uid), _enabled(enabled), _hover(hover) {} virtual ~Pointer(); @@ -57,9 +57,9 @@ public: virtual void setLength(float length) {} virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay) {} - void update(); + void update(unsigned int pointerID); virtual void updateVisuals(const QVariantMap& pickResult) = 0; - void generatePointerEvents(const QVariantMap& pickResult); + void generatePointerEvents(unsigned int pointerID, const QVariantMap& pickResult); struct PickedObject { PickedObject() {} @@ -71,10 +71,10 @@ public: using Buttons = std::unordered_set; - QUuid getRayUID() { return _pickUID; } + unsigned int getRayUID() { return _pickUID; } protected: - const QUuid _pickUID; + const unsigned int _pickUID; bool _enabled; bool _hover; diff --git a/libraries/pointers/src/pointers/PointerManager.cpp b/libraries/pointers/src/pointers/PointerManager.cpp index 2d41543b6b..b6d826c6f1 100644 --- a/libraries/pointers/src/pointers/PointerManager.cpp +++ b/libraries/pointers/src/pointers/PointerManager.cpp @@ -8,7 +8,7 @@ #include "PointerManager.h" -std::shared_ptr PointerManager::find(const QUuid& uid) const { +std::shared_ptr PointerManager::find(unsigned int uid) const { return resultWithReadLock>([&] { auto itr = _pointers.find(uid); if (itr != _pointers.end()) { @@ -18,50 +18,55 @@ std::shared_ptr PointerManager::find(const QUuid& uid) const { }); } -QUuid PointerManager::addPointer(std::shared_ptr pointer) { - QUuid result; - if (!pointer->getRayUID().isNull()) { - result = QUuid::createUuid(); - withWriteLock([&] { _pointers[result] = pointer; }); +unsigned int PointerManager::addPointer(std::shared_ptr pointer) { + unsigned int result = 0; + if (pointer->getRayUID() > 0) { + withWriteLock([&] { + // Don't let the pointer IDs overflow + if (_nextPointerID < UINT32_MAX) { + result = _nextPointerID++; + _pointers[result] = pointer; + } + }); } return result; } -void PointerManager::removePointer(const QUuid& uid) { +void PointerManager::removePointer(unsigned int uid) { withWriteLock([&] { _pointers.remove(uid); }); } -void PointerManager::enablePointer(const QUuid& uid) const { +void PointerManager::enablePointer(unsigned int uid) const { auto pointer = find(uid); if (pointer) { pointer->enable(); } } -void PointerManager::disablePointer(const QUuid& uid) const { +void PointerManager::disablePointer(unsigned int uid) const { auto pointer = find(uid); if (pointer) { pointer->disable(); } } -void PointerManager::setRenderState(const QUuid& uid, const std::string& renderState) const { +void PointerManager::setRenderState(unsigned int uid, const std::string& renderState) const { auto pointer = find(uid); if (pointer) { pointer->setRenderState(renderState); } } -void PointerManager::editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const { +void PointerManager::editRenderState(unsigned int uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const { auto pointer = find(uid); if (pointer) { pointer->editRenderState(state, startProps, pathProps, endProps); } } -const QVariantMap PointerManager::getPrevPickResult(const QUuid& uid) const { +const QVariantMap PointerManager::getPrevPickResult(unsigned int uid) const { auto pointer = find(uid); if (pointer) { return pointer->getPrevPickResult(); @@ -70,44 +75,44 @@ const QVariantMap PointerManager::getPrevPickResult(const QUuid& uid) const { } void PointerManager::update() { - auto cachedPointers = resultWithReadLock>>([&] { - return _pointers.values(); + auto cachedPointers = resultWithReadLock>>([&] { + return _pointers; }); - for (const auto& pointer : cachedPointers) { - pointer->update(); + for (const auto& uid : cachedPointers.keys()) { + cachedPointers[uid]->update(uid); } } -void PointerManager::setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { +void PointerManager::setPrecisionPicking(unsigned int uid, bool precisionPicking) const { auto pointer = find(uid); if (pointer) { pointer->setPrecisionPicking(precisionPicking); } } -void PointerManager::setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const { +void PointerManager::setIgnoreItems(unsigned int uid, const QVector& ignoreEntities) const { auto pointer = find(uid); if (pointer) { pointer->setIgnoreItems(ignoreEntities); } } -void PointerManager::setIncludeItems(const QUuid& uid, const QVector& includeEntities) const { +void PointerManager::setIncludeItems(unsigned int uid, const QVector& includeEntities) const { auto pointer = find(uid); if (pointer) { pointer->setIncludeItems(includeEntities); } } -void PointerManager::setLength(const QUuid& uid, float length) const { +void PointerManager::setLength(unsigned int uid, float length) const { auto pointer = find(uid); if (pointer) { pointer->setLength(length); } } -void PointerManager::setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { +void PointerManager::setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay) const { auto pointer = find(uid); if (pointer) { pointer->setLockEndUUID(objectID, isOverlay); diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 574be8320a..fcb347fb82 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -23,26 +23,28 @@ class PointerManager : public QObject, public Dependency, protected ReadWriteLoc public: PointerManager() {} - QUuid addPointer(std::shared_ptr pointer); - void removePointer(const QUuid& uid); - void enablePointer(const QUuid& uid) const; - void disablePointer(const QUuid& uid) const; - void setRenderState(const QUuid& uid, const std::string& renderState) const; - void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; - const QVariantMap getPrevPickResult(const QUuid& uid) const; + unsigned int addPointer(std::shared_ptr pointer); + void removePointer(unsigned int uid); + void enablePointer(unsigned int uid) const; + void disablePointer(unsigned int uid) const; + void setRenderState(unsigned int uid, const std::string& renderState) const; + void editRenderState(unsigned int uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; + const QVariantMap getPrevPickResult(unsigned int uid) const; - void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; - void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; - void setIncludeItems(const QUuid& uid, const QVector& includeEntities) const; + void setPrecisionPicking(unsigned int uid, bool precisionPicking) const; + void setIgnoreItems(unsigned int uid, const QVector& ignoreEntities) const; + void setIncludeItems(unsigned int uid, const QVector& includeEntities) const; - void setLength(const QUuid& uid, float length) const; - void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const; + void setLength(unsigned int uid, float length) const; + void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay) const; void update(); private: - std::shared_ptr find(const QUuid& uid) const; - QHash> _pointers; + std::shared_ptr find(unsigned int uid) const; + QHash> _pointers; + // 0 = invalid, 1 = reserved for system mouse + unsigned int _nextPointerID { 2 }; signals: void triggerBeginOverlay(const QUuid& id, const PointerEvent& pointerEvent); diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index d3b72f072c..239e7c6e4e 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -57,6 +57,7 @@ public: Qt::KeyboardModifiers getKeyboardModifiers() const { return _keyboardModifiers; } bool shouldFocus() const { return _shouldFocus; } + void setID(uint32_t id) { _id = id; } void setType(EventType type) { _type = type; } void setButton(Button button); void setShouldFocus(bool focus) { _shouldFocus = focus; } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 3363a47092..204986090c 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -959,7 +959,7 @@ void OffscreenQmlSurface::handlePointerEvent(const QUuid& id, const PointerEvent return; } - QEvent::Type type; + QEvent::Type type = QEvent::Type::MouseMove; switch (event.getType()) { case PointerEvent::Press: type = QEvent::Type::MouseButtonPress; @@ -973,6 +973,8 @@ void OffscreenQmlSurface::handlePointerEvent(const QUuid& id, const PointerEvent case PointerEvent::Move: type = QEvent::Type::MouseMove; break; + default: + break; } QPointF screenPos(event.getPos2D().x, event.getPos2D().y); QMouseEvent mouseEvent(type, screenPos, Qt::MouseButton(event.getButton()), Qt::MouseButtons(event.getButtons()), event.getKeyboardModifiers()); From abb6f786fab6918b76774cf0fd63844603ca8e21 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 1 Nov 2017 11:03:48 -0700 Subject: [PATCH 051/292] added homebutton message and scripts cleanup --- scripts/system/controllers/controllerDispatcher.js | 11 +++++++++-- .../controllerModules/disableOtherModule.js | 8 ++++---- .../controllerModules/farActionGrabEntity.js | 4 ++-- .../controllerModules/nearActionGrabEntity.js | 4 ++-- .../controllerModules/nearParentGrabEntity.js | 4 ++-- .../controllerModules/nearParentGrabOverlay.js | 4 ++-- .../controllers/controllerModules/nearTrigger.js | 4 ++-- .../controllers/controllerModules/scaleEntity.js | 4 ++-- 8 files changed, 25 insertions(+), 18 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 6f68edad07..915d683724 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -168,7 +168,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var pointer = (hand === RIGHT_HAND) ? _this.rightControllerPointer : _this.leftControllerPointer; var targetID = laserLockInfo.targetID; var targetIsOverlay = laserLockInfo.isOverlay; - Pointers.setLockEndUUID(pointer, targetID, targetIsOverlay); + Pointers.setLockEndUid(pointer, targetID, targetIsOverlay); _this.laserLockStatus[hand] = targetID; } } else { @@ -634,7 +634,14 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Pointers.removePointer(_this.leftControllerHudRayPick); }; } - + function mouseReleaseOnOverlay(overlayID, event) { + if (overlayID === HMD.homeButtonID) { + print(JSON.stringify(event)); + print("---------> go home <--------"); + Messages.sendLocalMessage("home", overlayID); + } + } + Overlays.mouseReleaseOnOverlay.connect(mouseReleaseOnOverlay); var controllerDispatcher = new ControllerDispatcher(); Messages.subscribe('Hifi-Hand-RayPick-Blacklist'); Messages.messageReceived.connect(controllerDispatcher.handleHandMessage); diff --git a/scripts/system/controllers/controllerModules/disableOtherModule.js b/scripts/system/controllers/controllerModules/disableOtherModule.js index 92784ec2ed..e873579ba7 100644 --- a/scripts/system/controllers/controllerModules/disableOtherModule.js +++ b/scripts/system/controllers/controllerModules/disableOtherModule.js @@ -53,7 +53,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); enableDispatcherModule("LeftDisableModules", leftDisableModules); enableDispatcherModule("RightDisableModules", rightDisableModules); - this.handleMessage = function(channel, message, sender) { + function handleMessage(channel, message, sender) { if (sender === MyAvatar.sessionUUID) { if (channel === 'Hifi-Hand-Disabler') { if (message === 'left') { @@ -76,10 +76,10 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); }; Messages.subscribe('Hifi-Hand-Disabler'); - this.cleanup = function() { + function cleanup() { disableDispatcherModule("LeftDisableModules"); disableDispatcherModule("RightDisableModules"); }; - Messages.messageReceived.connect(this.handleMessage); - Script.scriptEnding.connect(this.cleanup); + Messages.messageReceived.connect(handleMessage); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 6f818b8b1e..e0f8834e38 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -475,11 +475,11 @@ Script.include("/~/system/libraries/controllers.js"); enableDispatcherModule("LeftFarActionGrabEntity", leftFarActionGrabEntity); enableDispatcherModule("RightFarActionGrabEntity", rightFarActionGrabEntity); - this.cleanup = function () { + function cleanup() { leftFarActionGrabEntity.cleanup(); rightFarActionGrabEntity.cleanup(); disableDispatcherModule("LeftFarActionGrabEntity"); disableDispatcherModule("RightFarActionGrabEntity"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index 6b2a986f0f..4fc192cc6b 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -256,11 +256,11 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); enableDispatcherModule("LeftNearActionGrabEntity", leftNearActionGrabEntity); enableDispatcherModule("RightNearActionGrabEntity", rightNearActionGrabEntity); - this.cleanup = function () { + function cleanup() { leftNearActionGrabEntity.cleanup(); rightNearActionGrabEntity.cleanup(); disableDispatcherModule("LeftNearActionGrabEntity"); disableDispatcherModule("RightNearActionGrabEntity"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 178d459b1d..1a5e82599d 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -338,11 +338,11 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); enableDispatcherModule("LeftNearParentingGrabEntity", leftNearParentingGrabEntity); enableDispatcherModule("RightNearParentingGrabEntity", rightNearParentingGrabEntity); - this.cleanup = function () { + function cleanup() { leftNearParentingGrabEntity.cleanup(); rightNearParentingGrabEntity.cleanup(); disableDispatcherModule("LeftNearParentingGrabEntity"); disableDispatcherModule("RightNearParentingGrabEntity"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js index 925c50df5e..5333196bd0 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -224,11 +224,11 @@ Script.include("/~/system/libraries/utils.js"); enableDispatcherModule("LeftNearParentingGrabOverlay", leftNearParentingGrabOverlay); enableDispatcherModule("RightNearParentingGrabOverlay", rightNearParentingGrabOverlay); - this.cleanup = function () { + function cleanup() { leftNearParentingGrabOverlay.cleanup(); rightNearParentingGrabOverlay.cleanup(); disableDispatcherModule("LeftNearParentingGrabOverlay"); disableDispatcherModule("RightNearParentingGrabOverlay"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/nearTrigger.js b/scripts/system/controllers/controllerModules/nearTrigger.js index 56a4e93495..a8aa72f1aa 100644 --- a/scripts/system/controllers/controllerModules/nearTrigger.js +++ b/scripts/system/controllers/controllerModules/nearTrigger.js @@ -110,11 +110,11 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); enableDispatcherModule("LeftNearTriggerEntity", leftNearTriggerEntity); enableDispatcherModule("RightNearTriggerEntity", rightNearTriggerEntity); - this.cleanup = function () { + function cleanup() { leftNearTriggerEntity.cleanup(); rightNearTriggerEntity.cleanup(); disableDispatcherModule("LeftNearTriggerEntity"); disableDispatcherModule("RightNearTriggerEntity"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/scaleEntity.js b/scripts/system/controllers/controllerModules/scaleEntity.js index 79b1d18db9..d45a4a5071 100644 --- a/scripts/system/controllers/controllerModules/scaleEntity.js +++ b/scripts/system/controllers/controllerModules/scaleEntity.js @@ -98,9 +98,9 @@ dispatcherUtils.enableDispatcherModule("LeftScaleEntity", leftScaleEntity); dispatcherUtils.enableDispatcherModule("RightScaleEntity", rightScaleEntity); - this.cleanup = function() { + function cleanup() { dispatcherUtils.disableDispatcherModule("LeftScaleEntity"); dispatcherUtils.disableDispatcherModule("RightScaleEntity"); }; - Script.scriptEnding.connect(this.cleanup); + Script.scriptEnding.connect(cleanup); })(); From f061b9c2da92d9a8f85376b8c272644ab63c8209 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 25 Oct 2017 15:11:18 -0700 Subject: [PATCH 052/292] Add stylus functionality to pointer manager --- interface/src/Application.cpp | 16 +- interface/src/raypick/JointRayPick.cpp | 2 +- interface/src/raypick/JointRayPick.h | 2 +- interface/src/raypick/LaserPointer.cpp | 44 +- interface/src/raypick/LaserPointer.h | 6 +- .../LaserPointerScriptingInterface.cpp | 6 +- .../raypick/LaserPointerScriptingInterface.h | 2 +- interface/src/raypick/MouseRayPick.cpp | 2 +- interface/src/raypick/MouseRayPick.h | 2 +- .../src/raypick/PickScriptingInterface.cpp | 7 +- .../src/raypick/PointerScriptingInterface.cpp | 41 +- .../src/raypick/PointerScriptingInterface.h | 5 +- interface/src/raypick/RayPick.h | 2 +- .../src/raypick/RayPickScriptingInterface.cpp | 7 +- interface/src/raypick/StaticRayPick.cpp | 2 +- interface/src/raypick/StaticRayPick.h | 2 +- interface/src/raypick/StylusPointer.cpp | 627 ++++++++++++++++++ interface/src/raypick/StylusPointer.h | 145 ++++ libraries/pointers/src/pointers/Pick.h | 4 +- .../src/pointers/PickCacheOptimizer.h | 16 +- .../pointers/src/pointers/PickManager.cpp | 9 +- libraries/pointers/src/pointers/PickManager.h | 8 +- libraries/pointers/src/pointers/Pointer.cpp | 10 +- libraries/pointers/src/pointers/Pointer.h | 16 +- .../pointers/src/pointers/PointerManager.cpp | 11 +- .../pointers/src/pointers/PointerManager.h | 4 +- libraries/script-engine/src/ScriptCache.cpp | 1 + libraries/shared/src/PointerEvent.h | 6 +- libraries/shared/src/RegisteredMetaTypes.h | 67 +- libraries/shared/src/shared/Bilateral.h | 21 +- scripts/defaultScripts.js | 2 +- .../controllerModules/tabletStylusInput.js | 454 +------------ 32 files changed, 1019 insertions(+), 530 deletions(-) create mode 100644 interface/src/raypick/StylusPointer.cpp create mode 100644 interface/src/raypick/StylusPointer.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 07962d838b..420c4e7ce6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1819,14 +1819,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo DependencyManager::get()->setMouseRayPickResultOperator([&](QUuid rayPickID) { RayToEntityIntersectionResult entityResult; entityResult.intersects = false; - QVariantMap result = DependencyManager::get()->getPrevPickResult(rayPickID); - if (result["type"].isValid()) { - entityResult.intersects = result["type"] != PickScriptingInterface::INTERSECTED_NONE(); + auto pickResult = DependencyManager::get()->getPrevPickResultTyped(rayPickID); + if (pickResult) { + entityResult.intersects = pickResult->type != IntersectionType::NONE; if (entityResult.intersects) { - entityResult.intersection = vec3FromVariant(result["intersection"]); - entityResult.distance = result["distance"].toFloat(); - entityResult.surfaceNormal = vec3FromVariant(result["surfaceNormal"]); - entityResult.entityID = result["objectID"].toUuid(); + entityResult.intersection = pickResult->intersection; + entityResult.distance = pickResult->distance; + entityResult.surfaceNormal = pickResult->surfaceNormal; + entityResult.entityID = pickResult->objectID; entityResult.entity = DependencyManager::get()->getTree()->findEntityByID(entityResult.entityID); } } @@ -4957,7 +4957,7 @@ void Application::update(float deltaTime) { { PROFILE_RANGE(app, "PointerManager"); - DependencyManager::get()->update(); + DependencyManager::get()->update(deltaTime); } { diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index c2a7fb11e5..fdffb9796d 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -20,7 +20,7 @@ JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOff { } -const PickRay JointRayPick::getMathematicalPick() const { +PickRay JointRayPick::getMathematicalPick() const { auto myAvatar = DependencyManager::get()->getMyAvatar(); int jointIndex = myAvatar->getJointIndex(QString::fromStdString(_jointName)); bool useAvatarHead = _jointName == "Avatar"; diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index ab44bf67c8..0ef39d6336 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -18,7 +18,7 @@ class JointRayPick : public RayPick { public: JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getMathematicalPick() const override; + PickRay getMathematicalPick() const override; private: std::string _jointName; diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 83e3757514..bf1847e3f6 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -16,6 +16,7 @@ #include #include #include "PickScriptingInterface.h" +#include "RayPick.h" LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, bool hover, const PointerTriggers& triggers, bool faceAvatar, bool centerEndY, bool lockEnd, bool distanceScaleEnd, bool enabled) : @@ -177,17 +178,20 @@ void LaserPointer::disableRenderState(const RenderState& renderState) { } } -void LaserPointer::updateVisuals(const QVariantMap& prevRayPickResult) { - IntersectionType type = IntersectionType(prevRayPickResult["type"].toInt()); - PickRay pickRay = PickRay(prevRayPickResult["searchRay"].toMap()); - QUuid uid = prevRayPickResult["objectID"].toUuid(); +void LaserPointer::updateVisuals(const PickResultPointer& pickResult) { + auto rayPickResult = std::static_pointer_cast(pickResult); + + IntersectionType type = rayPickResult ? rayPickResult->type : IntersectionType::NONE; if (_enabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && (type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { - float distance = _laserLength > 0.0f ? _laserLength : prevRayPickResult["distance"].toFloat(); + PickRay pickRay{ rayPickResult->pickVariant }; + QUuid uid = rayPickResult->objectID; + float distance = _laserLength > 0.0f ? _laserLength : rayPickResult->distance; updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay, false); disableRenderState(_defaultRenderStates[_currentRenderState].second); } else if (_enabled && !_currentRenderState.empty() && _defaultRenderStates.find(_currentRenderState) != _defaultRenderStates.end()) { disableRenderState(_renderStates[_currentRenderState]); + PickRay pickRay = rayPickResult ? PickRay(rayPickResult->pickVariant) : PickRay(); updateRenderState(_defaultRenderStates[_currentRenderState].second, IntersectionType::NONE, _defaultRenderStates[_currentRenderState].first, QUuid(), pickRay, true); } else if (!_currentRenderState.empty()) { disableRenderState(_renderStates[_currentRenderState]); @@ -195,8 +199,12 @@ void LaserPointer::updateVisuals(const QVariantMap& prevRayPickResult) { } } -Pointer::PickedObject LaserPointer::getHoveredObject(const QVariantMap& pickResult) { - return Pointer::PickedObject(pickResult["objectID"].toUuid(), IntersectionType(pickResult["type"].toUInt())); +Pointer::PickedObject LaserPointer::getHoveredObject(const PickResultPointer& pickResult) { + auto rayPickResult = std::static_pointer_cast(pickResult); + if (!rayPickResult) { + return PickedObject(); + } + return PickedObject(rayPickResult->objectID, rayPickResult->type); } Pointer::Buttons LaserPointer::getPressedButtons() { @@ -281,16 +289,22 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) { return RenderState(startID, pathID, endID); } -PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const { +PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const { uint32_t id = 0; - glm::vec3 intersection = vec3FromVariant(pickResult["intersection"]); - glm::vec3 surfaceNormal = vec3FromVariant(pickResult["surfaceNormal"]); - QVariantMap searchRay = pickResult["searchRay"].toMap(); - glm::vec3 direction = vec3FromVariant(searchRay["direction"]); - QUuid pickedID = pickResult["objectID"].toUuid(); + QUuid pickedID; + glm::vec3 intersection, surfaceNormal, direction, origin; + if (target.type != NONE) { + auto rayPickResult = std::static_pointer_cast(pickResult); + intersection = rayPickResult->intersection; + surfaceNormal = rayPickResult->surfaceNormal; + const QVariantMap& searchRay = rayPickResult->pickVariant; + direction = vec3FromVariant(searchRay["direction"]); + origin = vec3FromVariant(searchRay["origin"]); + pickedID = rayPickResult->objectID;; + } + glm::vec2 pos2D; if (pickedID != target.objectID) { - glm::vec3 origin = vec3FromVariant(searchRay["origin"]); if (target.type == ENTITY) { intersection = intersectRayWithEntityXYPlane(target.objectID, origin, direction); } else if (target.type == OVERLAY) { @@ -355,4 +369,4 @@ glm::vec2 LaserPointer::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const { auto props = DependencyManager::get()->getEntityProperties(entityID); return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint()); -} \ No newline at end of file +} diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index bdd3f2ffa0..9fbbadb475 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -65,15 +65,15 @@ public: void setLength(float length) override; void setLockEndUUID(const QUuid& objectID, bool isOverlay) override; - void updateVisuals(const QVariantMap& prevRayPickResult) override; + void updateVisuals(const PickResultPointer& prevRayPickResult) override; - PickedObject getHoveredObject(const QVariantMap& pickResult) override; + PickedObject getHoveredObject(const PickResultPointer& pickResult) override; Pointer::Buttons getPressedButtons() override; static RenderState buildRenderState(const QVariantMap& propMap); protected: - PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const override; + PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const override; private: PointerTriggers _triggers; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 533dffafb9..92ad837e7a 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -27,4 +27,8 @@ QUuid LaserPointerScriptingInterface::createLaserPointer(const QVariant& propert void LaserPointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { DependencyManager::get()->editRenderState(uid, renderState, properties); -} \ No newline at end of file +} + +QVariantMap LaserPointerScriptingInterface::getPrevRayPickResult(const QUuid& uid) const { + return DependencyManager::get()->getPrevPickResult(uid); +} diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index 1116da1528..d1dd5499f4 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -27,7 +27,7 @@ public slots: Q_INVOKABLE void removeLaserPointer(const QUuid& uid) const { DependencyManager::get()->removePointer(uid); } Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } - Q_INVOKABLE QVariantMap getPrevRayPickResult(QUuid uid) const { return DependencyManager::get()->getPrevPickResult(uid); } + Q_INVOKABLE QVariantMap getPrevRayPickResult(const QUuid& uid) const; Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } diff --git a/interface/src/raypick/MouseRayPick.cpp b/interface/src/raypick/MouseRayPick.cpp index f691dafc01..1f39b61614 100644 --- a/interface/src/raypick/MouseRayPick.cpp +++ b/interface/src/raypick/MouseRayPick.cpp @@ -18,7 +18,7 @@ MouseRayPick::MouseRayPick(const PickFilter& filter, const float maxDistance, co { } -const PickRay MouseRayPick::getMathematicalPick() const { +PickRay MouseRayPick::getMathematicalPick() const { QVariant position = qApp->getApplicationCompositor().getReticleInterface()->getPosition(); if (position.isValid()) { QVariantMap posMap = position.toMap(); diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h index e9eb3ccabf..81561d7459 100644 --- a/interface/src/raypick/MouseRayPick.h +++ b/interface/src/raypick/MouseRayPick.h @@ -18,7 +18,7 @@ class MouseRayPick : public RayPick { public: MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getMathematicalPick() const override; + PickRay getMathematicalPick() const override; }; #endif // hifi_MouseRayPick_h diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 40f898e65d..ac81bcf72f 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -94,7 +94,12 @@ void PickScriptingInterface::removePick(const QUuid& uid) { } QVariantMap PickScriptingInterface::getPrevPickResult(const QUuid& uid) { - return DependencyManager::get()->getPrevPickResult(uid); + QVariantMap result; + auto pickResult = DependencyManager::get()->getPrevPickResult(uid); + if (pickResult) { + result = pickResult->toVariantMap(); + } + return result; } void PickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) { diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index c3a4ac164a..74f207f793 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -10,9 +10,11 @@ #include #include +#include #include "Application.h" #include "LaserPointer.h" +#include "StylusPointer.h" void PointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); @@ -21,15 +23,40 @@ void PointerScriptingInterface::setIncludeItems(const QUuid& uid, const QScriptV DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } -QUuid PointerScriptingInterface::createPointer(const PickQuery::PickType& type, const QVariant& properties) const { +QUuid PointerScriptingInterface::createPointer(const PickQuery::PickType& type, const QVariant& properties) { + // Interaction with managers should always happen ont he main thread + if (QThread::currentThread() != qApp->thread()) { + QUuid result; + BLOCKING_INVOKE_METHOD(this, "createPointer", Q_RETURN_ARG(QUuid, result), Q_ARG(PickQuery::PickType, type), Q_ARG(QVariant, properties)); + return result; + } + switch (type) { case PickQuery::PickType::Ray: return createLaserPointer(properties); + case PickQuery::PickType::Stylus: + return createStylus(properties); default: return QUuid(); } } +QUuid PointerScriptingInterface::createStylus(const QVariant& properties) const { + bilateral::Side side = bilateral::Side::Invalid; + { + QVariant handVar = properties.toMap()["hand"]; + if (handVar.isValid()) { + side = bilateral::side(handVar.toInt()); + } + } + + if (bilateral::Side::Invalid == side) { + return QUuid(); + } + + return DependencyManager::get()->addPointer(std::make_shared(side)); +} + QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) const { QVariantMap propertyMap = properties.toMap(); @@ -133,4 +160,14 @@ void PointerScriptingInterface::editRenderState(const QUuid& uid, const QString& } DependencyManager::get()->editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps); -} \ No newline at end of file +} + +QVariantMap PointerScriptingInterface::getPrevPickResult(const QUuid& uid) const { + QVariantMap result; + auto pickResult = DependencyManager::get()->getPrevPickResult(uid); + if (pickResult) { + result = pickResult->toVariantMap(); + } + return result; +} + diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index cc2ffbc3cc..0cba7e2a6d 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -20,15 +20,16 @@ class PointerScriptingInterface : public QObject, public Dependency { public: QUuid createLaserPointer(const QVariant& properties) const; + QUuid createStylus(const QVariant& properties) const; public slots: - Q_INVOKABLE QUuid createPointer(const PickQuery::PickType& type, const QVariant& properties) const; + Q_INVOKABLE QUuid createPointer(const PickQuery::PickType& type, const QVariant& properties); Q_INVOKABLE void enablePointer(const QUuid& uid) const { DependencyManager::get()->enablePointer(uid); } Q_INVOKABLE void disablePointer(const QUuid& uid) const { DependencyManager::get()->disablePointer(uid); } Q_INVOKABLE void removePointer(const QUuid& uid) const { DependencyManager::get()->removePointer(uid); } Q_INVOKABLE void editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const; Q_INVOKABLE void setRenderState(const QUuid& uid, const QString& renderState) const { DependencyManager::get()->setRenderState(uid, renderState.toStdString()); } - Q_INVOKABLE QVariantMap getPrevPickResult(const QUuid& uid) const { return DependencyManager::get()->getPrevPickResult(uid); } + Q_INVOKABLE QVariantMap getPrevPickResult(const QUuid& uid) const; Q_INVOKABLE void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const { DependencyManager::get()->setPrecisionPicking(uid, precisionPicking); } Q_INVOKABLE void setLaserLength(const QUuid& uid, float laserLength) const { DependencyManager::get()->setLength(uid, laserLength); } diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index b5d7ea7c3e..1c2b3fbb80 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -53,7 +53,7 @@ public: bool doesIntersect() const override { return intersects; } bool checkOrFilterAgainstMaxDistance(float maxDistance) override { return distance < maxDistance; } - PickResultPointer compareAndProcessNewResult(const PickResultPointer newRes) override { + PickResultPointer compareAndProcessNewResult(const PickResultPointer& newRes) override { auto newRayRes = std::static_pointer_cast(newRes); if (newRayRes->distance < distance) { return std::make_shared(*newRayRes); diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index 92bf3ec521..8cee02270d 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -37,7 +37,12 @@ void RayPickScriptingInterface::removeRayPick(const QUuid& uid) { } QVariantMap RayPickScriptingInterface::getPrevRayPickResult(const QUuid& uid) { - return DependencyManager::get()->getPrevPickResult(uid); + QVariantMap result; + auto pickResult = DependencyManager::get()->getPrevPickResult(uid); + if (pickResult) { + result = pickResult->toVariantMap(); + } + return result; } void RayPickScriptingInterface::setPrecisionPicking(const QUuid& uid, const bool precisionPicking) { diff --git a/interface/src/raypick/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp index f7803aade6..c79f87ad0e 100644 --- a/interface/src/raypick/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -13,6 +13,6 @@ StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& directi { } -const PickRay StaticRayPick::getMathematicalPick() const { +PickRay StaticRayPick::getMathematicalPick() const { return _pickRay; } \ No newline at end of file diff --git a/interface/src/raypick/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h index 6dc0a809ae..ded57caf4e 100644 --- a/interface/src/raypick/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -15,7 +15,7 @@ class StaticRayPick : public RayPick { public: StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); - const PickRay getMathematicalPick() const override; + PickRay getMathematicalPick() const override; private: PickRay _pickRay; diff --git a/interface/src/raypick/StylusPointer.cpp b/interface/src/raypick/StylusPointer.cpp new file mode 100644 index 0000000000..4cc34f36d9 --- /dev/null +++ b/interface/src/raypick/StylusPointer.cpp @@ -0,0 +1,627 @@ +// +// Created by Bradley Austin Davis on 2017/10/24 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "StylusPointer.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Application.h" +#include "avatar/AvatarManager.h" +#include "avatar/MyAvatar.h" + +#include "scripting/HMDScriptingInterface.h" +#include "ui/overlays/Web3DOverlay.h" +#include "ui/overlays/Sphere3DOverlay.h" +#include "avatar/AvatarManager.h" +#include "InterfaceLogging.h" +#include "PickScriptingInterface.h" + +using namespace controller; +using namespace bilateral; + +static Setting::Handle USE_FINGER_AS_STYLUS("preferAvatarFingerOverStylus", false); +static const float WEB_STYLUS_LENGTH = 0.2f; +static const float WEB_TOUCH_Y_OFFSET = 0.105f; // how far forward (or back with a negative number) to slide stylus in hand +static const vec3 TIP_OFFSET{ 0.0f, WEB_STYLUS_LENGTH - WEB_TOUCH_Y_OFFSET, 0.0f }; +static const float TABLET_MIN_HOVER_DISTANCE = 0.01f; +static const float TABLET_MAX_HOVER_DISTANCE = 0.1f; +static const float TABLET_MIN_TOUCH_DISTANCE = -0.05f; +static const float TABLET_MAX_TOUCH_DISTANCE = TABLET_MIN_HOVER_DISTANCE; +static const float EDGE_BORDER = 0.075f; + +static const float HOVER_HYSTERESIS = 0.01f; +static const float NEAR_HYSTERESIS = 0.05f; +static const float TOUCH_HYSTERESIS = 0.002f; + +// triggered when stylus presses a web overlay/entity +static const float HAPTIC_STYLUS_STRENGTH = 1.0f; +static const float HAPTIC_STYLUS_DURATION = 20.0f; +static const float POINTER_PRESS_TO_MOVE_DELAY = 0.33f; // seconds + +static const float WEB_DISPLAY_STYLUS_DISTANCE = 0.5f; +static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f; +static const float TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED = TOUCH_PRESS_TO_MOVE_DEADSPOT * TOUCH_PRESS_TO_MOVE_DEADSPOT; + +std::array STYLUSES; + +static OverlayID getHomeButtonID() { + return DependencyManager::get()->getCurrentHomeButtonID(); +} + +static OverlayID getTabletScreenID() { + return DependencyManager::get()->getCurrentTabletScreenID(); +} + +struct SideData { + QString avatarJoint; + QString cameraJoint; + controller::StandardPoseChannel channel; + controller::Hand hand; + vec3 grabPointSphereOffset; + + int getJointIndex(bool finger) { + const auto& jointName = finger ? avatarJoint : cameraJoint; + return DependencyManager::get()->getMyAvatar()->getJointIndex(jointName); + } +}; + +static const std::array SIDES{ { { "LeftHandIndex4", + "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", + StandardPoseChannel::LEFT_HAND, + Hand::LEFT, + { -0.04f, 0.13f, 0.039f } }, + { "RightHandIndex4", + "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", + StandardPoseChannel::RIGHT_HAND, + Hand::RIGHT, + { 0.04f, 0.13f, 0.039f } } } }; + +static StylusTip getFingerWorldLocation(Side side) { + const auto& sideData = SIDES[index(side)]; + auto myAvatar = DependencyManager::get()->getMyAvatar(); + auto fingerJointIndex = myAvatar->getJointIndex(sideData.avatarJoint); + + if (-1 == fingerJointIndex) { + return StylusTip(); + } + + auto fingerPosition = myAvatar->getAbsoluteJointTranslationInObjectFrame(fingerJointIndex); + auto fingerRotation = myAvatar->getAbsoluteJointRotationInObjectFrame(fingerJointIndex); + auto avatarOrientation = myAvatar->getOrientation(); + auto avatarPosition = myAvatar->getPosition(); + StylusTip result; + result.side = side; + result.orientation = avatarOrientation * fingerRotation; + result.position = avatarPosition + (avatarOrientation * fingerPosition); + return result; +} + +// controllerWorldLocation is where the controller would be, in-world, with an added offset +static StylusTip getControllerWorldLocation(Side side, float sensorToWorldScale) { + static const std::array INPUTS{ { UserInputMapper::makeStandardInput(SIDES[0].channel), + UserInputMapper::makeStandardInput(SIDES[1].channel) } }; + const auto sideIndex = index(side); + const auto& input = INPUTS[sideIndex]; + + const auto pose = DependencyManager::get()->getPose(input); + const auto& valid = pose.valid; + StylusTip result; + if (valid) { + result.side = side; + const auto& sideData = SIDES[sideIndex]; + auto myAvatar = DependencyManager::get()->getMyAvatar(); + auto controllerJointIndex = myAvatar->getJointIndex(sideData.cameraJoint); + + const auto avatarOrientation = myAvatar->getOrientation(); + const auto avatarPosition = myAvatar->getPosition(); + result.orientation = avatarOrientation * myAvatar->getAbsoluteJointRotationInObjectFrame(controllerJointIndex); + result.position = + avatarPosition + (avatarOrientation * myAvatar->getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)); + // add to the real position so the grab-point is out in front of the hand, a bit + result.position += result.orientation * (sideData.grabPointSphereOffset * sensorToWorldScale); + auto worldControllerPos = avatarPosition + avatarOrientation * pose.translation; + // compute tip velocity from hand controller motion, it is more accurate than computing it from previous positions. + auto worldControllerLinearVel = avatarOrientation * pose.velocity; + auto worldControllerAngularVel = avatarOrientation * pose.angularVelocity; + result.velocity = + worldControllerLinearVel + glm::cross(worldControllerAngularVel, result.position - worldControllerPos); + } + + return result; +} + +bool StylusPickResult::isNormalized() const { + return valid && (normalizedPosition == glm::clamp(normalizedPosition, vec3(0), vec3(1))); +} + +bool StylusPickResult::isNearNormal(float min, float max, float hystersis) const { + return valid && (distance == glm::clamp(distance, min - hystersis, max + hystersis)); +} + +bool StylusPickResult::isNear2D(float border, float hystersis) const { + return valid && position2D == glm::clamp(position2D, vec2(0) - border - hystersis, vec2(dimensions) + border + hystersis); +} + +bool StylusPickResult::isNear(float min, float max, float border, float hystersis) const { + // check to see if the projected stylusTip is within within the 2d border + return isNearNormal(min, max, hystersis) && isNear2D(border, hystersis); +} + +StylusPickResult::operator bool() const { + return valid; +} + +bool StylusPickResult::hasKeyboardFocus() const { + if (!overlayID.isNull()) { + return qApp->getOverlays().getKeyboardFocusOverlay() == overlayID; + } +#if 0 + if (!entityID.isNull()) { + return qApp->getKeyboardFocusEntity() == entityID; + } +#endif + return false; +} + +void StylusPickResult::setKeyboardFocus() const { + if (!overlayID.isNull()) { + qApp->getOverlays().setKeyboardFocusOverlay(overlayID); + qApp->setKeyboardFocusEntity(EntityItemID()); +#if 0 + } else if (!entityID.isNull()) { + qApp->getOverlays().setKeyboardFocusOverlay(OverlayID()); + qApp->setKeyboardFocusEntity(entityID); +#endif + } +} + +void StylusPickResult::sendHoverOverEvent() const { + if (!overlayID.isNull()) { + qApp->getOverlays().hoverOverOverlay(overlayID, PointerEvent{ PointerEvent::Move, deviceId(), position2D, position, + normal, -normal }); + } + // FIXME support entity +} + +void StylusPickResult::sendHoverEnterEvent() const { + if (!overlayID.isNull()) { + qApp->getOverlays().hoverEnterOverlay(overlayID, PointerEvent{ PointerEvent::Move, deviceId(), position2D, position, + normal, -normal }); + } + // FIXME support entity +} + +void StylusPickResult::sendTouchStartEvent() const { + if (!overlayID.isNull()) { + qApp->getOverlays().sendMousePressOnOverlay(overlayID, PointerEvent{ PointerEvent::Press, deviceId(), position2D, position, + normal, -normal, PointerEvent::PrimaryButton, + PointerEvent::PrimaryButton }); + } + // FIXME support entity +} + +void StylusPickResult::sendTouchEndEvent() const { + if (!overlayID.isNull()) { + qApp->getOverlays().sendMouseReleaseOnOverlay(overlayID, + PointerEvent{ PointerEvent::Release, deviceId(), position2D, position, normal, + -normal, PointerEvent::PrimaryButton }); + } + // FIXME support entity +} + +void StylusPickResult::sendTouchMoveEvent() const { + if (!overlayID.isNull()) { + qApp->getOverlays().sendMouseMoveOnOverlay(overlayID, PointerEvent{ PointerEvent::Move, deviceId(), position2D, position, + normal, -normal, PointerEvent::PrimaryButton, + PointerEvent::PrimaryButton }); + } + // FIXME support entity +} + +bool StylusPickResult::doesIntersect() const { + return true; +} + +// for example: if we want the closest result, compare based on distance +// if we want all results, combine them +// must return a new pointer +std::shared_ptr StylusPickResult::compareAndProcessNewResult(const std::shared_ptr& newRes) { + auto newStylusResult = std::static_pointer_cast(newRes); + if (newStylusResult && newStylusResult->distance < distance) { + return std::make_shared(*newStylusResult); + } else { + return std::make_shared(*this); + } +} + +// returns true if this result contains any valid results with distance < maxDistance +// can also filter out results with distance >= maxDistance +bool StylusPickResult::checkOrFilterAgainstMaxDistance(float maxDistance) { + return distance < maxDistance; +} + +uint32_t StylusPickResult::deviceId() const { + // 0 is reserved for hardware mouse + return index(tip.side) + 1; +} + +StylusPick::StylusPick(Side side) + : Pick(PickFilter(PickScriptingInterface::PICK_OVERLAYS()), FLT_MAX, true) + , _side(side) { +} + +StylusTip StylusPick::getMathematicalPick() const { + StylusTip result; + if (_useFingerInsteadOfStylus) { + result = getFingerWorldLocation(_side); + } else { + auto myAvatar = DependencyManager::get()->getMyAvatar(); + float sensorScaleFactor = myAvatar->getSensorToWorldScale(); + result = getControllerWorldLocation(_side, sensorScaleFactor); + result.position += result.orientation * (TIP_OFFSET * sensorScaleFactor); + } + return result; +} + +PickResultPointer StylusPick::getDefaultResult(const QVariantMap& pickVariant) const { + return std::make_shared(); +} + +PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) { + return PickResultPointer(); +} + +PickResultPointer StylusPick::getOverlayIntersection(const StylusTip& pick) { + if (!getFilter().doesPickOverlays()) { + return PickResultPointer(); + } + + std::vector results; + for (const auto& target : getIncludeItems()) { + if (target.isNull()) { + continue; + } + + auto overlay = qApp->getOverlays().getOverlay(target); + // Don't interact with non-3D or invalid overlays + if (!overlay || !overlay->is3D()) { + continue; + } + + if (!overlay->getVisible() && !getFilter().doesPickInvisible()) { + continue; + } + + auto overlayType = overlay->getType(); + auto overlay3D = std::static_pointer_cast(overlay); + const auto overlayRotation = overlay3D->getRotation(); + const auto overlayPosition = overlay3D->getPosition(); + + StylusPickResult result; + result.tip = pick; + result.overlayID = target; + result.normal = overlayRotation * Vectors::UNIT_Z; + result.distance = glm::dot(pick.position - overlayPosition, result.normal); + result.position = pick.position - (result.normal * result.distance); + if (overlayType == Web3DOverlay::TYPE) { + result.dimensions = vec3(std::static_pointer_cast(overlay3D)->getSize(), 0.01f); + } else if (overlayType == Sphere3DOverlay::TYPE) { + result.dimensions = std::static_pointer_cast(overlay3D)->getDimensions(); + } else { + result.dimensions = vec3(0.01f); + } + auto tipRelativePosition = result.position - overlayPosition; + auto localPos = glm::inverse(overlayRotation) * tipRelativePosition; + auto normalizedPosition = localPos / result.dimensions; + result.normalizedPosition = normalizedPosition + 0.5f; + result.position2D = { result.normalizedPosition.x * result.dimensions.x, + (1.0f - result.normalizedPosition.y) * result.dimensions.y }; + result.valid = true; + results.push_back(result); + } + + StylusPickResult nearestTarget; + for (const auto& result : results) { + if (result && result.isNormalized() && result.distance < nearestTarget.distance) { + nearestTarget = result; + } + } + return std::make_shared(nearestTarget); +} + +PickResultPointer StylusPick::getAvatarIntersection(const StylusTip& pick) { + return PickResultPointer(); +} + +PickResultPointer StylusPick::getHUDIntersection(const StylusTip& pick) { + return PickResultPointer(); +} + +StylusPointer::StylusPointer(Side side) + : Pointer(DependencyManager::get()->addPick(PickQuery::Stylus, std::make_shared(side)), + false, + true) + , _side(side) + , _sideData(SIDES[index(side)]) { + setIncludeItems({ { getHomeButtonID(), getTabletScreenID() } }); + STYLUSES[index(_side)] = this; +} + +StylusPointer::~StylusPointer() { + if (!_stylusOverlay.isNull()) { + qApp->getOverlays().deleteOverlay(_stylusOverlay); + } + STYLUSES[index(_side)] = nullptr; +} + +StylusPointer* StylusPointer::getOtherStylus() { + return STYLUSES[((index(_side) + 1) % 2)]; +} + +void StylusPointer::enable() { + Parent::enable(); + withWriteLock([&] { _renderingEnabled = true; }); +} + +void StylusPointer::disable() { + Parent::disable(); + withWriteLock([&] { _renderingEnabled = false; }); +} + +void StylusPointer::updateStylusTarget() { + const float minNearDistance = TABLET_MIN_TOUCH_DISTANCE * _sensorScaleFactor; + const float maxNearDistance = WEB_DISPLAY_STYLUS_DISTANCE * _sensorScaleFactor; + const float edgeBorder = EDGE_BORDER * _sensorScaleFactor; + + auto pickResult = DependencyManager::get()->getPrevPickResultTyped(_pickUID); + + if (pickResult) { + _state.target = *pickResult; + float hystersis = 0.0f; + // If we're already near the target, add hystersis to ensure we don't rapidly toggle between near and not near + // but only for the current near target + if (_previousState.nearTarget && pickResult->overlayID == _previousState.target.overlayID) { + hystersis = _nearHysteresis; + } + _state.nearTarget = pickResult->isNear(minNearDistance, maxNearDistance, edgeBorder, hystersis); + } + + // Not near anything, short circuit the rest + if (!_state.nearTarget) { + relinquishTouchFocus(); + hide(); + return; + } + + show(); + + auto minTouchDistance = TABLET_MIN_TOUCH_DISTANCE * _sensorScaleFactor; + auto maxTouchDistance = TABLET_MAX_TOUCH_DISTANCE * _sensorScaleFactor; + auto maxHoverDistance = TABLET_MAX_HOVER_DISTANCE * _sensorScaleFactor; + + float hystersis = 0.0f; + if (_previousState.nearTarget && _previousState.target.overlayID == _previousState.target.overlayID) { + hystersis = _nearHysteresis; + } + + // If we're in hover distance (calculated as the normal distance from the XY plane of the overlay) + if ((getOtherStylus() && getOtherStylus()->_state.touchingTarget) || !_state.target.isNearNormal(minTouchDistance, maxHoverDistance, hystersis)) { + relinquishTouchFocus(); + return; + } + + requestTouchFocus(_state.target); + + if (!_state.target.hasKeyboardFocus()) { + _state.target.setKeyboardFocus(); + } + + if (hasTouchFocus(_state.target) && !_previousState.touchingTarget) { + _state.target.sendHoverOverEvent(); + } + + hystersis = 0.0f; + if (_previousState.touchingTarget && _previousState.target.overlayID == _state.target.overlayID) { + hystersis = _touchHysteresis; + } + + // If we're in touch distance + if (_state.target.isNearNormal(minTouchDistance, maxTouchDistance, _touchHysteresis) && _state.target.isNormalized()) { + _state.touchingTarget = true; + } +} + +void StylusPointer::update(float deltaTime) { + // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts + withReadLock([&] { + auto myAvatar = DependencyManager::get()->getMyAvatar(); + + // Store and reset the state + { + _previousState = _state; + _state = State(); + } + +#if 0 + // Update finger as stylus setting + { + useFingerInsteadOfStylus = (USE_FINGER_AS_STYLUS.get() && myAvatar->getJointIndex(sideData.avatarJoint) != -1); + } +#endif + + // Update scale factor + { + _sensorScaleFactor = myAvatar->getSensorToWorldScale(); + _hoverHysteresis = HOVER_HYSTERESIS * _sensorScaleFactor; + _nearHysteresis = NEAR_HYSTERESIS * _sensorScaleFactor; + _touchHysteresis = TOUCH_HYSTERESIS * _sensorScaleFactor; + } + + // Identify the current near or touching target + updateStylusTarget(); + + // If we stopped touching, or if the target overlay ID changed, send a touching exit to the previous touch target + if (_previousState.touchingTarget && + (!_state.touchingTarget || _state.target.overlayID != _previousState.target.overlayID)) { + stylusTouchingExit(); + } + + // Handle new or continuing touch + if (_state.touchingTarget) { + // If we were previously not touching, or we were touching a different overlay, add a touch enter + if (!_previousState.touchingTarget || _previousState.target.overlayID != _state.target.overlayID) { + stylusTouchingEnter(); + } else { + _touchingEnterTimer += deltaTime; + } + + stylusTouching(); + } + }); + + setIncludeItems({ { getHomeButtonID(), getTabletScreenID() } }); +} + +void StylusPointer::show() { + if (!_stylusOverlay.isNull()) { + return; + } + + auto myAvatar = DependencyManager::get()->getMyAvatar(); + // FIXME perhaps instantiate a stylus and use show / hide instead of create / destroy + // however, the current design doesn't really allow for this because it assumes that + // hide / show are idempotent and low cost, but constantly querying the visibility + QVariantMap overlayProperties; + overlayProperties["name"] = "stylus"; + overlayProperties["url"] = PathUtils::resourcesPath() + "/meshes/tablet-stylus-fat.fbx"; + overlayProperties["loadPriority"] = 10.0f; + overlayProperties["dimensions"] = vec3toVariant(_sensorScaleFactor * vec3(0.01f, 0.01f, WEB_STYLUS_LENGTH)); + overlayProperties["solid"] = true; + overlayProperties["visible"] = true; + overlayProperties["ignoreRayIntersection"] = true; + overlayProperties["drawInFront"] = false; + overlayProperties["parentID"] = AVATAR_SELF_ID; + overlayProperties["parentJointIndex"] = myAvatar->getJointIndex(_sideData.cameraJoint); + + static const glm::quat X_ROT_NEG_90{ 0.70710678f, -0.70710678f, 0.0f, 0.0f }; + auto modelOrientation = _state.target.tip.orientation * X_ROT_NEG_90; + auto modelPositionOffset = modelOrientation * (vec3(0.0f, 0.0f, -WEB_STYLUS_LENGTH / 2.0f) * _sensorScaleFactor); + overlayProperties["position"] = vec3toVariant(_state.target.tip.position + modelPositionOffset); + overlayProperties["rotation"] = quatToVariant(modelOrientation); + _stylusOverlay = qApp->getOverlays().addOverlay("model", overlayProperties); +} + +void StylusPointer::hide() { + if (_stylusOverlay.isNull()) { + return; + } + + qApp->getOverlays().deleteOverlay(_stylusOverlay); + _stylusOverlay = OverlayID(); +} +#if 0 + void pointFinger(bool value) { + static const QString HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index"; + static const std::array KEYS{ { "pointLeftIndex", "pointLeftIndex" } }; + if (fingerPointing != value) { + QString message = QJsonDocument(QJsonObject{ { KEYS[index(side)], value } }).toJson(); + DependencyManager::get()->sendMessage(HIFI_POINT_INDEX_MESSAGE_CHANNEL, message); + fingerPointing = value; + } + } +#endif +void StylusPointer::requestTouchFocus(const StylusPickResult& pickResult) { + if (!pickResult) { + return; + } + // send hover events to target if we can. + // record the entity or overlay we are hovering over. + if (!pickResult.overlayID.isNull() && pickResult.overlayID != _hoverOverlay && + getOtherStylus() && pickResult.overlayID != getOtherStylus()->_hoverOverlay) { + _hoverOverlay = pickResult.overlayID; + pickResult.sendHoverEnterEvent(); + } +} + +bool StylusPointer::hasTouchFocus(const StylusPickResult& pickResult) { + return (!pickResult.overlayID.isNull() && pickResult.overlayID == _hoverOverlay); +} + +void StylusPointer::relinquishTouchFocus() { + // send hover leave event. + if (!_hoverOverlay.isNull()) { + PointerEvent pointerEvent{ PointerEvent::Move, (uint32_t)(index(_side) + 1) }; + auto& overlays = qApp->getOverlays(); + overlays.sendMouseMoveOnOverlay(_hoverOverlay, pointerEvent); + overlays.sendHoverOverOverlay(_hoverOverlay, pointerEvent); + overlays.sendHoverLeaveOverlay(_hoverOverlay, pointerEvent); + _hoverOverlay = OverlayID(); + } +}; + +void StylusPointer::stealTouchFocus() { + // send hover events to target + if (getOtherStylus() && _state.target.overlayID == getOtherStylus()->_hoverOverlay) { + getOtherStylus()->relinquishTouchFocus(); + } + requestTouchFocus(_state.target); +} + +void StylusPointer::stylusTouchingEnter() { + stealTouchFocus(); + _state.target.sendTouchStartEvent(); + DependencyManager::get()->triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, + _sideData.hand); + _touchingEnterTimer = 0; + _touchingEnterPosition = _state.target.position2D; + _deadspotExpired = false; +} + +void StylusPointer::stylusTouchingExit() { + if (!_previousState.target) { + return; + } + + // special case to handle home button. + if (_previousState.target.overlayID == getHomeButtonID()) { + DependencyManager::get()->sendLocalMessage("home", _previousState.target.overlayID.toString()); + } + + // send touch end event + _state.target.sendTouchEndEvent(); +} + +void StylusPointer::stylusTouching() { + qDebug() << "QQQ " << __FUNCTION__; + if (_state.target.overlayID.isNull()) { + return; + } + + if (!_deadspotExpired) { + _deadspotExpired = + (_touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY) || + glm::distance2(_state.target.position2D, _touchingEnterPosition) > TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED; + } + + // Only send moves if the target moves more than the deadspot position or if we've timed out the deadspot + if (_deadspotExpired) { + _state.target.sendTouchMoveEvent(); + } +} diff --git a/interface/src/raypick/StylusPointer.h b/interface/src/raypick/StylusPointer.h new file mode 100644 index 0000000000..7e67a7398e --- /dev/null +++ b/interface/src/raypick/StylusPointer.h @@ -0,0 +1,145 @@ +// +// Created by Bradley Austin Davis on 2017/10/24 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_StylusPointer_h +#define hifi_StylusPointer_h + +#include +#include + +#include +#include +#include +#include +#include + +#include "ui/overlays/Overlay.h" + + +class StylusPick : public Pick { + using Side = bilateral::Side; +public: + StylusPick(Side side); + + StylusTip getMathematicalPick() const override; + PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override; + PickResultPointer getEntityIntersection(const StylusTip& pick) override; + PickResultPointer getOverlayIntersection(const StylusTip& pick) override; + PickResultPointer getAvatarIntersection(const StylusTip& pick) override; + PickResultPointer getHUDIntersection(const StylusTip& pick) override; + +private: + const Side _side; + const bool _useFingerInsteadOfStylus{ false }; +}; + +struct SideData; + +struct StylusPickResult : public PickResult { + using Side = bilateral::Side; + // FIXME make into a single ID + OverlayID overlayID; + // FIXME restore entity functionality +#if 0 + EntityItemID entityID; +#endif + StylusTip tip; + float distance{ FLT_MAX }; + vec3 position; + vec2 position2D; + vec3 normal; + vec3 normalizedPosition; + vec3 dimensions; + bool valid{ false }; + + virtual bool doesIntersect() const override; + virtual std::shared_ptr compareAndProcessNewResult(const std::shared_ptr& newRes) override; + virtual bool checkOrFilterAgainstMaxDistance(float maxDistance) override; + + bool isNormalized() const; + bool isNearNormal(float min, float max, float hystersis) const; + bool isNear2D(float border, float hystersis) const; + bool isNear(float min, float max, float border, float hystersis) const; + operator bool() const; + bool hasKeyboardFocus() const; + void setKeyboardFocus() const; + void sendHoverOverEvent() const; + void sendHoverEnterEvent() const; + void sendTouchStartEvent() const; + void sendTouchEndEvent() const; + void sendTouchMoveEvent() const; + +private: + uint32_t deviceId() const; +}; + + +class StylusPointer : public Pointer { + using Parent = Pointer; + using Side = bilateral::Side; + using Ptr = std::shared_ptr; + +public: + StylusPointer(Side side); + ~StylusPointer(); + + void enable() override; + void disable() override; + void update(float deltaTime) override; + +private: + + virtual void setRenderState(const std::string& state) override {} + virtual void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override {} + virtual PickedObject getHoveredObject(const PickResultPointer& pickResult) override { return PickedObject(); } + virtual Buttons getPressedButtons() override { return {}; } + virtual PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const override { return PointerEvent(); } + + + StylusPointer* getOtherStylus(); + + void updateStylusTarget(); + void requestTouchFocus(const StylusPickResult& pickResult); + bool hasTouchFocus(const StylusPickResult& pickResult); + void relinquishTouchFocus(); + void stealTouchFocus(); + void stylusTouchingEnter(); + void stylusTouchingExit(); + void stylusTouching(); + void show(); + void hide(); + + struct State { + StylusPickResult target; + bool nearTarget{ false }; + bool touchingTarget{ false }; + }; + + State _state; + State _previousState; + + float _nearHysteresis{ 0.0f }; + float _touchHysteresis{ 0.0f }; + float _hoverHysteresis{ 0.0f }; + + float _sensorScaleFactor{ 1.0f }; + float _touchingEnterTimer{ 0 }; + vec2 _touchingEnterPosition; + bool _deadspotExpired{ false }; + + bool _renderingEnabled; + OverlayID _stylusOverlay; + OverlayID _hoverOverlay; + const Side _side; + const SideData& _sideData; +}; + +#endif // hifi_StylusPointer_h + + + + diff --git a/libraries/pointers/src/pointers/Pick.h b/libraries/pointers/src/pointers/Pick.h index 9ab17f87d8..791238d601 100644 --- a/libraries/pointers/src/pointers/Pick.h +++ b/libraries/pointers/src/pointers/Pick.h @@ -118,7 +118,7 @@ public: // for example: if we want the closest result, compare based on distance // if we want all results, combine them // must return a new pointer - virtual std::shared_ptr compareAndProcessNewResult(const std::shared_ptr newRes) = 0; + virtual std::shared_ptr compareAndProcessNewResult(const std::shared_ptr& newRes) = 0; // returns true if this result contains any valid results with distance < maxDistance // can also filter out results with distance >= maxDistance @@ -198,7 +198,7 @@ class Pick : public PickQuery { public: Pick(const PickFilter& filter, const float maxDistance, const bool enabled) : PickQuery(filter, maxDistance, enabled) {} - virtual const T getMathematicalPick() const = 0; + virtual T getMathematicalPick() const = 0; virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0; virtual PickResultPointer getEntityIntersection(const T& pick) = 0; virtual PickResultPointer getOverlayIntersection(const T& pick) = 0; diff --git a/libraries/pointers/src/pointers/PickCacheOptimizer.h b/libraries/pointers/src/pointers/PickCacheOptimizer.h index c4bf96ab51..58c3ac9098 100644 --- a/libraries/pointers/src/pointers/PickCacheOptimizer.h +++ b/libraries/pointers/src/pointers/PickCacheOptimizer.h @@ -87,7 +87,9 @@ void PickCacheOptimizer::update(QHash>& pic PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { PickResultPointer entityRes = pick->getEntityIntersection(mathematicalPick); - cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); + if (entityRes) { + cacheResult(entityRes->doesIntersect(), entityRes, entityKey, res, mathematicalPick, results, pick); + } } } @@ -95,7 +97,9 @@ void PickCacheOptimizer::update(QHash>& pic PickCacheKey overlayKey = { pick->getFilter().getOverlayFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, overlayKey)) { PickResultPointer overlayRes = pick->getOverlayIntersection(mathematicalPick); - cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); + if (overlayRes) { + cacheResult(overlayRes->doesIntersect(), overlayRes, overlayKey, res, mathematicalPick, results, pick); + } } } @@ -103,7 +107,9 @@ void PickCacheOptimizer::update(QHash>& pic PickCacheKey avatarKey = { pick->getFilter().getAvatarFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, avatarKey)) { PickResultPointer avatarRes = pick->getAvatarIntersection(mathematicalPick); - cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); + if (avatarRes) { + cacheResult(avatarRes->doesIntersect(), avatarRes, avatarKey, res, mathematicalPick, results, pick); + } } } @@ -112,7 +118,9 @@ void PickCacheOptimizer::update(QHash>& pic PickCacheKey hudKey = { pick->getFilter().getHUDFlags(), QVector(), QVector() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, hudKey)) { PickResultPointer hudRes = pick->getHUDIntersection(mathematicalPick); - cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick); + if (hudRes) { + cacheResult(true, hudRes, hudKey, res, mathematicalPick, results, pick); + } } } diff --git a/libraries/pointers/src/pointers/PickManager.cpp b/libraries/pointers/src/pointers/PickManager.cpp index 571f9f04cd..385115d732 100644 --- a/libraries/pointers/src/pointers/PickManager.cpp +++ b/libraries/pointers/src/pointers/PickManager.cpp @@ -40,12 +40,12 @@ void PickManager::removePick(const QUuid& uid) { }); } -QVariantMap PickManager::getPrevPickResult(const QUuid& uid) const { +PickResultPointer PickManager::getPrevPickResult(const QUuid& uid) const { auto pick = findPick(uid); - if (pick && pick->getPrevPickResult()) { - return pick->getPrevPickResult()->toVariantMap(); + if (pick) { + return pick->getPrevPickResult(); } - return QVariantMap(); + return PickResultPointer(); } void PickManager::enablePick(const QUuid& uid) const { @@ -91,4 +91,5 @@ void PickManager::update() { bool shouldPickHUD = _shouldPickHUDOperator(); _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], shouldPickHUD); + _stylusPickCacheOptimizer.update(cachedPicks[PickQuery::Stylus], false); } \ No newline at end of file diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index b8abb077c7..5c3ed6ef25 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -27,7 +27,12 @@ public: void enablePick(const QUuid& uid) const; void disablePick(const QUuid& uid) const; - QVariantMap getPrevPickResult(const QUuid& uid) const; + PickResultPointer getPrevPickResult(const QUuid& uid) const; + + template + std::shared_ptr getPrevPickResultTyped(const QUuid& uid) const { + return std::static_pointer_cast(getPrevPickResult(uid)); + } void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; void setIgnoreItems(const QUuid& uid, const QVector& ignore) const; @@ -43,6 +48,7 @@ protected: QHash _typeMap; PickCacheOptimizer _rayPickCacheOptimizer; + PickCacheOptimizer _stylusPickCacheOptimizer; }; #endif // hifi_PickManager_h \ No newline at end of file diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 8796b1e47d..8551f29dd9 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -30,7 +30,7 @@ void Pointer::disable() { DependencyManager::get()->disablePick(_pickUID); } -const QVariantMap Pointer::getPrevPickResult() { +PickResultPointer Pointer::getPrevPickResult() { return DependencyManager::get()->getPrevPickResult(_pickUID); } @@ -46,16 +46,16 @@ void Pointer::setIncludeItems(const QVector& includeItems) const { DependencyManager::get()->setIncludeItems(_pickUID, includeItems); } -void Pointer::update() { +void Pointer::update(float deltaTime) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { - QVariantMap pickResult = getPrevPickResult(); + auto pickResult = getPrevPickResult(); updateVisuals(pickResult); generatePointerEvents(pickResult); }); } -void Pointer::generatePointerEvents(const QVariantMap& pickResult) { +void Pointer::generatePointerEvents(const PickResultPointer& pickResult) { // TODO: avatars/HUD? auto pointerManager = DependencyManager::get(); @@ -176,4 +176,4 @@ PointerEvent::Button Pointer::chooseButton(const std::string& button) { } else { return PointerEvent::NoButtons; } -} \ No newline at end of file +} diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index ca35c38c7a..fa09442c83 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -16,6 +16,7 @@ #include #include +#include "Pick.h" #include #include "PointerEvent.h" @@ -44,7 +45,7 @@ public: virtual void enable(); virtual void disable(); - virtual const QVariantMap getPrevPickResult(); + virtual PickResultPointer getPrevPickResult(); virtual void setRenderState(const std::string& state) = 0; virtual void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) = 0; @@ -57,13 +58,12 @@ public: virtual void setLength(float length) {} virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay) {} - void update(); - virtual void updateVisuals(const QVariantMap& pickResult) = 0; - void generatePointerEvents(const QVariantMap& pickResult); + virtual void update(float deltaTime); + virtual void updateVisuals(const PickResultPointer& pickResult) {} + void generatePointerEvents(const PickResultPointer& pickResult); struct PickedObject { - PickedObject() {} - PickedObject(const QUuid& objectID, IntersectionType type) : objectID(objectID), type(type) {} + PickedObject(const QUuid& objectID = QUuid(), IntersectionType type = IntersectionType::NONE) : objectID(objectID), type(type) {} QUuid objectID; IntersectionType type; @@ -71,7 +71,7 @@ public: using Buttons = std::unordered_set; - virtual PickedObject getHoveredObject(const QVariantMap& pickResult) = 0; + virtual PickedObject getHoveredObject(const PickResultPointer& pickResult) = 0; virtual Buttons getPressedButtons() = 0; QUuid getRayUID() { return _pickUID; } @@ -81,7 +81,7 @@ protected: bool _enabled; bool _hover; - virtual PointerEvent buildPointerEvent(const PickedObject& target, const QVariantMap& pickResult) const = 0; + virtual PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const = 0; private: PickedObject _prevHoveredObject; diff --git a/libraries/pointers/src/pointers/PointerManager.cpp b/libraries/pointers/src/pointers/PointerManager.cpp index 2d41543b6b..cd1273900d 100644 --- a/libraries/pointers/src/pointers/PointerManager.cpp +++ b/libraries/pointers/src/pointers/PointerManager.cpp @@ -61,21 +61,22 @@ void PointerManager::editRenderState(const QUuid& uid, const std::string& state, } } -const QVariantMap PointerManager::getPrevPickResult(const QUuid& uid) const { +PickResultPointer PointerManager::getPrevPickResult(const QUuid& uid) const { + PickResultPointer result; auto pointer = find(uid); if (pointer) { - return pointer->getPrevPickResult(); + result = pointer->getPrevPickResult(); } - return QVariantMap(); + return result; } -void PointerManager::update() { +void PointerManager::update(float deltaTime) { auto cachedPointers = resultWithReadLock>>([&] { return _pointers.values(); }); for (const auto& pointer : cachedPointers) { - pointer->update(); + pointer->update(deltaTime); } } diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index 9f477d9eb2..a9c0a47b17 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -29,7 +29,7 @@ public: void disablePointer(const QUuid& uid) const; void setRenderState(const QUuid& uid, const std::string& renderState) const; void editRenderState(const QUuid& uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) const; - const QVariantMap getPrevPickResult(const QUuid& uid) const; + PickResultPointer getPrevPickResult(const QUuid& uid) const; void setPrecisionPicking(const QUuid& uid, bool precisionPicking) const; void setIgnoreItems(const QUuid& uid, const QVector& ignoreEntities) const; @@ -38,7 +38,7 @@ public: void setLength(const QUuid& uid, float length) const; void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const; - void update(); + void update(float deltaTime); private: std::shared_ptr find(const QUuid& uid) const; diff --git a/libraries/script-engine/src/ScriptCache.cpp b/libraries/script-engine/src/ScriptCache.cpp index dba2db0458..8e3cebfbf2 100644 --- a/libraries/script-engine/src/ScriptCache.cpp +++ b/libraries/script-engine/src/ScriptCache.cpp @@ -69,6 +69,7 @@ void ScriptCache::getScriptContents(const QString& scriptOrURL, contentAvailable #ifdef THREAD_DEBUGGING qCDebug(scriptengine) << "ScriptCache::getScriptContents() on thread [" << QThread::currentThread() << "] expected thread [" << thread() << "]"; #endif + forceDownload = true; QUrl unnormalizedURL(scriptOrURL); QUrl url = DependencyManager::get()->normalizeURL(unnormalizedURL); diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index 074e5ab79b..73e37c7509 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -37,9 +37,9 @@ public: PointerEvent(); PointerEvent(EventType type, uint32_t id, - const glm::vec2& pos2D, const glm::vec3& pos3D, - const glm::vec3& normal, const glm::vec3& direction, - Button button, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::KeyboardModifier::NoModifier); + const glm::vec2& pos2D = glm::vec2(), const glm::vec3& pos3D = glm::vec3(), + const glm::vec3& normal = glm::vec3(), const glm::vec3& direction = glm::vec3(), + Button button = NoButtons, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::KeyboardModifier::NoModifier); static QScriptValue toScriptValue(QScriptEngine* engine, const PointerEvent& event); static void fromScriptValue(const QScriptValue& object, PointerEvent& event); diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index a716c9231e..c4ac7aba14 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -21,6 +21,7 @@ #include "AACube.h" #include "SharedUtil.h" +#include "shared/Bilateral.h" class QColor; class QUrl; @@ -152,17 +153,73 @@ public: return pickRay; } }; + +struct StylusTip : public MathPick { + bilateral::Side side{ bilateral::Side::Invalid }; + glm::vec3 position; + glm::quat orientation; + glm::vec3 velocity; + virtual operator bool() const override { return side != bilateral::Side::Invalid; } + QVariantMap toVariantMap() const override { + QVariantMap pickRay; + pickRay["position"] = vec3toVariant(position); + pickRay["orientation"] = quatToVariant(orientation); + pickRay["velocity"] = vec3toVariant(velocity); + return pickRay; + } +}; + + namespace std { + inline void hash_combine(std::size_t& seed) { } + + template + inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) { + std::hash hasher; + seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); + hash_combine(seed, rest...); + } + template <> - struct hash { - size_t operator()(const glm::vec3& a) const { - return ((hash()(a.x) ^ (hash()(a.y) << 1)) >> 1) ^ (hash()(a.z) << 1); + struct hash { + size_t operator()(const bilateral::Side& a) const { + return std::hash()((int)a); } }; - template <> + + template <> + struct hash { + size_t operator()(const glm::vec3& a) const { + size_t result = 0; + hash_combine(result, a.x, a.y, a.z); + return result; + } + }; + + template <> + struct hash { + size_t operator()(const glm::quat& a) const { + size_t result = 0; + hash_combine(result, a.x, a.y, a.z, a.w); + return result; + } + }; + + template <> struct hash { size_t operator()(const PickRay& a) const { - return (hash()(a.origin) ^ (hash()(a.direction) << 1)); + size_t result = 0; + hash_combine(result, a.origin, a.direction); + return result; + } + }; + + template <> + struct hash { + size_t operator()(const StylusTip& a) const { + size_t result = 0; + hash_combine(result, a.side, a.position, a.orientation, a.velocity); + return result; } }; } diff --git a/libraries/shared/src/shared/Bilateral.h b/libraries/shared/src/shared/Bilateral.h index edcaa49540..1ecc7f3d48 100644 --- a/libraries/shared/src/shared/Bilateral.h +++ b/libraries/shared/src/shared/Bilateral.h @@ -11,7 +11,8 @@ namespace bilateral { enum class Side { Left = 0, - Right = 1 + Right = 1, + Invalid = -1 }; using Indices = Side; @@ -27,8 +28,10 @@ namespace bilateral { return 0x01; case Side::Right: return 0x02; + default: + break; } - return std::numeric_limits::max(); + return 0x00; } inline uint8_t index(Side side) { @@ -37,10 +40,24 @@ namespace bilateral { return 0; case Side::Right: return 1; + default: + break; } return std::numeric_limits::max(); } + inline Side side(int index) { + switch (index) { + case 0: + return Side::Left; + case 1: + return Side::Right; + default: + break; + } + return Side::Invalid; + } + template void for_each_side(F f) { f(Side::Left); diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 1243ed28e2..61e520af21 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -32,7 +32,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/tablet-ui/tabletUI.js" ]; var DEFAULT_SCRIPTS_SEPARATE = [ - //"system/controllers/controllerScripts.js" + "system/controllers/controllerScripts.js" // "system/chat.js" ]; diff --git a/scripts/system/controllers/controllerModules/tabletStylusInput.js b/scripts/system/controllers/controllerModules/tabletStylusInput.js index 46b630d023..dc41a5453e 100644 --- a/scripts/system/controllers/controllerModules/tabletStylusInput.js +++ b/scripts/system/controllers/controllerModules/tabletStylusInput.js @@ -16,256 +16,16 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { - var TouchEventUtils = Script.require("/~/system/libraries/touchEventUtils.js"); - // triggered when stylus presses a web overlay/entity - var HAPTIC_STYLUS_STRENGTH = 1.0; - var HAPTIC_STYLUS_DURATION = 20.0; - - var WEB_DISPLAY_STYLUS_DISTANCE = 0.5; - var WEB_STYLUS_LENGTH = 0.2; - var WEB_TOUCH_Y_OFFSET = 0.105; // how far forward (or back with a negative number) to slide stylus in hand - - function isNearStylusTarget(stylusTargets, edgeBorder, minNormalDistance, maxNormalDistance) { - for (var i = 0; i < stylusTargets.length; i++) { - var stylusTarget = stylusTargets[i]; - - // check to see if the projected stylusTip is within within the 2d border - var borderMin = {x: -edgeBorder, y: -edgeBorder}; - var borderMax = {x: stylusTarget.dimensions.x + edgeBorder, y: stylusTarget.dimensions.y + edgeBorder}; - if (stylusTarget.distance >= minNormalDistance && stylusTarget.distance <= maxNormalDistance && - stylusTarget.position2D.x >= borderMin.x && stylusTarget.position2D.y >= borderMin.y && - stylusTarget.position2D.x <= borderMax.x && stylusTarget.position2D.y <= borderMax.y) { - return true; - } - } - return false; - } - - function calculateNearestStylusTarget(stylusTargets) { - var nearestStylusTarget; - - for (var i = 0; i < stylusTargets.length; i++) { - var stylusTarget = stylusTargets[i]; - - if ((!nearestStylusTarget || stylusTarget.distance < nearestStylusTarget.distance) && - stylusTarget.normalizedPosition.x >= 0 && stylusTarget.normalizedPosition.y >= 0 && - stylusTarget.normalizedPosition.x <= 1 && stylusTarget.normalizedPosition.y <= 1) { - nearestStylusTarget = stylusTarget; - } - } - - return nearestStylusTarget; - } - - function getFingerWorldLocation(hand) { - var fingerJointName = (hand === RIGHT_HAND) ? "RightHandIndex4" : "LeftHandIndex4"; - - var fingerJointIndex = MyAvatar.getJointIndex(fingerJointName); - var fingerPosition = MyAvatar.getAbsoluteJointTranslationInObjectFrame(fingerJointIndex); - var fingerRotation = MyAvatar.getAbsoluteJointRotationInObjectFrame(fingerJointIndex); - var worldFingerRotation = Quat.multiply(MyAvatar.orientation, fingerRotation); - var worldFingerPosition = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, fingerPosition)); - - return { - position: worldFingerPosition, - orientation: worldFingerRotation, - rotation: worldFingerRotation, - valid: true - }; - } - - function distance2D(a, b) { - var dx = (a.x - b.x); - var dy = (a.y - b.y); - return Math.sqrt(dx * dx + dy * dy); - } - - function TabletStylusInput(hand) { + function TabletStylusInput(hand) { this.hand = hand; - this.previousStylusTouchingTarget = false; - this.stylusTouchingTarget = false; - - this.useFingerInsteadOfStylus = false; - this.fingerPointing = false; - - // initialize stylus tip - var DEFAULT_STYLUS_TIP = { - position: {x: 0, y: 0, z: 0}, - orientation: {x: 0, y: 0, z: 0, w: 0}, - rotation: {x: 0, y: 0, z: 0, w: 0}, - velocity: {x: 0, y: 0, z: 0}, - valid: false - }; - this.stylusTip = DEFAULT_STYLUS_TIP; - this.parameters = makeDispatcherModuleParameters( 100, this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], [], 100); - - this.getOtherHandController = function() { - return (this.hand === RIGHT_HAND) ? leftTabletStylusInput : rightTabletStylusInput; - }; - - this.handToController = function() { - return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; - }; - - this.updateFingerAsStylusSetting = function () { - var DEFAULT_USE_FINGER_AS_STYLUS = false; - var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus"); - if (USE_FINGER_AS_STYLUS === "") { - USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS; - } - if (USE_FINGER_AS_STYLUS && MyAvatar.getJointIndex("LeftHandIndex4") !== -1) { - this.useFingerInsteadOfStylus = true; - } else { - this.useFingerInsteadOfStylus = false; - } - }; - - this.updateStylusTip = function() { - if (this.useFingerInsteadOfStylus) { - this.stylusTip = getFingerWorldLocation(this.hand); - } else { - this.stylusTip = getControllerWorldLocation(this.handToController(), true); - - // translate tip forward according to constant. - var TIP_OFFSET = Vec3.multiply(MyAvatar.sensorToWorldScale, {x: 0, y: WEB_STYLUS_LENGTH - WEB_TOUCH_Y_OFFSET, z: 0}); - this.stylusTip.position = Vec3.sum(this.stylusTip.position, - Vec3.multiplyQbyV(this.stylusTip.orientation, TIP_OFFSET)); - } - - // compute tip velocity from hand controller motion, it is more accurate than computing it from previous positions. - var pose = Controller.getPoseValue(this.handToController()); - if (pose.valid) { - var worldControllerPos = Vec3.sum(MyAvatar.position, Vec3.multiplyQbyV(MyAvatar.orientation, pose.translation)); - var worldControllerLinearVel = Vec3.multiplyQbyV(MyAvatar.orientation, pose.velocity); - var worldControllerAngularVel = Vec3.multiplyQbyV(MyAvatar.orientation, pose.angularVelocity); - var tipVelocity = Vec3.sum(worldControllerLinearVel, Vec3.cross(worldControllerAngularVel, - Vec3.subtract(this.stylusTip.position, worldControllerPos))); - this.stylusTip.velocity = tipVelocity; - } else { - this.stylusTip.velocity = {x: 0, y: 0, z: 0}; - } - }; - - this.showStylus = function() { - if (this.stylus) { - var X_ROT_NEG_90 = { x: -0.70710678, y: 0, z: 0, w: 0.70710678 }; - var modelOrientation = Quat.multiply(this.stylusTip.orientation, X_ROT_NEG_90); - var modelOrientationAngles = Quat.safeEulerAngles(modelOrientation); - - var rotation = Overlays.getProperty(this.stylus, "rotation"); - var rotationAngles = Quat.safeEulerAngles(rotation); - - if(!Vec3.withinEpsilon(modelOrientationAngles, rotationAngles, 1)) { - var modelPositionOffset = Vec3.multiplyQbyV(modelOrientation, { x: 0, y: 0, z: MyAvatar.sensorToWorldScale * -WEB_STYLUS_LENGTH / 2 }); - - var updatedStylusProperties = { - position: Vec3.sum(this.stylusTip.position, modelPositionOffset), - rotation: modelOrientation, - dimensions: Vec3.multiply(MyAvatar.sensorToWorldScale, { x: 0.01, y: 0.01, z: WEB_STYLUS_LENGTH }), - }; - - Overlays.editOverlay(this.stylus, updatedStylusProperties); - } - - return; - } - - var X_ROT_NEG_90 = { x: -0.70710678, y: 0, z: 0, w: 0.70710678 }; - var modelOrientation = Quat.multiply(this.stylusTip.orientation, X_ROT_NEG_90); - var modelPositionOffset = Vec3.multiplyQbyV(modelOrientation, { x: 0, y: 0, z: MyAvatar.sensorToWorldScale * -WEB_STYLUS_LENGTH / 2 }); - - var stylusProperties = { - name: "stylus", - url: Script.resourcesPath() + "meshes/tablet-stylus-fat.fbx", - loadPriority: 10.0, - position: Vec3.sum(this.stylusTip.position, modelPositionOffset), - rotation: modelOrientation, - dimensions: Vec3.multiply(MyAvatar.sensorToWorldScale, { x: 0.01, y: 0.01, z: WEB_STYLUS_LENGTH }), - solid: true, - visible: true, - ignoreRayIntersection: true, - drawInFront: false, - parentID: MyAvatar.SELF_ID, - parentJointIndex: MyAvatar.getJointIndex(this.hand === RIGHT_HAND ? - "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : - "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND") - }; - this.stylus = Overlays.addOverlay("model", stylusProperties); - }; - - this.hideStylus = function() { - if (!this.stylus) { - return; - } - Overlays.deleteOverlay(this.stylus); - this.stylus = null; - }; - - this.stealTouchFocus = function(stylusTarget) { - // send hover events to target - // record the entity or overlay we are hovering over. - if ((stylusTarget.entityID === this.getOtherHandController().hoverEntity) || - (stylusTarget.overlayID === this.getOtherHandController().hoverOverlay)) { - this.getOtherHandController().relinquishTouchFocus(); - } - this.requestTouchFocus(stylusTarget); - }; - - this.requestTouchFocus = function(stylusTarget) { - - // send hover events to target if we can. - // record the entity or overlay we are hovering over. - if (stylusTarget.entityID && - stylusTarget.entityID !== this.hoverEntity && - stylusTarget.entityID !== this.getOtherHandController().hoverEntity) { - this.hoverEntity = stylusTarget.entityID; - TouchEventUtils.sendHoverEnterEventToTouchTarget(this.hand, stylusTarget); - } else if (stylusTarget.overlayID && - stylusTarget.overlayID !== this.hoverOverlay && - stylusTarget.overlayID !== this.getOtherHandController().hoverOverlay) { - this.hoverOverlay = stylusTarget.overlayID; - TouchEventUtils.sendHoverEnterEventToTouchTarget(this.hand, stylusTarget); - } - }; - - this.hasTouchFocus = function(stylusTarget) { - return ((stylusTarget.entityID && stylusTarget.entityID === this.hoverEntity) || - (stylusTarget.overlayID && stylusTarget.overlayID === this.hoverOverlay)); - }; - - this.relinquishTouchFocus = function() { - // send hover leave event. - var pointerEvent = { type: "Move", id: this.hand + 1 }; - if (this.hoverEntity) { - Entities.sendHoverLeaveEntity(this.hoverEntity, pointerEvent); - this.hoverEntity = null; - } else if (this.hoverOverlay) { - Overlays.sendMouseMoveOnOverlay(this.hoverOverlay, pointerEvent); - Overlays.sendHoverOverOverlay(this.hoverOverlay, pointerEvent); - Overlays.sendHoverLeaveOverlay(this.hoverOverlay, pointerEvent); - this.hoverOverlay = null; - } - }; - - this.pointFinger = function(value) { - var HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index"; - if (this.fingerPointing !== value) { - var message; - if (this.hand === RIGHT_HAND) { - message = { pointRightIndex: value }; - } else { - message = { pointLeftIndex: value }; - } - Messages.sendMessage(HIFI_POINT_INDEX_MESSAGE_CHANNEL, JSON.stringify(message), true); - this.fingerPointing = value; - } - }; + + this.pointer = Pointers.createPointer(PickType.Stylus, { hand: this.hand }); this.otherModuleNeedsToRun = function(controllerData) { var grabOverlayModuleName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"; @@ -277,189 +37,6 @@ Script.include("/~/system/libraries/controllers.js"); return grabOverlayModuleReady.active || farGrabModuleReady.active; }; - this.processStylus = function(controllerData) { - this.updateStylusTip(); - - if (!this.stylusTip.valid || this.overlayLaserActive(controllerData) || this.otherModuleNeedsToRun(controllerData)) { - this.pointFinger(false); - this.hideStylus(); - this.stylusTouchingTarget = false; - this.relinquishTouchFocus(); - return false; - } - - if (this.useFingerInsteadOfStylus) { - this.hideStylus(); - } - - // build list of stylus targets, near the stylusTip - var stylusTargets = []; - var candidateEntities = controllerData.nearbyEntityProperties; - var i, props, stylusTarget; - for (i = 0; i < candidateEntities.length; i++) { - props = candidateEntities[i]; - if (props && props.type === "Web") { - stylusTarget = TouchEventUtils.calculateTouchTargetFromEntity(this.stylusTip, candidateEntities[i]); - if (stylusTarget) { - stylusTargets.push(stylusTarget); - } - } - } - - // add the tabletScreen, if it is valid - if (HMD.tabletScreenID && HMD.tabletScreenID !== Uuid.NULL && - Overlays.getProperty(HMD.tabletScreenID, "visible")) { - stylusTarget = TouchEventUtils.calculateTouchTargetFromOverlay(this.stylusTip, HMD.tabletScreenID); - if (stylusTarget) { - stylusTargets.push(stylusTarget); - } - } - - // add the tablet home button. - if (HMD.homeButtonID && HMD.homeButtonID !== Uuid.NULL && - Overlays.getProperty(HMD.homeButtonID, "visible")) { - stylusTarget = TouchEventUtils.calculateTouchTargetFromOverlay(this.stylusTip, HMD.homeButtonID); - if (stylusTarget) { - stylusTargets.push(stylusTarget); - } - } - - var TABLET_MIN_HOVER_DISTANCE = 0.01; - var TABLET_MAX_HOVER_DISTANCE = 0.1; - var TABLET_MIN_TOUCH_DISTANCE = -0.05; - var TABLET_MAX_TOUCH_DISTANCE = TABLET_MIN_HOVER_DISTANCE; - var EDGE_BORDER = 0.075; - - var hysteresisOffset = 0.0; - if (this.isNearStylusTarget) { - hysteresisOffset = 0.05; - } - - var sensorScaleFactor = MyAvatar.sensorToWorldScale; - this.isNearStylusTarget = isNearStylusTarget(stylusTargets, - (EDGE_BORDER + hysteresisOffset) * sensorScaleFactor, - (TABLET_MIN_TOUCH_DISTANCE - hysteresisOffset) * sensorScaleFactor, - (WEB_DISPLAY_STYLUS_DISTANCE + hysteresisOffset) * sensorScaleFactor); - - if (this.isNearStylusTarget) { - if (!this.useFingerInsteadOfStylus) { - this.showStylus(); - } else { - this.pointFinger(true); - } - } else { - this.hideStylus(); - this.pointFinger(false); - } - - var nearestStylusTarget = calculateNearestStylusTarget(stylusTargets); - - var SCALED_TABLET_MIN_TOUCH_DISTANCE = TABLET_MIN_TOUCH_DISTANCE * sensorScaleFactor; - var SCALED_TABLET_MAX_TOUCH_DISTANCE = TABLET_MAX_TOUCH_DISTANCE * sensorScaleFactor; - var SCALED_TABLET_MAX_HOVER_DISTANCE = TABLET_MAX_HOVER_DISTANCE * sensorScaleFactor; - - if (nearestStylusTarget && nearestStylusTarget.distance > SCALED_TABLET_MIN_TOUCH_DISTANCE && - nearestStylusTarget.distance < SCALED_TABLET_MAX_HOVER_DISTANCE && !this.getOtherHandController().stylusTouchingTarget) { - - this.requestTouchFocus(nearestStylusTarget); - - if (!TouchEventUtils.touchTargetHasKeyboardFocus(nearestStylusTarget)) { - TouchEventUtils.setKeyboardFocusOnTouchTarget(nearestStylusTarget); - } - - if (this.hasTouchFocus(nearestStylusTarget) && !this.stylusTouchingTarget) { - TouchEventUtils.sendHoverOverEventToTouchTarget(this.hand, nearestStylusTarget); - } - - // filter out presses when tip is moving away from tablet. - // ensure that stylus is within bounding box by checking normalizedPosition - if (nearestStylusTarget.valid && nearestStylusTarget.distance > SCALED_TABLET_MIN_TOUCH_DISTANCE && - nearestStylusTarget.distance < SCALED_TABLET_MAX_TOUCH_DISTANCE && - Vec3.dot(this.stylusTip.velocity, nearestStylusTarget.normal) < 0 && - nearestStylusTarget.normalizedPosition.x >= 0 && nearestStylusTarget.normalizedPosition.x <= 1 && - nearestStylusTarget.normalizedPosition.y >= 0 && nearestStylusTarget.normalizedPosition.y <= 1) { - - this.stylusTarget = nearestStylusTarget; - this.stylusTouchingTarget = true; - } - } else { - this.relinquishTouchFocus(); - } - - this.homeButtonTouched = false; - - if (this.isNearStylusTarget) { - return true; - } else { - this.pointFinger(false); - this.hideStylus(); - return false; - } - }; - - this.stylusTouchingEnter = function () { - this.stealTouchFocus(this.stylusTarget); - TouchEventUtils.sendTouchStartEventToTouchTarget(this.hand, this.stylusTarget); - Controller.triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, this.hand); - - this.touchingEnterTimer = 0; - this.touchingEnterStylusTarget = this.stylusTarget; - this.deadspotExpired = false; - - var TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481; - this.deadspotRadius = TOUCH_PRESS_TO_MOVE_DEADSPOT; - }; - - this.stylusTouchingExit = function () { - - if (this.stylusTarget === undefined) { - return; - } - - // special case to handle home button. - if (this.stylusTarget.overlayID === HMD.homeButtonID) { - Messages.sendLocalMessage("home", this.stylusTarget.overlayID); - } - - // send press event - if (this.deadspotExpired) { - TouchEventUtils.sendTouchEndEventToTouchTarget(this.hand, this.stylusTarget); - } else { - TouchEventUtils.sendTouchEndEventToTouchTarget(this.hand, this.touchingEnterStylusTarget); - } - }; - - this.stylusTouching = function (controllerData, dt) { - - this.touchingEnterTimer += dt; - - if (this.stylusTarget.entityID) { - this.stylusTarget = TouchEventUtils.calculateTouchTargetFromEntity(this.stylusTip, this.stylusTarget.entityProps); - } else if (this.stylusTarget.overlayID) { - this.stylusTarget = TouchEventUtils.calculateTouchTargetFromOverlay(this.stylusTip, this.stylusTarget.overlayID); - } - - var TABLET_MIN_TOUCH_DISTANCE = -0.1; - var TABLET_MAX_TOUCH_DISTANCE = 0.01; - - if (this.stylusTarget) { - if (this.stylusTarget.distance > TABLET_MIN_TOUCH_DISTANCE && - this.stylusTarget.distance < TABLET_MAX_TOUCH_DISTANCE) { - var POINTER_PRESS_TO_MOVE_DELAY = 0.33; // seconds - if (this.deadspotExpired || this.touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY || - distance2D(this.stylusTarget.position2D, - this.touchingEnterStylusTarget.position2D) > this.deadspotRadius) { - TouchEventUtils.sendTouchMoveEventToTouchTarget(this.hand, this.stylusTarget); - this.deadspotExpired = true; - } - } else { - this.stylusTouchingTarget = false; - } - } else { - this.stylusTouchingTarget = false; - } - }; - this.overlayLaserActive = function(controllerData) { var rightOverlayLaserModule = getEnabledModuleByName("RightOverlayLaserInput"); var leftOverlayLaserModule = getEnabledModuleByName("LeftOverlayLaserInput"); @@ -469,7 +46,7 @@ Script.include("/~/system/libraries/controllers.js"); }; this.isReady = function (controllerData) { - if (this.processStylus(controllerData)) { + if (!this.overlayLaserActive(controllerData) && !this.otherModuleNeedsToRun(controllerData)) { return makeRunningValues(true, [], []); } else { return makeRunningValues(false, [], []); @@ -477,28 +54,11 @@ Script.include("/~/system/libraries/controllers.js"); }; this.run = function (controllerData, deltaTime) { - this.updateFingerAsStylusSetting(); - - if (!this.previousStylusTouchingTarget && this.stylusTouchingTarget) { - this.stylusTouchingEnter(); - } - if (this.previousStylusTouchingTarget && !this.stylusTouchingTarget) { - this.stylusTouchingExit(); - } - this.previousStylusTouchingTarget = this.stylusTouchingTarget; - - if (this.stylusTouchingTarget) { - this.stylusTouching(controllerData, deltaTime); - } - if (this.processStylus(controllerData)) { - return makeRunningValues(true, [], []); - } else { - return makeRunningValues(false, [], []); - } + return this.isReady(controllerData); }; - + this.cleanup = function () { - this.hideStylus(); + Pointers.createPointer(this.pointer); }; } From 66f07cb21b7460126bf3353c0929daeceea9065d Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 1 Nov 2017 11:36:36 -0700 Subject: [PATCH 053/292] eslint controller modules --- .../controllers/controllerDispatcher.js | 13 +++++------ .../controllerModules/disableOtherModule.js | 4 ++-- .../controllerModules/equipEntity.js | 2 +- .../controllerModules/farActionGrabEntity.js | 7 +++--- .../controllerModules/farTrigger.js | 2 +- .../controllerModules/inEditMode.js | 4 ++-- .../controllerModules/nearActionGrabEntity.js | 2 +- .../controllerModules/nearParentGrabEntity.js | 2 +- .../nearParentGrabOverlay.js | 2 +- .../controllerModules/nearTrigger.js | 2 +- .../controllerModules/overlayLaserInput.js | 2 +- .../controllerModules/scaleAvatar.js | 5 ++--- .../controllerModules/scaleEntity.js | 6 ++--- .../controllers/controllerModules/teleport.js | 22 +++++++++---------- .../controllerModules/webEntityLaserInput.js | 2 +- 15 files changed, 36 insertions(+), 41 deletions(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 915d683724..933ca1e2b1 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -10,7 +10,8 @@ /* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation, RayPick, controllerDispatcherPlugins:true, controllerDispatcherPluginsNeedSort:true, LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES, - getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities + getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Pointers, PickType, COLORS_GRAB_SEARCHING_HALF_SQUEEZE + COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, Picks */ controllerDispatcherPlugins = {}; @@ -157,7 +158,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var handLaser = plugin.parameters.handLaser; if (handLaser !== undefined) { _this.laserVisibleStatus[handLaser] = false; - _this.laserLockStatus[handLaser] = false; + _this.laserLockStatus[handLaser] = false; } }; @@ -258,16 +259,16 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); // update left hand laser var HUD_LASER_OFFSET = 2; + var laserLocked; if (_this.laserVisibleStatus[LEFT_HAND]) { - var laserLocked = _this.laserLockStatus[LEFT_HAND]; + laserLocked = _this.laserLockStatus[LEFT_HAND]; _this.updateLaserRenderState(_this.leftControllerPointer,_this.leftTriggerClicked, laserLocked); } else { Pointers.setRenderState(_this.leftControllerPointer, ""); } - //update right hand laser if (_this.laserVisibleStatus[RIGHT_HAND]) { - var laserLocked = _this.laserLockStatus[RIGHT_HAND]; + laserLocked = _this.laserLockStatus[RIGHT_HAND]; _this.updateLaserRenderState(_this.rightControllerPointer, _this.rightTriggerClicked, laserLocked); } else { Pointers.setRenderState(_this.rightControllerPointer, ""); @@ -636,8 +637,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } function mouseReleaseOnOverlay(overlayID, event) { if (overlayID === HMD.homeButtonID) { - print(JSON.stringify(event)); - print("---------> go home <--------"); Messages.sendLocalMessage("home", overlayID); } } diff --git a/scripts/system/controllers/controllerModules/disableOtherModule.js b/scripts/system/controllers/controllerModules/disableOtherModule.js index e873579ba7..0928b29d5d 100644 --- a/scripts/system/controllers/controllerModules/disableOtherModule.js +++ b/scripts/system/controllers/controllerModules/disableOtherModule.js @@ -73,13 +73,13 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } } } - }; + } Messages.subscribe('Hifi-Hand-Disabler'); function cleanup() { disableDispatcherModule("LeftDisableModules"); disableDispatcherModule("RightDisableModules"); - }; + } Messages.messageReceived.connect(handleMessage); Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/equipEntity.js b/scripts/system/controllers/controllerModules/equipEntity.js index 7843f3a18a..b8c20d5bd6 100644 --- a/scripts/system/controllers/controllerModules/equipEntity.js +++ b/scripts/system/controllers/controllerModules/equipEntity.js @@ -773,6 +773,6 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa disableDispatcherModule("LeftEquipEntity"); disableDispatcherModule("RightEquipEntity"); clearAttachPoints(); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index e0f8834e38..5403b4742f 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -14,14 +14,13 @@ PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic, getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays, isPointingAtUI - + Picks, makeLaserLockInfo */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { - var PICK_WITH_HAND_RAY = true; var GRABBABLE_PROPERTIES = [ "position", "registrationPoint", @@ -249,7 +248,7 @@ Script.include("/~/system/libraries/controllers.js"); this.grabbedThingID = null; }; - this.updateRecommendedArea = function() { + this.updateRecommendedArea = function() { var dims = Controller.getViewportDimensions(); this.reticleMaxX = dims.x - MARGIN; this.reticleMaxY = dims.y - MARGIN; @@ -480,6 +479,6 @@ Script.include("/~/system/libraries/controllers.js"); rightFarActionGrabEntity.cleanup(); disableDispatcherModule("LeftFarActionGrabEntity"); disableDispatcherModule("RightFarActionGrabEntity"); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/farTrigger.js b/scripts/system/controllers/controllerModules/farTrigger.js index 4a4c83a9d2..24f336d581 100644 --- a/scripts/system/controllers/controllerModules/farTrigger.js +++ b/scripts/system/controllers/controllerModules/farTrigger.js @@ -99,6 +99,6 @@ Script.include("/~/system/libraries/controllers.js"); function cleanup() { disableDispatcherModule("LeftFarTriggerEntity"); disableDispatcherModule("RightFarTriggerEntity"); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index cfa1f0a9e3..c4c53b4d97 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -10,7 +10,7 @@ /* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues, Messages, makeDispatcherModuleParameters, HMD, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, - getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, LaserPointers, RayPick + getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, LaserPointers, RayPick, Picks */ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); @@ -128,7 +128,7 @@ Script.include("/~/system/libraries/utils.js"); rightHandInEditMode.cleanup(); disableDispatcherModule("LeftHandInEditMode"); disableDispatcherModule("RightHandInEditMode"); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js index 4fc192cc6b..147d6b807f 100644 --- a/scripts/system/controllers/controllerModules/nearActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearActionGrabEntity.js @@ -261,6 +261,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); rightNearActionGrabEntity.cleanup(); disableDispatcherModule("LeftNearActionGrabEntity"); disableDispatcherModule("RightNearActionGrabEntity"); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js index 1a5e82599d..ff20d0bbde 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabEntity.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabEntity.js @@ -343,6 +343,6 @@ Script.include("/~/system/libraries/cloneEntityUtils.js"); rightNearParentingGrabEntity.cleanup(); disableDispatcherModule("LeftNearParentingGrabEntity"); disableDispatcherModule("RightNearParentingGrabEntity"); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js index 5333196bd0..fa0fe31de2 100644 --- a/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js +++ b/scripts/system/controllers/controllerModules/nearParentGrabOverlay.js @@ -229,6 +229,6 @@ Script.include("/~/system/libraries/utils.js"); rightNearParentingGrabOverlay.cleanup(); disableDispatcherModule("LeftNearParentingGrabOverlay"); disableDispatcherModule("RightNearParentingGrabOverlay"); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/nearTrigger.js b/scripts/system/controllers/controllerModules/nearTrigger.js index a8aa72f1aa..42db3d6f61 100644 --- a/scripts/system/controllers/controllerModules/nearTrigger.js +++ b/scripts/system/controllers/controllerModules/nearTrigger.js @@ -115,6 +115,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); rightNearTriggerEntity.cleanup(); disableDispatcherModule("LeftNearTriggerEntity"); disableDispatcherModule("RightNearTriggerEntity"); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/overlayLaserInput.js b/scripts/system/controllers/controllerModules/overlayLaserInput.js index 6c9258ead7..3997dcaab1 100644 --- a/scripts/system/controllers/controllerModules/overlayLaserInput.js +++ b/scripts/system/controllers/controllerModules/overlayLaserInput.js @@ -95,6 +95,6 @@ Script.include("/~/system/libraries/controllers.js"); function cleanup() { disableDispatcherModule("LeftOverlayLaserInput"); disableDispatcherModule("RightOverlayLaserInput"); - }; + } Script.scriptEnding.connect(cleanup); }()); diff --git a/scripts/system/controllers/controllerModules/scaleAvatar.js b/scripts/system/controllers/controllerModules/scaleAvatar.js index de0434258c..8dbdb90824 100644 --- a/scripts/system/controllers/controllerModules/scaleAvatar.js +++ b/scripts/system/controllers/controllerModules/scaleAvatar.js @@ -8,7 +8,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html /* global Script, Vec3, MyAvatar, RIGHT_HAND */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function () { var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); @@ -59,7 +58,7 @@ if (this.hand === dispatcherUtils.RIGHT_HAND) { var scalingCurrentDistance = Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, - controllerData.controllerLocations[this.otherHand()].position)); + controllerData.controllerLocations[this.otherHand()].position)); var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale; MyAvatar.scale = newAvatarScale; @@ -79,6 +78,6 @@ function cleanup() { dispatcherUtils.disableDispatcherModule("LeftScaleAvatar"); dispatcherUtils.disableDispatcherModule("RightScaleAvatar"); - }; + } Script.scriptEnding.connect(cleanup); })(); diff --git a/scripts/system/controllers/controllerModules/scaleEntity.js b/scripts/system/controllers/controllerModules/scaleEntity.js index d45a4a5071..9d54eef98e 100644 --- a/scripts/system/controllers/controllerModules/scaleEntity.js +++ b/scripts/system/controllers/controllerModules/scaleEntity.js @@ -8,11 +8,9 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html /* global Script, Vec3, MyAvatar, RIGHT_HAND */ -/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */ (function() { var dispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); - function ScaleEntity(hand) { this.hand = hand; this.grabbedThingID = false; @@ -81,7 +79,7 @@ if (this.hand === dispatcherUtils.RIGHT_HAND) { var scalingCurrentDistance = Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position, - controllerData.controllerLocations[this.otherHand()].position)); + controllerData.controllerLocations[this.otherHand()].position)); var currentRescale = scalingCurrentDistance / this.scalingStartDistance; var newDimensions = Vec3.multiply(currentRescale, this.scalingStartDimensions); Entities.editEntity(this.grabbedThingID, { dimensions: newDimensions }); @@ -101,6 +99,6 @@ function cleanup() { dispatcherUtils.disableDispatcherModule("LeftScaleEntity"); dispatcherUtils.disableDispatcherModule("RightScaleEntity"); - }; + } Script.scriptEnding.connect(cleanup); })(); diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index c207ba56ae..6d6d93d640 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -12,7 +12,7 @@ /* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3, - LaserPointers, RayPick, HMD, Uuid, AvatarList + LaserPointers, RayPick, HMD, Uuid, AvatarList, Picks */ Script.include("/~/system/libraries/Xform.js"); @@ -109,8 +109,8 @@ Script.include("/~/system/libraries/controllers.js"); var teleportRenderStates = [{name: "cancel", path: cancelPath, end: cancelEnd}, - {name: "teleport", path: teleportPath, end: teleportEnd}, - {name: "seat", path: seatPath, end: seatEnd}]; + {name: "teleport", path: teleportPath, end: teleportEnd}, + {name: "seat", path: seatPath, end: seatEnd}]; var DEFAULT_DISTANCE = 50; var teleportDefaultRenderStates = [{name: "cancel", distance: DEFAULT_DISTANCE, path: cancelPath}]; @@ -127,18 +127,18 @@ Script.include("/~/system/libraries/controllers.js"); }; var TARGET = { - NONE: 'none', // Not currently targetting anything - INVISIBLE: 'invisible', // The current target is an invvsible surface - INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) - SURFACE: 'surface', // The current target is a valid surface - SEAT: 'seat' // The current target is a seat + NONE: 'none', // Not currently targetting anything + INVISIBLE: 'invisible', // The current target is an invvsible surface + INVALID: 'invalid', // The current target is invalid (wall, ceiling, etc.) + SURFACE: 'surface', // The current target is a valid surface + SEAT: 'seat' // The current target is a seat }; function Teleporter(hand) { var _this = this; this.hand = hand; this.buttonValue = 0; - this.disabled = false; // used by the 'Hifi-Teleport-Disabler' message handler + this.disabled = false; // used by the 'Hifi-Teleport-Disabler' message handler this.active = false; this.state = TELEPORTER_STATES.IDLE; this.currentTarget = TARGET.INVALID; @@ -218,8 +218,8 @@ Script.include("/~/system/libraries/controllers.js"); seatEnd.dimensions = AVATAR_PROPORTIONAL_TARGET_MODEL_DIMENSIONS; teleportRenderStates = [{name: "cancel", path: cancelPath, end: cancelEnd}, - {name: "teleport", path: teleportPath, end: teleportEnd}, - {name: "seat", path: seatPath, end: seatEnd}]; + {name: "teleport", path: teleportPath, end: teleportEnd}, + {name: "seat", path: seatPath, end: seatEnd}]; LaserPointers.editRenderState(this.teleportRayHandVisible, "cancel", teleportRenderStates[0]); LaserPointers.editRenderState(this.teleportRayHandInvisible, "cancel", teleportRenderStates[0]); diff --git a/scripts/system/controllers/controllerModules/webEntityLaserInput.js b/scripts/system/controllers/controllerModules/webEntityLaserInput.js index 20bd272542..9b6e0cc4f7 100644 --- a/scripts/system/controllers/controllerModules/webEntityLaserInput.js +++ b/scripts/system/controllers/controllerModules/webEntityLaserInput.js @@ -60,7 +60,7 @@ Script.include("/~/system/libraries/controllers.js"); function cleanup() { disableDispatcherModule("LeftWebEntityLaserInput"); disableDispatcherModule("RightWebEntityLaserInput"); - }; + } Script.scriptEnding.connect(cleanup); }()); From 0580e2368666a0977b39eeb40338cdf627501e14 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Wed, 1 Nov 2017 15:16:02 -0700 Subject: [PATCH 054/292] fixed edit mode and allow to scroll off tablet --- .../controllers/controllerDispatcher.js | 27 ++++---- .../controllerModules/inEditMode.js | 7 +- .../controllerModules/overlayLaserInput.js | 38 ++++++----- .../controllerModules/webEntityLaserInput.js | 66 ------------------- .../system/controllers/controllerScripts.js | 1 - 5 files changed, 40 insertions(+), 99 deletions(-) delete mode 100644 scripts/system/controllers/controllerModules/webEntityLaserInput.js diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 933ca1e2b1..cd52caae38 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -11,7 +11,7 @@ controllerDispatcherPlugins:true, controllerDispatcherPluginsNeedSort:true, LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES, getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Pointers, PickType, COLORS_GRAB_SEARCHING_HALF_SQUEEZE - COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, Picks + COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, Picks, TRIGGER_ON_VALUE */ controllerDispatcherPlugins = {}; @@ -262,41 +262,40 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var laserLocked; if (_this.laserVisibleStatus[LEFT_HAND]) { laserLocked = _this.laserLockStatus[LEFT_HAND]; - _this.updateLaserRenderState(_this.leftControllerPointer,_this.leftTriggerClicked, laserLocked); + _this.updateLaserRenderState(_this.leftControllerPointer,_this.leftTriggerClicked, _this.leftTriggerValue, laserLocked); } else { Pointers.setRenderState(_this.leftControllerPointer, ""); } if (_this.laserVisibleStatus[RIGHT_HAND]) { laserLocked = _this.laserLockStatus[RIGHT_HAND]; - _this.updateLaserRenderState(_this.rightControllerPointer, _this.rightTriggerClicked, laserLocked); + _this.updateLaserRenderState(_this.rightControllerPointer, _this.rightTriggerClicked, _this.rightTriggerValue, laserLocked); } else { Pointers.setRenderState(_this.rightControllerPointer, ""); } if (_this.laserVisibleStatus[LEFT_HAND + HUD_LASER_OFFSET]) { - _this.updateLaserRenderState(_this.leftControllerHudRayPick, _this.leftTriggerClicked, false); + _this.updateLaserRenderState(_this.leftControllerHudRayPick, _this.leftTriggerClicked, _this.leftTriggerValue, false); } else { Pointers.setRenderState(_this.leftControllerHudRayPick, ""); } if (_this.laserVisibleStatus[RIGHT_HAND + HUD_LASER_OFFSET]) { - _this.updateLaserRenderState(_this.rightControllerHudRayPick, _this.rightTriggerClicked, false); + _this.updateLaserRenderState(_this.rightControllerHudRayPick, _this.rightTriggerClicked, _this.rightTriggerValue, false); } else { Pointers.setRenderState(_this.rightControllerHudRayPick, ""); } }; - this.updateLaserRenderState = function(laser, triggerClicked, laserLocked) { - var mode = "hold"; - if (!laserLocked) { - if (triggerClicked) { - mode = "full"; - } else { - mode = "half"; - } + this.updateLaserRenderState = function(laser, triggerClicked, triggerValue, laserLocked) { + var mode = ""; + if (laserLocked) { + mode = "hold"; + } else if (triggerClicked) { + mode = "full"; + } else if (triggerValue > TRIGGER_ON_VALUE) { + mode = "half"; } - Pointers.setRenderState(laser, mode); }; diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index c4c53b4d97..10c2f049d4 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -26,7 +26,8 @@ Script.include("/~/system/libraries/utils.js"); 160, this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip", "rightHandTrigger"] : ["leftHand", "leftHandEquip", "leftHandTrigger"], [], - 100); + 100, + this.hand); this.nearTablet = function(overlays) { for (var i = 0; i < overlays.length; i++) { @@ -69,6 +70,10 @@ Script.include("/~/system/libraries/utils.js"); } }; + this.exitModule = function() { + return makeRunningValues(false, [], []); + }; + this.isReady = function(controllerData) { if (isInEditMode()) { this.triggerClicked = false; diff --git a/scripts/system/controllers/controllerModules/overlayLaserInput.js b/scripts/system/controllers/controllerModules/overlayLaserInput.js index 3997dcaab1..10235a63e9 100644 --- a/scripts/system/controllers/controllerModules/overlayLaserInput.js +++ b/scripts/system/controllers/controllerModules/overlayLaserInput.js @@ -26,13 +26,6 @@ Script.include("/~/system/libraries/controllers.js"); 100, this.hand); - this.processLaser = function(controllerData) { - if (this.shouldExit(controllerData)) { - return false; - } - return true; - }; - this.grabModuleWantsNearbyOverlay = function(controllerData) { if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { var nearGrabName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"; @@ -51,15 +44,19 @@ Script.include("/~/system/libraries/controllers.js"); return false; }; - this.shouldExit = function(controllerData) { + this.isPointingAtWebEntity = function(controllerData) { var intersection = controllerData.rayPicks[this.hand]; - var offOverlay = (intersection.type !== Picks.INTERSECTED_OVERLAY); - var triggerOff = (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE); - if (triggerOff) { - this.deleteContextOverlay(); + var entityProperty = Entities.getEntityProperties(intersection.objectID); + var entityType = entityProperty.type; + if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web")) { + return true; } - var grabbingOverlay = this.grabModuleWantsNearbyOverlay(controllerData); - return offOverlay || grabbingOverlay || triggerOff; + return false; + }; + + this.isPointingAtOverlay = function(controllerData) { + var intersection = controllerData.rayPicks[this.hand]; + return intersection.type === Picks.INTERSECTED_OVERLAY; }; this.deleteContextOverlay = function() { @@ -75,14 +72,21 @@ Script.include("/~/system/libraries/controllers.js"); }; this.isReady = function (controllerData) { - if (this.processLaser(controllerData)) { - return makeRunningValues(true, [], []); + if (this.isPointingAtOverlay(controllerData) || this.isPointingAtWebEntity(controllerData)) { + if (controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE) { + return makeRunningValues(true, [], []); + } } return makeRunningValues(false, [], []); }; this.run = function (controllerData, deltaTime) { - return this.isReady(controllerData); + var grabModuleNeedsToRun = this.grabModuleWantsNearbyOverlay(controllerData); + if (controllerData.triggerValues[this.hand] > TRIGGER_OFF_VALUE && !grabModuleNeedsToRun) { + return makeRunningValues(true, [], []); + } + this.deleteContextOverlay(); + return makeRunningValues(false, [], []); }; } diff --git a/scripts/system/controllers/controllerModules/webEntityLaserInput.js b/scripts/system/controllers/controllerModules/webEntityLaserInput.js deleted file mode 100644 index 9b6e0cc4f7..0000000000 --- a/scripts/system/controllers/controllerModules/webEntityLaserInput.js +++ /dev/null @@ -1,66 +0,0 @@ -"use strict"; - -// webEntityLaserInput.js -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -/* jslint bitwise: true */ - -/* global Script, Controller, LaserPointers, RayPick, RIGHT_HAND, LEFT_HAND, Vec3, Quat, getGrabPointSphereOffset, - makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters, - PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, - DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, ZERO_VEC, Overlays, Picks -*/ - -Script.include("/~/system/libraries/controllerDispatcherUtils.js"); -Script.include("/~/system/libraries/controllers.js"); - -(function() { - function WebEntityLaserInput(hand) { - this.hand = hand; - this.parameters = makeDispatcherModuleParameters( - 550, - this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], - [], - 100); - - this.isPointingAtWebEntity = function(controllerData) { - var intersection = controllerData.rayPicks[this.hand]; - var entityProperty = Entities.getEntityProperties(intersection.objectID); - var entityType = entityProperty.type; - - if ((intersection.type === Picks.INTERSECTED_ENTITY && entityType === "Web")) { - return true; - } - return false; - }; - - this.isReady = function(controllerData) { - if (this.isPointingAtWebEntity(controllerData)) { - return makeRunningValues(true, [], []); - } - return makeRunningValues(false, [], []); - }; - - this.run = function(controllerData, deltaTime) { - if (!this.isPointingAtWebEntity(controllerData)) { - return makeRunningValues(false, [], []); - } - return makeRunningValues(true, [], []); - }; - } - - var leftWebEntityLaserInput = new WebEntityLaserInput(LEFT_HAND); - var rightWebEntityLaserInput = new WebEntityLaserInput(RIGHT_HAND); - - enableDispatcherModule("LeftWebEntityLaserInput", leftWebEntityLaserInput); - enableDispatcherModule("RightWebEntityLaserInput", rightWebEntityLaserInput); - - function cleanup() { - disableDispatcherModule("LeftWebEntityLaserInput"); - disableDispatcherModule("RightWebEntityLaserInput"); - } - Script.scriptEnding.connect(cleanup); - -}()); diff --git a/scripts/system/controllers/controllerScripts.js b/scripts/system/controllers/controllerScripts.js index 09602b33eb..7ab5a88948 100644 --- a/scripts/system/controllers/controllerScripts.js +++ b/scripts/system/controllers/controllerScripts.js @@ -23,7 +23,6 @@ var CONTOLLER_SCRIPTS = [ "controllerModules/equipEntity.js", "controllerModules/nearTrigger.js", "controllerModules/overlayLaserInput.js", - "controllerModules/webEntityLaserInput.js", "controllerModules/inEditMode.js", "controllerModules/inVREditMode.js", "controllerModules/disableOtherModule.js", From c834cf1cf3f442be3ad34da09066e65e5a9e07cc Mon Sep 17 00:00:00 2001 From: luiscuenca Date: Wed, 1 Nov 2017 21:55:31 -0700 Subject: [PATCH 055/292] Comments and corrections --- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 114 ++++++++++++-------- libraries/ui/src/ui/OffscreenQmlSurface.h | 1 - 2 files changed, 70 insertions(+), 45 deletions(-) diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index b7f717db04..8232c6a064 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -117,6 +117,69 @@ uint64_t uvec2ToUint64(const uvec2& v) { return result; } +// Class to handle changing QML audio output device using another thread +class AudioHandler : public QObject, QRunnable { + Q_OBJECT +public: + AudioHandler(QObject* container, const QString& deviceName, int runDelayMs = 0, QObject* parent = nullptr) : QObject(parent) { + _container = container; + _newTargetDevice = deviceName; + _runDelayMs = runDelayMs; + setAutoDelete(true); + QThreadPool::globalInstance()->start(this); + } + virtual ~AudioHandler() { + qDebug() << "Audio Handler Destroyed"; + } + void run() override { + if (_newTargetDevice.isEmpty()) { + return; + } + if (_runDelayMs > 0) { + QThread::msleep(_runDelayMs); + } + auto audioIO = DependencyManager::get(); + QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); + for (auto player : _container->findChildren()) { + auto mediaState = player->state(); + QMediaService *svc = player->service(); + if (nullptr == svc) { + return; + } + QAudioOutputSelectorControl *out = qobject_cast + (svc->requestControl(QAudioOutputSelectorControl_iid)); + if (nullptr == out) { + return; + } + QString deviceOuput; + auto outputs = out->availableOutputs(); + for (int i = 0; i < outputs.size(); i++) { + QString output = outputs[i]; + QString description = out->outputDescription(output); + if (description == deviceName) { + deviceOuput = output; + break; + } + } + out->setActiveOutput(deviceOuput); + svc->releaseControl(out); + // if multimedia was paused, it will start playing automatically after changing audio device + // this will reset it back to a paused state + if (mediaState == QMediaPlayer::State::PausedState) { + player->pause(); + } else if (mediaState == QMediaPlayer::State::StoppedState) { + player->stop(); + } + } + qDebug() << "QML Audio changed to " << deviceName; + } + +private: + QString _newTargetDevice; + QObject* _container; + int _runDelayMs; +}; + class OffscreenTextures { public: GLuint getNextTexture(const uvec2& size) { @@ -604,7 +667,7 @@ void OffscreenQmlSurface::create() { auto audioIO = DependencyManager::get(); connect(audioIO.data(), &AudioClient::deviceChanged, this, [&](QAudio::Mode mode, const QAudioDeviceInfo& device) { if (mode == QAudio::Mode::AudioOutput) { - QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::DirectConnection, Q_ARG(QString, device.deviceName())); + QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection, Q_ARG(QString, device.deviceName())); } }); @@ -619,7 +682,7 @@ void OffscreenQmlSurface::create() { void OffscreenQmlSurface::changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate) { if (_rootItem != nullptr && !isHtmlUpdate) { - QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::DirectConnection); + QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); } emit audioOutputDeviceChanged(deviceName); } @@ -627,7 +690,7 @@ void OffscreenQmlSurface::changeAudioOutputDevice(const QString& deviceName, boo void OffscreenQmlSurface::forceHtmlAudioOutputDeviceUpdate() { auto audioIO = DependencyManager::get(); QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); - QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::DirectConnection, + QMetaObject::invokeMethod(this, "changeAudioOutputDevice", Qt::QueuedConnection, Q_ARG(QString, deviceName), Q_ARG(bool, true)); } @@ -635,51 +698,14 @@ void OffscreenQmlSurface::forceQmlAudioOutputDeviceUpdate() { if (QThread::currentThread() != qApp->thread()) { QMetaObject::invokeMethod(this, "forceQmlAudioOutputDeviceUpdate", Qt::QueuedConnection); } else { + auto audioIO = DependencyManager::get(); + QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); int waitForAudioQmlMs = 500; - QTimer::singleShot(waitForAudioQmlMs, this, [this] { - updateQmlAudio(); - }); + // The audio device need to be change using oth + new AudioHandler(_rootItem, deviceName, waitForAudioQmlMs); } } -void OffscreenQmlSurface::updateQmlAudio() { - auto audioIO = DependencyManager::get(); - QString deviceName = audioIO->getActiveAudioDevice(QAudio::AudioOutput).deviceName(); - for (auto player : _rootItem->findChildren()) { - auto mediaState = player->state(); - QMediaService *svc = player->service(); - if (nullptr == svc) { - return; - } - QAudioOutputSelectorControl *out = qobject_cast - (svc->requestControl(QAudioOutputSelectorControl_iid)); - if (nullptr == out) { - return; - } - QString deviceOuput; - auto outputs = out->availableOutputs(); - for (int i = 0; i < outputs.size(); i++) { - QString output = outputs[i]; - QString description = out->outputDescription(output); - if (description == deviceName) { - deviceOuput = output; - break; - } - } - out->setActiveOutput(deviceOuput); - svc->releaseControl(out); - // if multimedia was paused, it will start playing automatically after changing audio device - // this will reset it back to a paused state - if (mediaState == QMediaPlayer::State::PausedState) { - player->pause(); - } - else if (mediaState == QMediaPlayer::State::StoppedState) { - player->stop(); - } - } - qDebug() << "QML Audio changed to " << deviceName; -} - static uvec2 clampSize(const uvec2& size, uint32_t maxDimension) { return glm::clamp(size, glm::uvec2(1), glm::uvec2(maxDimension)); } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 0d053b373d..2d64ae12b5 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -108,7 +108,6 @@ public slots: void changeAudioOutputDevice(const QString& deviceName, bool isHtmlUpdate = false); void forceHtmlAudioOutputDeviceUpdate(); void forceQmlAudioOutputDeviceUpdate(); - void updateQmlAudio(); signals: void audioOutputDeviceChanged(const QString& deviceName); From b6e32621640631a97e69e82f62648f19a63b7933 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 2 Nov 2017 11:31:13 -0700 Subject: [PATCH 056/292] removing the last remaining laserPointers --- .../controllers/controllerModules/teleport.js | 90 +++++++++---------- scripts/system/controllers/grab.js | 18 ++-- 2 files changed, 54 insertions(+), 54 deletions(-) diff --git a/scripts/system/controllers/controllerModules/teleport.js b/scripts/system/controllers/controllerModules/teleport.js index 6d6d93d640..44ee822505 100644 --- a/scripts/system/controllers/controllerModules/teleport.js +++ b/scripts/system/controllers/controllerModules/teleport.js @@ -12,7 +12,7 @@ /* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, getControllerJointIndex, enableDispatcherModule, disableDispatcherModule, Messages, makeDispatcherModuleParameters, makeRunningValues, Vec3, - LaserPointers, RayPick, HMD, Uuid, AvatarList, Picks + RayPick, HMD, Uuid, AvatarList, Picks, Pointers, PickType */ Script.include("/~/system/libraries/Xform.js"); @@ -149,7 +149,7 @@ Script.include("/~/system/libraries/controllers.js"); return otherModule; }; - this.teleportRayHandVisible = LaserPointers.createLaserPointer({ + this.teleportRayHandVisible = Pointers.createPointer(PickType.Ray, { joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand", filter: Picks.PICK_ENTITIES, faceAvatar: true, @@ -157,14 +157,14 @@ Script.include("/~/system/libraries/controllers.js"); renderStates: teleportRenderStates, defaultRenderStates: teleportDefaultRenderStates }); - this.teleportRayHandInvisible = LaserPointers.createLaserPointer({ + this.teleportRayHandInvisible = Pointers.createPointer(PickType.Ray, { joint: (_this.hand === RIGHT_HAND) ? "RightHand" : "LeftHand", filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, centerEndY: false, renderStates: teleportRenderStates }); - this.teleportRayHeadVisible = LaserPointers.createLaserPointer({ + this.teleportRayHeadVisible = Pointers.createPointer(PickType.Ray, { joint: "Avatar", filter: Picks.PICK_ENTITIES, faceAvatar: true, @@ -172,7 +172,7 @@ Script.include("/~/system/libraries/controllers.js"); renderStates: teleportRenderStates, defaultRenderStates: teleportDefaultRenderStates }); - this.teleportRayHeadInvisible = LaserPointers.createLaserPointer({ + this.teleportRayHeadInvisible = Pointers.createPointer(PickType.Ray, { joint: "Avatar", filter: Picks.PICK_ENTITIES | Picks.PICK_INCLUDE_INVISIBLE, faceAvatar: true, @@ -181,10 +181,10 @@ Script.include("/~/system/libraries/controllers.js"); }); this.cleanup = function() { - LaserPointers.removeLaserPointer(this.teleportRayHandVisible); - LaserPointers.removeLaserPointer(this.teleportRayHandInvisible); - LaserPointers.removeLaserPointer(this.teleportRayHeadVisible); - LaserPointers.removeLaserPointer(this.teleportRayHeadInvisible); + Pointers.removePointer(this.teleportRayHandVisible); + Pointers.removePointer(this.teleportRayHandInvisible); + Pointers.removePointer(this.teleportRayHeadVisible); + Pointers.removePointer(this.teleportRayHeadInvisible); }; this.buttonPress = function(value) { @@ -221,20 +221,20 @@ Script.include("/~/system/libraries/controllers.js"); {name: "teleport", path: teleportPath, end: teleportEnd}, {name: "seat", path: seatPath, end: seatEnd}]; - LaserPointers.editRenderState(this.teleportRayHandVisible, "cancel", teleportRenderStates[0]); - LaserPointers.editRenderState(this.teleportRayHandInvisible, "cancel", teleportRenderStates[0]); - LaserPointers.editRenderState(this.teleportRayHeadVisible, "cancel", teleportRenderStates[0]); - LaserPointers.editRenderState(this.teleportRayHeadInvisible, "cancel", teleportRenderStates[0]); + Pointers.editRenderState(this.teleportRayHandVisible, "cancel", teleportRenderStates[0]); + Pointers.editRenderState(this.teleportRayHandInvisible, "cancel", teleportRenderStates[0]); + Pointers.editRenderState(this.teleportRayHeadVisible, "cancel", teleportRenderStates[0]); + Pointers.editRenderState(this.teleportRayHeadInvisible, "cancel", teleportRenderStates[0]); - LaserPointers.editRenderState(this.teleportRayHandVisible, "teleport", teleportRenderStates[1]); - LaserPointers.editRenderState(this.teleportRayHandInvisible, "teleport", teleportRenderStates[1]); - LaserPointers.editRenderState(this.teleportRayHeadVisible, "teleport", teleportRenderStates[1]); - LaserPointers.editRenderState(this.teleportRayHeadInvisible, "teleport", teleportRenderStates[1]); + Pointers.editRenderState(this.teleportRayHandVisible, "teleport", teleportRenderStates[1]); + Pointers.editRenderState(this.teleportRayHandInvisible, "teleport", teleportRenderStates[1]); + Pointers.editRenderState(this.teleportRayHeadVisible, "teleport", teleportRenderStates[1]); + Pointers.editRenderState(this.teleportRayHeadInvisible, "teleport", teleportRenderStates[1]); - LaserPointers.editRenderState(this.teleportRayHandVisible, "seat", teleportRenderStates[2]); - LaserPointers.editRenderState(this.teleportRayHandInvisible, "seat", teleportRenderStates[2]); - LaserPointers.editRenderState(this.teleportRayHeadVisible, "seat", teleportRenderStates[2]); - LaserPointers.editRenderState(this.teleportRayHeadInvisible, "seat", teleportRenderStates[2]); + Pointers.editRenderState(this.teleportRayHandVisible, "seat", teleportRenderStates[2]); + Pointers.editRenderState(this.teleportRayHandInvisible, "seat", teleportRenderStates[2]); + Pointers.editRenderState(this.teleportRayHeadVisible, "seat", teleportRenderStates[2]); + Pointers.editRenderState(this.teleportRayHeadInvisible, "seat", teleportRenderStates[2]); } }; @@ -254,15 +254,15 @@ Script.include("/~/system/libraries/controllers.js"); var pose = Controller.getPoseValue(handInfo[(_this.hand === RIGHT_HAND) ? 'right' : 'left'].controllerInput); var mode = pose.valid ? _this.hand : 'head'; if (!pose.valid) { - LaserPointers.disableLaserPointer(_this.teleportRayHandVisible); - LaserPointers.disableLaserPointer(_this.teleportRayHandInvisible); - LaserPointers.enableLaserPointer(_this.teleportRayHeadVisible); - LaserPointers.enableLaserPointer(_this.teleportRayHeadInvisible); + Pointers.disablePointer(_this.teleportRayHandVisible); + Pointers.disablePointer(_this.teleportRayHandInvisible); + Pointers.enablePointer(_this.teleportRayHeadVisible); + Pointers.enablePointer(_this.teleportRayHeadInvisible); } else { - LaserPointers.enableLaserPointer(_this.teleportRayHandVisible); - LaserPointers.enableLaserPointer(_this.teleportRayHandInvisible); - LaserPointers.disableLaserPointer(_this.teleportRayHeadVisible); - LaserPointers.disableLaserPointer(_this.teleportRayHeadInvisible); + Pointers.enablePointer(_this.teleportRayHandVisible); + Pointers.enablePointer(_this.teleportRayHandInvisible); + Pointers.disablePointer(_this.teleportRayHeadVisible); + Pointers.disablePointer(_this.teleportRayHeadInvisible); } // We do up to 2 ray picks to find a teleport location. @@ -276,17 +276,17 @@ Script.include("/~/system/libraries/controllers.js"); // var result; if (mode === 'head') { - result = LaserPointers.getPrevRayPickResult(_this.teleportRayHeadInvisible); + result = Pointers.getPrevPickResult(_this.teleportRayHeadInvisible); } else { - result = LaserPointers.getPrevRayPickResult(_this.teleportRayHandInvisible); + result = Pointers.getPrevPickResult(_this.teleportRayHandInvisible); } var teleportLocationType = getTeleportTargetType(result); if (teleportLocationType === TARGET.INVISIBLE) { if (mode === 'head') { - result = LaserPointers.getPrevRayPickResult(_this.teleportRayHeadVisible); + result = Pointers.getPrevPickResult(_this.teleportRayHeadVisible); } else { - result = LaserPointers.getPrevRayPickResult(_this.teleportRayHandVisible); + result = Pointers.getPrevPickResult(_this.teleportRayHandVisible); } teleportLocationType = getTeleportTargetType(result); } @@ -332,27 +332,27 @@ Script.include("/~/system/libraries/controllers.js"); }; this.disableLasers = function() { - LaserPointers.disableLaserPointer(_this.teleportRayHandVisible); - LaserPointers.disableLaserPointer(_this.teleportRayHandInvisible); - LaserPointers.disableLaserPointer(_this.teleportRayHeadVisible); - LaserPointers.disableLaserPointer(_this.teleportRayHeadInvisible); + Pointers.disablePointer(_this.teleportRayHandVisible); + Pointers.disablePointer(_this.teleportRayHandInvisible); + Pointers.disablePointer(_this.teleportRayHeadVisible); + Pointers.disablePointer(_this.teleportRayHeadInvisible); }; this.setTeleportState = function(mode, visibleState, invisibleState) { if (mode === 'head') { - LaserPointers.setRenderState(_this.teleportRayHeadVisible, visibleState); - LaserPointers.setRenderState(_this.teleportRayHeadInvisible, invisibleState); + Pointers.setRenderState(_this.teleportRayHeadVisible, visibleState); + Pointers.setRenderState(_this.teleportRayHeadInvisible, invisibleState); } else { - LaserPointers.setRenderState(_this.teleportRayHandVisible, visibleState); - LaserPointers.setRenderState(_this.teleportRayHandInvisible, invisibleState); + Pointers.setRenderState(_this.teleportRayHandVisible, visibleState); + Pointers.setRenderState(_this.teleportRayHandInvisible, invisibleState); } }; this.setIgnoreEntities = function(entitiesToIgnore) { - LaserPointers.setIgnoreItems(this.teleportRayHandVisible, entitiesToIgnore); - LaserPointers.setIgnoreItems(this.teleportRayHandInvisible, entitiesToIgnore); - LaserPointers.setIgnoreItems(this.teleportRayHeadVisible, entitiesToIgnore); - LaserPointers.setIgnoreItems(this.teleportRayHeadInvisible, entitiesToIgnore); + Pointers.setIgnoreItems(this.teleportRayHandVisible, entitiesToIgnore); + Pointers.setIgnoreItems(this.teleportRayHandInvisible, entitiesToIgnore); + Pointers.setIgnoreItems(this.teleportRayHeadVisible, entitiesToIgnore); + Pointers.setIgnoreItems(this.teleportRayHeadInvisible, entitiesToIgnore); }; } diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 7e575e38b0..7a6b190d44 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -15,7 +15,7 @@ // /* global MyAvatar, Entities, Script, Camera, Vec3, Reticle, Overlays, getEntityCustomData, Messages, Quat, Controller, - isInEditMode, HMD entityIsGrabbable*/ + isInEditMode, HMD entityIsGrabbable, Pointers, PickType RayPick*/ (function() { // BEGIN LOCAL_SCOPE @@ -265,7 +265,7 @@ function Grabber() { }); RayPick.setIncludeItems(this.mouseRayOverlays, [HMD.tabletID, HMD.tabletScreenID, HMD.homeButtonID]); var renderStates = [{name: "grabbed", end: beacon}]; - this.mouseRayEntities = LaserPointers.createLaserPointer({ + this.mouseRayEntities = Pointers.createPointer(PickType.Ray, { joint: "Mouse", filter: Picks.PICK_ENTITIES, faceAvatar: true, @@ -325,9 +325,9 @@ Grabber.prototype.pressEvent = function(event) { return; } - var pickResults = LaserPointers.getPrevRayPickResult(this.mouseRayEntities); + var pickResults = Pointers.getPrevPickResult(this.mouseRayEntities); if (pickResults.type == Picks.INTERSECTED_NONE) { - LaserPointers.setRenderState(this.mouseRayEntities, ""); + Pointers.setRenderState(this.mouseRayEntities, ""); return; } @@ -344,8 +344,8 @@ Grabber.prototype.pressEvent = function(event) { return; } - LaserPointers.setRenderState(this.mouseRayEntities, "grabbed"); - LaserPointers.setLockEndUUID(this.mouseRayEntities, pickResults.objectID, false); + Pointers.setRenderState(this.mouseRayEntities, "grabbed"); + Pointers.setLockEndUid(this.mouseRayEntities, pickResults.objectID, false); mouse.startDrag(event); @@ -358,7 +358,7 @@ Grabber.prototype.pressEvent = function(event) { var objectBoundingDiameter = Vec3.length(entityProperties.dimensions); beacon.dimensions.y = objectBoundingDiameter; - LaserPointers.editRenderState(this.mouseRayEntities, "grabbed", {end: beacon}); + Pointers.editRenderState(this.mouseRayEntities, "grabbed", {end: beacon}); this.maxDistance = objectBoundingDiameter / MAX_SOLID_ANGLE; if (Vec3.distance(this.startPosition, cameraPosition) > this.maxDistance) { // don't allow grabs of things far away @@ -435,7 +435,7 @@ Grabber.prototype.releaseEvent = function(event) { this.actionID = null; - LaserPointers.setRenderState(this.mouseRayEntities, ""); + Pointers.setRenderState(this.mouseRayEntities, ""); var args = "mouse"; Entities.callEntityMethod(this.entityID, "releaseGrab", args); @@ -590,7 +590,7 @@ Grabber.prototype.keyPressEvent = function(event) { }; Grabber.prototype.cleanup = function() { - LaserPointers.removeLaserPointer(this.mouseRayEntities); + Pointers.removePointer(this.mouseRayEntities); RayPick.removeRayPick(this.mouseRayOverlays); }; From 53c6eeb58bdf5082bccf686fb91c0852b3cf1f43 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 2 Nov 2017 15:58:50 -0700 Subject: [PATCH 057/292] updatePosition now setPosition --- libraries/entities/src/EntityItem.cpp | 6 +++--- libraries/entities/src/EntityItem.h | 3 +-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 2ab960ef81..e4f88f6856 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -735,7 +735,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // reasons and the contract is that the client handles them in an idempotent manner. auto customUpdatePositionFromNetwork = [this, shouldUpdate, lastEdited](glm::vec3 value){ if (shouldUpdate(_lastUpdatedPositionTimestamp, value != _lastUpdatedPositionValue)) { - updatePosition(value); + setPosition(value); _lastUpdatedPositionTimestamp = lastEdited; _lastUpdatedPositionValue = value; } @@ -1316,7 +1316,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { // these affect TerseUpdate properties SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, updatePosition); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocity, setVelocity); SET_ENTITY_PROPERTY_FROM_PROPERTIES(angularVelocity, setAngularVelocity); @@ -1691,7 +1691,7 @@ void EntityItem::setRegistrationPoint(const glm::vec3& value) { } } -void EntityItem::updatePosition(const glm::vec3& value) { +void EntityItem::setPosition(const glm::vec3& value) { if (getLocalPosition() != value) { setLocalPosition(value); diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 80fe1b3352..a57e4fefda 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -347,8 +347,7 @@ public: virtual void setCollisionShape(const btCollisionShape* shape) {} - // updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags - void updatePosition(const glm::vec3& value); + void setPosition(const glm::vec3& value); virtual void setParentID(const QUuid& parentID); virtual void setRotation(glm::quat orientation); virtual void setVelocity(const glm::vec3& velocity); From 68e9ec9b23862e00295c4dbe084a09cd1a44449d Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 2 Nov 2017 16:36:45 -0700 Subject: [PATCH 058/292] Use qCDebug instead of qDebug in audio-mixer --- assignment-client/src/audio/AudioMixer.cpp | 34 +++++++++---------- .../src/audio/AudioMixerClientData.cpp | 17 +++++----- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 9ed6c7fdbc..7f088d8183 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -29,6 +29,7 @@ #include #include +#include "AudioLogging.h" #include "AudioHelpers.h" #include "AudioRingBuffer.h" #include "AudioMixerClientData.h" @@ -130,7 +131,7 @@ void AudioMixer::queueReplicatedAudioPacket(QSharedPointer mess PacketType rewrittenType = PacketTypeEnum::getReplicatedPacketMapping().key(message->getType()); if (rewrittenType == PacketType::Unknown) { - qDebug() << "Cannot unwrap replicated packet type not present in REPLICATED_PACKET_WRAPPING"; + qCDebug(audio) << "Cannot unwrap replicated packet type not present in REPLICATED_PACKET_WRAPPING"; } auto replicatedMessage = QSharedPointer::create(audioData, rewrittenType, @@ -345,7 +346,7 @@ void AudioMixer::sendStatsPacket() { void AudioMixer::run() { - qDebug() << "Waiting for connection to domain to request settings from domain-server."; + qCDebug(audio) << "Waiting for connection to domain to request settings from domain-server."; // wait until we have the domain-server settings, otherwise we bail DomainHandler& domainHandler = DependencyManager::get()->getDomainHandler(); @@ -502,14 +503,14 @@ void AudioMixer::throttle(std::chrono::microseconds duration, int frame) { int proportionalTerm = 1 + (_trailingMixRatio - TARGET) / 0.1f; _throttlingRatio += THROTTLE_RATE * proportionalTerm; _throttlingRatio = std::min(_throttlingRatio, 1.0f); - qDebug("audio-mixer is struggling (%f mix/sleep) - throttling %f of streams", - (double)_trailingMixRatio, (double)_throttlingRatio); + qCDebug(audio) << "audio-mixer is struggling (" << _trailingMixRatio << "mix/sleep) - throttling" + << _throttlingRatio << "of streams"; } else if (_throttlingRatio > 0.0f && _trailingMixRatio <= BACKOFF_TARGET) { int proportionalTerm = 1 + (TARGET - _trailingMixRatio) / 0.2f; _throttlingRatio -= BACKOFF_RATE * proportionalTerm; _throttlingRatio = std::max(_throttlingRatio, 0.0f); - qDebug("audio-mixer is recovering (%f mix/sleep) - throttling %f of streams", - (double)_trailingMixRatio, (double)_throttlingRatio); + qCDebug(audio) << "audio-mixer is recovering (" << _trailingMixRatio << "mix/sleep) - throttling" + << _throttlingRatio << "of streams"; } } } @@ -534,7 +535,7 @@ void AudioMixer::clearDomainSettings() { } void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { - qDebug() << "AVX2 Support:" << (cpuSupportsAVX2() ? "enabled" : "disabled"); + qCDebug(audio) << "AVX2 Support:" << (cpuSupportsAVX2() ? "enabled" : "disabled"); if (settingsObject.contains(AUDIO_THREADING_GROUP_KEY)) { QJsonObject audioThreadingGroupObject = settingsObject[AUDIO_THREADING_GROUP_KEY].toObject(); @@ -557,7 +558,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { const QString DYNAMIC_JITTER_BUFFER_JSON_KEY = "dynamic_jitter_buffer"; bool enableDynamicJitterBuffer = audioBufferGroupObject[DYNAMIC_JITTER_BUFFER_JSON_KEY].toBool(); if (enableDynamicJitterBuffer) { - qDebug() << "Enabling dynamic jitter buffers."; + qCDebug(audio) << "Enabling dynamic jitter buffers."; bool ok; const QString DESIRED_JITTER_BUFFER_FRAMES_KEY = "static_desired_jitter_buffer_frames"; @@ -565,9 +566,9 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { if (!ok) { _numStaticJitterFrames = InboundAudioStream::DEFAULT_STATIC_JITTER_FRAMES; } - qDebug() << "Static desired jitter buffer frames:" << _numStaticJitterFrames; + qCDebug(audio) << "Static desired jitter buffer frames:" << _numStaticJitterFrames; } else { - qDebug() << "Disabling dynamic jitter buffers."; + qCDebug(audio) << "Disabling dynamic jitter buffers."; _numStaticJitterFrames = DISABLE_STATIC_JITTER_FRAMES; } @@ -621,7 +622,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { if (audioEnvGroupObject[CODEC_PREFERENCE_ORDER].isString()) { QString codecPreferenceOrder = audioEnvGroupObject[CODEC_PREFERENCE_ORDER].toString(); _codecPreferenceOrder = codecPreferenceOrder.split(","); - qDebug() << "Codec preference order changed to" << _codecPreferenceOrder; + qCDebug(audio) << "Codec preference order changed to" << _codecPreferenceOrder; } const QString ATTENATION_PER_DOULING_IN_DISTANCE = "attenuation_per_doubling_in_distance"; @@ -630,7 +631,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { float attenuation = audioEnvGroupObject[ATTENATION_PER_DOULING_IN_DISTANCE].toString().toFloat(&ok); if (ok) { _attenuationPerDoublingInDistance = attenuation; - qDebug() << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance; + qCDebug(audio) << "Attenuation per doubling in distance changed to" << _attenuationPerDoublingInDistance; } } @@ -640,7 +641,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { float noiseMutingThreshold = audioEnvGroupObject[NOISE_MUTING_THRESHOLD].toString().toFloat(&ok); if (ok) { _noiseMutingThreshold = noiseMutingThreshold; - qDebug() << "Noise muting threshold changed to" << _noiseMutingThreshold; + qCDebug(audio) << "Noise muting threshold changed to" << _noiseMutingThreshold; } } @@ -680,8 +681,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { glm::vec3 dimensions(xMax - xMin, yMax - yMin, zMax - zMin); AABox zoneAABox(corner, dimensions); _audioZones.insert(zone, zoneAABox); - qDebug() << "Added zone:" << zone << "(corner:" << corner - << ", dimensions:" << dimensions << ")"; + qCDebug(audio) << "Added zone:" << zone << "(corner:" << corner << ", dimensions:" << dimensions << ")"; } } } @@ -712,7 +712,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { _audioZones.contains(settings.source) && _audioZones.contains(settings.listener)) { _zoneSettings.push_back(settings); - qDebug() << "Added Coefficient:" << settings.source << settings.listener << settings.coefficient; + qCDebug(audio) << "Added Coefficient:" << settings.source << settings.listener << settings.coefficient; } } } @@ -745,7 +745,7 @@ void AudioMixer::parseSettingsObject(const QJsonObject& settingsObject) { _zoneReverbSettings.push_back(settings); - qDebug() << "Added Reverb:" << zone << reverbTime << wetLevel; + qCDebug(audio) << "Added Reverb:" << zone << reverbTime << wetLevel; } } } diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 3b3d6549ee..49453c6fc6 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -19,6 +19,7 @@ #include "InjectedAudioStream.h" +#include "AudioLogging.h" #include "AudioHelpers.h" #include "AudioMixer.h" #include "AudioMixerClientData.h" @@ -132,7 +133,7 @@ void AudioMixerClientData::optionallyReplicatePacket(ReceivedMessage& message, c if (PacketTypeEnum::getReplicatedPacketMapping().key(message.getType()) != PacketType::Unknown) { mirroredType = message.getType(); } else { - qDebug() << "Packet passed to optionallyReplicatePacket was not a replicatable type - returning"; + qCDebug(audio) << "Packet passed to optionallyReplicatePacket was not a replicatable type - returning"; return; } } @@ -193,11 +194,11 @@ void AudioMixerClientData::parsePerAvatarGainSet(ReceivedMessage& message, const if (avatarUuid.isNull()) { // set the MASTER avatar gain setMasterAvatarGain(gain); - qDebug() << "Setting MASTER avatar gain for " << uuid << " to " << gain; + qCDebug(audio) << "Setting MASTER avatar gain for " << uuid << " to " << gain; } else { // set the per-source avatar gain hrtfForStream(avatarUuid, QUuid()).setGainAdjustment(gain); - qDebug() << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUuid << "] to " << gain; + qCDebug(audio) << "Setting avatar gain adjustment for hrtf[" << uuid << "][" << avatarUuid << "] to " << gain; } } @@ -284,7 +285,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { auto avatarAudioStream = new AvatarAudioStream(isStereo, AudioMixer::getStaticJitterFrames()); avatarAudioStream->setupCodec(_codec, _selectedCodecName, AudioConstants::MONO); - qDebug() << "creating new AvatarAudioStream... codec:" << _selectedCodecName; + qCDebug(audio) << "creating new AvatarAudioStream... codec:" << _selectedCodecName; connect(avatarAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioMixerClientData::handleMismatchAudioFormat); @@ -323,7 +324,7 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { #if INJECTORS_SUPPORT_CODECS injectorStream->setupCodec(_codec, _selectedCodecName, isStereo ? AudioConstants::STEREO : AudioConstants::MONO); - qDebug() << "creating new injectorStream... codec:" << _selectedCodecName; + qCDebug(audio) << "creating new injectorStream... codec:" << _selectedCodecName; #endif auto emplaced = _audioStreams.emplace( @@ -347,8 +348,8 @@ int AudioMixerClientData::parseData(ReceivedMessage& message) { auto parseResult = matchingStream->parseData(message); if (matchingStream->getOverflowCount() > overflowBefore) { - qDebug() << "Just overflowed on stream from" << message.getSourceID() << "at" << message.getSenderSockAddr(); - qDebug() << "This stream is for" << (isMicStream ? "microphone audio" : "injected audio"); + qCDebug(audio) << "Just overflowed on stream from" << message.getSourceID() << "at" << message.getSenderSockAddr(); + qCDebug(audio) << "This stream is for" << (isMicStream ? "microphone audio" : "injected audio"); } return parseResult; @@ -697,7 +698,7 @@ void AudioMixerClientData::setupCodecForReplicatedAgent(QSharedPointerreadString(); if (codecString != _selectedCodecName) { - qDebug() << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID()) + qCDebug(audio) << "Manually setting codec for replicated agent" << uuidStringWithoutCurlyBraces(getNodeID()) << "-" << codecString; const std::pair codec = AudioMixer::negotiateCodec({ codecString }); From b5199220ab459aaffd0539612543c4cf3952f46c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 2 Nov 2017 17:07:53 -0700 Subject: [PATCH 059/292] cleanup SpatiallyNestable Velocity to match WorldVelocity naming --- interface/src/avatar/AvatarMotionState.cpp | 4 +-- interface/src/avatar/MyAvatar.cpp | 12 +++---- interface/src/ui/OverlayConductor.cpp | 2 +- interface/src/ui/Stats.cpp | 2 +- .../src/avatars-renderer/Avatar.cpp | 6 ++-- libraries/avatars/src/AvatarData.h | 4 +-- libraries/avatars/src/ScriptAvatarData.cpp | 4 +-- libraries/entities/src/EntityItem.h | 13 +++---- .../entities/src/EntityScriptingInterface.cpp | 4 +-- libraries/entities/src/PolyLineEntityItem.h | 2 +- libraries/physics/src/EntityMotionState.cpp | 6 ++-- libraries/physics/src/EntityMotionState.h | 4 +-- libraries/shared/src/SpatiallyNestable.cpp | 34 +++++++++---------- libraries/shared/src/SpatiallyNestable.h | 16 ++++----- 14 files changed, 57 insertions(+), 56 deletions(-) diff --git a/interface/src/avatar/AvatarMotionState.cpp b/interface/src/avatar/AvatarMotionState.cpp index 4f6f2b0b71..900c1c0a11 100644 --- a/interface/src/avatar/AvatarMotionState.cpp +++ b/interface/src/avatar/AvatarMotionState.cpp @@ -116,12 +116,12 @@ glm::quat AvatarMotionState::getObjectRotation() const { // virtual glm::vec3 AvatarMotionState::getObjectLinearVelocity() const { - return _avatar->getVelocity(); + return _avatar->getWorldVelocity(); } // virtual glm::vec3 AvatarMotionState::getObjectAngularVelocity() const { - return _avatar->getAngularVelocity(); + return _avatar->getWorldAngularVelocity(); } // virtual diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index bfaae00f68..5427f3974d 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1617,13 +1617,13 @@ void MyAvatar::harvestResultsFromPhysicsSimulation(float deltaTime) { _bodySensorMatrix = _follow.postPhysicsUpdate(*this, _bodySensorMatrix); if (_characterController.isEnabledAndReady()) { - setVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity()); + setWorldVelocity(_characterController.getLinearVelocity() + _characterController.getFollowVelocity()); if (_characterController.isStuck()) { _physicsSafetyPending = true; _goToPosition = getWorldPosition(); } } else { - setVelocity(getVelocity() + _characterController.getFollowVelocity()); + setWorldVelocity(getWorldVelocity() + _characterController.getFollowVelocity()); } } @@ -1962,7 +1962,7 @@ void MyAvatar::updateOrientation(float deltaTime) { if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover && _hmdRollControlEnabled && hasDriveInput()) { // Turn with head roll. const float MIN_CONTROL_SPEED = 0.01f; - float speed = glm::length(getVelocity()); + float speed = glm::length(getWorldVelocity()); if (speed >= MIN_CONTROL_SPEED) { // Feather turn when stopping moving. float speedFactor; @@ -1973,7 +1973,7 @@ void MyAvatar::updateOrientation(float deltaTime) { speedFactor = glm::min(speed / _lastDrivenSpeed, 1.0f); } - float direction = glm::dot(getVelocity(), getWorldOrientation() * Vectors::UNIT_NEG_Z) > 0.0f ? 1.0f : -1.0f; + float direction = glm::dot(getWorldVelocity(), getWorldOrientation() * Vectors::UNIT_NEG_Z) > 0.0f ? 1.0f : -1.0f; float rollAngle = glm::degrees(asinf(glm::dot(IDENTITY_UP, _hmdSensorOrientation * IDENTITY_RIGHT))); float rollSign = rollAngle < 0.0f ? -1.0f : 1.0f; @@ -2084,7 +2084,7 @@ void MyAvatar::updatePosition(float deltaTime) { updateActionMotor(deltaTime); } - vec3 velocity = getVelocity(); + vec3 velocity = getWorldVelocity(); float sensorToWorldScale = getSensorToWorldScale(); float sensorToWorldScale2 = sensorToWorldScale * sensorToWorldScale; const float MOVING_SPEED_THRESHOLD_SQUARED = 0.0001f; // 0.01 m/s @@ -2896,7 +2896,7 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co } float MyAvatar::getAccelerationEnergy() { - glm::vec3 velocity = getVelocity(); + glm::vec3 velocity = getWorldVelocity(); int changeInVelocity = abs(velocity.length() - priorVelocity.length()); float changeInEnergy = priorVelocity.length() * changeInVelocity * AVATAR_MOVEMENT_ENERGY_CONSTANT; priorVelocity = velocity; diff --git a/interface/src/ui/OverlayConductor.cpp b/interface/src/ui/OverlayConductor.cpp index dbf58c5cbc..ed8fa53fe2 100644 --- a/interface/src/ui/OverlayConductor.cpp +++ b/interface/src/ui/OverlayConductor.cpp @@ -49,7 +49,7 @@ bool OverlayConductor::updateAvatarIsAtRest() { const quint64 REST_DISABLE_TIME_USECS = 200 * 1000; // 200 ms const float AT_REST_THRESHOLD = 0.01f; - bool desiredAtRest = glm::length(myAvatar->getVelocity()) < AT_REST_THRESHOLD; + bool desiredAtRest = glm::length(myAvatar->getWorldVelocity()) < AT_REST_THRESHOLD; if (desiredAtRest != _desiredAtRest) { // start timer _desiredAtRestTimer = usecTimestampNow() + (desiredAtRest ? REST_ENABLE_TIME_USECS : REST_DISABLE_TIME_USECS); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 4fa5e5726b..e194551add 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -194,7 +194,7 @@ void Stats::updateStats(bool force) { auto myAvatar = avatarManager->getMyAvatar(); glm::vec3 avatarPos = myAvatar->getWorldPosition(); STAT_UPDATE(position, QVector3D(avatarPos.x, avatarPos.y, avatarPos.z)); - STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getVelocity()), 0.01f); + STAT_UPDATE_FLOAT(speed, glm::length(myAvatar->getWorldVelocity()), 0.01f); STAT_UPDATE_FLOAT(yaw, myAvatar->getBodyYaw(), 0.1f); if (_expanded || force) { SharedNodePointer avatarMixer = nodeList->soloNodeOfType(NodeType::AvatarMixer); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 072eb22532..881f30299e 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -436,7 +436,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { void Avatar::slamPosition(const glm::vec3& newPosition) { setWorldPosition(newPosition); _positionDeltaAccumulator = glm::vec3(0.0f); - setVelocity(glm::vec3(0.0f)); + setWorldVelocity(glm::vec3(0.0f)); _lastVelocity = glm::vec3(0.0f); } @@ -460,13 +460,13 @@ void Avatar::measureMotionDerivatives(float deltaTime) { _positionDeltaAccumulator = glm::vec3(0.0f); _acceleration = (velocity - _lastVelocity) * invDeltaTime; _lastVelocity = velocity; - setVelocity(velocity); + setWorldVelocity(velocity); // angular glm::quat orientation = getWorldOrientation(); glm::quat delta = glm::inverse(_lastOrientation) * orientation; glm::vec3 angularVelocity = glm::axis(delta) * glm::angle(delta) * invDeltaTime; - setAngularVelocity(angularVelocity); + setWorldAngularVelocity(angularVelocity); _lastOrientation = getWorldOrientation(); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 61e27a482e..cad547b03c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -365,8 +365,8 @@ class AvatarData : public QObject, public SpatiallyNestable { Q_PROPERTY(float headYaw READ getHeadYaw WRITE setHeadYaw) Q_PROPERTY(float headRoll READ getHeadRoll WRITE setHeadRoll) - Q_PROPERTY(glm::vec3 velocity READ getVelocity WRITE setVelocity) - Q_PROPERTY(glm::vec3 angularVelocity READ getAngularVelocity WRITE setAngularVelocity) + Q_PROPERTY(glm::vec3 velocity READ getWorldVelocity WRITE setWorldVelocity) + Q_PROPERTY(glm::vec3 angularVelocity READ getWorldAngularVelocity WRITE setWorldAngularVelocity) Q_PROPERTY(float audioLoudness READ getAudioLoudness WRITE setAudioLoudness) Q_PROPERTY(float audioAverageLoudness READ getAudioAverageLoudness WRITE setAudioAverageLoudness) diff --git a/libraries/avatars/src/ScriptAvatarData.cpp b/libraries/avatars/src/ScriptAvatarData.cpp index 6a57bab0b7..64cd534c8b 100644 --- a/libraries/avatars/src/ScriptAvatarData.cpp +++ b/libraries/avatars/src/ScriptAvatarData.cpp @@ -110,14 +110,14 @@ float ScriptAvatarData::getHeadRoll() const { // glm::vec3 ScriptAvatarData::getVelocity() const { if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) { - return sharedAvatarData->getVelocity(); + return sharedAvatarData->getWorldVelocity(); } else { return glm::vec3(); } } glm::vec3 ScriptAvatarData::getAngularVelocity() const { if (AvatarSharedPointer sharedAvatarData = _avatarData.lock()) { - return sharedAvatarData->getAngularVelocity(); + return sharedAvatarData->getWorldAngularVelocity(); } else { return glm::vec3(); } diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index a57e4fefda..403c41704b 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -192,7 +192,7 @@ public: float getDensity() const; - bool hasVelocity() const { return getVelocity() != ENTITY_ITEM_ZERO_VEC3; } + bool hasVelocity() const { return getWorldVelocity() != ENTITY_ITEM_ZERO_VEC3; } bool hasLocalVelocity() const { return getLocalVelocity() != ENTITY_ITEM_ZERO_VEC3; } glm::vec3 getGravity() const; /// get gravity in meters @@ -254,9 +254,9 @@ public: glm::vec3 getRegistrationPoint() const; /// registration point as ratio of entity /// registration point as ratio of entity - virtual void setRegistrationPoint(const glm::vec3& value); + virtual void setRegistrationPoint(const glm::vec3& value); // FIXME: this is suspicious! - bool hasAngularVelocity() const { return getAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } + bool hasAngularVelocity() const { return getWorldAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } bool hasLocalAngularVelocity() const { return getLocalAngularVelocity() != ENTITY_ITEM_ZERO_VEC3; } virtual void setAngularVelocity(const glm::vec3& angularVelocity); @@ -292,7 +292,7 @@ public: void setLocked(bool value); QString getUserData() const; - virtual void setUserData(const QString& value); + virtual void setUserData(const QString& value); // FIXME: This is suspicious // FIXME not thread safe? const SimulationOwner& getSimulationOwner() const { return _simulationOwner; } @@ -349,10 +349,11 @@ public: void setPosition(const glm::vec3& value); virtual void setParentID(const QUuid& parentID); - virtual void setRotation(glm::quat orientation); - virtual void setVelocity(const glm::vec3& velocity); virtual void setShapeType(ShapeType type) { /* do nothing */ } + void setRotation(glm::quat orientation); + void setVelocity(const glm::vec3& velocity); + uint32_t getDirtyFlags() const; void markDirtyFlags(uint32_t mask); void clearDirtyFlags(uint32_t mask = 0xffffffff); diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index 8382bc1920..155ec5b84a 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -376,7 +376,7 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& // If any of these changed, pull any missing properties from the entity. //existing entity, retrieve old velocity for check down below - oldVelocity = entity->getVelocity().length(); + oldVelocity = entity->getWorldVelocity().length(); if (!scriptSideProperties.parentIDChanged()) { properties.setParentID(entity->getParentID()); @@ -532,7 +532,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) { auto dimensions = entity->getDimensions(); float volume = dimensions.x * dimensions.y * dimensions.z; auto density = entity->getDensity(); - auto velocity = entity->getVelocity().length(); + auto velocity = entity->getWorldVelocity().length(); float cost = calculateCost(density * volume, velocity, 0); cost *= costMultiplier; diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index 7e47ce3aa7..3164a9646b 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -99,7 +99,7 @@ class PolyLineEntityItem : public EntityItem { void** intersectedObject, bool precisionPicking) const override { return false; } // disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain - virtual void setRegistrationPoint(const glm::vec3& value) override {}; + virtual void setRegistrationPoint(const glm::vec3& value) override {}; // FIXME: this is suspicious! virtual void debugDump() const override; static const float DEFAULT_LINE_WIDTH; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index da98e838b0..8ebce9f811 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -125,7 +125,7 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) { if (flags & Simulation::DIRTY_SIMULATOR_ID) { if (_entity->getSimulatorID().isNull()) { // simulation ownership has been removed by an external simulator - if (glm::length2(_entity->getVelocity()) == 0.0f) { + if (glm::length2(_entity->getWorldVelocity()) == 0.0f) { // this object is coming to rest --> clear the ACTIVATION flag and _outgoingPriority flags &= ~Simulation::DIRTY_PHYSICS_ACTIVATION; _body->setActivationState(WANTS_DEACTIVATION); @@ -542,8 +542,8 @@ void EntityMotionState::sendUpdate(OctreeEditPacketSender* packetSender, uint32_ const float DYNAMIC_ANGULAR_VELOCITY_THRESHOLD = 0.087266f; // ~5 deg/sec bool movingSlowlyLinear = - glm::length2(_entity->getVelocity()) < (DYNAMIC_LINEAR_VELOCITY_THRESHOLD * DYNAMIC_LINEAR_VELOCITY_THRESHOLD); - bool movingSlowlyAngular = glm::length2(_entity->getAngularVelocity()) < + glm::length2(_entity->getWorldVelocity()) < (DYNAMIC_LINEAR_VELOCITY_THRESHOLD * DYNAMIC_LINEAR_VELOCITY_THRESHOLD); + bool movingSlowlyAngular = glm::length2(_entity->getWorldAngularVelocity()) < (DYNAMIC_ANGULAR_VELOCITY_THRESHOLD * DYNAMIC_ANGULAR_VELOCITY_THRESHOLD); bool movingSlowly = movingSlowlyLinear && movingSlowlyAngular && _entity->getAcceleration() == Vectors::ZERO; diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 2bb692da81..ddfd7e1e4c 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -59,8 +59,8 @@ public: virtual glm::vec3 getObjectPosition() const override { return _entity->getWorldPosition() - ObjectMotionState::getWorldOffset(); } virtual glm::quat getObjectRotation() const override { return _entity->getWorldOrientation(); } - virtual glm::vec3 getObjectLinearVelocity() const override { return _entity->getVelocity(); } - virtual glm::vec3 getObjectAngularVelocity() const override { return _entity->getAngularVelocity(); } + virtual glm::vec3 getObjectLinearVelocity() const override { return _entity->getWorldVelocity(); } + virtual glm::vec3 getObjectAngularVelocity() const override { return _entity->getWorldAngularVelocity(); } virtual glm::vec3 getObjectGravity() const override { return _entity->getGravity(); } virtual glm::vec3 getObjectLinearVelocityChange() const override; diff --git a/libraries/shared/src/SpatiallyNestable.cpp b/libraries/shared/src/SpatiallyNestable.cpp index a931a524fd..2114cbf944 100644 --- a/libraries/shared/src/SpatiallyNestable.cpp +++ b/libraries/shared/src/SpatiallyNestable.cpp @@ -240,7 +240,7 @@ glm::vec3 SpatiallyNestable::worldToLocalVelocity(const glm::vec3& velocity, con if (!success) { return velocity; } - glm::vec3 parentVelocity = parent->getVelocity(success); + glm::vec3 parentVelocity = parent->getWorldVelocity(success); if (!success) { return velocity; } @@ -345,7 +345,7 @@ glm::vec3 SpatiallyNestable::localToWorldVelocity(const glm::vec3& velocity, con if (!success) { return velocity; } - glm::vec3 parentVelocity = parent->getVelocity(success); + glm::vec3 parentVelocity = parent->getWorldVelocity(success); if (!success) { return velocity; } @@ -473,7 +473,7 @@ void SpatiallyNestable::setWorldOrientation(const glm::quat& orientation) { #endif } -glm::vec3 SpatiallyNestable::getVelocity(bool& success) const { +glm::vec3 SpatiallyNestable::getWorldVelocity(bool& success) const { glm::vec3 result; Transform parentTransform = getParentTransform(success); if (!success) { @@ -490,16 +490,16 @@ glm::vec3 SpatiallyNestable::getVelocity(bool& success) const { return result; } -glm::vec3 SpatiallyNestable::getVelocity() const { +glm::vec3 SpatiallyNestable::getWorldVelocity() const { bool success; - glm::vec3 result = getVelocity(success); + glm::vec3 result = getWorldVelocity(success); if (!success) { - qCDebug(shared) << "Warning -- getVelocity failed" << getID(); + qCDebug(shared) << "Warning -- getWorldVelocity failed" << getID(); } return result; } -void SpatiallyNestable::setVelocity(const glm::vec3& velocity, bool& success) { +void SpatiallyNestable::setWorldVelocity(const glm::vec3& velocity, bool& success) { glm::vec3 parentVelocity = getParentVelocity(success); Transform parentTransform = getParentTransform(success); _velocityLock.withWriteLock([&] { @@ -518,9 +518,9 @@ void SpatiallyNestable::setVelocity(const glm::vec3& velocity, bool& success) { }); } -void SpatiallyNestable::setVelocity(const glm::vec3& velocity) { +void SpatiallyNestable::setWorldVelocity(const glm::vec3& velocity) { bool success; - setVelocity(velocity, success); + setWorldVelocity(velocity, success); if (!success) { qCDebug(shared) << "Warning -- setVelocity failed" << getID(); } @@ -533,12 +533,12 @@ glm::vec3 SpatiallyNestable::getParentVelocity(bool& success) const { return result; } if (parent) { - result = parent->getVelocity(success); + result = parent->getWorldVelocity(success); } return result; } -glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const { +glm::vec3 SpatiallyNestable::getWorldAngularVelocity(bool& success) const { glm::vec3 result; Transform parentTransform = getParentTransform(success); if (!success) { @@ -554,16 +554,16 @@ glm::vec3 SpatiallyNestable::getAngularVelocity(bool& success) const { return result; } -glm::vec3 SpatiallyNestable::getAngularVelocity() const { +glm::vec3 SpatiallyNestable::getWorldAngularVelocity() const { bool success; - glm::vec3 result = getAngularVelocity(success); + glm::vec3 result = getWorldAngularVelocity(success); if (!success) { qCDebug(shared) << "Warning -- getAngularVelocity failed" << getID(); } return result; } -void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity, bool& success) { +void SpatiallyNestable::setWorldAngularVelocity(const glm::vec3& angularVelocity, bool& success) { glm::vec3 parentAngularVelocity = getParentAngularVelocity(success); Transform parentTransform = getParentTransform(success); _angularVelocityLock.withWriteLock([&] { @@ -571,9 +571,9 @@ void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity, boo }); } -void SpatiallyNestable::setAngularVelocity(const glm::vec3& angularVelocity) { +void SpatiallyNestable::setWorldAngularVelocity(const glm::vec3& angularVelocity) { bool success; - setAngularVelocity(angularVelocity, success); + setWorldAngularVelocity(angularVelocity, success); if (!success) { qCDebug(shared) << "Warning -- setAngularVelocity failed" << getID(); } @@ -586,7 +586,7 @@ glm::vec3 SpatiallyNestable::getParentAngularVelocity(bool& success) const { return result; } if (parent) { - result = parent->getAngularVelocity(success); + result = parent->getWorldAngularVelocity(success); } return result; } diff --git a/libraries/shared/src/SpatiallyNestable.h b/libraries/shared/src/SpatiallyNestable.h index 929c2d53f2..9cd38f9ce9 100644 --- a/libraries/shared/src/SpatiallyNestable.h +++ b/libraries/shared/src/SpatiallyNestable.h @@ -89,16 +89,16 @@ public: virtual void setWorldOrientation(const glm::quat& orientation, bool& success, bool tellPhysics = true); virtual void setWorldOrientation(const glm::quat& orientation); - virtual glm::vec3 getVelocity(bool& success) const; - virtual glm::vec3 getVelocity() const; - virtual void setVelocity(const glm::vec3& velocity, bool& success); - virtual void setVelocity(const glm::vec3& velocity); + virtual glm::vec3 getWorldVelocity(bool& success) const; + virtual glm::vec3 getWorldVelocity() const; + virtual void setWorldVelocity(const glm::vec3& velocity, bool& success); + virtual void setWorldVelocity(const glm::vec3& velocity); virtual glm::vec3 getParentVelocity(bool& success) const; - virtual glm::vec3 getAngularVelocity(bool& success) const; - virtual glm::vec3 getAngularVelocity() const; - virtual void setAngularVelocity(const glm::vec3& angularVelocity, bool& success); - virtual void setAngularVelocity(const glm::vec3& angularVelocity); + virtual glm::vec3 getWorldAngularVelocity(bool& success) const; + virtual glm::vec3 getWorldAngularVelocity() const; + virtual void setWorldAngularVelocity(const glm::vec3& angularVelocity, bool& success); + virtual void setWorldAngularVelocity(const glm::vec3& angularVelocity); virtual glm::vec3 getParentAngularVelocity(bool& success) const; virtual AACube getMaximumAACube(bool& success) const; From baff900839e61c7a207256d53cd767bb1f4b186a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 2 Nov 2017 17:46:15 -0700 Subject: [PATCH 060/292] cleanup some writeLocks --- libraries/entities/src/EntityItem.cpp | 135 ++++++++++++++------------ 1 file changed, 73 insertions(+), 62 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index e4f88f6856..5b90d75b58 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1734,9 +1734,11 @@ void EntityItem::setParentID(const QUuid& value) { void EntityItem::setDimensions(const glm::vec3& value) { glm::vec3 newDimensions = glm::max(value, glm::vec3(0.0f)); // can never have negative dimensions if (getDimensions() != newDimensions) { - _dimensions = newDimensions; - markDirtyFlags(Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); - _queryAACubeSet = false; + withWriteLock([&] { + _dimensions = newDimensions; + _dirtyFlags |= (Simulation::DIRTY_SHAPE | Simulation::DIRTY_MASS); + _queryAACubeSet = false; + }); locationChanged(); dimensionsChanged(); } @@ -1783,29 +1785,33 @@ void EntityItem::setVelocity(const glm::vec3& value) { void EntityItem::setDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); - if (_damping != clampedDamping) { - _damping = clampedDamping; - _dirtyFlags |= Simulation::DIRTY_MATERIAL; - } + withWriteLock([&] { + if (_damping != clampedDamping) { + _damping = clampedDamping; + _dirtyFlags |= Simulation::DIRTY_MATERIAL; + } + }); } void EntityItem::setGravity(const glm::vec3& value) { - if (_gravity != value) { - if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { - _gravity = Vectors::ZERO; - } else { - float magnitude = glm::length(value); - if (!glm::isnan(magnitude)) { - const float MAX_ACCELERATION_OF_GRAVITY = 10.0f * 9.8f; // 10g - if (magnitude > MAX_ACCELERATION_OF_GRAVITY) { - _gravity = (MAX_ACCELERATION_OF_GRAVITY / magnitude) * value; - } else { - _gravity = value; + withWriteLock([&] { + if (_gravity != value) { + if (getShapeType() == SHAPE_TYPE_STATIC_MESH) { + _gravity = Vectors::ZERO; + } else { + float magnitude = glm::length(value); + if (!glm::isnan(magnitude)) { + const float MAX_ACCELERATION_OF_GRAVITY = 10.0f * 9.8f; // 10g + if (magnitude > MAX_ACCELERATION_OF_GRAVITY) { + _gravity = (MAX_ACCELERATION_OF_GRAVITY / magnitude) * value; + } else { + _gravity = value; + } + _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; } - _dirtyFlags |= Simulation::DIRTY_LINEAR_VELOCITY; } } - } + }); } void EntityItem::setAngularVelocity(const glm::vec3& value) { @@ -1834,47 +1840,58 @@ void EntityItem::setAngularVelocity(const glm::vec3& value) { void EntityItem::setAngularDamping(float value) { auto clampedDamping = glm::clamp(value, 0.0f, 1.0f); - if (_angularDamping != clampedDamping) { - _angularDamping = clampedDamping; - _dirtyFlags |= Simulation::DIRTY_MATERIAL; - } + withWriteLock([&] { + if (_angularDamping != clampedDamping) { + _angularDamping = clampedDamping; + _dirtyFlags |= Simulation::DIRTY_MATERIAL; + } + }); } void EntityItem::setCollisionless(bool value) { - if (_collisionless != value) { - _collisionless = value; - _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; - } + withWriteLock([&] { + if (_collisionless != value) { + _collisionless = value; + _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; + } + }); } void EntityItem::setCollisionMask(uint8_t value) { - if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) { - _collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT); - _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; - } + withWriteLock([&] { + if ((_collisionMask & ENTITY_COLLISION_MASK_DEFAULT) != (value & ENTITY_COLLISION_MASK_DEFAULT)) { + _collisionMask = (value & ENTITY_COLLISION_MASK_DEFAULT); + _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; + } + }); } void EntityItem::setDynamic(bool value) { if (getDynamic() != value) { - // dynamic and STATIC_MESH are incompatible so we check for that case - if (value && getShapeType() == SHAPE_TYPE_STATIC_MESH) { - if (_dynamic) { - _dynamic = false; + withWriteLock([&] { + // dynamic and STATIC_MESH are incompatible so we check for that case + if (value && getShapeType() == SHAPE_TYPE_STATIC_MESH) { + if (_dynamic) { + _dynamic = false; + _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; + } + } else { + _dynamic = value; _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; } - } else { - _dynamic = value; - _dirtyFlags |= Simulation::DIRTY_MOTION_TYPE; - } + }); } } void EntityItem::setRestitution(float value) { float clampedValue = glm::max(glm::min(ENTITY_ITEM_MAX_RESTITUTION, value), ENTITY_ITEM_MIN_RESTITUTION); - if (_restitution != clampedValue) { - _restitution = clampedValue; - _dirtyFlags |= Simulation::DIRTY_MATERIAL; - } + withWriteLock([&] { + if (_restitution != clampedValue) { + _restitution = clampedValue; + _dirtyFlags |= Simulation::DIRTY_MATERIAL; + } + }); + } void EntityItem::setFriction(float value) { @@ -1888,17 +1905,21 @@ void EntityItem::setFriction(float value) { } void EntityItem::setLifetime(float value) { - if (_lifetime != value) { - _lifetime = value; - _dirtyFlags |= Simulation::DIRTY_LIFETIME; - } + withWriteLock([&] { + if (_lifetime != value) { + _lifetime = value; + _dirtyFlags |= Simulation::DIRTY_LIFETIME; + } + }); } void EntityItem::setCreated(uint64_t value) { - if (_created != value) { - _created = value; - _dirtyFlags |= Simulation::DIRTY_LIFETIME; - } + withWriteLock([&] { + if (_created != value) { + _created = value; + _dirtyFlags |= Simulation::DIRTY_LIFETIME; + } + }); } void EntityItem::computeCollisionGroupAndFinalMask(int16_t& group, int16_t& mask) const { @@ -1970,16 +1991,6 @@ void EntityItem::setSimulationOwner(const QUuid& id, quint8 priority) { _simulationOwner.set(id, priority); } -/* -void EntityItem::setSimulationOwner(const SimulationOwner& owner) { - if (wantTerseEditLogging() && _simulationOwner != owner) { - qCDebug(entities) << "sim ownership for" << getDebugName() << "is now" << owner; - } - - _simulationOwner.set(owner); -} -*/ - void EntityItem::setSimulationOwner(const SimulationOwner& owner) { // NOTE: this method only used by EntityServer. The Interface uses special code in readEntityDataFromBuffer(). if (wantTerseEditLogging() && _simulationOwner != owner) { From dd4275430b830309ae4a341605c1599e81dcf055 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Thu, 2 Nov 2017 17:48:37 -0700 Subject: [PATCH 061/292] fix hover events, working on HUD events --- interface/src/Application.cpp | 36 ++++++++++ interface/src/Application.h | 2 + .../src/raypick/PointerScriptingInterface.h | 2 +- interface/src/ui/overlays/Web3DOverlay.cpp | 27 +++---- .../src/RenderableWebEntityItem.cpp | 10 +-- .../src/pointers/PickCacheOptimizer.h | 9 +-- libraries/pointers/src/pointers/Pointer.cpp | 70 +++++++++++++------ libraries/pointers/src/pointers/Pointer.h | 2 + libraries/shared/src/PointerEvent.h | 9 ++- libraries/ui/CMakeLists.txt | 3 +- libraries/ui/src/ui/OffscreenQmlSurface.cpp | 59 +++------------- libraries/ui/src/ui/OffscreenQmlSurface.h | 5 -- 12 files changed, 129 insertions(+), 105 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3a1f970438..d81332e7d5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1504,6 +1504,14 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); }); + auto pointerManager = DependencyManager::get(); + connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &Application::handleHUDPointerEvent); + connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &Application::handleHUDPointerEvent); + connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &Application::handleHUDPointerEvent); + connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &Application::handleHUDPointerEvent); + connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &Application::handleHUDPointerEvent); + connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &Application::handleHUDPointerEvent); + // Add periodic checks to send user activity data static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000; static int NEARBY_AVATAR_RADIUS_METERS = 10; @@ -7479,4 +7487,32 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) { _avatarOverrideUrl = url; _saveAvatarOverrideUrl = save; } + +void Application::handleHUDPointerEvent(const QUuid& id, const PointerEvent& event) { + QEvent::Type type = QEvent::Type::MouseMove; + switch (event.getType()) { + case PointerEvent::Press: + type = QEvent::Type::MouseButtonPress; + break; + case PointerEvent::DoublePress: + type = QEvent::Type::MouseButtonDblClick; + break; + case PointerEvent::Release: + type = QEvent::Type::MouseButtonRelease; + break; + case PointerEvent::Move: + type = QEvent::Type::MouseMove; + break; + default: + break; + } + + QPointF screenPos(event.getPos2D().x, event.getPos2D().y); + //QMouseEvent mouseEvent(type, screenPos, Qt::MouseButton(event.getButton()), Qt::MouseButtons(event.getButtons()), event.getKeyboardModifiers()); + QMouseEvent moveEvent(QEvent::Type::MouseMove, screenPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + sendEvent(_glWidget, &moveEvent); + QMouseEvent mouseEvent(type, screenPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); + sendEvent(_glWidget, &mouseEvent); +} + #include "Application.moc" diff --git a/interface/src/Application.h b/interface/src/Application.h index d2a55db216..a229c4b91a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -434,6 +434,8 @@ private slots: void handleSandboxStatus(QNetworkReply* reply); void switchDisplayMode(); + + void handleHUDPointerEvent(const QUuid& id, const PointerEvent& event); private: static void initDisplay(); void init(); diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 722ba8cec5..8ea9594fda 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -35,7 +35,7 @@ public slots: Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities) const; Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities) const; - Q_INVOKABLE void setLockEndUid(unsigned int uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } + Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } signals: void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent); diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 5339deba2b..b8683b43e3 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -160,14 +160,6 @@ void Web3DOverlay::buildWebSurface() { QObject::connect(_webSurface.data(), &OffscreenQmlSurface::webEventReceived, this, &Web3DOverlay::webEventReceived); } -void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) { - if ((_pressed || (!_activeTouchPoints.empty() && _touchBeginAccepted))) { - PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), - event.getButton(), event.getButtons(), event.getKeyboardModifiers()); - handlePointerEvent(endEvent); - } -} - void Web3DOverlay::update(float deltatime) { if (_webSurface) { // update globalPosition @@ -348,6 +340,17 @@ void Web3DOverlay::setProxyWindow(QWindow* proxyWindow) { _webSurface->setProxyWindow(proxyWindow); } +void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) { + if ((_pressed || (!_activeTouchPoints.empty() && _touchBeginAccepted)) && event.sendReleaseOnHoverLeave()) { + PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), + event.getButton(), event.getButtons(), event.getKeyboardModifiers()); + handlePointerEvent(endEvent); + // QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited. + PointerEvent endMoveEvent(PointerEvent::Move, event.getID()); + handlePointerEvent(endMoveEvent); + } +} + void Web3DOverlay::handlePointerEvent(const PointerEvent& event) { if (event.getType() == PointerEvent::Press) { _pressed = true; @@ -386,7 +389,7 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) { } if (state == Qt::TouchPointReleased && _activeTouchPoints.size() == 1 && _activeTouchPoints.count(event.getID())) { // If the last active touch point is being released, send an end touchType = QEvent::TouchEnd; - } + } { QTouchEvent::TouchPoint point; @@ -428,7 +431,7 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) { #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) if (event.getType() == PointerEvent::Move) { - QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier); + QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); } #endif @@ -446,7 +449,7 @@ void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) { #if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) if (event.getType() == PointerEvent::Move) { - QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier); + QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); } #endif @@ -485,7 +488,7 @@ void Web3DOverlay::handlePointerEventAsMouse(const PointerEvent& event) { return; } - QMouseEvent mouseEvent(type, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier); + QMouseEvent mouseEvent(type, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); } diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index ad4230c55b..cdeba865ba 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -315,11 +315,13 @@ void WebEntityRenderer::loadSourceURL() { } void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) { - if (!_lastLocked && _webSurface && _pressed) { - // If the user mouses off the entity while the button is down, simulate a touch end. + if (!_lastLocked && _webSurface && _pressed && event.sendReleaseOnHoverLeave()) { PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), event.getButton(), event.getButtons(), event.getKeyboardModifiers()); handlePointerEvent(endEvent); + // QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited. + PointerEvent endMoveEvent(PointerEvent::Move, event.getID()); + handlePointerEvent(endMoveEvent); } } @@ -396,7 +398,7 @@ void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) { #if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) if (event.getType() == PointerEvent::Move) { - QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier); + QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); } #endif @@ -414,7 +416,7 @@ void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) { #if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) if (event.getType() == PointerEvent::Move) { - QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, Qt::NoModifier); + QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); } #endif diff --git a/libraries/pointers/src/pointers/PickCacheOptimizer.h b/libraries/pointers/src/pointers/PickCacheOptimizer.h index f3bdbb87b0..18285f3a6f 100644 --- a/libraries/pointers/src/pointers/PickCacheOptimizer.h +++ b/libraries/pointers/src/pointers/PickCacheOptimizer.h @@ -71,18 +71,15 @@ void PickCacheOptimizer::update(QHash> pick = std::static_pointer_cast>(picks[uid]); - if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f) { - continue; - } T mathematicalPick = pick->getMathematicalPick(); + PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap()); - if (!mathematicalPick) { + if (!pick->isEnabled() || pick->getFilter().doesPickNothing() || pick->getMaxDistance() < 0.0f || !mathematicalPick) { + pick->setPickResult(res); continue; } - PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap()); - if (pick->getFilter().doesPickEntities()) { PickCacheKey entityKey = { pick->getFilter().getEntityFlags(), pick->getIncludeItems(), pick->getIgnoreItems() }; if (!checkAndCompareCachedResults(mathematicalPick, results, res, entityKey)) { diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index f57bded5ad..354669a55e 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -59,14 +59,45 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p // TODO: avatars? auto pointerManager = DependencyManager::get(); + // NOTE: After this loop: _prevButtons = buttons that were removed + // If switching to disabled or should stop triggering, release all buttons + Buttons buttons; + Buttons newButtons; + Buttons sameButtons; + const std::string PRIMARY_BUTTON = "Primary"; + bool primaryPressed = false; + if (_enabled && shouldTrigger()) { + buttons = getPressedButtons(); + primaryPressed = buttons.find(PRIMARY_BUTTON) != buttons.end(); + for (const std::string& button : buttons) { + if (_prevButtons.find(button) == _prevButtons.end()) { + newButtons.insert(button); + } else { + sameButtons.insert(button); + _prevButtons.erase(button); + } + } + } + // Hover events + bool doHover = shouldHover(); Pointer::PickedObject hoveredObject = getHoveredObject(pickResult); PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult); hoveredEvent.setType(PointerEvent::Move); hoveredEvent.setID(pointerID); - // TODO: set buttons on hover events - hoveredEvent.setButton(PointerEvent::NoButtons); - if (_enabled && _hover && shouldHover()) { + bool releaseOnHoverLeave = !primaryPressed || (!_enabled && _prevEnabled) || (!doHover && _prevDoHover); + hoveredEvent.setReleaseOnHoverLeave(releaseOnHoverLeave); + + // if shouldHover && !_prevDoHover, only send hoverBegin + if (_enabled && _hover && doHover && !_prevDoHover) { + if (hoveredObject.type == ENTITY) { + emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); + } else if (hoveredObject.type == OVERLAY) { + emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); + } else if (hoveredObject.type == HUD) { + emit pointerManager->hoverBeginHUD(hoveredObject.objectID, hoveredEvent); + } + } else if (_enabled && _hover && doHover) { if (hoveredObject.type == OVERLAY) { if (_prevHoveredObject.type == OVERLAY) { if (hoveredObject.objectID == _prevHoveredObject.objectID) { @@ -74,6 +105,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } else { PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult); prevHoveredEvent.setID(pointerID); + prevHoveredEvent.setReleaseOnHoverLeave(releaseOnHoverLeave); emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, prevHoveredEvent); emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); } @@ -95,6 +127,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } else { PointerEvent prevHoveredEvent = buildPointerEvent(_prevHoveredObject, pickResult); prevHoveredEvent.setID(pointerID); + prevHoveredEvent.setReleaseOnHoverLeave(releaseOnHoverLeave); emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, prevHoveredEvent); emit pointerManager->hoverBeginEntity(hoveredObject.objectID, hoveredEvent); } @@ -123,20 +156,15 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } } - // Trigger events - Buttons buttons; - Buttons newButtons; - Buttons sameButtons; - // NOTE: After this loop: _prevButtons = buttons that were removed - // If switching to disabled or should stop triggering, release all buttons - if (_enabled && shouldTrigger()) { - buttons = getPressedButtons(); - for (const std::string& button : buttons) { - if (_prevButtons.find(button) == _prevButtons.end()) { - newButtons.insert(button); - } else { - sameButtons.insert(button); - _prevButtons.erase(button); + if (_hover) { + // send hoverEnd events if we disable the pointer, disable hovering, or actually stop hovering over an object + if ((!_enabled && _prevEnabled) || (!doHover && _prevDoHover) || (hoveredObject.type == NONE && _prevHoveredObject.type != NONE)) { + if (_prevHoveredObject.type == ENTITY) { + emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); + } else if (_prevHoveredObject.type == OVERLAY) { + emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent); + } else if (_prevHoveredObject.type == HUD) { + emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent); } } } @@ -156,15 +184,13 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } _triggeredObjects[button] = hoveredObject; } - // We still want other trigger events for Focus buttons, but they only set focus on triggerBegin - hoveredEvent.setShouldFocus(false); // Trigger continue for (const std::string& button : sameButtons) { PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); triggeredEvent.setID(pointerID); triggeredEvent.setType(PointerEvent::Move); - hoveredEvent.setButton(chooseButton(button)); + triggeredEvent.setButton(chooseButton(button)); if (_triggeredObjects[button].type == ENTITY) { emit pointerManager->triggerContinueEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { @@ -179,7 +205,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); triggeredEvent.setID(pointerID); triggeredEvent.setType(PointerEvent::Release); - hoveredEvent.setButton(chooseButton(button)); + triggeredEvent.setButton(chooseButton(button)); if (_triggeredObjects[button].type == ENTITY) { emit pointerManager->triggerEndEntity(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == OVERLAY) { @@ -192,6 +218,8 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p _prevHoveredObject = hoveredObject; _prevButtons = buttons; + _prevEnabled = _enabled; + _prevDoHover = doHover; } PointerEvent::Button Pointer::chooseButton(const std::string& button) { diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index fc43e121f0..d8661436b9 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -89,6 +89,8 @@ protected: private: PickedObject _prevHoveredObject; Buttons _prevButtons; + bool _prevEnabled { false }; + bool _prevDoHover { false }; std::unordered_map _triggeredObjects; PointerEvent::Button chooseButton(const std::string& button); diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index 239e7c6e4e..f6b1a81602 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -37,9 +37,9 @@ public: PointerEvent(); PointerEvent(EventType type, uint32_t id, - const glm::vec2& pos2D, const glm::vec3& pos3D, - const glm::vec3& normal, const glm::vec3& direction, - Button button, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::KeyboardModifier::NoModifier); + const glm::vec2& pos2D = glm::vec2(NAN), const glm::vec3& pos3D = glm::vec3(NAN), + const glm::vec3& normal = glm::vec3(NAN), const glm::vec3& direction = glm::vec3(NAN), + Button button = NoButtons, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::KeyboardModifier::NoModifier); static QScriptValue toScriptValue(QScriptEngine* engine, const PointerEvent& event); static void fromScriptValue(const QScriptValue& object, PointerEvent& event); @@ -56,11 +56,13 @@ public: uint32_t getButtons() const { return _buttons; } Qt::KeyboardModifiers getKeyboardModifiers() const { return _keyboardModifiers; } bool shouldFocus() const { return _shouldFocus; } + bool sendReleaseOnHoverLeave() const { return _releaseOnHoverLeave; } void setID(uint32_t id) { _id = id; } void setType(EventType type) { _type = type; } void setButton(Button button); void setShouldFocus(bool focus) { _shouldFocus = focus; } + void setReleaseOnHoverLeave(bool releaseOnHoverLeave) { _releaseOnHoverLeave = releaseOnHoverLeave; } private: EventType _type; @@ -75,6 +77,7 @@ private: Qt::KeyboardModifiers _keyboardModifiers; // set of keys held when event was generated bool _shouldFocus { true }; + bool _releaseOnHoverLeave { true }; }; QDebug& operator<<(QDebug& dbg, const PointerEvent& p); diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index 334cce97e5..f28157ff97 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,7 +1,6 @@ set(TARGET_NAME ui) setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns) -link_hifi_libraries(shared networking gl audio pointers) -include_hifi_library_headers(controllers) +link_hifi_libraries(shared networking gl audio) # Required for some low level GL interaction in the OffscreenQMLSurface target_opengl() diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 204986090c..08662031da 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -49,8 +49,6 @@ #include "Logging.h" -#include - Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml") Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl") Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus") @@ -531,13 +529,6 @@ bool OffscreenQmlSurface::allowNewFrame(uint8_t fps) { } OffscreenQmlSurface::OffscreenQmlSurface() { - auto pointerManager = DependencyManager::get(); - connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &OffscreenQmlSurface::handlePointerEvent); - connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &OffscreenQmlSurface::handlePointerEvent); - connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &OffscreenQmlSurface::handlePointerEvent); - connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &OffscreenQmlSurface::handlePointerEvent); - connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &OffscreenQmlSurface::handlePointerEvent); - connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &OffscreenQmlSurface::handlePointerEvent); } OffscreenQmlSurface::~OffscreenQmlSurface() { @@ -941,8 +932,14 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even transformedPos, mouseEvent->screenPos(), mouseEvent->button(), mouseEvent->buttons(), mouseEvent->modifiers()); - if (sendMouseEvent(mappedEvent)) { - return true; + if (event->type() == QEvent::MouseMove) { + // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install + // need to investigate into why this crash is happening. + //_qmlContext->setContextProperty("lastMousePosition", mouseEvent.localPos()); + } + mappedEvent.ignore(); + if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) { + return mappedEvent.isAccepted(); } break; } @@ -954,46 +951,6 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even return false; } -void OffscreenQmlSurface::handlePointerEvent(const QUuid& id, const PointerEvent& event) { - if (_paused) { - return; - } - - QEvent::Type type = QEvent::Type::MouseMove; - switch (event.getType()) { - case PointerEvent::Press: - type = QEvent::Type::MouseButtonPress; - break; - case PointerEvent::DoublePress: - type = QEvent::Type::MouseButtonDblClick; - break; - case PointerEvent::Release: - type = QEvent::Type::MouseButtonRelease; - break; - case PointerEvent::Move: - type = QEvent::Type::MouseMove; - break; - default: - break; - } - QPointF screenPos(event.getPos2D().x, event.getPos2D().y); - QMouseEvent mouseEvent(type, screenPos, Qt::MouseButton(event.getButton()), Qt::MouseButtons(event.getButtons()), event.getKeyboardModifiers()); - sendMouseEvent(mouseEvent); -} - -bool OffscreenQmlSurface::sendMouseEvent(QMouseEvent& mouseEvent) { - if (mouseEvent.type() == QEvent::MouseMove) { - // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install - // need to investigate into why this crash is happening. - //_qmlContext->setContextProperty("lastMousePosition", mouseEvent.localPos()); - } - mouseEvent.ignore(); - if (QCoreApplication::sendEvent(_quickWindow, &mouseEvent)) { - return mouseEvent.isAccepted(); - } - return false; -} - void OffscreenQmlSurface::pause() { _paused = true; } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 3deab07411..12ee9e59a1 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -30,8 +30,6 @@ class QQmlContext; class QQmlComponent; class QQuickWindow; class QQuickItem; -class QMouseEvent; -class PointerEvent; // GPU resources are typically buffered for one copy being used by the renderer, // one copy in flight, and one copy being used by the receiver @@ -137,7 +135,6 @@ private: private slots: void updateQuick(); void onFocusObjectChanged(QObject* newFocus); - void handlePointerEvent(const QUuid& id, const PointerEvent& event); private: QQuickWindow* _quickWindow { nullptr }; @@ -164,8 +161,6 @@ private: QWindow* _proxyWindow { nullptr }; QQuickItem* _currentFocusItem { nullptr }; - - bool sendMouseEvent(QMouseEvent& mouseEvent); }; #endif From 74ceab1e680f70d18084336a0e9332340c49ac4a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 2 Nov 2017 19:30:39 -0700 Subject: [PATCH 062/292] fix mac and unic build --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityItem.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 5b90d75b58..a60b98a711 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1913,7 +1913,7 @@ void EntityItem::setLifetime(float value) { }); } -void EntityItem::setCreated(uint64_t value) { +void EntityItem::setCreated(quint64 value) { withWriteLock([&] { if (_created != value) { _created = value; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 403c41704b..a7d8adc472 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -348,7 +348,7 @@ public: virtual void setCollisionShape(const btCollisionShape* shape) {} void setPosition(const glm::vec3& value); - virtual void setParentID(const QUuid& parentID); + virtual void setParentID(const QUuid& parentID) override; virtual void setShapeType(ShapeType type) { /* do nothing */ } void setRotation(glm::quat orientation); From ce58b6c4017b2f0343694417065c6363af33235c Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 3 Nov 2017 17:15:30 -0700 Subject: [PATCH 063/292] trying to fix HUD events, abstracting touch event logic (wip), seth's comments --- interface/src/Application.cpp | 44 +---- interface/src/Application.h | 2 - interface/src/raypick/LaserPointer.cpp | 2 +- .../src/raypick/PickScriptingInterface.cpp | 4 +- .../src/raypick/PointerScriptingInterface.cpp | 2 +- .../src/RenderableWebEntityItem.cpp | 106 +----------- .../src/RenderableWebEntityItem.h | 8 +- libraries/pointers/src/pointers/Pick.h | 9 + .../src/pointers/PickCacheOptimizer.h | 9 +- .../pointers/src/pointers/PickManager.cpp | 10 +- libraries/pointers/src/pointers/PickManager.h | 10 +- libraries/pointers/src/pointers/Pointer.cpp | 18 +- .../pointers/src/pointers/PointerManager.cpp | 16 +- .../pointers/src/pointers/PointerManager.h | 19 +- libraries/shared/src/PointerEvent.cpp | 25 ++- libraries/shared/src/PointerEvent.h | 26 +-- libraries/ui/CMakeLists.txt | 3 +- libraries/ui/src/OffscreenUi.cpp | 42 +++++ libraries/ui/src/OffscreenUi.h | 4 + libraries/ui/src/ui/OffscreenQmlSurface.cpp | 163 +++++++++++++++--- libraries/ui/src/ui/OffscreenQmlSurface.h | 15 +- 21 files changed, 304 insertions(+), 233 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d81332e7d5..d9770818e1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1504,14 +1504,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo setKeyboardFocusEntity(UNKNOWN_ENTITY_ID); }); - auto pointerManager = DependencyManager::get(); - connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &Application::handleHUDPointerEvent); - connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &Application::handleHUDPointerEvent); - connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &Application::handleHUDPointerEvent); - connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &Application::handleHUDPointerEvent); - connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &Application::handleHUDPointerEvent); - connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &Application::handleHUDPointerEvent); - // Add periodic checks to send user activity data static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000; static int NEARBY_AVATAR_RADIUS_METERS = 10; @@ -3304,7 +3296,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { auto offscreenUi = DependencyManager::get(); auto eventPosition = compositor.getMouseEventPosition(event); - QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget); + QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); auto button = event->button(); auto buttons = event->buttons(); // Determine if the ReticleClick Action is 1 and if so, fake include the LeftMouseButton @@ -3350,7 +3342,7 @@ void Application::mousePressEvent(QMouseEvent* event) { offscreenUi->unfocusWindows(); auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); - QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget); + QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), @@ -3380,7 +3372,7 @@ void Application::mousePressEvent(QMouseEvent* event) { void Application::mouseDoublePressEvent(QMouseEvent* event) { auto offscreenUi = DependencyManager::get(); auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); - QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget); + QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), @@ -3406,7 +3398,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { auto offscreenUi = DependencyManager::get(); auto eventPosition = getApplicationCompositor().getMouseEventPosition(event); - QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition, _glWidget); + QPointF transformedPos = offscreenUi->mapToVirtualScreen(eventPosition); QMouseEvent mappedEvent(event->type(), transformedPos, event->screenPos(), event->button(), @@ -7487,32 +7479,4 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) { _avatarOverrideUrl = url; _saveAvatarOverrideUrl = save; } - -void Application::handleHUDPointerEvent(const QUuid& id, const PointerEvent& event) { - QEvent::Type type = QEvent::Type::MouseMove; - switch (event.getType()) { - case PointerEvent::Press: - type = QEvent::Type::MouseButtonPress; - break; - case PointerEvent::DoublePress: - type = QEvent::Type::MouseButtonDblClick; - break; - case PointerEvent::Release: - type = QEvent::Type::MouseButtonRelease; - break; - case PointerEvent::Move: - type = QEvent::Type::MouseMove; - break; - default: - break; - } - - QPointF screenPos(event.getPos2D().x, event.getPos2D().y); - //QMouseEvent mouseEvent(type, screenPos, Qt::MouseButton(event.getButton()), Qt::MouseButtons(event.getButtons()), event.getKeyboardModifiers()); - QMouseEvent moveEvent(QEvent::Type::MouseMove, screenPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); - sendEvent(_glWidget, &moveEvent); - QMouseEvent mouseEvent(type, screenPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier); - sendEvent(_glWidget, &mouseEvent); -} - #include "Application.moc" diff --git a/interface/src/Application.h b/interface/src/Application.h index a229c4b91a..d2a55db216 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -434,8 +434,6 @@ private slots: void handleSandboxStatus(QNetworkReply* reply); void switchDisplayMode(); - - void handleHUDPointerEvent(const QUuid& id, const PointerEvent& event); private: static void initDisplay(); void init(); diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 2506c6222d..7d681cd35d 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -303,7 +303,7 @@ PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const Q } else if (target.type == HUD) { pos2D = DependencyManager::get()->calculatePos2DFromHUD(intersection); } - return PointerEvent(PointerEvent::Move, 0, pos2D, intersection, surfaceNormal, direction, PointerEvent::NoButtons); + return PointerEvent(pos2D, intersection, surfaceNormal, direction); } glm::vec3 LaserPointer::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const { diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index a59e96ccbf..445a7e9b69 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -25,7 +25,7 @@ unsigned int PickScriptingInterface::createPick(const PickQuery::PickType type, case PickQuery::PickType::Ray: return createRayPick(properties); default: - return 0; + return PickManager::INVALID_PICK_ID; } } @@ -78,7 +78,7 @@ unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) { return DependencyManager::get()->addPick(PickQuery::Ray, std::make_shared(position, direction, filter, maxDistance, enabled)); } - return 0; + return PickManager::INVALID_PICK_ID; } void PickScriptingInterface::enablePick(unsigned int uid) { diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index b7211830a8..2f044acc4c 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -26,7 +26,7 @@ unsigned int PointerScriptingInterface::createPointer(const PickQuery::PickType& case PickQuery::PickType::Ray: return createLaserPointer(properties); default: - return 0; + return PointerEvent::INVALID_POINTER_ID; } } diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index cdeba865ba..b87a1a994f 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -315,111 +315,17 @@ void WebEntityRenderer::loadSourceURL() { } void WebEntityRenderer::hoverLeaveEntity(const PointerEvent& event) { - if (!_lastLocked && _webSurface && _pressed && event.sendReleaseOnHoverLeave()) { - PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), - event.getButton(), event.getButtons(), event.getKeyboardModifiers()); - handlePointerEvent(endEvent); - // QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited. - PointerEvent endMoveEvent(PointerEvent::Move, event.getID()); - handlePointerEvent(endMoveEvent); + if (!_lastLocked && _webSurface) { + _webSurface->hoverEndEvent(event, _touchDevice); } } -void WebEntityRenderer::handlePointerEvent(const PointerEvent& event) { +void WebEntityRenderer::handlePointerEvent(PointerEvent& event) { + event.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _lastDPI)); // Ignore mouse interaction if we're locked - if (_lastLocked || !_webSurface) { - return; + if (!_lastLocked && _webSurface) { + _webSurface->handlePointerEvent(event, _touchDevice); } - - if (event.getType() == PointerEvent::Press) { - _pressed = true; - } else if (event.getType() == PointerEvent::Release) { - _pressed = false; - } - - glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _lastDPI); - QPointF windowPoint(windowPos.x, windowPos.y); - - Qt::TouchPointState state = Qt::TouchPointStationary; - if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) { - state = Qt::TouchPointPressed; - } else if (event.getType() == PointerEvent::Release) { - state = Qt::TouchPointReleased; - } else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].pos()) { - state = Qt::TouchPointMoved; - } - - QEvent::Type touchType = QEvent::TouchUpdate; - if (_activeTouchPoints.empty()) { - // If the first active touch point is being created, send a begin - touchType = QEvent::TouchBegin; - } if (state == Qt::TouchPointReleased && _activeTouchPoints.size() == 1 && _activeTouchPoints.count(event.getID())) { - // If the last active touch point is being released, send an end - touchType = QEvent::TouchEnd; - } - - { - QTouchEvent::TouchPoint point; - point.setId(event.getID()); - point.setState(state); - point.setPos(windowPoint); - point.setScreenPos(windowPoint); - _activeTouchPoints[event.getID()] = point; - } - - QTouchEvent touchEvent(touchType, &_touchDevice, event.getKeyboardModifiers()); - { - QList touchPoints; - Qt::TouchPointStates touchPointStates; - for (const auto& entry : _activeTouchPoints) { - touchPointStates |= entry.second.state(); - touchPoints.push_back(entry.second); - } - - touchEvent.setWindow(_webSurface->getWindow()); - touchEvent.setDevice(&_touchDevice); - touchEvent.setTarget(_webSurface->getRootItem()); - touchEvent.setTouchPoints(touchPoints); - touchEvent.setTouchPointStates(touchPointStates); - } - - // Send mouse events to the Web surface so that HTML dialog elements work with mouse press and hover. - // - // In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will - // receive mouse events - Qt::MouseButton button = Qt::NoButton; - Qt::MouseButtons buttons = Qt::NoButton; - if (event.getButton() == PointerEvent::PrimaryButton) { - button = Qt::LeftButton; - } - if (event.getButtons() & PointerEvent::PrimaryButton) { - buttons |= Qt::LeftButton; - } - -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) - if (event.getType() == PointerEvent::Move) { - QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); - QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); - } -#endif - - if (touchType == QEvent::TouchBegin) { - _touchBeginAccepted = QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent); - } else if (_touchBeginAccepted) { - QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent); - } - - // If this was a release event, remove the point from the active touch points - if (state == Qt::TouchPointReleased) { - _activeTouchPoints.erase(event.getID()); - } - -#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) - if (event.getType() == PointerEvent::Move) { - QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); - QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); - } -#endif } void WebEntityRenderer::setProxyWindow(QWindow* proxyWindow) { diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.h b/libraries/entities-renderer/src/RenderableWebEntityItem.h index 8adbc17a75..84f2a6ccb7 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.h +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.h @@ -12,8 +12,6 @@ #include #include "RenderableEntityItem.h" -#include - class OffscreenQmlSurface; class PointerEvent; @@ -28,7 +26,7 @@ public: WebEntityRenderer(const EntityItemPointer& entity); Q_INVOKABLE void hoverLeaveEntity(const PointerEvent& event); - Q_INVOKABLE void handlePointerEvent(const PointerEvent& event); + Q_INVOKABLE void handlePointerEvent(PointerEvent& event); protected: virtual void onRemoveFromSceneTyped(const TypedEntityPointer& entity) override; @@ -66,10 +64,6 @@ private: QTimer _timer; uint64_t _lastRenderTime { 0 }; Transform _renderTransform; - - bool _pressed{ false }; - bool _touchBeginAccepted{ false }; - std::map _activeTouchPoints; }; } } // namespace diff --git a/libraries/pointers/src/pointers/Pick.h b/libraries/pointers/src/pointers/Pick.h index 9ab17f87d8..e4ce5d3dce 100644 --- a/libraries/pointers/src/pointers/Pick.h +++ b/libraries/pointers/src/pointers/Pick.h @@ -206,4 +206,13 @@ public: virtual PickResultPointer getHUDIntersection(const T& pick) = 0; }; +namespace std { + template <> + struct hash { + size_t operator()(const PickQuery::PickType& a) const { + return a; + } + }; +} + #endif // hifi_Pick_h diff --git a/libraries/pointers/src/pointers/PickCacheOptimizer.h b/libraries/pointers/src/pointers/PickCacheOptimizer.h index 18285f3a6f..46038d14b5 100644 --- a/libraries/pointers/src/pointers/PickCacheOptimizer.h +++ b/libraries/pointers/src/pointers/PickCacheOptimizer.h @@ -37,7 +37,7 @@ template class PickCacheOptimizer { public: - void update(QHash>& picks, bool shouldPickHUD); + void update(std::unordered_map>& picks, bool shouldPickHUD); protected: typedef std::unordered_map> PickCache; @@ -67,10 +67,11 @@ void PickCacheOptimizer::cacheResult(const bool intersects, const PickResultP } template -void PickCacheOptimizer::update(QHash>& picks, bool shouldPickHUD) { +void PickCacheOptimizer::update(std::unordered_map>& picks, bool shouldPickHUD) { PickCache results; - for (const auto& uid : picks.keys()) { - std::shared_ptr> pick = std::static_pointer_cast>(picks[uid]); + for (const auto& pickPair : picks) { + unsigned int uid = pickPair.first; + std::shared_ptr> pick = std::static_pointer_cast>(pickPair.second); T mathematicalPick = pick->getMathematicalPick(); PickResultPointer res = pick->getDefaultResult(mathematicalPick.toVariantMap()); diff --git a/libraries/pointers/src/pointers/PickManager.cpp b/libraries/pointers/src/pointers/PickManager.cpp index 903113d79d..cb9d715ba9 100644 --- a/libraries/pointers/src/pointers/PickManager.cpp +++ b/libraries/pointers/src/pointers/PickManager.cpp @@ -13,7 +13,7 @@ PickManager::PickManager() { } unsigned int PickManager::addPick(PickQuery::PickType type, const std::shared_ptr pick) { - unsigned int id = 0; + unsigned int id = INVALID_PICK_ID; withWriteLock([&] { // Don't let the pick IDs overflow if (_nextPickID < UINT32_MAX) { @@ -29,7 +29,7 @@ std::shared_ptr PickManager::findPick(unsigned int uid) const { return resultWithReadLock>([&] { auto type = _typeMap.find(uid); if (type != _typeMap.end()) { - return _picks[type.value()][uid]; + return _picks.find(type->second)->second.find(uid)->second; } return std::shared_ptr(); }); @@ -39,8 +39,8 @@ void PickManager::removePick(unsigned int uid) { withWriteLock([&] { auto type = _typeMap.find(uid); if (type != _typeMap.end()) { - _picks[type.value()].remove(uid); - _typeMap.remove(uid); + _picks[type->second].erase(uid); + _typeMap.erase(uid); } }); } @@ -89,7 +89,7 @@ void PickManager::setIncludeItems(unsigned int uid, const QVector& includ } void PickManager::update() { - QHash>> cachedPicks; + std::unordered_map>> cachedPicks; withReadLock([&] { cachedPicks = _picks; }); diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index 7ff4fcc941..0794ac0a41 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -37,16 +37,16 @@ public: void setCalculatePos2DFromHUDOperator(std::function calculatePos2DFromHUDOperator) { _calculatePos2DFromHUDOperator = calculatePos2DFromHUDOperator; } glm::vec2 calculatePos2DFromHUD(const glm::vec3& intersection) { return _calculatePos2DFromHUDOperator(intersection); } + static const unsigned int INVALID_PICK_ID { 0 }; + protected: std::function _shouldPickHUDOperator; std::function _calculatePos2DFromHUDOperator; std::shared_ptr findPick(unsigned int uid) const; - QHash>> _picks; - QHash _typeMap; - // 0 = invalid - const unsigned int FIRST_PICK_ID { 1 }; - unsigned int _nextPickID { FIRST_PICK_ID }; + std::unordered_map>> _picks; + std::unordered_map _typeMap; + unsigned int _nextPickID { INVALID_PICK_ID + 1 }; PickCacheOptimizer _rayPickCacheOptimizer; }; diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 354669a55e..0fc5c54ad2 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -95,7 +95,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } else if (hoveredObject.type == OVERLAY) { emit pointerManager->hoverBeginOverlay(hoveredObject.objectID, hoveredEvent); } else if (hoveredObject.type == HUD) { - emit pointerManager->hoverBeginHUD(hoveredObject.objectID, hoveredEvent); + emit pointerManager->hoverBeginHUD(hoveredEvent); } } else if (_enabled && _hover && doHover) { if (hoveredObject.type == OVERLAY) { @@ -114,7 +114,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p if (_prevHoveredObject.type == ENTITY) { emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); } else if (_prevHoveredObject.type == HUD) { - emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent); + emit pointerManager->hoverEndHUD(hoveredEvent); } } } @@ -136,7 +136,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p if (_prevHoveredObject.type == OVERLAY) { emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent); } else if (_prevHoveredObject.type == HUD) { - emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent); + emit pointerManager->hoverEndHUD(hoveredEvent); } } } @@ -144,9 +144,9 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p if (hoveredObject.type == HUD) { if (_prevHoveredObject.type == HUD) { // There's only one HUD - emit pointerManager->hoverContinueHUD(hoveredObject.objectID, hoveredEvent); + emit pointerManager->hoverContinueHUD(hoveredEvent); } else { - emit pointerManager->hoverBeginHUD(hoveredObject.objectID, hoveredEvent); + emit pointerManager->hoverBeginHUD(hoveredEvent); if (_prevHoveredObject.type == ENTITY) { emit pointerManager->hoverEndEntity(_prevHoveredObject.objectID, hoveredEvent); } else if (_prevHoveredObject.type == OVERLAY) { @@ -164,7 +164,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } else if (_prevHoveredObject.type == OVERLAY) { emit pointerManager->hoverEndOverlay(_prevHoveredObject.objectID, hoveredEvent); } else if (_prevHoveredObject.type == HUD) { - emit pointerManager->hoverEndHUD(_prevHoveredObject.objectID, hoveredEvent); + emit pointerManager->hoverEndHUD(hoveredEvent); } } } @@ -180,7 +180,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } else if (hoveredObject.type == OVERLAY) { emit pointerManager->triggerBeginOverlay(hoveredObject.objectID, hoveredEvent); } else if (hoveredObject.type == HUD) { - emit pointerManager->triggerBeginHUD(hoveredObject.objectID, hoveredEvent); + emit pointerManager->triggerBeginHUD(hoveredEvent); } _triggeredObjects[button] = hoveredObject; } @@ -196,7 +196,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } else if (_triggeredObjects[button].type == OVERLAY) { emit pointerManager->triggerContinueOverlay(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == HUD) { - emit pointerManager->triggerContinueHUD(_triggeredObjects[button].objectID, triggeredEvent); + emit pointerManager->triggerContinueHUD(triggeredEvent); } } @@ -211,7 +211,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const QVariantMap& p } else if (_triggeredObjects[button].type == OVERLAY) { emit pointerManager->triggerEndOverlay(_triggeredObjects[button].objectID, triggeredEvent); } else if (_triggeredObjects[button].type == HUD) { - emit pointerManager->triggerEndHUD(_triggeredObjects[button].objectID, triggeredEvent); + emit pointerManager->triggerEndHUD(triggeredEvent); } _triggeredObjects.erase(button); } diff --git a/libraries/pointers/src/pointers/PointerManager.cpp b/libraries/pointers/src/pointers/PointerManager.cpp index b6d826c6f1..b117b24770 100644 --- a/libraries/pointers/src/pointers/PointerManager.cpp +++ b/libraries/pointers/src/pointers/PointerManager.cpp @@ -8,19 +8,21 @@ #include "PointerManager.h" +#include "PickManager.h" + std::shared_ptr PointerManager::find(unsigned int uid) const { return resultWithReadLock>([&] { auto itr = _pointers.find(uid); if (itr != _pointers.end()) { - return *itr; + return itr->second; } return std::shared_ptr(); }); } unsigned int PointerManager::addPointer(std::shared_ptr pointer) { - unsigned int result = 0; - if (pointer->getRayUID() > 0) { + unsigned int result = PointerEvent::INVALID_POINTER_ID; + if (pointer->getRayUID() != PickManager::INVALID_PICK_ID) { withWriteLock([&] { // Don't let the pointer IDs overflow if (_nextPointerID < UINT32_MAX) { @@ -34,7 +36,7 @@ unsigned int PointerManager::addPointer(std::shared_ptr pointer) { void PointerManager::removePointer(unsigned int uid) { withWriteLock([&] { - _pointers.remove(uid); + _pointers.erase(uid); }); } @@ -75,12 +77,12 @@ const QVariantMap PointerManager::getPrevPickResult(unsigned int uid) const { } void PointerManager::update() { - auto cachedPointers = resultWithReadLock>>([&] { + auto cachedPointers = resultWithReadLock>>([&] { return _pointers; }); - for (const auto& uid : cachedPointers.keys()) { - cachedPointers[uid]->update(uid); + for (const auto& pointerPair : cachedPointers) { + pointerPair.second->update(pointerPair.first); } } diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index fcb347fb82..a415c9dbd9 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -40,11 +40,12 @@ public: void update(); + static const unsigned int MOUSE_POINTER_ID { PointerEvent::INVALID_POINTER_ID + 1 }; + private: std::shared_ptr find(unsigned int uid) const; - QHash> _pointers; - // 0 = invalid, 1 = reserved for system mouse - unsigned int _nextPointerID { 2 }; + std::unordered_map> _pointers; + unsigned int _nextPointerID { MOUSE_POINTER_ID + 1 }; signals: void triggerBeginOverlay(const QUuid& id, const PointerEvent& pointerEvent); @@ -61,12 +62,12 @@ signals: void hoverContinueEntity(const QUuid& id, const PointerEvent& pointerEvent); void hoverEndEntity(const QUuid& id, const PointerEvent& pointerEvent); - void triggerBeginHUD(const QUuid& id, const PointerEvent& pointerEvent); - void triggerContinueHUD(const QUuid& id, const PointerEvent& pointerEvent); - void triggerEndHUD(const QUuid& id, const PointerEvent& pointerEvent); - void hoverBeginHUD(const QUuid& id, const PointerEvent& pointerEvent); - void hoverContinueHUD(const QUuid& id, const PointerEvent& pointerEvent); - void hoverEndHUD(const QUuid& id, const PointerEvent& pointerEvent); + void triggerBeginHUD(const PointerEvent& pointerEvent); + void triggerContinueHUD(const PointerEvent& pointerEvent); + void triggerEndHUD(const PointerEvent& pointerEvent); + void hoverBeginHUD(const PointerEvent& pointerEvent); + void hoverContinueHUD(const PointerEvent& pointerEvent); + void hoverEndHUD(const PointerEvent& pointerEvent); }; #endif // hifi_pointers_PointerManager_h diff --git a/libraries/shared/src/PointerEvent.cpp b/libraries/shared/src/PointerEvent.cpp index 183b7c332a..f0f868655c 100644 --- a/libraries/shared/src/PointerEvent.cpp +++ b/libraries/shared/src/PointerEvent.cpp @@ -20,8 +20,28 @@ static bool areFlagsSet(uint32_t flags, uint32_t mask) { return (flags & mask) != 0; } -PointerEvent::PointerEvent() { - ; +PointerEvent::PointerEvent(EventType type, uint32_t id) : + _type(type), + _id(id) +{ +} + +PointerEvent::PointerEvent(EventType type, uint32_t id, const glm::vec2& pos2D, Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers) : + _type(type), + _id(id), + _pos2D(pos2D), + _button(button), + _buttons(buttons), + _keyboardModifiers(keyboardModifiers) +{ +} + +PointerEvent::PointerEvent(const glm::vec2& pos2D, const glm::vec3& pos3D, const glm::vec3& normal, const glm::vec3& direction) : + _pos2D(pos2D), + _pos3D(pos3D), + _normal(normal), + _direction(direction) +{ } PointerEvent::PointerEvent(EventType type, uint32_t id, @@ -38,7 +58,6 @@ PointerEvent::PointerEvent(EventType type, uint32_t id, _buttons(buttons), _keyboardModifiers(keyboardModifiers) { - ; } void PointerEvent::setButton(Button button) { diff --git a/libraries/shared/src/PointerEvent.h b/libraries/shared/src/PointerEvent.h index f6b1a81602..6ace262fe1 100644 --- a/libraries/shared/src/PointerEvent.h +++ b/libraries/shared/src/PointerEvent.h @@ -35,11 +35,14 @@ public: NumEventTypes }; - PointerEvent(); + PointerEvent() {} + PointerEvent(EventType type, uint32_t id); + PointerEvent(EventType type, uint32_t id, const glm::vec2& pos2D, Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers); + PointerEvent(const glm::vec2& pos2D, const glm::vec3& pos3D, const glm::vec3& normal, const glm::vec3& direction); PointerEvent(EventType type, uint32_t id, - const glm::vec2& pos2D = glm::vec2(NAN), const glm::vec3& pos3D = glm::vec3(NAN), - const glm::vec3& normal = glm::vec3(NAN), const glm::vec3& direction = glm::vec3(NAN), - Button button = NoButtons, uint32_t buttons = NoButtons, Qt::KeyboardModifiers keyboardModifiers = Qt::KeyboardModifier::NoModifier); + const glm::vec2& pos2D, const glm::vec3& pos3D, + const glm::vec3& normal, const glm::vec3& direction, + Button button, uint32_t buttons, Qt::KeyboardModifiers keyboardModifiers); static QScriptValue toScriptValue(QScriptEngine* engine, const PointerEvent& event); static void fromScriptValue(const QScriptValue& object, PointerEvent& event); @@ -63,18 +66,21 @@ public: void setButton(Button button); void setShouldFocus(bool focus) { _shouldFocus = focus; } void setReleaseOnHoverLeave(bool releaseOnHoverLeave) { _releaseOnHoverLeave = releaseOnHoverLeave; } + void setPos2D(const glm::vec2& pos2D) { _pos2D = pos2D; } + + static const unsigned int INVALID_POINTER_ID { 0 }; private: EventType _type; - uint32_t _id; // used to identify the pointer. (left vs right hand, for example) - glm::vec2 _pos2D; // (in meters) projected onto the xy plane of entities dimension box, (0, 0) is upper right hand corner - glm::vec3 _pos3D; // surface location in world coordinates (in meters) - glm::vec3 _normal; // surface normal - glm::vec3 _direction; // incoming direction of pointer ray. + uint32_t _id { INVALID_POINTER_ID }; // used to identify the pointer. (left vs right hand, for example) + glm::vec2 _pos2D { glm::vec2(NAN) }; // (in meters) projected onto the xy plane of entities dimension box, (0, 0) is upper right hand corner + glm::vec3 _pos3D { glm::vec3(NAN) }; // surface location in world coordinates (in meters) + glm::vec3 _normal { glm::vec3(NAN) }; // surface normal + glm::vec3 _direction { glm::vec3(NAN) }; // incoming direction of pointer ray. Button _button { NoButtons }; // button associated with this event, (if type is Press, this will be the button that is pressed) uint32_t _buttons { NoButtons }; // the current state of all the buttons. - Qt::KeyboardModifiers _keyboardModifiers; // set of keys held when event was generated + Qt::KeyboardModifiers _keyboardModifiers { Qt::KeyboardModifier::NoModifier }; // set of keys held when event was generated bool _shouldFocus { true }; bool _releaseOnHoverLeave { true }; diff --git a/libraries/ui/CMakeLists.txt b/libraries/ui/CMakeLists.txt index f28157ff97..334cce97e5 100644 --- a/libraries/ui/CMakeLists.txt +++ b/libraries/ui/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME ui) setup_hifi_library(OpenGL Network Qml Quick Script WebChannel WebEngine WebSockets XmlPatterns) -link_hifi_libraries(shared networking gl audio) +link_hifi_libraries(shared networking gl audio pointers) +include_hifi_library_headers(controllers) # Required for some low level GL interaction in the OffscreenQMLSurface target_opengl() diff --git a/libraries/ui/src/OffscreenUi.cpp b/libraries/ui/src/OffscreenUi.cpp index 297ed9ca50..c41ef9d4a4 100644 --- a/libraries/ui/src/OffscreenUi.cpp +++ b/libraries/ui/src/OffscreenUi.cpp @@ -28,6 +28,7 @@ #include "ui/Logging.h" +#include // Needs to match the constants in resources/qml/Global.js class OffscreenFlags : public QObject { @@ -84,7 +85,31 @@ bool OffscreenUi::shouldSwallowShortcut(QEvent* event) { return false; } +static QTouchDevice _touchDevice; OffscreenUi::OffscreenUi() { + static std::once_flag once; + std::call_once(once, [&] { + _touchDevice.setCapabilities(QTouchDevice::Position); + _touchDevice.setType(QTouchDevice::TouchScreen); + _touchDevice.setName("OffscreenUiTouchDevice"); + _touchDevice.setMaximumTouchPoints(4); + }); + + auto pointerManager = DependencyManager::get(); + connect(pointerManager.data(), &PointerManager::hoverBeginHUD, this, &OffscreenUi::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::hoverContinueHUD, this, &OffscreenUi::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::hoverEndHUD, this, &OffscreenUi::hoverEndEvent); + connect(pointerManager.data(), &PointerManager::triggerBeginHUD, this, &OffscreenUi::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::triggerContinueHUD, this, &OffscreenUi::handlePointerEvent); + connect(pointerManager.data(), &PointerManager::triggerEndHUD, this, &OffscreenUi::handlePointerEvent); +} + +void OffscreenUi::hoverEndEvent(const PointerEvent& event) { + OffscreenQmlSurface::hoverEndEvent(event, _touchDevice); +} + +void OffscreenUi::handlePointerEvent(const PointerEvent& event) { + OffscreenQmlSurface::handlePointerEvent(event, _touchDevice); } QObject* OffscreenUi::getFlags() { @@ -1072,6 +1097,23 @@ bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) { // let the parent class do it's work bool result = OffscreenQmlSurface::eventFilter(originalDestination, event); + switch (event->type()) { + // Fall through + case QEvent::MouseButtonDblClick: + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + case QEvent::MouseMove: { + QMouseEvent* mouseEvent = static_cast(event); + QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos()); + PointerEvent pointerEvent(choosePointerEventType(mouseEvent->type()), PointerManager::MOUSE_POINTER_ID, glm::vec2(transformedPos.x(), transformedPos.y()), + PointerEvent::Button(mouseEvent->button()), mouseEvent->buttons(), mouseEvent->modifiers()); + result = OffscreenQmlSurface::handlePointerEvent(pointerEvent, _touchDevice); + break; + } + default: + break; + } + // Check if this is a key press/release event that might need special attention auto type = event->type(); diff --git a/libraries/ui/src/OffscreenUi.h b/libraries/ui/src/OffscreenUi.h index 93c55d06f7..0261591295 100644 --- a/libraries/ui/src/OffscreenUi.h +++ b/libraries/ui/src/OffscreenUi.h @@ -249,6 +249,10 @@ signals: public slots: void removeModalDialog(QObject* modal); +private slots: + void hoverEndEvent(const PointerEvent& event); + void handlePointerEvent(const PointerEvent& event); + private: QString fileDialog(const QVariantMap& properties); ModalDialogListener *fileDialogAsync(const QVariantMap &properties); diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 08662031da..e2675008f9 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -855,7 +855,7 @@ QPointF OffscreenQmlSurface::mapWindowToUi(const QPointF& sourcePosition, QObjec return QPointF(offscreenPosition.x, offscreenPosition.y); } -QPointF OffscreenQmlSurface::mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget) { +QPointF OffscreenQmlSurface::mapToVirtualScreen(const QPointF& originalPoint) { return _mouseTranslator(originalPoint); } @@ -909,7 +909,7 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even case QEvent::Wheel: { QWheelEvent* wheelEvent = static_cast(event); - QPointF transformedPos = mapToVirtualScreen(wheelEvent->pos(), originalDestination); + QPointF transformedPos = mapToVirtualScreen(wheelEvent->pos()); QWheelEvent mappedEvent( transformedPos, wheelEvent->delta(), wheelEvent->buttons(), @@ -920,30 +920,6 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even } break; } - - // Fall through - case QEvent::MouseButtonDblClick: - case QEvent::MouseButtonPress: - case QEvent::MouseButtonRelease: - case QEvent::MouseMove: { - QMouseEvent* mouseEvent = static_cast(event); - QPointF transformedPos = mapToVirtualScreen(mouseEvent->localPos(), originalDestination); - QMouseEvent mappedEvent(mouseEvent->type(), - transformedPos, - mouseEvent->screenPos(), mouseEvent->button(), - mouseEvent->buttons(), mouseEvent->modifiers()); - if (event->type() == QEvent::MouseMove) { - // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install - // need to investigate into why this crash is happening. - //_qmlContext->setContextProperty("lastMousePosition", mouseEvent.localPos()); - } - mappedEvent.ignore(); - if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) { - return mappedEvent.isAccepted(); - } - break; - } - default: break; } @@ -951,6 +927,141 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even return false; } +PointerEvent::EventType OffscreenQmlSurface::choosePointerEventType(QEvent::Type type) { + switch (type) { + case QEvent::MouseButtonDblClick: + return PointerEvent::DoublePress; + case QEvent::MouseButtonPress: + return PointerEvent::Press; + case QEvent::MouseButtonRelease: + return PointerEvent::Release; + case QEvent::MouseMove: + return PointerEvent::Move; + default: + return PointerEvent::Move; + } +} + +void OffscreenQmlSurface::hoverEndEvent(const PointerEvent& event, class QTouchDevice& device) { + if (!_paused && _quickWindow && _pressed && event.sendReleaseOnHoverLeave()) { + PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), + event.getButton(), event.getButtons(), event.getKeyboardModifiers()); + handlePointerEvent(endEvent, device); + // QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited. + PointerEvent endMoveEvent(PointerEvent::Move, event.getID()); + handlePointerEvent(endMoveEvent, device); + } +} + +bool OffscreenQmlSurface::handlePointerEvent(const PointerEvent& event, class QTouchDevice& device) { + // Ignore mouse interaction if we're paused + if (_paused || !_quickWindow) { + return false; + } + + if (event.getType() == PointerEvent::Press) { + _pressed = true; + } else if (event.getType() == PointerEvent::Release) { + _pressed = false; + } + + QPointF windowPoint(event.getPos2D().x, event.getPos2D().y); + + Qt::TouchPointState state = Qt::TouchPointStationary; + if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) { + state = Qt::TouchPointPressed; + } else if (event.getType() == PointerEvent::Release) { + state = Qt::TouchPointReleased; + } else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].pos()) { + state = Qt::TouchPointMoved; + } + + QEvent::Type touchType = QEvent::TouchUpdate; + if (_activeTouchPoints.empty()) { + // If the first active touch point is being created, send a begin + touchType = QEvent::TouchBegin; + } if (state == Qt::TouchPointReleased && _activeTouchPoints.size() == 1 && _activeTouchPoints.count(event.getID())) { + // If the last active touch point is being released, send an end + touchType = QEvent::TouchEnd; + } + + { + QTouchEvent::TouchPoint point; + point.setId(event.getID()); + point.setState(state); + point.setPos(windowPoint); + point.setScreenPos(windowPoint); + _activeTouchPoints[event.getID()] = point; + } + + QTouchEvent touchEvent(touchType, &device, event.getKeyboardModifiers()); + { + QList touchPoints; + Qt::TouchPointStates touchPointStates; + for (const auto& entry : _activeTouchPoints) { + touchPointStates |= entry.second.state(); + touchPoints.push_back(entry.second); + } + + touchEvent.setWindow(_quickWindow); + touchEvent.setDevice(&device); + touchEvent.setTarget(_rootItem); + touchEvent.setTouchPoints(touchPoints); + touchEvent.setTouchPointStates(touchPointStates); + } + + // Send mouse events to the surface so that HTML dialog elements work with mouse press and hover. + // + // In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will + // receive mouse events + Qt::MouseButton button = Qt::NoButton; + Qt::MouseButtons buttons = Qt::NoButton; + if (event.getButton() == PointerEvent::PrimaryButton) { + button = Qt::LeftButton; + } + if (event.getButtons() & PointerEvent::PrimaryButton) { + buttons |= Qt::LeftButton; + } + + bool eventsAccepted = false; + +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) + if (event.getType() == PointerEvent::Move) { + QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); + // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install + // need to investigate into why this crash is happening. + //_qmlContext->setContextProperty("lastMousePosition", windowPoint); + QCoreApplication::sendEvent(_quickWindow, &mouseEvent); + eventsAccepted &= mouseEvent.isAccepted(); + } +#endif + + if (touchType == QEvent::TouchBegin) { + _touchBeginAccepted = QCoreApplication::sendEvent(_quickWindow, &touchEvent); + } else if (_touchBeginAccepted) { + QCoreApplication::sendEvent(_quickWindow, &touchEvent); + } + eventsAccepted &= touchEvent.isAccepted(); + + // If this was a release event, remove the point from the active touch points + if (state == Qt::TouchPointReleased) { + _activeTouchPoints.erase(event.getID()); + } + +#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) + if (event.getType() == PointerEvent::Move) { + // TODO - this line necessary for the QML Tooltop to work (which is not currently being used), but it causes interface to crash on launch on a fresh install + // need to investigate into why this crash is happening. + //_qmlContext->setContextProperty("lastMousePosition", windowPoint); + QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); + QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); + eventsAccepted &= mouseEvent.isAccepted(); + } +#endif + + return eventsAccepted; +} + void OffscreenQmlSurface::pause() { _paused = true; } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 12ee9e59a1..1f1817faa2 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -21,6 +21,9 @@ #include #include +#include +#include "PointerEvent.h" + class QWindow; class QMyQuickRenderControl; class OffscreenGLCanvas; @@ -79,7 +82,7 @@ public: QObject* getEventHandler(); QQmlContext* getSurfaceContext(); - QPointF mapToVirtualScreen(const QPointF& originalPoint, QObject* originalWidget); + QPointF mapToVirtualScreen(const QPointF& originalPoint); bool eventFilter(QObject* originalDestination, QEvent* event) override; void setKeyboardRaised(QObject* object, bool raised, bool numeric = false, bool passwordField = false); @@ -95,6 +98,8 @@ public: static std::function getDiscardLambda(); static size_t getUsedTextureMemory(); + PointerEvent::EventType choosePointerEventType(QEvent::Type type); + signals: void focusObjectChanged(QObject* newFocus); void focusTextChanged(bool focusText); @@ -136,6 +141,10 @@ private slots: void updateQuick(); void onFocusObjectChanged(QObject* newFocus); +public slots: + void hoverEndEvent(const PointerEvent& event, class QTouchDevice& device); + bool handlePointerEvent(const PointerEvent& event, class QTouchDevice& device); + private: QQuickWindow* _quickWindow { nullptr }; QMyQuickRenderControl* _renderControl{ nullptr }; @@ -161,6 +170,10 @@ private: QWindow* _proxyWindow { nullptr }; QQuickItem* _currentFocusItem { nullptr }; + + bool _pressed { false }; + bool _touchBeginAccepted { false }; + std::map _activeTouchPoints; }; #endif From ac1df7b8150fe0fbe0b044ea681f53026134c351 Mon Sep 17 00:00:00 2001 From: Menithal Date: Sun, 5 Nov 2017 00:18:48 +0200 Subject: [PATCH 064/292] 21539: Allow HMD to turned off in Desktop Mode --- .../qml/hifi/tablet/OpenVrConfiguration.qml | 37 ++++++++++++++++++- plugins/openvr/src/ViveControllerManager.cpp | 32 ++++++++++++++-- plugins/openvr/src/ViveControllerManager.h | 6 ++- 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index 78c10e2ffa..5e9bf40d41 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -36,7 +36,9 @@ Rectangle { readonly property bool hmdHead: headBox.checked readonly property bool headPuck: headPuckBox.checked readonly property bool handController: handBox.checked + readonly property bool handPuck: handPuckBox.checked + readonly property bool hmdDesktop: hmdInDesktop.checked property int state: buttonState.disabled property var lastConfiguration: null @@ -789,6 +791,7 @@ Rectangle { verticalCenter: viveInDesktop.verticalCenter } } + NumberAnimation { id: numberAnimation @@ -797,6 +800,35 @@ Rectangle { to: 0 } + HifiControls.CheckBox { + id: hmdInDesktop + width: 15 + height: 15 + boxRadius: 7 + + anchors.top: viveInDesktop.bottom + anchors.topMargin: 5 + anchors.left: openVrConfiguration.left + anchors.leftMargin: leftMargin + 10 + + onClicked: { + sendConfigurationSettings(); + } + } + + RalewayBold { + id: hmdDesktopText + size: 10 + text: "Use HMD in desktop mode" + color: hifi.colors.white + + anchors { + left: hmdInDesktop.right + leftMargin: 5 + verticalCenter: hmdInDesktop.verticalCenter + } + } + function logAction(action, status) { console.log("calibrated from ui"); var data = { @@ -877,6 +909,7 @@ Rectangle { var HmdHead = settings["HMDHead"]; var viveController = settings["handController"]; var desktopMode = settings["desktopMode"]; + var hmdDesktopPosition = settings["hmdDesktopTracking"]; armCircumference.value = settings.armCircumference; shoulderWidth.value = settings.shoulderWidth; @@ -898,6 +931,7 @@ Rectangle { } viveInDesktop.checked = desktopMode; + hmdInDesktop.checked = hmdDesktopPosition; initializeButtonState(); updateCalibrationText(); @@ -1058,7 +1092,8 @@ Rectangle { "handConfiguration": handObject, "armCircumference": armCircumference.value, "shoulderWidth": shoulderWidth.value, - "desktopMode": viveInDesktop.checked + "desktopMode": viveInDesktop.checked, + "hmdDesktopTracking": hmdInDesktop.checked } return settingsObject; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 430dc193a3..6b24aa0b5b 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -166,6 +166,12 @@ void ViveControllerManager::setConfigurationSettings(const QJsonObject configura _resetMatCalculated = false; } } + + if (configurationSettings.contains("hmdDesktopTracking")) { + + _hmdDesktopTracking = configurationSettings["hmdDesktopTracking"].toBool(); + } + _inputDevice->configureCalibrationSettings(configurationSettings); saveSettings(); } @@ -175,6 +181,7 @@ QJsonObject ViveControllerManager::configurationSettings() { if (isSupported()) { QJsonObject configurationSettings = _inputDevice->configurationSettings(); configurationSettings["desktopMode"] = _desktopMode; + configurationSettings["hmdDesktopTracking"] = _hmdDesktopTracking; return configurationSettings; } @@ -414,6 +421,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso if (!configurationSettings.empty()) { auto iter = configurationSettings.begin(); auto end = configurationSettings.end(); + bool hmdDesktopTracking = true; + bool hmdDesktopMode = false; while (iter != end) { if (iter.key() == "bodyConfiguration") { setConfigFromString(iter.value().toString()); @@ -441,9 +450,17 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso _armCircumference = (float)iter.value().toDouble() * CM_TO_M; } else if (iter.key() == "shoulderWidth") { _shoulderWidth = (float)iter.value().toDouble() * CM_TO_M; + } else if (iter.key() == "hmdDesktopTracking") { + hmdDesktopTracking = iter.value().toBool(); + } else if (iter.key() == "desktopMode") { + hmdDesktopMode = iter.value().toBool(); } iter++; } + + _hmdTrackingEnabled = !(hmdDesktopMode && !hmdDesktopTracking); + + qDebug() << "HMD desktop tracking Enabled" << _hmdTrackingEnabled << "-" << hmdDesktopMode << "-" << hmdDesktopTracking << !(hmdDesktopMode && !hmdDesktopTracking); } } @@ -735,11 +752,18 @@ void ViveControllerManager::InputDevice::handleHmd(uint32_t deviceIndex, const c _system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_HMD && _nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid) { - const mat4& mat = _nextSimPoseData.poses[deviceIndex]; - const vec3 linearVelocity = _nextSimPoseData.linearVelocities[deviceIndex]; - const vec3 angularVelocity = _nextSimPoseData.angularVelocities[deviceIndex]; + if (_hmdTrackingEnabled){ + const mat4& mat = _nextSimPoseData.poses[deviceIndex]; + const vec3 linearVelocity = _nextSimPoseData.linearVelocities[deviceIndex]; + const vec3 angularVelocity = _nextSimPoseData.angularVelocities[deviceIndex]; - handleHeadPoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity); + handleHeadPoseEvent(inputCalibrationData, mat, linearVelocity, angularVelocity); + } else { + const mat4& mat = mat4(); + const vec3 zero = vec3(); + + handleHeadPoseEvent(inputCalibrationData, mat, zero, zero); + } } } diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 4a7fcaf85e..cbe331feb3 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -113,7 +113,6 @@ private: void emitCalibrationStatus(); void calibrateNextFrame(); - class FilteredStick { public: glm::vec2 process(float deltaTime, const glm::vec2& stick) { @@ -195,6 +194,8 @@ private: bool _overrideHands { false }; mutable std::recursive_mutex _lock; + bool _hmdTrackingEnabled{ false }; + QString configToString(Config config); friend class ViveControllerManager; }; @@ -204,7 +205,10 @@ private: bool _registeredWithInputMapper { false }; bool _modelLoaded { false }; bool _resetMatCalculated { false }; + bool _desktopMode { false }; + bool _hmdDesktopTracking{ false }; + glm::mat4 _resetMat { glm::mat4() }; model::Geometry _modelGeometry; gpu::TexturePointer _texture; From e28f80401f32760006489a1b021489343fee1bb4 Mon Sep 17 00:00:00 2001 From: Menithal Date: Sun, 5 Nov 2017 01:05:35 +0200 Subject: [PATCH 065/292] 21539: Removed debug, added whitespace for format --- plugins/openvr/src/ViveControllerManager.cpp | 2 -- plugins/openvr/src/ViveControllerManager.h | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 6b24aa0b5b..4e1f8717c6 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -459,8 +459,6 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso } _hmdTrackingEnabled = !(hmdDesktopMode && !hmdDesktopTracking); - - qDebug() << "HMD desktop tracking Enabled" << _hmdTrackingEnabled << "-" << hmdDesktopMode << "-" << hmdDesktopTracking << !(hmdDesktopMode && !hmdDesktopTracking); } } diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index cbe331feb3..6767aafad2 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -194,7 +194,7 @@ private: bool _overrideHands { false }; mutable std::recursive_mutex _lock; - bool _hmdTrackingEnabled{ false }; + bool _hmdTrackingEnabled { false }; QString configToString(Config config); friend class ViveControllerManager; @@ -207,7 +207,7 @@ private: bool _resetMatCalculated { false }; bool _desktopMode { false }; - bool _hmdDesktopTracking{ false }; + bool _hmdDesktopTracking { false }; glm::mat4 _resetMat { glm::mat4() }; model::Geometry _modelGeometry; From 7d420f5242bb421485a6c67d4f89fe536aae9440 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Mon, 6 Nov 2017 12:29:21 -0800 Subject: [PATCH 066/292] isLeftHand, isRightHand, isMouse --- interface/resources/qml/controls-uit/Key.qml | 9 +- interface/src/raypick/JointRayPick.h | 3 + .../raypick/LaserPointerScriptingInterface.h | 6 +- interface/src/raypick/MouseRayPick.h | 2 + .../src/raypick/PickScriptingInterface.cpp | 12 ++ .../src/raypick/PickScriptingInterface.h | 6 +- .../src/raypick/PointerScriptingInterface.h | 5 +- .../src/raypick/RayPickScriptingInterface.cpp | 12 ++ .../src/raypick/RayPickScriptingInterface.h | 7 +- .../ui/overlays/ContextOverlayInterface.cpp | 14 ++- interface/src/ui/overlays/Overlays.cpp | 4 +- interface/src/ui/overlays/Web3DOverlay.cpp | 113 +++--------------- interface/src/ui/overlays/Web3DOverlay.h | 4 +- .../src/EntityTreeRenderer.cpp | 16 ++- libraries/pointers/src/pointers/Pick.h | 4 + .../pointers/src/pointers/PickManager.cpp | 24 ++++ libraries/pointers/src/pointers/PickManager.h | 4 + libraries/pointers/src/pointers/Pointer.cpp | 12 ++ libraries/pointers/src/pointers/Pointer.h | 4 + .../pointers/src/pointers/PointerManager.cpp | 24 ++++ .../pointers/src/pointers/PointerManager.h | 4 + libraries/ui/src/ui/OffscreenQmlSurface.cpp | 12 ++ libraries/ui/src/ui/OffscreenQmlSurface.h | 2 + 23 files changed, 176 insertions(+), 127 deletions(-) diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controls-uit/Key.qml index e54250c872..3bba1e5f07 100644 --- a/interface/resources/qml/controls-uit/Key.qml +++ b/interface/resources/qml/controls-uit/Key.qml @@ -64,11 +64,12 @@ Item { keyItem.state = "mouseOver"; var globalPosition = keyItem.mapToGlobal(mouseArea1.mouseX, mouseArea1.mouseY); - var deviceId = Web3DOverlay.deviceIdByTouchPoint(globalPosition.x, globalPosition.y); - var hand = deviceId - 1; // based on touchEventUtils.js, deviceId is 'hand + 1', so 'hand' is 'deviceId' - 1 + var pointerID = Web3DOverlay.deviceIdByTouchPoint(globalPosition.x, globalPosition.y); - if (hand == leftHand || hand == rightHand) { - Controller.triggerHapticPulse(_HAPTIC_STRENGTH, _HAPTIC_DURATION, hand); + if (Pointers.isLeftHand(pointerID)) { + Controller.triggerHapticPulse(_HAPTIC_STRENGTH, _HAPTIC_DURATION, leftHand); + } else if (Pointers.isRightHand(pointerID)) { + Controller.triggerHapticPulse(_HAPTIC_STRENGTH, _HAPTIC_DURATION, rightHand); } } diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index ab44bf67c8..67e6bf6945 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -20,6 +20,9 @@ public: const PickRay getMathematicalPick() const override; + bool isLeftHand() const override { return (_jointName == "_CONTROLLER_LEFTHAND") || (_jointName == "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND"); } + bool isRightHand() const override { return (_jointName == "_CONTROLLER_RIGHTHAND") || (_jointName == "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND"); } + private: std::string _jointName; glm::vec3 _posOffset; diff --git a/interface/src/raypick/LaserPointerScriptingInterface.h b/interface/src/raypick/LaserPointerScriptingInterface.h index da62f4eb12..baf8f0b2e6 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.h +++ b/interface/src/raypick/LaserPointerScriptingInterface.h @@ -20,7 +20,7 @@ class LaserPointerScriptingInterface : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY -public slots: +public: Q_INVOKABLE unsigned int createLaserPointer(const QVariant& properties) const; Q_INVOKABLE void enableLaserPointer(unsigned int uid) const { DependencyManager::get()->enablePointer(uid); } Q_INVOKABLE void disableLaserPointer(unsigned int uid) const { DependencyManager::get()->disablePointer(uid); } @@ -36,6 +36,10 @@ public slots: Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } + Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get()->isLeftHand(uid); } + Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get()->isRightHand(uid); } + Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get()->isMouse(uid); } + }; #endif // hifi_LaserPointerScriptingInterface_h diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h index e9eb3ccabf..6ce9e7d8d2 100644 --- a/interface/src/raypick/MouseRayPick.h +++ b/interface/src/raypick/MouseRayPick.h @@ -19,6 +19,8 @@ public: MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); const PickRay getMathematicalPick() const override; + + bool isMouse() const override { return true; } }; #endif // hifi_MouseRayPick_h diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 445a7e9b69..05e4a2acb0 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -109,6 +109,18 @@ void PickScriptingInterface::setIncludeItems(unsigned int uid, const QScriptValu DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } +bool PickScriptingInterface::isLeftHand(unsigned int uid) { + return DependencyManager::get()->isLeftHand(uid); +} + +bool PickScriptingInterface::isRightHand(unsigned int uid) { + return DependencyManager::get()->isRightHand(uid); +} + +bool PickScriptingInterface::isMouse(unsigned int uid) { + return DependencyManager::get()->isMouse(uid); +} + QScriptValue pickTypesToScriptValue(QScriptEngine* engine, const PickQuery::PickType& pickType) { return pickType; } diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 900fa2ef40..cd296993fb 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -37,7 +37,6 @@ public: void registerMetaTypes(QScriptEngine* engine); -public slots: Q_INVOKABLE unsigned int createPick(const PickQuery::PickType type, const QVariant& properties); Q_INVOKABLE void enablePick(unsigned int uid); Q_INVOKABLE void disablePick(unsigned int uid); @@ -48,6 +47,11 @@ public slots: Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities); Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities); + Q_INVOKABLE bool isLeftHand(unsigned int uid); + Q_INVOKABLE bool isRightHand(unsigned int uid); + Q_INVOKABLE bool isMouse(unsigned int uid); + +public slots: static constexpr unsigned int PICK_NOTHING() { return 0; } static constexpr unsigned int PICK_ENTITIES() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_ENTITIES); } static constexpr unsigned int PICK_OVERLAYS() { return PickFilter::getBitMask(PickFilter::FlagBit::PICK_OVERLAYS); } diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 8ea9594fda..e34a9ef74d 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -21,7 +21,6 @@ class PointerScriptingInterface : public QObject, public Dependency { public: unsigned int createLaserPointer(const QVariant& properties) const; -public slots: Q_INVOKABLE unsigned int createPointer(const PickQuery::PickType& type, const QVariant& properties) const; Q_INVOKABLE void enablePointer(unsigned int uid) const { DependencyManager::get()->enablePointer(uid); } Q_INVOKABLE void disablePointer(unsigned int uid) const { DependencyManager::get()->disablePointer(uid); } @@ -37,6 +36,10 @@ public slots: Q_INVOKABLE void setLockEndUUID(unsigned int uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } + Q_INVOKABLE bool isLeftHand(unsigned int uid) { return DependencyManager::get()->isLeftHand(uid); } + Q_INVOKABLE bool isRightHand(unsigned int uid) { return DependencyManager::get()->isRightHand(uid); } + Q_INVOKABLE bool isMouse(unsigned int uid) { return DependencyManager::get()->isMouse(uid); } + signals: void triggerBegin(const QUuid& id, const PointerEvent& pointerEvent); void triggerContinue(const QUuid& id, const PointerEvent& pointerEvent); diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index f9774dda31..6b0b8dc167 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -51,3 +51,15 @@ void RayPickScriptingInterface::setIgnoreItems(uint32_t uid, const QScriptValue& void RayPickScriptingInterface::setIncludeItems(uint32_t uid, const QScriptValue& includeItems) { DependencyManager::get()->setIncludeItems(uid, qVectorQUuidFromScriptValue(includeItems)); } + +bool RayPickScriptingInterface::isLeftHand(unsigned int uid) { + return DependencyManager::get()->isLeftHand(uid); +} + +bool RayPickScriptingInterface::isRightHand(unsigned int uid) { + return DependencyManager::get()->isRightHand(uid); +} + +bool RayPickScriptingInterface::isMouse(unsigned int uid) { + return DependencyManager::get()->isMouse(uid); +} \ No newline at end of file diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index 844add9012..65b0b2aced 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -36,7 +36,7 @@ class RayPickScriptingInterface : public QObject, public Dependency { Q_PROPERTY(unsigned int INTERSECTED_HUD READ INTERSECTED_HUD CONSTANT) SINGLETON_DEPENDENCY -public slots: +public: Q_INVOKABLE unsigned int createRayPick(const QVariant& properties); Q_INVOKABLE void enableRayPick(unsigned int uid); Q_INVOKABLE void disableRayPick(unsigned int uid); @@ -47,6 +47,11 @@ public slots: Q_INVOKABLE void setIgnoreItems(unsigned int uid, const QScriptValue& ignoreEntities); Q_INVOKABLE void setIncludeItems(unsigned int uid, const QScriptValue& includeEntities); + Q_INVOKABLE bool isLeftHand(unsigned int uid); + Q_INVOKABLE bool isRightHand(unsigned int uid); + Q_INVOKABLE bool isMouse(unsigned int uid); + +public slots: static unsigned int PICK_NOTHING() { return PickScriptingInterface::PICK_NOTHING(); } static unsigned int PICK_ENTITIES() { return PickScriptingInterface::PICK_ENTITIES(); } static unsigned int PICK_OVERLAYS() { return PickScriptingInterface::PICK_OVERLAYS(); } diff --git a/interface/src/ui/overlays/ContextOverlayInterface.cpp b/interface/src/ui/overlays/ContextOverlayInterface.cpp index b5af529f2b..fa02d4107c 100644 --- a/interface/src/ui/overlays/ContextOverlayInterface.cpp +++ b/interface/src/ui/overlays/ContextOverlayInterface.cpp @@ -19,6 +19,8 @@ #include #include +#include + #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -79,8 +81,6 @@ ContextOverlayInterface::ContextOverlayInterface() { _challengeOwnershipTimeoutTimer.setSingleShot(true); } -static const uint32_t MOUSE_HW_ID = 0; -static const uint32_t LEFT_HAND_HW_ID = 1; static const xColor CONTEXT_OVERLAY_COLOR = { 255, 255, 255 }; static const float CONTEXT_OVERLAY_INSIDE_DISTANCE = 1.0f; // in meters static const float CONTEXT_OVERLAY_SIZE = 0.09f; // in meters, same x and y dims @@ -100,7 +100,7 @@ void ContextOverlayInterface::setEnabled(bool enabled) { bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& entityItemID, const PointerEvent& event) { if (_enabled && event.getButton() == PointerEvent::SecondaryButton) { if (contextOverlayFilterPassed(entityItemID)) { - if (event.getID() == MOUSE_HW_ID) { + if (event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get()->isMouse(event.getID())) { enableEntityHighlight(entityItemID); } @@ -151,7 +151,7 @@ bool ContextOverlayInterface::createOrDestroyContextOverlay(const EntityItemID& glm::vec3 normal; boundingBox.findRayIntersection(cameraPosition, direction, distance, face, normal); float offsetAngle = -CONTEXT_OVERLAY_OFFSET_ANGLE; - if (event.getID() == LEFT_HAND_HW_ID) { + if (DependencyManager::get()->isLeftHand(event.getID())) { offsetAngle *= -1.0f; } contextOverlayPosition = cameraPosition + @@ -253,13 +253,15 @@ void ContextOverlayInterface::contextOverlays_hoverLeaveOverlay(const OverlayID& } void ContextOverlayInterface::contextOverlays_hoverEnterEntity(const EntityItemID& entityID, const PointerEvent& event) { - if (contextOverlayFilterPassed(entityID) && _enabled && event.getID() != MOUSE_HW_ID) { + bool isMouse = event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get()->isMouse(event.getID()); + if (contextOverlayFilterPassed(entityID) && _enabled && !isMouse) { enableEntityHighlight(entityID); } } void ContextOverlayInterface::contextOverlays_hoverLeaveEntity(const EntityItemID& entityID, const PointerEvent& event) { - if (_currentEntityWithContextOverlay != entityID && _enabled && event.getID() != MOUSE_HW_ID) { + bool isMouse = event.getID() == PointerManager::MOUSE_POINTER_ID || DependencyManager::get()->isMouse(event.getID()); + if (_currentEntityWithContextOverlay != entityID && _enabled && !isMouse) { disableEntityHighlight(entityID); } } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 5a7b1bd76c..05ff3e289b 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -784,8 +784,6 @@ float Overlays::height() { return offscreenUi->getWindow()->size().height(); } -static const uint32_t MOUSE_POINTER_ID = 0; - static glm::vec2 projectOntoOverlayXYPlane(glm::vec3 position, glm::quat rotation, glm::vec2 dimensions, const PickRay& pickRay, const RayToOverlayIntersectionResult& rayPickResult) { @@ -846,7 +844,7 @@ PointerEvent Overlays::calculateOverlayPointerEvent(OverlayID overlayID, PickRay glm::vec2 pos2D = projectOntoOverlayXYPlane(position, rotation, dimensions, ray, rayPickResult); - PointerEvent pointerEvent(eventType, MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, + PointerEvent pointerEvent(eventType, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), event->modifiers()); return pointerEvent; diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index b8683b43e3..658b4edab8 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -56,6 +56,8 @@ #include "ui/Snapshot.h" #include "SoundCache.h" +#include "raypick/PointerScriptingInterface.h" + static const float DPI = 30.47f; static const float INCHES_TO_METERS = 1.0f / 39.3701f; static const float METERS_TO_INCHES = 39.3701f; @@ -216,6 +218,7 @@ void Web3DOverlay::setupQmlSurface() { _webSurface->getSurfaceContext()->setContextProperty("Settings", SettingsScriptingInterface::getInstance()); _webSurface->getSurfaceContext()->setContextProperty("Render", AbstractViewStateInterface::instance()->getRenderEngine()->getConfiguration().get()); _webSurface->getSurfaceContext()->setContextProperty("Controller", DependencyManager::get().data()); + _webSurface->getSurfaceContext()->setContextProperty("Pointers", DependencyManager::get().data()); _webSurface->getSurfaceContext()->setContextProperty("Web3DOverlay", this); _webSurface->getSurfaceContext()->setContextProperty("pathToFonts", "../../"); @@ -245,18 +248,12 @@ void Web3DOverlay::onResizeWebSurface() { _webSurface->resize(QSize(_resolution.x, _resolution.y)); } -const int INVALID_DEVICE_ID = -1; - -Q_INVOKABLE int Web3DOverlay::deviceIdByTouchPoint(qreal x, qreal y) { - auto mapped = _webSurface->getRootItem()->mapFromGlobal(QPoint(x, y)); - - for (auto pair : _activeTouchPoints) { - if (mapped.x() == (int)pair.second.pos().x() && mapped.y() == (int)pair.second.pos().y()) { - return pair.first; - } +unsigned int Web3DOverlay::deviceIdByTouchPoint(qreal x, qreal y) { + if (_webSurface) { + return _webSurface->deviceIdByTouchPoint(x, y); + } else { + return PointerEvent::INVALID_POINTER_ID; } - - return INVALID_DEVICE_ID; } void Web3DOverlay::render(RenderArgs* args) { @@ -341,13 +338,15 @@ void Web3DOverlay::setProxyWindow(QWindow* proxyWindow) { } void Web3DOverlay::hoverLeaveOverlay(const PointerEvent& event) { - if ((_pressed || (!_activeTouchPoints.empty() && _touchBeginAccepted)) && event.sendReleaseOnHoverLeave()) { + if (_inputMode == Mouse) { PointerEvent endEvent(PointerEvent::Release, event.getID(), event.getPos2D(), event.getPos3D(), event.getNormal(), event.getDirection(), event.getButton(), event.getButtons(), event.getKeyboardModifiers()); handlePointerEvent(endEvent); // QML onReleased is only triggered if a click has happened first. We need to send this "fake" mouse move event to properly trigger an onExited. PointerEvent endMoveEvent(PointerEvent::Move, event.getID()); handlePointerEvent(endMoveEvent); + } else if (_webSurface) { + _webSurface->hoverEndEvent(event, _touchDevice); } } @@ -366,93 +365,11 @@ void Web3DOverlay::handlePointerEvent(const PointerEvent& event) { } void Web3DOverlay::handlePointerEventAsTouch(const PointerEvent& event) { - if (!_webSurface) { - return; + if (_webSurface) { + PointerEvent webEvent = event; + webEvent.setPos2D(event.getPos2D() * (METERS_TO_INCHES * _dpi)); + _webSurface->handlePointerEvent(webEvent, _touchDevice); } - - glm::vec2 windowPos = event.getPos2D() * (METERS_TO_INCHES * _dpi); - QPointF windowPoint(windowPos.x, windowPos.y); - - Qt::TouchPointState state = Qt::TouchPointStationary; - if (event.getType() == PointerEvent::Press && event.getButton() == PointerEvent::PrimaryButton) { - state = Qt::TouchPointPressed; - } else if (event.getType() == PointerEvent::Release) { - state = Qt::TouchPointReleased; - } else if (_activeTouchPoints.count(event.getID()) && windowPoint != _activeTouchPoints[event.getID()].pos()) { - state = Qt::TouchPointMoved; - } - - QEvent::Type touchType = QEvent::TouchUpdate; - if (_activeTouchPoints.empty()) { - // If the first active touch point is being created, send a begin - touchType = QEvent::TouchBegin; - } if (state == Qt::TouchPointReleased && _activeTouchPoints.size() == 1 && _activeTouchPoints.count(event.getID())) { - // If the last active touch point is being released, send an end - touchType = QEvent::TouchEnd; - } - - { - QTouchEvent::TouchPoint point; - point.setId(event.getID()); - point.setState(state); - point.setPos(windowPoint); - point.setScreenPos(windowPoint); - _activeTouchPoints[event.getID()] = point; - } - - QTouchEvent touchEvent(touchType, &_touchDevice, event.getKeyboardModifiers()); - { - QList touchPoints; - Qt::TouchPointStates touchPointStates; - for (const auto& entry : _activeTouchPoints) { - touchPointStates |= entry.second.state(); - touchPoints.push_back(entry.second); - } - - touchEvent.setWindow(_webSurface->getWindow()); - touchEvent.setDevice(&_touchDevice); - touchEvent.setTarget(_webSurface->getRootItem()); - touchEvent.setTouchPoints(touchPoints); - touchEvent.setTouchPointStates(touchPointStates); - } - - // Send mouse events to the Web surface so that HTML dialog elements work with mouse press and hover. - // - // In Qt 5.9 mouse events must be sent before touch events to make sure some QtQuick components will - // receive mouse events - Qt::MouseButton button = Qt::NoButton; - Qt::MouseButtons buttons = Qt::NoButton; - if (event.getButton() == PointerEvent::PrimaryButton) { - button = Qt::LeftButton; - } - if (event.getButtons() & PointerEvent::PrimaryButton) { - buttons |= Qt::LeftButton; - } - -#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) - if (event.getType() == PointerEvent::Move) { - QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); - QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); - } -#endif - - if (touchType == QEvent::TouchBegin) { - _touchBeginAccepted = QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent); - } else if (_touchBeginAccepted) { - QCoreApplication::sendEvent(_webSurface->getWindow(), &touchEvent); - } - - // If this was a release event, remove the point from the active touch points - if (state == Qt::TouchPointReleased) { - _activeTouchPoints.erase(event.getID()); - } - -#if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) - if (event.getType() == PointerEvent::Move) { - QMouseEvent mouseEvent(QEvent::MouseMove, windowPoint, windowPoint, windowPoint, button, buttons, event.getKeyboardModifiers()); - QCoreApplication::sendEvent(_webSurface->getWindow(), &mouseEvent); - } -#endif } void Web3DOverlay::handlePointerEventAsMouse(const PointerEvent& event) { diff --git a/interface/src/ui/overlays/Web3DOverlay.h b/interface/src/ui/overlays/Web3DOverlay.h index 2fc63df76a..d2da1f7310 100644 --- a/interface/src/ui/overlays/Web3DOverlay.h +++ b/interface/src/ui/overlays/Web3DOverlay.h @@ -67,7 +67,7 @@ public: void destroyWebSurface(); void onResizeWebSurface(); - Q_INVOKABLE int deviceIdByTouchPoint(qreal x, qreal y); + Q_INVOKABLE unsigned int deviceIdByTouchPoint(qreal x, qreal y); public slots: void emitScriptEvent(const QVariant& scriptMessage); @@ -98,8 +98,6 @@ private: bool _showKeyboardFocusHighlight{ true }; bool _pressed{ false }; - bool _touchBeginAccepted { false }; - std::map _activeTouchPoints; QTouchDevice _touchDevice; uint8_t _desiredMaxFPS { 10 }; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index ad1c617287..8493d73db3 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -571,8 +571,6 @@ static PointerEvent::Button toPointerButton(const QMouseEvent& event) { } } -static const uint32_t MOUSE_POINTER_ID = 0; - void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { // If we don't have a tree, or we're in the process of shutting down, then don't // process these events. @@ -593,7 +591,7 @@ void EntityTreeRenderer::mousePressEvent(QMouseEvent* event) { } glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); - PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID, + PointerEvent pointerEvent(PointerEvent::Press, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), @@ -625,7 +623,7 @@ void EntityTreeRenderer::mouseDoublePressEvent(QMouseEvent* event) { RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); if (rayPickResult.intersects && rayPickResult.entity) { glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); - PointerEvent pointerEvent(PointerEvent::Press, MOUSE_POINTER_ID, + PointerEvent pointerEvent(PointerEvent::Press, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), Qt::NoModifier); @@ -657,7 +655,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) { //qCDebug(entitiesrenderer) << "mouseReleaseEvent over entity:" << rayPickResult.entityID; glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); - PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID, + PointerEvent pointerEvent(PointerEvent::Release, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), @@ -673,7 +671,7 @@ void EntityTreeRenderer::mouseReleaseEvent(QMouseEvent* event) { // we're releasing the button, then this is considered a clickReleaseOn event if (!_currentClickingOnEntityID.isInvalidID()) { glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); - PointerEvent pointerEvent(PointerEvent::Release, MOUSE_POINTER_ID, + PointerEvent pointerEvent(PointerEvent::Release, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), @@ -699,7 +697,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { RayToEntityIntersectionResult rayPickResult = _getPrevRayPickResultOperator(_mouseRayPickID); if (rayPickResult.intersects && rayPickResult.entity) { glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); - PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID, + PointerEvent pointerEvent(PointerEvent::Move, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), @@ -713,7 +711,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { // then we need to send the hover leave. if (!_currentHoverOverEntityID.isInvalidID() && rayPickResult.entityID != _currentHoverOverEntityID) { glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); - PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID, + PointerEvent pointerEvent(PointerEvent::Move, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), @@ -744,7 +742,7 @@ void EntityTreeRenderer::mouseMoveEvent(QMouseEvent* event) { // send the hover leave for our previous entity if (!_currentHoverOverEntityID.isInvalidID()) { glm::vec2 pos2D = projectOntoEntityXYPlane(rayPickResult.entity, ray, rayPickResult); - PointerEvent pointerEvent(PointerEvent::Move, MOUSE_POINTER_ID, + PointerEvent pointerEvent(PointerEvent::Move, PointerManager::MOUSE_POINTER_ID, pos2D, rayPickResult.intersection, rayPickResult.surfaceNormal, ray.direction, toPointerButton(*event), toPointerButtons(*event), diff --git a/libraries/pointers/src/pointers/Pick.h b/libraries/pointers/src/pointers/Pick.h index e4ce5d3dce..b875285ad7 100644 --- a/libraries/pointers/src/pointers/Pick.h +++ b/libraries/pointers/src/pointers/Pick.h @@ -182,6 +182,10 @@ public: void setIgnoreItems(const QVector& items); void setIncludeItems(const QVector& items); + virtual bool isLeftHand() const { return false; } + virtual bool isRightHand() const { return false; } + virtual bool isMouse() const { return false; } + private: PickFilter _filter; const float _maxDistance; diff --git a/libraries/pointers/src/pointers/PickManager.cpp b/libraries/pointers/src/pointers/PickManager.cpp index cb9d715ba9..d601801d76 100644 --- a/libraries/pointers/src/pointers/PickManager.cpp +++ b/libraries/pointers/src/pointers/PickManager.cpp @@ -96,4 +96,28 @@ void PickManager::update() { bool shouldPickHUD = _shouldPickHUDOperator(); _rayPickCacheOptimizer.update(cachedPicks[PickQuery::Ray], shouldPickHUD); +} + +bool PickManager::isLeftHand(unsigned int uid) { + auto pick = findPick(uid); + if (pick) { + return pick->isLeftHand(); + } + return false; +} + +bool PickManager::isRightHand(unsigned int uid) { + auto pick = findPick(uid); + if (pick) { + return pick->isRightHand(); + } + return false; +} + +bool PickManager::isMouse(unsigned int uid) { + auto pick = findPick(uid); + if (pick) { + return pick->isMouse(); + } + return false; } \ No newline at end of file diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index 0794ac0a41..bdc3e16054 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -33,6 +33,10 @@ public: void setIgnoreItems(unsigned int uid, const QVector& ignore) const; void setIncludeItems(unsigned int uid, const QVector& include) const; + bool isLeftHand(unsigned int uid); + bool isRightHand(unsigned int uid); + bool isMouse(unsigned int uid); + void setShouldPickHUDOperator(std::function shouldPickHUDOperator) { _shouldPickHUDOperator = shouldPickHUDOperator; } void setCalculatePos2DFromHUDOperator(std::function calculatePos2DFromHUDOperator) { _calculatePos2DFromHUDOperator = calculatePos2DFromHUDOperator; } glm::vec2 calculatePos2DFromHUD(const glm::vec3& intersection) { return _calculatePos2DFromHUDOperator(intersection); } diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 0fc5c54ad2..6e95b48280 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -46,6 +46,18 @@ void Pointer::setIncludeItems(const QVector& includeItems) const { DependencyManager::get()->setIncludeItems(_pickUID, includeItems); } +bool Pointer::isLeftHand() const { + return DependencyManager::get()->isLeftHand(_pickUID); +} + +bool Pointer::isRightHand() const { + return DependencyManager::get()->isRightHand(_pickUID); +} + +bool Pointer::isMouse() const { + return DependencyManager::get()->isMouse(_pickUID); +} + void Pointer::update(unsigned int pointerID) { // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts withReadLock([&] { diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index d8661436b9..6d9c1a172b 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -53,6 +53,10 @@ public: virtual void setIgnoreItems(const QVector& ignoreItems) const; virtual void setIncludeItems(const QVector& includeItems) const; + bool isLeftHand() const; + bool isRightHand() const; + bool isMouse() const; + // Pointers can choose to implement these virtual void setLength(float length) {} virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay) {} diff --git a/libraries/pointers/src/pointers/PointerManager.cpp b/libraries/pointers/src/pointers/PointerManager.cpp index b117b24770..de85e74da1 100644 --- a/libraries/pointers/src/pointers/PointerManager.cpp +++ b/libraries/pointers/src/pointers/PointerManager.cpp @@ -120,3 +120,27 @@ void PointerManager::setLockEndUUID(unsigned int uid, const QUuid& objectID, boo pointer->setLockEndUUID(objectID, isOverlay); } } + +bool PointerManager::isLeftHand(unsigned int uid) { + auto pointer = find(uid); + if (pointer) { + return pointer->isLeftHand(); + } + return false; +} + +bool PointerManager::isRightHand(unsigned int uid) { + auto pointer = find(uid); + if (pointer) { + return pointer->isRightHand(); + } + return false; +} + +bool PointerManager::isMouse(unsigned int uid) { + auto pointer = find(uid); + if (pointer) { + return pointer->isMouse(); + } + return false; +} \ No newline at end of file diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index a415c9dbd9..461d27959c 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -40,6 +40,10 @@ public: void update(); + bool isLeftHand(unsigned int uid); + bool isRightHand(unsigned int uid); + bool isMouse(unsigned int uid); + static const unsigned int MOUSE_POINTER_ID { PointerEvent::INVALID_POINTER_ID + 1 }; private: diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index e2675008f9..41c3da2a4f 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -927,6 +927,18 @@ bool OffscreenQmlSurface::eventFilter(QObject* originalDestination, QEvent* even return false; } +unsigned int OffscreenQmlSurface::deviceIdByTouchPoint(qreal x, qreal y) { + auto mapped = _rootItem->mapFromGlobal(QPoint(x, y)); + + for (auto pair : _activeTouchPoints) { + if (mapped.x() == (int)pair.second.pos().x() && mapped.y() == (int)pair.second.pos().y()) { + return pair.first; + } + } + + return PointerEvent::INVALID_POINTER_ID; +} + PointerEvent::EventType OffscreenQmlSurface::choosePointerEventType(QEvent::Type type) { switch (type) { case QEvent::MouseButtonDblClick: diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 1f1817faa2..8ddfbfe8cc 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -100,6 +100,8 @@ public: PointerEvent::EventType choosePointerEventType(QEvent::Type type); + unsigned int deviceIdByTouchPoint(qreal x, qreal y); + signals: void focusObjectChanged(QObject* newFocus); void focusTextChanged(bool focusText); From bdd31b63ede80089745caf94403ebb86e4c499ed Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Mon, 6 Nov 2017 17:23:40 -0800 Subject: [PATCH 067/292] update functions call names to match pointer API changes --- scripts/system/controllers/controllerDispatcher.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index cd52caae38..401c223992 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -169,7 +169,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var pointer = (hand === RIGHT_HAND) ? _this.rightControllerPointer : _this.leftControllerPointer; var targetID = laserLockInfo.targetID; var targetIsOverlay = laserLockInfo.isOverlay; - Pointers.setLockEndUid(pointer, targetID, targetIsOverlay); + Pointers.setLockEndUUID(pointer, targetID, targetIsOverlay); _this.laserLockStatus[hand] = targetID; } } else { From f997ad4628bf95b18f4ced5390adc23f989cab1b Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Nov 2017 16:15:48 -0800 Subject: [PATCH 068/292] changed Wallet from RSA to ECSDA cryto --- interface/src/commerce/Wallet.cpp | 150 ++++++++++++++++-------------- 1 file changed, 79 insertions(+), 71 deletions(-) diff --git a/interface/src/commerce/Wallet.cpp b/interface/src/commerce/Wallet.cpp index 85632ff8f1..8c606f0418 100644 --- a/interface/src/commerce/Wallet.cpp +++ b/interface/src/commerce/Wallet.cpp @@ -32,6 +32,7 @@ #include #include #include +#include // I know, right? But per https://www.openssl.org/docs/faq.html // this avoids OPENSSL_Uplink(00007FF847238000,08): no OPENSSL_Applink @@ -78,18 +79,19 @@ int passwordCallback(char* password, int maxPasswordSize, int rwFlag, void* u) { } } -RSA* readKeys(const char* filename) { +EC_KEY* readKeys(const char* filename) { FILE* fp; - RSA* key = NULL; + EC_KEY *key = NULL; if ((fp = fopen(filename, "rt"))) { // file opened successfully qCDebug(commerce) << "opened key file" << filename; - if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) { + + if ((key = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL))) { // now read private key qCDebug(commerce) << "read public key"; - if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) { + if ((key = PEM_read_ECPrivateKey(fp, &key, passwordCallback, NULL))) { qCDebug(commerce) << "read private key"; fclose(fp); return key; @@ -137,18 +139,18 @@ bool Wallet::writeBackupInstructions() { return retval; } -bool writeKeys(const char* filename, RSA* keys) { +bool writeKeys(const char* filename, EC_KEY* keys) { FILE* fp; bool retval = false; if ((fp = fopen(filename, "wt"))) { - if (!PEM_write_RSAPublicKey(fp, keys)) { + if (!PEM_write_EC_PUBKEY(fp, keys)) { fclose(fp); qCDebug(commerce) << "failed to write public key"; QFile(QString(filename)).remove(); return retval; } - if (!PEM_write_RSAPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) { + if (!PEM_write_ECPrivateKey(fp, keys, EVP_des_ede3_cbc(), NULL, 0, passwordCallback, NULL)) { fclose(fp); qCDebug(commerce) << "failed to write private key"; QFile(QString(filename)).remove(); @@ -170,44 +172,28 @@ bool writeKeys(const char* filename, RSA* keys) { // TODO: we don't really use the private keys returned - we can see how this evolves, but probably // we should just return a list of public keys? // or perhaps return the RSA* instead? -QPair generateRSAKeypair() { - - RSA* keyPair = RSA_new(); - BIGNUM* exponent = BN_new(); +QPair generateECKeypair() { + + EC_KEY* keyPair = EC_KEY_new_by_curve_name(NID_secp256k1); QPair retval; - - const unsigned long RSA_KEY_EXPONENT = 65537; - BN_set_word(exponent, RSA_KEY_EXPONENT); - - // seed the random number generator before we call RSA_generate_key_ex - srand(time(NULL)); - - const int RSA_KEY_BITS = 2048; - - if (!RSA_generate_key_ex(keyPair, RSA_KEY_BITS, exponent, NULL)) { - qCDebug(commerce) << "Error generating 2048-bit RSA Keypair -" << ERR_get_error(); - - // we're going to bust out of here but first we cleanup the BIGNUM - BN_free(exponent); + if (!EC_KEY_generate_key(keyPair)) { + qCDebug(commerce) << "Error generating EC Keypair -" << ERR_get_error(); return retval; } - // we don't need the BIGNUM anymore so clean that up - BN_free(exponent); - // grab the public key and private key from the file unsigned char* publicKeyDER = NULL; - int publicKeyLength = i2d_RSAPublicKey(keyPair, &publicKeyDER); + int publicKeyLength = i2d_EC_PUBKEY(keyPair, &publicKeyDER); unsigned char* privateKeyDER = NULL; - int privateKeyLength = i2d_RSAPrivateKey(keyPair, &privateKeyDER); + int privateKeyLength = i2d_ECPrivateKey(keyPair, &privateKeyDER); if (publicKeyLength <= 0 || privateKeyLength <= 0) { qCDebug(commerce) << "Error getting DER public or private key from RSA struct -" << ERR_get_error(); // cleanup the RSA struct - RSA_free(keyPair); + EC_KEY_free(keyPair); // cleanup the public and private key DER data, if required if (publicKeyLength > 0) { @@ -227,7 +213,7 @@ QPair generateRSAKeypair() { return retval; } - RSA_free(keyPair); + EC_KEY_free(keyPair); // prepare the return values. TODO: Fix this - we probably don't really even want the // private key at all (better to read it when we need it?). Or maybe we do, when we have @@ -245,18 +231,18 @@ QPair generateRSAKeypair() { // the public key can just go into a byte array QByteArray readPublicKey(const char* filename) { FILE* fp; - RSA* key = NULL; + EC_KEY* key = NULL; if ((fp = fopen(filename, "r"))) { // file opened successfully qCDebug(commerce) << "opened key file" << filename; - if ((key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL))) { + if ((key = PEM_read_EC_PUBKEY(fp, NULL, NULL, NULL))) { // file read successfully unsigned char* publicKeyDER = NULL; - int publicKeyLength = i2d_RSAPublicKey(key, &publicKeyDER); + int publicKeyLength = i2d_EC_PUBKEY(key, &publicKeyDER); // TODO: check for 0 length? // cleanup - RSA_free(key); + EC_KEY_free(key); fclose(fp); qCDebug(commerce) << "parsed public key file successfully"; @@ -274,15 +260,15 @@ QByteArray readPublicKey(const char* filename) { return QByteArray(); } -// the private key should be read/copied into heap memory. For now, we need the RSA struct +// the private key should be read/copied into heap memory. For now, we need the EC_KEY struct // so I'll return that. Note we need to RSA_free(key) later!!! -RSA* readPrivateKey(const char* filename) { +EC_KEY* readPrivateKey(const char* filename) { FILE* fp; - RSA* key = NULL; + EC_KEY* key = NULL; if ((fp = fopen(filename, "r"))) { // file opened successfully qCDebug(commerce) << "opened key file" << filename; - if ((key = PEM_read_RSAPrivateKey(fp, &key, passwordCallback, NULL))) { + if ((key = PEM_read_ECPrivateKey(fp, &key, passwordCallback, NULL))) { qCDebug(commerce) << "parsed private key file successfully"; } else { @@ -509,7 +495,7 @@ bool Wallet::walletIsAuthenticatedWithPassphrase() { if (publicKey.size() > 0) { if (auto key = readPrivateKey(keyFilePath().toStdString().c_str())) { - RSA_free(key); + EC_KEY_free(key); // be sure to add the public key so we don't do this over and over _publicKeys.push_back(publicKey.toBase64()); @@ -525,7 +511,7 @@ bool Wallet::generateKeyPair() { initialize(); qCInfo(commerce) << "Generating keypair."; - auto keyPair = generateRSAKeypair(); + auto keyPair = generateECKeypair(); writeBackupInstructions(); @@ -558,22 +544,30 @@ QStringList Wallet::listPublicKeys() { // encoded string representing the signature (suitable for http, etc...) QString Wallet::signWithKey(const QByteArray& text, const QString& key) { qCInfo(commerce) << "Signing text."; - RSA* rsaPrivateKey = NULL; - if ((rsaPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) { - QByteArray signature(RSA_size(rsaPrivateKey), 0); + EC_KEY* ecPrivateKey = NULL; + if ((ecPrivateKey = readPrivateKey(keyFilePath().toStdString().c_str()))) { + QByteArray signature(ECDSA_size(ecPrivateKey), 0); unsigned int signatureBytes = 0; QByteArray hashedPlaintext = QCryptographicHash::hash(text, QCryptographicHash::Sha256); - int encryptReturn = RSA_sign(NID_sha256, - reinterpret_cast(hashedPlaintext.constData()), - hashedPlaintext.size(), - reinterpret_cast(signature.data()), - &signatureBytes, - rsaPrivateKey); + + int encryptReturn = ECDSA_sign(0, + reinterpret_cast(hashedPlaintext.constData()), + hashedPlaintext.size(), + reinterpret_cast(signature.data()), + &signatureBytes, ecPrivateKey); + + //Previous pattern, retained by ECDSA_sign + //int encryptReturn = RSA_sign(NID_sha256, + // reinterpret_cast(hashedPlaintext.constData()), + // hashedPlaintext.size(), + // reinterpret_cast(signature.data()), + // &signatureBytes, + // rsaPrivateKey); // free the private key RSA struct now that we are done with it - RSA_free(rsaPrivateKey); + EC_KEY_free(ecPrivateKey); if (encryptReturn != -1) { return signature.toBase64(); @@ -674,7 +668,7 @@ void Wallet::reset() { keyFile.remove(); } bool Wallet::writeWallet(const QString& newPassphrase) { - RSA* keys = readKeys(keyFilePath().toStdString().c_str()); + EC_KEY* keys = readKeys(keyFilePath().toStdString().c_str()); if (keys) { // we read successfully, so now write to a new temp file QString tempFileName = QString("%1.%2").arg(keyFilePath(), QString("temp")); @@ -720,18 +714,23 @@ bool Wallet::changePassphrase(const QString& newPassphrase) { void Wallet::handleChallengeOwnershipPacket(QSharedPointer packet, SharedNodePointer sendingNode) { auto nodeList = DependencyManager::get(); + //With EC keys, we receive a nonce from the metaverse server, which is signed + //here with the private key and returned. Verification is done at server. + bool challengeOriginatedFromClient = packet->getType() == PacketType::ChallengeOwnershipRequest; - unsigned char decryptedText[64]; + //unsigned char decryptedText[64]; + int decryptionStatus; int certIDByteArraySize; int encryptedTextByteArraySize; int challengingNodeUUIDByteArraySize; packet->readPrimitive(&certIDByteArraySize); - packet->readPrimitive(&encryptedTextByteArraySize); + packet->readPrimitive(&encryptedTextByteArraySize); //rerturns a cast char*, size if (challengeOriginatedFromClient) { packet->readPrimitive(&challengingNodeUUIDByteArraySize); } + //"encryptedText" is now a series of random bytes, a nonce QByteArray certID = packet->read(certIDByteArraySize); QByteArray encryptedText = packet->read(encryptedTextByteArraySize); QByteArray challengingNodeUUID; @@ -739,25 +738,34 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack challengingNodeUUID = packet->read(challengingNodeUUIDByteArraySize); } - RSA* rsa = readKeys(keyFilePath().toStdString().c_str()); - int decryptionStatus = -1; + EC_KEY* ec = readKeys(keyFilePath().toStdString().c_str()); + QString sig; + // int decryptionStatus = -1; - if (rsa) { + if (ec) { ERR_clear_error(); - decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize, - reinterpret_cast(encryptedText.constData()), - decryptedText, - rsa, - RSA_PKCS1_OAEP_PADDING); + sig = signWithKey(encryptedText, ""); //base64 signature, QByteArray cast + //upon return to QString - RSA_free(rsa); + // decryptionStatus = RSA_private_decrypt(encryptedTextByteArraySize, + // reinterpret_cast(encryptedText.constData()), + // decryptedText, //unsigned char* + // ec, + // RSA_PKCS1_OAEP_PADDING); + + EC_KEY_free(ec); + decryptionStatus = 1; } else { - qCDebug(commerce) << "During entity ownership challenge, creating the RSA object failed."; + qCDebug(commerce) << "During entity ownership challenge, creating the EC-signed nonce failed."; + decryptionStatus = -1; } + QByteArray ba = sig.toLocal8Bit(); + const char *sigChar = ba.data(); + QByteArray decryptedTextByteArray; if (decryptionStatus > -1) { - decryptedTextByteArray = QByteArray(reinterpret_cast(decryptedText), decryptionStatus); + decryptedTextByteArray = QByteArray(sigChar, decryptionStatus); } int decryptedTextByteArraySize = decryptedTextByteArray.size(); int certIDSize = certID.size(); @@ -774,7 +782,7 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack decryptedTextPacket->write(decryptedTextByteArray); decryptedTextPacket->write(challengingNodeUUID); - qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID; + qCDebug(commerce) << "Sending ChallengeOwnershipReply Packet containing signed text" << decryptedTextByteArray << "for CertID" << certID; nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode); } else { @@ -785,17 +793,17 @@ void Wallet::handleChallengeOwnershipPacket(QSharedPointer pack decryptedTextPacket->write(certID); decryptedTextPacket->write(decryptedTextByteArray); - qCDebug(commerce) << "Sending ChallengeOwnership Packet containing decrypted text" << decryptedTextByteArray << "for CertID" << certID; + qCDebug(commerce) << "Sending ChallengeOwnership Packet containing signed text" << decryptedTextByteArray << "for CertID" << certID; nodeList->sendPacket(std::move(decryptedTextPacket), *sendingNode); } if (decryptionStatus == -1) { - qCDebug(commerce) << "During entity ownership challenge, decrypting the encrypted text failed."; + qCDebug(commerce) << "During entity ownership challenge, signing the text failed."; long error = ERR_get_error(); if (error != 0) { const char* error_str = ERR_error_string(error, NULL); - qCWarning(entities) << "RSA error:" << error_str; + qCWarning(entities) << "EC error:" << error_str; } } } @@ -818,4 +826,4 @@ void Wallet::getWalletStatus() { walletScriptingInterface->setWalletStatus(status); return; } -} +} \ No newline at end of file From addcb51ed98e09693f79dd6c8bcf3f063b1f58df Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Wed, 8 Nov 2017 07:50:35 -0800 Subject: [PATCH 069/292] Change slider label from "master gain" to "master volume" --- interface/resources/qml/hifi/NameCard.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index 0adcde3ad9..7f78a29b2a 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -576,7 +576,7 @@ Item { // The slider for my card is special, it controls the master gain id: gainSliderText; visible: isMyCard; - text: "master gain"; + text: "master volume"; size: hifi.fontSizes.tabularData; anchors.left: parent.right; anchors.leftMargin: 8; From 393b55424fd5c64a4ff53af70891be8216b7b554 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 8 Nov 2017 11:37:22 -0800 Subject: [PATCH 070/292] Fix Create-new-domain-id not saving in DS settings --- domain-server/resources/web/settings/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 7f99b367a3..d13dde18ca 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -533,7 +533,7 @@ function createNewDomainID(label, justConnected) { $.post("/api/domains", domainJSON, function(data){ // we successfully created a domain ID, set it on that field - var domainID = data.domain_id; + var domainID = data.domain.id; console.log("Setting domain id to ", data, domainID); $(Settings.DOMAIN_ID_SELECTOR).val(domainID).change(); From 3a9c364837d9797ca146a61be95e397e3c6f0bd1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 8 Nov 2017 13:09:42 -0800 Subject: [PATCH 071/292] Fix domain server label not handling spaces correctly --- libraries/embedded-webserver/src/HTTPConnection.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/embedded-webserver/src/HTTPConnection.cpp b/libraries/embedded-webserver/src/HTTPConnection.cpp index 0a8448108e..a61bc95f8b 100644 --- a/libraries/embedded-webserver/src/HTTPConnection.cpp +++ b/libraries/embedded-webserver/src/HTTPConnection.cpp @@ -65,7 +65,9 @@ QHash HTTPConnection::parseUrlEncodedForm() { QUrlQuery form { _requestContent }; QHash pairs; for (auto pair : form.queryItems()) { - pairs[QUrl::fromPercentEncoding(pair.first.toLatin1())] = QUrl::fromPercentEncoding(pair.second.toLatin1()); + auto key = QUrl::fromPercentEncoding(pair.first.toLatin1().replace('+', ' ')); + auto value = QUrl::fromPercentEncoding(pair.second.toLatin1().replace('+', ' ')); + pairs[key] = value; } return pairs; From c77942c542e539a6bf9b5c746327362d4be1cd15 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 8 Nov 2017 13:36:03 -0800 Subject: [PATCH 072/292] Fix domain settings not showing label when first setting a placename This occurs because previously we only created the input elements if you have a domain id when the page loads. Because you can now have a domain id assigned after the page initially loads, we need to always create the input. --- domain-server/resources/web/settings/js/settings.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index d13dde18ca..a0bb407236 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -629,9 +629,7 @@ function showOrHideLabel() { } function setupDomainLabelSetting() { - if (!showOrHideLabel()) { - return; - } + showOrHideLabel(); var html = "
" html += " Edit"; From a55a30f87febdacf4e53693f47db33ac1c6bbfcd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 8 Nov 2017 14:00:43 -0800 Subject: [PATCH 073/292] Fix 'Path' label when adding a place name --- domain-server/resources/web/js/shared.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index 66159209ea..bff79ce863 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -236,7 +236,7 @@ function chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAd if (forcePathTo === undefined || forcePathTo === null) { var path = "
"; - path += ""; + path += ""; path += ""; path += "
"; modal_body.append($(path)); From 1db8e2a0ec2a4f8ba9abb76636a48bedfac64b84 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 8 Nov 2017 14:01:04 -0800 Subject: [PATCH 074/292] Update create domain id language --- domain-server/resources/web/settings/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index a0bb407236..419b55685f 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -503,7 +503,7 @@ function showDomainCreationAlert(justConnected) { swal({ title: 'Create new domain ID', type: 'input', - text: 'Enter a short description for this machine.

This will help you identify which domain ID belongs to which machine.

', + text: 'Enter a label this machine.

This will help you identify which domain ID belongs to which machine.

', showCancelButton: true, confirmButtonText: "Create", closeOnConfirm: false, From 028410a26a5c60ce7a00c79865c36ff7ebf37011 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 8 Nov 2017 14:05:51 -0800 Subject: [PATCH 075/292] Fix alignment of Disconnect btn on ds settings --- domain-server/resources/web/css/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index 8b004687b9..fb1e1aa9f5 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -302,6 +302,7 @@ table .headers + .headers td { } .account-connected-header { + vertical-align: middle; color: #6FCF97; font-size: 30px; margin-right: 20px; From 3b702a7ae342098453ac5a58189979da18a5e6f9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 9 Nov 2017 09:05:07 -0800 Subject: [PATCH 076/292] Make ESC close dialog windows on DS settings --- domain-server/resources/web/js/shared.js | 3 ++- domain-server/resources/web/settings/js/settings.js | 5 +++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/web/js/shared.js b/domain-server/resources/web/js/shared.js index bff79ce863..b21d1a2f79 100644 --- a/domain-server/resources/web/js/shared.js +++ b/domain-server/resources/web/js/shared.js @@ -363,7 +363,8 @@ function chooseFromHighFidelityPlaces(accessToken, forcePathTo, onSuccessfullyAd title: Strings.ADD_PLACE_TITLE, message: modal_body, closeButton: false, - buttons: modal_buttons + buttons: modal_buttons, + onEscape: true }); } else { bootbox.alert(Strings.ADD_PLACE_UNABLE_TO_LOAD_ERROR); diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 419b55685f..c24e2879ef 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -652,6 +652,7 @@ function setupDomainLabelSetting() { title: 'Edit Label', message: modal_body, closeButton: false, + onEscape: true, buttons: [ { label: 'Cancel', @@ -775,6 +776,7 @@ function setupDomainNetworkingSettings() { title: 'Edit Network', message: modal_body, closeButton: false, + onEscape: true, buttons: [ { label: 'Cancel', @@ -922,6 +924,7 @@ function placeTableRow(name, path, isTemporary, placeID) { var dialog = bootbox.dialog({ message: confirmString, closeButton: false, + onEscape: true, buttons: [ { label: Strings.REMOVE_PLACE_CANCEL_BUTTON, @@ -1096,6 +1099,7 @@ function editHighFidelityPlace(placeID, name, path) { dialog = bootbox.dialog({ title: Strings.EDIT_PLACE_TITLE, closeButton: false, + onEscape: true, message: modal_body, buttons: modal_buttons }) @@ -1178,6 +1182,7 @@ function chooseFromHighFidelityDomains(clickedButton) { bootbox.dialog({ title: "Choose matching domain", + onEscape: true, message: modal_body, buttons: modal_buttons }) From e274df065d006f8af7f1f6bb58a3f20efb2252f7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 9 Nov 2017 09:25:16 -0800 Subject: [PATCH 077/292] Fix label nav always being shown in ds settings nav --- domain-server/resources/web/settings/js/settings.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index c24e2879ef..19d711ebd8 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -620,12 +620,10 @@ function parseJSONResponse(xhr) { function showOrHideLabel() { var type = getCurrentDomainIDType(); - if (!accessTokenIsSet() || (type !== DOMAIN_ID_TYPE_FULL && type !== DOMAIN_ID_TYPE_UNKNOWN)) { - $(".panel#label").hide(); - return false; - } - $(".panel#label").show(); - return true; + var shouldShow = accessTokenIsSet() && (type === DOMAIN_ID_TYPE_FULL || type === DOMAIN_ID_TYPE_UNKNOWN); + $(".panel#label").toggle(shouldShow); + $("li a[href='#label']").parent().toggle(shouldShow); + return shouldShow; } function setupDomainLabelSetting() { From d62c98c6e2a99224461e97d76ed08cf677e549d1 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 9 Nov 2017 10:03:41 -0800 Subject: [PATCH 078/292] Update network address/port label in DS settings --- domain-server/resources/web/settings/js/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/resources/web/settings/js/settings.js b/domain-server/resources/web/settings/js/settings.js index 19d711ebd8..8f2e076f6c 100644 --- a/domain-server/resources/web/settings/js/settings.js +++ b/domain-server/resources/web/settings/js/settings.js @@ -739,7 +739,7 @@ function setupDomainNetworkingSettings() { var includeAddress = autoNetworkingSetting === 'disabled'; if (includeAddress) { - var label = "Network Address and Port"; + var label = "Network Address:Port"; } else { var label = "Network Port"; } From 5a78c9ebfee6685c32abcef652fb6b3b3f7dc348 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 8 Nov 2017 17:17:00 -0800 Subject: [PATCH 079/292] integrated stylus into pointer system, need to update controller module --- interface/src/raypick/JointRayPick.cpp | 2 +- interface/src/raypick/JointRayPick.h | 2 +- interface/src/raypick/LaserPointer.cpp | 70 +- interface/src/raypick/LaserPointer.h | 12 +- interface/src/raypick/MouseRayPick.cpp | 2 +- interface/src/raypick/MouseRayPick.h | 2 +- .../src/raypick/PickScriptingInterface.cpp | 27 + .../src/raypick/PickScriptingInterface.h | 1 + .../src/raypick/PointerScriptingInterface.cpp | 18 +- interface/src/raypick/RayPick.cpp | 59 +- interface/src/raypick/RayPick.h | 14 +- interface/src/raypick/StaticRayPick.cpp | 2 +- interface/src/raypick/StaticRayPick.h | 2 +- interface/src/raypick/StylusPick.cpp | 230 ++++++ interface/src/raypick/StylusPick.h | 78 ++ interface/src/raypick/StylusPointer.cpp | 713 ++++-------------- interface/src/raypick/StylusPointer.h | 143 +--- libraries/pointers/src/pointers/Pointer.cpp | 4 +- libraries/pointers/src/pointers/Pointer.h | 8 +- libraries/shared/src/RegisteredMetaTypes.h | 28 +- .../controllerModules/inEditMode.js | 10 +- 21 files changed, 645 insertions(+), 782 deletions(-) create mode 100644 interface/src/raypick/StylusPick.cpp create mode 100644 interface/src/raypick/StylusPick.h diff --git a/interface/src/raypick/JointRayPick.cpp b/interface/src/raypick/JointRayPick.cpp index fdffb9796d..45b21f7bcc 100644 --- a/interface/src/raypick/JointRayPick.cpp +++ b/interface/src/raypick/JointRayPick.cpp @@ -12,7 +12,7 @@ #include "avatar/AvatarManager.h" -JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance, const bool enabled) : +JointRayPick::JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, float maxDistance, bool enabled) : RayPick(filter, maxDistance, enabled), _jointName(jointName), _posOffset(posOffset), diff --git a/interface/src/raypick/JointRayPick.h b/interface/src/raypick/JointRayPick.h index 947eb81ba8..c0031d87ff 100644 --- a/interface/src/raypick/JointRayPick.h +++ b/interface/src/raypick/JointRayPick.h @@ -16,7 +16,7 @@ class JointRayPick : public RayPick { public: - JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + JointRayPick(const std::string& jointName, const glm::vec3& posOffset, const glm::vec3& dirOffset, const PickFilter& filter, float maxDistance = 0.0f, bool enabled = false); PickRay getMathematicalPick() const override; diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 464de83565..bd54a24e97 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -184,7 +184,7 @@ void LaserPointer::updateVisuals(const PickResultPointer& pickResult) { IntersectionType type = rayPickResult ? rayPickResult->type : IntersectionType::NONE; if (_enabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() && (type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) { - PickRay pickRay{ rayPickResult->pickVariant }; + PickRay pickRay(rayPickResult->pickVariant); QUuid uid = rayPickResult->objectID; float distance = _laserLength > 0.0f ? _laserLength : rayPickResult->distance; updateRenderState(_renderStates[_currentRenderState], type, distance, uid, pickRay, false); @@ -292,82 +292,30 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) { PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const { QUuid pickedID; glm::vec3 intersection, surfaceNormal, direction, origin; - if (target.type != NONE) { - auto rayPickResult = std::static_pointer_cast(pickResult); + auto rayPickResult = std::static_pointer_cast(pickResult); + if (rayPickResult) { intersection = rayPickResult->intersection; surfaceNormal = rayPickResult->surfaceNormal; const QVariantMap& searchRay = rayPickResult->pickVariant; direction = vec3FromVariant(searchRay["direction"]); origin = vec3FromVariant(searchRay["origin"]); - pickedID = rayPickResult->objectID;; + pickedID = rayPickResult->objectID; } glm::vec2 pos2D; if (pickedID != target.objectID) { if (target.type == ENTITY) { - intersection = intersectRayWithEntityXYPlane(target.objectID, origin, direction); + intersection = RayPick::intersectRayWithEntityXYPlane(target.objectID, origin, direction); } else if (target.type == OVERLAY) { - intersection = intersectRayWithOverlayXYPlane(target.objectID, origin, direction); + intersection = RayPick::intersectRayWithOverlayXYPlane(target.objectID, origin, direction); } } if (target.type == ENTITY) { - pos2D = projectOntoEntityXYPlane(target.objectID, intersection); + pos2D = RayPick::projectOntoEntityXYPlane(target.objectID, intersection); } else if (target.type == OVERLAY) { - pos2D = projectOntoOverlayXYPlane(target.objectID, intersection); + pos2D = RayPick::projectOntoOverlayXYPlane(target.objectID, intersection); } else if (target.type == HUD) { pos2D = DependencyManager::get()->calculatePos2DFromHUD(intersection); } return PointerEvent(pos2D, intersection, surfaceNormal, direction); -} - -glm::vec3 LaserPointer::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const { - glm::vec3 n = rotation * Vectors::FRONT; - float t = glm::dot(n, point - origin) / glm::dot(n, direction); - return origin + t * direction; -} - -glm::vec3 LaserPointer::intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) const { - glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value); - glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value); - const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); - return intersectRayWithXYPlane(origin, direction, position, rotation, DEFAULT_REGISTRATION_POINT); -} - -glm::vec3 LaserPointer::intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) const { - auto props = DependencyManager::get()->getEntityProperties(entityID); - return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint()); -} - -glm::vec2 LaserPointer::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const { - glm::quat invRot = glm::inverse(rotation); - glm::vec3 localPos = invRot * (worldPos - position); - glm::vec3 invDimensions = glm::vec3(1.0f / dimensions.x, 1.0f / dimensions.y, 1.0f / dimensions.z); - - glm::vec3 normalizedPos = (localPos * invDimensions) + registrationPoint; - return glm::vec2(normalizedPos.x * dimensions.x, (1.0f - normalizedPos.y) * dimensions.y); -} - -glm::vec2 LaserPointer::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos) const { - glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value); - glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value); - glm::vec3 dimensions; - - float dpi = qApp->getOverlays().getProperty(overlayID, "dpi").value.toFloat(); - if (dpi > 0) { - // Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property is used as a scale. - glm::vec3 resolution = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "resolution").value), 1); - glm::vec3 scale = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01f); - const float INCHES_TO_METERS = 1.0f / 39.3701f; - dimensions = (resolution * INCHES_TO_METERS / dpi) * scale; - } else { - dimensions = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01); - } - - const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); - return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT); -} - -glm::vec2 LaserPointer::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const { - auto props = DependencyManager::get()->getEntityProperties(entityID); - return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint()); -} +} \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index c93404e14d..4874cadf0a 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -75,8 +75,8 @@ protected: PickedObject getHoveredObject(const PickResultPointer& pickResult) override; Pointer::Buttons getPressedButtons() override; - bool shouldHover() override { return _currentRenderState != ""; } - bool shouldTrigger() override { return _currentRenderState != ""; } + bool shouldHover(const PickResultPointer& pickResult) override { return _currentRenderState != ""; } + bool shouldTrigger(const PickResultPointer& pickResult) override { return _currentRenderState != ""; } private: PointerTriggers _triggers; @@ -94,14 +94,6 @@ private: void updateRenderState(const RenderState& renderState, const IntersectionType type, float distance, const QUuid& objectID, const PickRay& pickRay, bool defaultState); void disableRenderState(const RenderState& renderState); - - glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) const; - glm::vec3 intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) const; - glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat rotation, const glm::vec3& registration) const; - glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos) const; - glm::vec2 projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos) const; - glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint) const; - }; #endif // hifi_LaserPointer_h diff --git a/interface/src/raypick/MouseRayPick.cpp b/interface/src/raypick/MouseRayPick.cpp index 1f39b61614..2b55c44460 100644 --- a/interface/src/raypick/MouseRayPick.cpp +++ b/interface/src/raypick/MouseRayPick.cpp @@ -13,7 +13,7 @@ #include "Application.h" #include "display-plugins/CompositorHelper.h" -MouseRayPick::MouseRayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : +MouseRayPick::MouseRayPick(const PickFilter& filter, float maxDistance, bool enabled) : RayPick(filter, maxDistance, enabled) { } diff --git a/interface/src/raypick/MouseRayPick.h b/interface/src/raypick/MouseRayPick.h index 79e94ed777..a9070e8b92 100644 --- a/interface/src/raypick/MouseRayPick.h +++ b/interface/src/raypick/MouseRayPick.h @@ -16,7 +16,7 @@ class MouseRayPick : public RayPick { public: - MouseRayPick(const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + MouseRayPick(const PickFilter& filter, float maxDistance = 0.0f, bool enabled = false); PickRay getMathematicalPick() const override; diff --git a/interface/src/raypick/PickScriptingInterface.cpp b/interface/src/raypick/PickScriptingInterface.cpp index 137c3fa6ae..dad4cde3b7 100644 --- a/interface/src/raypick/PickScriptingInterface.cpp +++ b/interface/src/raypick/PickScriptingInterface.cpp @@ -16,6 +16,7 @@ #include "StaticRayPick.h" #include "JointRayPick.h" #include "MouseRayPick.h" +#include "StylusPick.h" #include #include @@ -24,6 +25,8 @@ unsigned int PickScriptingInterface::createPick(const PickQuery::PickType type, switch (type) { case PickQuery::PickType::Ray: return createRayPick(properties); + case PickQuery::PickType::Stylus: + return createStylusPick(properties); default: return PickManager::INVALID_PICK_ID; } @@ -81,6 +84,30 @@ unsigned int PickScriptingInterface::createRayPick(const QVariant& properties) { return PickManager::INVALID_PICK_ID; } +unsigned int PickScriptingInterface::createStylusPick(const QVariant& properties) { + QVariantMap propMap = properties.toMap(); + + bilateral::Side side = bilateral::Side::Invalid; + { + QVariant handVar = propMap["hand"]; + if (handVar.isValid()) { + side = bilateral::side(handVar.toInt()); + } + } + + bool enabled = false; + if (propMap["enabled"].isValid()) { + enabled = propMap["enabled"].toBool(); + } + + PickFilter filter = PickFilter(); + if (propMap["filter"].isValid()) { + filter = PickFilter(propMap["filter"].toUInt()); + } + + return DependencyManager::get()->addPick(PickQuery::Stylus, std::make_shared(filter, side, enabled)); +} + void PickScriptingInterface::enablePick(unsigned int uid) { DependencyManager::get()->enablePick(uid); } diff --git a/interface/src/raypick/PickScriptingInterface.h b/interface/src/raypick/PickScriptingInterface.h index 613686be9b..108ee99473 100644 --- a/interface/src/raypick/PickScriptingInterface.h +++ b/interface/src/raypick/PickScriptingInterface.h @@ -34,6 +34,7 @@ class PickScriptingInterface : public QObject, public Dependency { public: unsigned int createRayPick(const QVariant& properties); + unsigned int createStylusPick(const QVariant& properties); void registerMetaTypes(QScriptEngine* engine); diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 0572434c56..70d60fc467 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -43,19 +43,19 @@ unsigned int PointerScriptingInterface::createPointer(const PickQuery::PickType& } unsigned int PointerScriptingInterface::createStylus(const QVariant& properties) const { - bilateral::Side side = bilateral::Side::Invalid; - { - QVariant handVar = properties.toMap()["hand"]; - if (handVar.isValid()) { - side = bilateral::side(handVar.toInt()); - } + QVariantMap propertyMap = properties.toMap(); + + bool hover = false; + if (propertyMap["hover"].isValid()) { + hover = propertyMap["hover"].toBool(); } - if (bilateral::Side::Invalid == side) { - return PointerEvent::INVALID_POINTER_ID; + bool enabled = false; + if (propertyMap["enabled"].isValid()) { + enabled = propertyMap["enabled"].toBool(); } - return DependencyManager::get()->addPointer(std::make_shared(side)); + return DependencyManager::get()->addPointer(std::make_shared(properties, StylusPointer::buildStylusOverlay(propertyMap), hover, enabled)); } unsigned int PointerScriptingInterface::createLaserPointer(const QVariant& properties) const { diff --git a/interface/src/raypick/RayPick.cpp b/interface/src/raypick/RayPick.cpp index 4e1e0386f1..7689b295db 100644 --- a/interface/src/raypick/RayPick.cpp +++ b/interface/src/raypick/RayPick.cpp @@ -48,4 +48,61 @@ PickResultPointer RayPick::getAvatarIntersection(const PickRay& pick) { PickResultPointer RayPick::getHUDIntersection(const PickRay& pick) { glm::vec3 hudRes = DependencyManager::get()->calculateRayUICollisionPoint(pick.origin, pick.direction); return std::make_shared(IntersectionType::HUD, QUuid(), glm::distance(pick.origin, hudRes), hudRes, pick); -} \ No newline at end of file +} + +glm::vec3 RayPick::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat& rotation, const glm::vec3& registration) { + // TODO: take into account registration + glm::vec3 n = rotation * Vectors::FRONT; + float t = glm::dot(n, point - origin) / glm::dot(n, direction); + return origin + t * direction; +} + +glm::vec3 RayPick::intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction) { + glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value); + glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value); + const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); + return intersectRayWithXYPlane(origin, direction, position, rotation, DEFAULT_REGISTRATION_POINT); +} + +glm::vec3 RayPick::intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction) { + auto props = DependencyManager::get()->getEntityProperties(entityID); + return intersectRayWithXYPlane(origin, direction, props.getPosition(), props.getRotation(), props.getRegistrationPoint()); +} + +glm::vec2 RayPick::projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint, bool unNormalized) { + glm::quat invRot = glm::inverse(rotation); + glm::vec3 localPos = invRot * (worldPos - position); + + glm::vec3 normalizedPos = (localPos / dimensions) + registrationPoint; + + glm::vec2 pos2D = glm::vec2(normalizedPos.x, (1.0f - normalizedPos.y)); + if (unNormalized) { + pos2D *= glm::vec2(dimensions.x, dimensions.y); + } + return pos2D; +} + +glm::vec2 RayPick::projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos, bool unNormalized) { + glm::vec3 position = vec3FromVariant(qApp->getOverlays().getProperty(overlayID, "position").value); + glm::quat rotation = quatFromVariant(qApp->getOverlays().getProperty(overlayID, "rotation").value); + glm::vec3 dimensions; + + float dpi = qApp->getOverlays().getProperty(overlayID, "dpi").value.toFloat(); + if (dpi > 0) { + // Calculate physical dimensions for web3d overlay from resolution and dpi; "dimensions" property is used as a scale. + glm::vec3 resolution = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "resolution").value), 1); + glm::vec3 scale = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01f); + const float INCHES_TO_METERS = 1.0f / 39.3701f; + dimensions = (resolution * INCHES_TO_METERS / dpi) * scale; + } else { + dimensions = glm::vec3(vec2FromVariant(qApp->getOverlays().getProperty(overlayID, "dimensions").value), 0.01); + } + + const glm::vec3 DEFAULT_REGISTRATION_POINT = glm::vec3(0.5f); + return projectOntoXYPlane(worldPos, position, rotation, dimensions, DEFAULT_REGISTRATION_POINT, unNormalized); +} + +glm::vec2 RayPick::projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized) { + auto props = DependencyManager::get()->getEntityProperties(entityID); + return projectOntoXYPlane(worldPos, props.getPosition(), props.getRotation(), props.getDimensions(), props.getRegistrationPoint(), unNormalized); +} diff --git a/interface/src/raypick/RayPick.h b/interface/src/raypick/RayPick.h index 1c2b3fbb80..4a4ac69edd 100644 --- a/interface/src/raypick/RayPick.h +++ b/interface/src/raypick/RayPick.h @@ -18,7 +18,7 @@ class RayPickResult : public PickResult { public: RayPickResult() {} RayPickResult(const QVariantMap& pickVariant) : PickResult(pickVariant) {} - RayPickResult(const IntersectionType type, const QUuid& objectID, const float distance, const glm::vec3& intersection, const PickRay& searchRay, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + RayPickResult(const IntersectionType type, const QUuid& objectID, float distance, const glm::vec3& intersection, const PickRay& searchRay, const glm::vec3& surfaceNormal = glm::vec3(NAN)) : PickResult(searchRay.toVariantMap()), type(type), intersects(type != NONE), objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) { } @@ -67,13 +67,23 @@ public: class RayPick : public Pick { public: - RayPick(const PickFilter& filter, const float maxDistance, const bool enabled) : Pick(filter, maxDistance, enabled) {} + RayPick(const PickFilter& filter, float maxDistance, bool enabled) : Pick(filter, maxDistance, enabled) {} PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override { return std::make_shared(pickVariant); } PickResultPointer getEntityIntersection(const PickRay& pick) override; PickResultPointer getOverlayIntersection(const PickRay& pick) override; PickResultPointer getAvatarIntersection(const PickRay& pick) override; PickResultPointer getHUDIntersection(const PickRay& pick) override; + + // These are helper functions for projecting and intersecting rays + static glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction); + static glm::vec3 intersectRayWithOverlayXYPlane(const QUuid& overlayID, const glm::vec3& origin, const glm::vec3& direction); + static glm::vec2 projectOntoEntityXYPlane(const QUuid& entityID, const glm::vec3& worldPos, bool unNormalized = true); + static glm::vec2 projectOntoOverlayXYPlane(const QUuid& overlayID, const glm::vec3& worldPos, bool unNormalized = true); + +private: + static glm::vec3 intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat& rotation, const glm::vec3& registration); + static glm::vec2 projectOntoXYPlane(const glm::vec3& worldPos, const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions, const glm::vec3& registrationPoint, bool unNormalized); }; #endif // hifi_RayPick_h diff --git a/interface/src/raypick/StaticRayPick.cpp b/interface/src/raypick/StaticRayPick.cpp index c79f87ad0e..b74afd6b5d 100644 --- a/interface/src/raypick/StaticRayPick.cpp +++ b/interface/src/raypick/StaticRayPick.cpp @@ -7,7 +7,7 @@ // #include "StaticRayPick.h" -StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance, const bool enabled) : +StaticRayPick::StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, float maxDistance, bool enabled) : RayPick(filter, maxDistance, enabled), _pickRay(position, direction) { diff --git a/interface/src/raypick/StaticRayPick.h b/interface/src/raypick/StaticRayPick.h index ded57caf4e..e4da2dbd55 100644 --- a/interface/src/raypick/StaticRayPick.h +++ b/interface/src/raypick/StaticRayPick.h @@ -13,7 +13,7 @@ class StaticRayPick : public RayPick { public: - StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, const float maxDistance = 0.0f, const bool enabled = false); + StaticRayPick(const glm::vec3& position, const glm::vec3& direction, const PickFilter& filter, float maxDistance = 0.0f, bool enabled = false); PickRay getMathematicalPick() const override; diff --git a/interface/src/raypick/StylusPick.cpp b/interface/src/raypick/StylusPick.cpp new file mode 100644 index 0000000000..f2b650b5bf --- /dev/null +++ b/interface/src/raypick/StylusPick.cpp @@ -0,0 +1,230 @@ +// +// Created by Bradley Austin Davis on 2017/10/24 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#include "StylusPick.h" + +#include "RayPick.h" + +#include + +#include "ui/overlays/Base3DOverlay.h" + +#include "Application.h" +#include +#include "avatar/AvatarManager.h" + +#include +#include + +using namespace bilateral; + +// TODO: make these configurable per pick +static Setting::Handle USE_FINGER_AS_STYLUS("preferAvatarFingerOverStylus", false); +static const float WEB_STYLUS_LENGTH = 0.2f; +static const float WEB_TOUCH_Y_OFFSET = 0.105f; // how far forward (or back with a negative number) to slide stylus in hand +static const glm::vec3 TIP_OFFSET{ 0.0f, WEB_STYLUS_LENGTH - WEB_TOUCH_Y_OFFSET, 0.0f }; + +struct SideData { + QString avatarJoint; + QString cameraJoint; + controller::StandardPoseChannel channel; + controller::Hand hand; + glm::vec3 grabPointSphereOffset; + + int getJointIndex(bool finger) { + const auto& jointName = finger ? avatarJoint : cameraJoint; + return DependencyManager::get()->getMyAvatar()->getJointIndex(jointName); + } +}; + +static const std::array SIDES{ { { "LeftHandIndex4", + "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", + controller::StandardPoseChannel::LEFT_HAND, + controller::Hand::LEFT, + { -0.04f, 0.13f, 0.039f } }, + { "RightHandIndex4", + "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", + controller::StandardPoseChannel::RIGHT_HAND, + controller::Hand::RIGHT, + { 0.04f, 0.13f, 0.039f } } } }; + +std::shared_ptr StylusPickResult::compareAndProcessNewResult(const std::shared_ptr& newRes) { + auto newStylusResult = std::static_pointer_cast(newRes); + if (newStylusResult && newStylusResult->distance < distance) { + return std::make_shared(*newStylusResult); + } else { + return std::make_shared(*this); + } +} + +bool StylusPickResult::checkOrFilterAgainstMaxDistance(float maxDistance) { + return distance < maxDistance; +} + +StylusPick::StylusPick(const PickFilter& filter, Side side, bool enabled) : + Pick(filter, 0.0f, enabled), + _side(side) +{ +} + +static StylusTip getFingerWorldLocation(Side side) { + const auto& sideData = SIDES[index(side)]; + auto myAvatar = DependencyManager::get()->getMyAvatar(); + auto fingerJointIndex = myAvatar->getJointIndex(sideData.avatarJoint); + + if (fingerJointIndex == -1) { + return StylusTip(); + } + + auto fingerPosition = myAvatar->getAbsoluteJointTranslationInObjectFrame(fingerJointIndex); + auto fingerRotation = myAvatar->getAbsoluteJointRotationInObjectFrame(fingerJointIndex); + auto avatarOrientation = myAvatar->getOrientation(); + auto avatarPosition = myAvatar->getPosition(); + StylusTip result; + result.side = side; + result.orientation = avatarOrientation * fingerRotation; + result.position = avatarPosition + (avatarOrientation * fingerPosition); + return result; +} + +// controllerWorldLocation is where the controller would be, in-world, with an added offset +static StylusTip getControllerWorldLocation(Side side) { + static const std::array INPUTS{ { UserInputMapper::makeStandardInput(SIDES[0].channel), + UserInputMapper::makeStandardInput(SIDES[1].channel) } }; + const auto sideIndex = index(side); + const auto& input = INPUTS[sideIndex]; + + const auto pose = DependencyManager::get()->getPose(input); + const auto& valid = pose.valid; + StylusTip result; + if (valid) { + result.side = side; + const auto& sideData = SIDES[sideIndex]; + auto myAvatar = DependencyManager::get()->getMyAvatar(); + float sensorScaleFactor = myAvatar->getSensorToWorldScale(); + auto controllerJointIndex = myAvatar->getJointIndex(sideData.cameraJoint); + + const auto avatarOrientation = myAvatar->getOrientation(); + const auto avatarPosition = myAvatar->getPosition(); + result.orientation = avatarOrientation * myAvatar->getAbsoluteJointRotationInObjectFrame(controllerJointIndex); + + result.position = avatarPosition + (avatarOrientation * myAvatar->getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)); + // add to the real position so the grab-point is out in front of the hand, a bit + result.position += result.orientation * (sideData.grabPointSphereOffset * sensorScaleFactor); + // move the stylus forward a bit + result.position += result.orientation * (TIP_OFFSET * sensorScaleFactor); + + auto worldControllerPos = avatarPosition + avatarOrientation * pose.translation; + // compute tip velocity from hand controller motion, it is more accurate than computing it from previous positions. + auto worldControllerLinearVel = avatarOrientation * pose.velocity; + auto worldControllerAngularVel = avatarOrientation * pose.angularVelocity; + result.velocity = worldControllerLinearVel + glm::cross(worldControllerAngularVel, result.position - worldControllerPos); + } + + return result; +} + +StylusTip StylusPick::getMathematicalPick() const { + StylusTip result; + if (USE_FINGER_AS_STYLUS.get()) { + result = getFingerWorldLocation(_side); + } else { + result = getControllerWorldLocation(_side); + } + return result; +} + +PickResultPointer StylusPick::getDefaultResult(const QVariantMap& pickVariant) const { + return std::make_shared(pickVariant); +} + +PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) { + std::vector results; + for (const auto& target : getIncludeItems()) { + if (target.isNull()) { + continue; + } + + auto entity = qApp->getEntities()->getTree()->findEntityByEntityItemID(target); + // Don't interact with non-3D or invalid overlays + if (!entity) { + continue; + } + + if (!entity->getVisible() && !getFilter().doesPickInvisible()) { + continue; + } + + const auto entityRotation = entity->getRotation(); + const auto entityPosition = entity->getPosition(); + + glm::vec3 normal = entityRotation * Vectors::UNIT_Z; + float distance = glm::dot(pick.position - entityPosition, normal); + glm::vec3 intersection = pick.position - (normal * distance); + + glm::vec2 pos2D = RayPick::projectOntoEntityXYPlane(target, intersection, false); + if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) { + results.push_back(StylusPickResult(IntersectionType::ENTITY, target, distance, intersection, pick, normal)); + } + } + + StylusPickResult nearestTarget(pick.toVariantMap()); + for (const auto& result : results) { + if (result.distance < nearestTarget.distance) { + nearestTarget = result; + } + } + return std::make_shared(nearestTarget); +} + +PickResultPointer StylusPick::getOverlayIntersection(const StylusTip& pick) { + std::vector results; + for (const auto& target : getIncludeItems()) { + if (target.isNull()) { + continue; + } + + auto overlay = qApp->getOverlays().getOverlay(target); + // Don't interact with non-3D or invalid overlays + if (!overlay || !overlay->is3D()) { + continue; + } + + if (!overlay->getVisible() && !getFilter().doesPickInvisible()) { + continue; + } + + auto overlay3D = std::static_pointer_cast(overlay); + const auto overlayRotation = overlay3D->getRotation(); + const auto overlayPosition = overlay3D->getPosition(); + + glm::vec3 normal = overlayRotation * Vectors::UNIT_Z; + float distance = glm::dot(pick.position - overlayPosition, normal); + glm::vec3 intersection = pick.position - (normal * distance); + + glm::vec2 pos2D = RayPick::projectOntoOverlayXYPlane(target, intersection, false); + if (pos2D == glm::clamp(pos2D, glm::vec2(0), glm::vec2(1))) { + results.push_back(StylusPickResult(IntersectionType::OVERLAY, target, distance, intersection, pick, normal)); + } + } + + StylusPickResult nearestTarget(pick.toVariantMap()); + for (const auto& result : results) { + if (result.distance < nearestTarget.distance) { + nearestTarget = result; + } + } + return std::make_shared(nearestTarget); +} + +PickResultPointer StylusPick::getAvatarIntersection(const StylusTip& pick) { + return std::make_shared(pick.toVariantMap()); +} + +PickResultPointer StylusPick::getHUDIntersection(const StylusTip& pick) { + return std::make_shared(pick.toVariantMap()); +} \ No newline at end of file diff --git a/interface/src/raypick/StylusPick.h b/interface/src/raypick/StylusPick.h new file mode 100644 index 0000000000..9b465b9cc8 --- /dev/null +++ b/interface/src/raypick/StylusPick.h @@ -0,0 +1,78 @@ +// +// Created by Bradley Austin Davis on 2017/10/24 +// Copyright 2013-2017 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_StylusPick_h +#define hifi_StylusPick_h + +#include "pointers/Pick.h" +#include "RegisteredMetaTypes.h" + +class StylusPickResult : public PickResult { + using Side = bilateral::Side; + +public: + StylusPickResult() {} + StylusPickResult(const QVariantMap& pickVariant) : PickResult(pickVariant) {} + StylusPickResult(const IntersectionType type, const QUuid& objectID, float distance, const glm::vec3& intersection, const StylusTip& stylusTip, + const glm::vec3& surfaceNormal = glm::vec3(NAN)) : + PickResult(stylusTip.toVariantMap()), type(type), intersects(type != NONE), objectID(objectID), distance(distance), intersection(intersection), surfaceNormal(surfaceNormal) { + } + + StylusPickResult(const StylusPickResult& stylusPickResult) : PickResult(stylusPickResult.pickVariant) { + type = stylusPickResult.type; + intersects = stylusPickResult.intersects; + objectID = stylusPickResult.objectID; + distance = stylusPickResult.distance; + intersection = stylusPickResult.intersection; + surfaceNormal = stylusPickResult.surfaceNormal; + } + + IntersectionType type { NONE }; + bool intersects { false }; + QUuid objectID; + float distance { FLT_MAX }; + glm::vec3 intersection { NAN }; + glm::vec3 surfaceNormal { NAN }; + + virtual QVariantMap toVariantMap() const override { + QVariantMap toReturn; + toReturn["type"] = type; + toReturn["intersects"] = intersects; + toReturn["objectID"] = objectID; + toReturn["distance"] = distance; + toReturn["intersection"] = vec3toVariant(intersection); + toReturn["surfaceNormal"] = vec3toVariant(surfaceNormal); + toReturn["stylusTip"] = PickResult::toVariantMap(); + return toReturn; + } + + bool doesIntersect() const override { return intersects; } + std::shared_ptr compareAndProcessNewResult(const std::shared_ptr& newRes) override; + bool checkOrFilterAgainstMaxDistance(float maxDistance) override; +}; + +class StylusPick : public Pick { + using Side = bilateral::Side; +public: + StylusPick(const PickFilter& filter, Side side, bool enabled); + + StylusTip getMathematicalPick() const override; + PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override; + PickResultPointer getEntityIntersection(const StylusTip& pick) override; + PickResultPointer getOverlayIntersection(const StylusTip& pick) override; + PickResultPointer getAvatarIntersection(const StylusTip& pick) override; + PickResultPointer getHUDIntersection(const StylusTip& pick) override; + +private: + const Side _side; +}; + +#endif // hifi_StylusPick_h + + + + diff --git a/interface/src/raypick/StylusPointer.cpp b/interface/src/raypick/StylusPointer.cpp index 6da755a797..80e783cfe4 100644 --- a/interface/src/raypick/StylusPointer.cpp +++ b/interface/src/raypick/StylusPointer.cpp @@ -7,621 +7,200 @@ // #include "StylusPointer.h" -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include "RayPick.h" #include "Application.h" #include "avatar/AvatarManager.h" #include "avatar/MyAvatar.h" -#include "scripting/HMDScriptingInterface.h" -#include "ui/overlays/Web3DOverlay.h" -#include "ui/overlays/Sphere3DOverlay.h" -#include "avatar/AvatarManager.h" -#include "InterfaceLogging.h" +#include #include "PickScriptingInterface.h" +#include using namespace controller; -using namespace bilateral; -static Setting::Handle USE_FINGER_AS_STYLUS("preferAvatarFingerOverStylus", false); +// TODO: make these configurable per pointer static const float WEB_STYLUS_LENGTH = 0.2f; -static const float WEB_TOUCH_Y_OFFSET = 0.105f; // how far forward (or back with a negative number) to slide stylus in hand -static const vec3 TIP_OFFSET{ 0.0f, WEB_STYLUS_LENGTH - WEB_TOUCH_Y_OFFSET, 0.0f }; -static const float TABLET_MIN_HOVER_DISTANCE = 0.01f; + +static const float TABLET_MIN_HOVER_DISTANCE = -0.1f; static const float TABLET_MAX_HOVER_DISTANCE = 0.1f; -static const float TABLET_MIN_TOUCH_DISTANCE = -0.05f; -static const float TABLET_MAX_TOUCH_DISTANCE = TABLET_MIN_HOVER_DISTANCE; -static const float EDGE_BORDER = 0.075f; +static const float TABLET_MIN_TOUCH_DISTANCE = -0.1f; +static const float TABLET_MAX_TOUCH_DISTANCE = 0.01f; static const float HOVER_HYSTERESIS = 0.01f; -static const float NEAR_HYSTERESIS = 0.05f; -static const float TOUCH_HYSTERESIS = 0.002f; +static const float TOUCH_HYSTERESIS = 0.02f; -// triggered when stylus presses a web overlay/entity -static const float HAPTIC_STYLUS_STRENGTH = 1.0f; -static const float HAPTIC_STYLUS_DURATION = 20.0f; -static const float POINTER_PRESS_TO_MOVE_DELAY = 0.33f; // seconds - -static const float WEB_DISPLAY_STYLUS_DISTANCE = 0.5f; -static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f; -static const float TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED = TOUCH_PRESS_TO_MOVE_DEADSPOT * TOUCH_PRESS_TO_MOVE_DEADSPOT; - -std::array STYLUSES; - -static OverlayID getHomeButtonID() { - return DependencyManager::get()->getCurrentHomeButtonID(); -} - -static OverlayID getTabletScreenID() { - return DependencyManager::get()->getCurrentTabletScreenID(); -} - -struct SideData { - QString avatarJoint; - QString cameraJoint; - controller::StandardPoseChannel channel; - controller::Hand hand; - vec3 grabPointSphereOffset; - - int getJointIndex(bool finger) { - const auto& jointName = finger ? avatarJoint : cameraJoint; - return DependencyManager::get()->getMyAvatar()->getJointIndex(jointName); - } -}; - -static const std::array SIDES{ { { "LeftHandIndex4", - "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", - StandardPoseChannel::LEFT_HAND, - Hand::LEFT, - { -0.04f, 0.13f, 0.039f } }, - { "RightHandIndex4", - "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", - StandardPoseChannel::RIGHT_HAND, - Hand::RIGHT, - { 0.04f, 0.13f, 0.039f } } } }; - -static StylusTip getFingerWorldLocation(Side side) { - const auto& sideData = SIDES[index(side)]; - auto myAvatar = DependencyManager::get()->getMyAvatar(); - auto fingerJointIndex = myAvatar->getJointIndex(sideData.avatarJoint); - - if (-1 == fingerJointIndex) { - return StylusTip(); - } - - auto fingerPosition = myAvatar->getAbsoluteJointTranslationInObjectFrame(fingerJointIndex); - auto fingerRotation = myAvatar->getAbsoluteJointRotationInObjectFrame(fingerJointIndex); - auto avatarOrientation = myAvatar->getOrientation(); - auto avatarPosition = myAvatar->getPosition(); - StylusTip result; - result.side = side; - result.orientation = avatarOrientation * fingerRotation; - result.position = avatarPosition + (avatarOrientation * fingerPosition); - return result; -} - -// controllerWorldLocation is where the controller would be, in-world, with an added offset -static StylusTip getControllerWorldLocation(Side side, float sensorToWorldScale) { - static const std::array INPUTS{ { UserInputMapper::makeStandardInput(SIDES[0].channel), - UserInputMapper::makeStandardInput(SIDES[1].channel) } }; - const auto sideIndex = index(side); - const auto& input = INPUTS[sideIndex]; - - const auto pose = DependencyManager::get()->getPose(input); - const auto& valid = pose.valid; - StylusTip result; - if (valid) { - result.side = side; - const auto& sideData = SIDES[sideIndex]; - auto myAvatar = DependencyManager::get()->getMyAvatar(); - auto controllerJointIndex = myAvatar->getJointIndex(sideData.cameraJoint); - - const auto avatarOrientation = myAvatar->getOrientation(); - const auto avatarPosition = myAvatar->getPosition(); - result.orientation = avatarOrientation * myAvatar->getAbsoluteJointRotationInObjectFrame(controllerJointIndex); - result.position = - avatarPosition + (avatarOrientation * myAvatar->getAbsoluteJointTranslationInObjectFrame(controllerJointIndex)); - // add to the real position so the grab-point is out in front of the hand, a bit - result.position += result.orientation * (sideData.grabPointSphereOffset * sensorToWorldScale); - auto worldControllerPos = avatarPosition + avatarOrientation * pose.translation; - // compute tip velocity from hand controller motion, it is more accurate than computing it from previous positions. - auto worldControllerLinearVel = avatarOrientation * pose.velocity; - auto worldControllerAngularVel = avatarOrientation * pose.angularVelocity; - result.velocity = - worldControllerLinearVel + glm::cross(worldControllerAngularVel, result.position - worldControllerPos); - } - - return result; -} - -bool StylusPickResult::isNormalized() const { - return valid && (normalizedPosition == glm::clamp(normalizedPosition, vec3(0), vec3(1))); -} - -bool StylusPickResult::isNearNormal(float min, float max, float hystersis) const { - return valid && (distance == glm::clamp(distance, min - hystersis, max + hystersis)); -} - -bool StylusPickResult::isNear2D(float border, float hystersis) const { - return valid && position2D == glm::clamp(position2D, vec2(0) - border - hystersis, vec2(dimensions) + border + hystersis); -} - -bool StylusPickResult::isNear(float min, float max, float border, float hystersis) const { - // check to see if the projected stylusTip is within within the 2d border - return isNearNormal(min, max, hystersis) && isNear2D(border, hystersis); -} - -StylusPickResult::operator bool() const { - return valid; -} - -bool StylusPickResult::hasKeyboardFocus() const { - if (!overlayID.isNull()) { - return qApp->getOverlays().getKeyboardFocusOverlay() == overlayID; - } -#if 0 - if (!entityID.isNull()) { - return qApp->getKeyboardFocusEntity() == entityID; - } -#endif - return false; -} - -void StylusPickResult::setKeyboardFocus() const { - if (!overlayID.isNull()) { - qApp->getOverlays().setKeyboardFocusOverlay(overlayID); - qApp->setKeyboardFocusEntity(EntityItemID()); -#if 0 - } else if (!entityID.isNull()) { - qApp->getOverlays().setKeyboardFocusOverlay(OverlayID()); - qApp->setKeyboardFocusEntity(entityID); -#endif - } -} - -void StylusPickResult::sendHoverOverEvent() const { - if (!overlayID.isNull()) { - qApp->getOverlays().hoverOverOverlay(overlayID, PointerEvent{ PointerEvent::Move, deviceId(), position2D, position, - normal, -normal }); - } - // FIXME support entity -} - -void StylusPickResult::sendHoverEnterEvent() const { - if (!overlayID.isNull()) { - qApp->getOverlays().hoverEnterOverlay(overlayID, PointerEvent{ PointerEvent::Move, deviceId(), position2D, position, - normal, -normal }); - } - // FIXME support entity -} - -void StylusPickResult::sendTouchStartEvent() const { - if (!overlayID.isNull()) { - qApp->getOverlays().sendMousePressOnOverlay(overlayID, PointerEvent{ PointerEvent::Press, deviceId(), position2D, position, - normal, -normal, PointerEvent::PrimaryButton, - PointerEvent::PrimaryButton }); - } - // FIXME support entity -} - -void StylusPickResult::sendTouchEndEvent() const { - if (!overlayID.isNull()) { - qApp->getOverlays().sendMouseReleaseOnOverlay(overlayID, - PointerEvent{ PointerEvent::Release, deviceId(), position2D, position, normal, - -normal, PointerEvent::PrimaryButton }); - } - // FIXME support entity -} - -void StylusPickResult::sendTouchMoveEvent() const { - if (!overlayID.isNull()) { - qApp->getOverlays().sendMouseMoveOnOverlay(overlayID, PointerEvent{ PointerEvent::Move, deviceId(), position2D, position, - normal, -normal, PointerEvent::PrimaryButton, - PointerEvent::PrimaryButton }); - } - // FIXME support entity -} - -bool StylusPickResult::doesIntersect() const { - return true; -} - -// for example: if we want the closest result, compare based on distance -// if we want all results, combine them -// must return a new pointer -std::shared_ptr StylusPickResult::compareAndProcessNewResult(const std::shared_ptr& newRes) { - auto newStylusResult = std::static_pointer_cast(newRes); - if (newStylusResult && newStylusResult->distance < distance) { - return std::make_shared(*newStylusResult); - } else { - return std::make_shared(*this); - } -} - -// returns true if this result contains any valid results with distance < maxDistance -// can also filter out results with distance >= maxDistance -bool StylusPickResult::checkOrFilterAgainstMaxDistance(float maxDistance) { - return distance < maxDistance; -} - -uint32_t StylusPickResult::deviceId() const { - // 0 is reserved for hardware mouse - return index(tip.side) + 1; -} - -StylusPick::StylusPick(Side side) - : Pick(PickFilter(PickScriptingInterface::PICK_OVERLAYS()), FLT_MAX, true) - , _side(side) { -} - -StylusTip StylusPick::getMathematicalPick() const { - StylusTip result; - if (_useFingerInsteadOfStylus) { - result = getFingerWorldLocation(_side); - } else { - auto myAvatar = DependencyManager::get()->getMyAvatar(); - float sensorScaleFactor = myAvatar->getSensorToWorldScale(); - result = getControllerWorldLocation(_side, sensorScaleFactor); - result.position += result.orientation * (TIP_OFFSET * sensorScaleFactor); - } - return result; -} - -PickResultPointer StylusPick::getDefaultResult(const QVariantMap& pickVariant) const { - return std::make_shared(); -} - -PickResultPointer StylusPick::getEntityIntersection(const StylusTip& pick) { - return PickResultPointer(); -} - -PickResultPointer StylusPick::getOverlayIntersection(const StylusTip& pick) { - if (!getFilter().doesPickOverlays()) { - return PickResultPointer(); - } - - std::vector results; - for (const auto& target : getIncludeItems()) { - if (target.isNull()) { - continue; - } - - auto overlay = qApp->getOverlays().getOverlay(target); - // Don't interact with non-3D or invalid overlays - if (!overlay || !overlay->is3D()) { - continue; - } - - if (!overlay->getVisible() && !getFilter().doesPickInvisible()) { - continue; - } - - auto overlayType = overlay->getType(); - auto overlay3D = std::static_pointer_cast(overlay); - const auto overlayRotation = overlay3D->getRotation(); - const auto overlayPosition = overlay3D->getPosition(); - - StylusPickResult result; - result.tip = pick; - result.overlayID = target; - result.normal = overlayRotation * Vectors::UNIT_Z; - result.distance = glm::dot(pick.position - overlayPosition, result.normal); - result.position = pick.position - (result.normal * result.distance); - if (overlayType == Web3DOverlay::TYPE) { - result.dimensions = vec3(std::static_pointer_cast(overlay3D)->getSize(), 0.01f); - } else if (overlayType == Sphere3DOverlay::TYPE) { - result.dimensions = std::static_pointer_cast(overlay3D)->getDimensions(); - } else { - result.dimensions = vec3(0.01f); - } - auto tipRelativePosition = result.position - overlayPosition; - auto localPos = glm::inverse(overlayRotation) * tipRelativePosition; - auto normalizedPosition = localPos / result.dimensions; - result.normalizedPosition = normalizedPosition + 0.5f; - result.position2D = { result.normalizedPosition.x * result.dimensions.x, - (1.0f - result.normalizedPosition.y) * result.dimensions.y }; - result.valid = true; - results.push_back(result); - } - - StylusPickResult nearestTarget; - for (const auto& result : results) { - if (result && result.isNormalized() && result.distance < nearestTarget.distance) { - nearestTarget = result; - } - } - return std::make_shared(nearestTarget); -} - -PickResultPointer StylusPick::getAvatarIntersection(const StylusTip& pick) { - return PickResultPointer(); -} - -PickResultPointer StylusPick::getHUDIntersection(const StylusTip& pick) { - return PickResultPointer(); -} - -StylusPointer::StylusPointer(Side side) - : Pointer(DependencyManager::get()->addPick(PickQuery::Stylus, std::make_shared(side)), - false, - true) - , _side(side) - , _sideData(SIDES[index(side)]) { - setIncludeItems({ { getHomeButtonID(), getTabletScreenID() } }); - STYLUSES[index(_side)] = this; +StylusPointer::StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled) : + Pointer(DependencyManager::get()->createStylusPick(props), enabled, hover), + _stylusOverlay(stylusOverlay) +{ } StylusPointer::~StylusPointer() { if (!_stylusOverlay.isNull()) { qApp->getOverlays().deleteOverlay(_stylusOverlay); } - STYLUSES[index(_side)] = nullptr; } -StylusPointer* StylusPointer::getOtherStylus() { - return STYLUSES[((index(_side) + 1) % 2)]; -} - -void StylusPointer::enable() { - Parent::enable(); - withWriteLock([&] { _renderingEnabled = true; }); -} - -void StylusPointer::disable() { - Parent::disable(); - withWriteLock([&] { _renderingEnabled = false; }); -} - -void StylusPointer::updateStylusTarget() { - const float minNearDistance = TABLET_MIN_TOUCH_DISTANCE * _sensorScaleFactor; - const float maxNearDistance = WEB_DISPLAY_STYLUS_DISTANCE * _sensorScaleFactor; - const float edgeBorder = EDGE_BORDER * _sensorScaleFactor; - - auto pickResult = DependencyManager::get()->getPrevPickResultTyped(_pickUID); - - if (pickResult) { - _state.target = *pickResult; - float hystersis = 0.0f; - // If we're already near the target, add hystersis to ensure we don't rapidly toggle between near and not near - // but only for the current near target - if (_previousState.nearTarget && pickResult->overlayID == _previousState.target.overlayID) { - hystersis = _nearHysteresis; - } - _state.nearTarget = pickResult->isNear(minNearDistance, maxNearDistance, edgeBorder, hystersis); - } - - // Not near anything, short circuit the rest - if (!_state.nearTarget) { - relinquishTouchFocus(); - hide(); - return; - } - - show(); - - auto minTouchDistance = TABLET_MIN_TOUCH_DISTANCE * _sensorScaleFactor; - auto maxTouchDistance = TABLET_MAX_TOUCH_DISTANCE * _sensorScaleFactor; - auto maxHoverDistance = TABLET_MAX_HOVER_DISTANCE * _sensorScaleFactor; - - float hystersis = 0.0f; - if (_previousState.nearTarget && _previousState.target.overlayID == _previousState.target.overlayID) { - hystersis = _nearHysteresis; - } - - // If we're in hover distance (calculated as the normal distance from the XY plane of the overlay) - if ((getOtherStylus() && getOtherStylus()->_state.touchingTarget) || !_state.target.isNearNormal(minTouchDistance, maxHoverDistance, hystersis)) { - relinquishTouchFocus(); - return; - } - - requestTouchFocus(_state.target); - - if (!_state.target.hasKeyboardFocus()) { - _state.target.setKeyboardFocus(); - } - - if (hasTouchFocus(_state.target) && !_previousState.touchingTarget) { - _state.target.sendHoverOverEvent(); - } - - hystersis = 0.0f; - if (_previousState.touchingTarget && _previousState.target.overlayID == _state.target.overlayID) { - hystersis = _touchHysteresis; - } - - // If we're in touch distance - if (_state.target.isNearNormal(minTouchDistance, maxTouchDistance, _touchHysteresis) && _state.target.isNormalized()) { - _state.touchingTarget = true; - } -} - -void StylusPointer::update(unsigned int pointerID, float deltaTime) { - // This only needs to be a read lock because update won't change any of the properties that can be modified from scripts - withReadLock([&] { - auto myAvatar = DependencyManager::get()->getMyAvatar(); - - // Store and reset the state - { - _previousState = _state; - _state = State(); - } - -#if 0 - // Update finger as stylus setting - { - useFingerInsteadOfStylus = (USE_FINGER_AS_STYLUS.get() && myAvatar->getJointIndex(sideData.avatarJoint) != -1); - } -#endif - - // Update scale factor - { - _sensorScaleFactor = myAvatar->getSensorToWorldScale(); - _hoverHysteresis = HOVER_HYSTERESIS * _sensorScaleFactor; - _nearHysteresis = NEAR_HYSTERESIS * _sensorScaleFactor; - _touchHysteresis = TOUCH_HYSTERESIS * _sensorScaleFactor; - } - - // Identify the current near or touching target - updateStylusTarget(); - - // If we stopped touching, or if the target overlay ID changed, send a touching exit to the previous touch target - if (_previousState.touchingTarget && - (!_state.touchingTarget || _state.target.overlayID != _previousState.target.overlayID)) { - stylusTouchingExit(); - } - - // Handle new or continuing touch - if (_state.touchingTarget) { - // If we were previously not touching, or we were touching a different overlay, add a touch enter - if (!_previousState.touchingTarget || _previousState.target.overlayID != _state.target.overlayID) { - stylusTouchingEnter(); - } else { - _touchingEnterTimer += deltaTime; - } - - stylusTouching(); - } - }); - - setIncludeItems({ { getHomeButtonID(), getTabletScreenID() } }); -} - -void StylusPointer::show() { - if (!_stylusOverlay.isNull()) { - return; - } - - auto myAvatar = DependencyManager::get()->getMyAvatar(); - // FIXME perhaps instantiate a stylus and use show / hide instead of create / destroy - // however, the current design doesn't really allow for this because it assumes that - // hide / show are idempotent and low cost, but constantly querying the visibility +OverlayID StylusPointer::buildStylusOverlay(const QVariantMap& properties) { QVariantMap overlayProperties; + // TODO: make these configurable per pointer overlayProperties["name"] = "stylus"; overlayProperties["url"] = PathUtils::resourcesPath() + "/meshes/tablet-stylus-fat.fbx"; overlayProperties["loadPriority"] = 10.0f; - overlayProperties["dimensions"] = vec3toVariant(_sensorScaleFactor * vec3(0.01f, 0.01f, WEB_STYLUS_LENGTH)); overlayProperties["solid"] = true; - overlayProperties["visible"] = true; + overlayProperties["visible"] = false; overlayProperties["ignoreRayIntersection"] = true; overlayProperties["drawInFront"] = false; - overlayProperties["parentID"] = AVATAR_SELF_ID; - overlayProperties["parentJointIndex"] = myAvatar->getJointIndex(_sideData.cameraJoint); - static const glm::quat X_ROT_NEG_90{ 0.70710678f, -0.70710678f, 0.0f, 0.0f }; - auto modelOrientation = _state.target.tip.orientation * X_ROT_NEG_90; - auto modelPositionOffset = modelOrientation * (vec3(0.0f, 0.0f, -WEB_STYLUS_LENGTH / 2.0f) * _sensorScaleFactor); - overlayProperties["position"] = vec3toVariant(_state.target.tip.position + modelPositionOffset); - overlayProperties["rotation"] = quatToVariant(modelOrientation); - _stylusOverlay = qApp->getOverlays().addOverlay("model", overlayProperties); + return qApp->getOverlays().addOverlay("model", overlayProperties); +} + +void StylusPointer::updateVisuals(const PickResultPointer& pickResult) { + auto stylusPickResult = std::static_pointer_cast(pickResult); + + if (_enabled && _renderState != DISABLED && stylusPickResult) { + StylusTip tip(stylusPickResult->pickVariant); + if (tip.side != bilateral::Side::Invalid) { + show(tip); + return; + } + } + hide(); +} + +void StylusPointer::show(const StylusTip& tip) { + if (!_stylusOverlay.isNull()) { + QVariantMap props; + static const glm::quat X_ROT_NEG_90{ 0.70710678f, -0.70710678f, 0.0f, 0.0f }; + auto modelOrientation = tip.orientation * X_ROT_NEG_90; + auto sensorToWorldScale = DependencyManager::get()->getMyAvatar()->getSensorToWorldScale(); + auto modelPositionOffset = modelOrientation * (vec3(0.0f, 0.0f, -WEB_STYLUS_LENGTH / 2.0f) * sensorToWorldScale); + props["position"] = vec3toVariant(tip.position + modelPositionOffset); + props["rotation"] = quatToVariant(modelOrientation); + props["dimensions"] = vec3toVariant(sensorToWorldScale * vec3(0.01f, 0.01f, WEB_STYLUS_LENGTH)); + props["visible"] = true; + qApp->getOverlays().editOverlay(_stylusOverlay, props); + } } void StylusPointer::hide() { - if (_stylusOverlay.isNull()) { - return; + if (!_stylusOverlay.isNull()) { + QVariantMap props; + props.insert("visible", false); + qApp->getOverlays().editOverlay(_stylusOverlay, props); + } +} + +bool StylusPointer::shouldHover(const PickResultPointer& pickResult) { + auto stylusPickResult = std::static_pointer_cast(pickResult); + if (_renderState == EVENTS_ON && stylusPickResult && stylusPickResult->intersects) { + auto sensorScaleFactor = DependencyManager::get()->getMyAvatar()->getSensorToWorldScale(); + float hysteresis = _state.hovering ? HOVER_HYSTERESIS * sensorScaleFactor : 0.0f; + bool hovering = isWithinBounds(stylusPickResult->distance, TABLET_MIN_HOVER_DISTANCE * sensorScaleFactor, + TABLET_MAX_HOVER_DISTANCE * sensorScaleFactor, hysteresis); + + _state.hovering = hovering; + return hovering; } - qApp->getOverlays().deleteOverlay(_stylusOverlay); - _stylusOverlay = OverlayID(); + _state.hovering = false; + return false; } -#if 0 - void pointFinger(bool value) { - static const QString HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index"; - static const std::array KEYS{ { "pointLeftIndex", "pointLeftIndex" } }; - if (fingerPointing != value) { - QString message = QJsonDocument(QJsonObject{ { KEYS[index(side)], value } }).toJson(); - DependencyManager::get()->sendMessage(HIFI_POINT_INDEX_MESSAGE_CHANNEL, message); - fingerPointing = value; + +bool StylusPointer::shouldTrigger(const PickResultPointer& pickResult) { + auto stylusPickResult = std::static_pointer_cast(pickResult); + if (_renderState == EVENTS_ON && stylusPickResult) { + auto sensorScaleFactor = DependencyManager::get()->getMyAvatar()->getSensorToWorldScale(); + float distance = stylusPickResult->distance; + + // If we're triggering on an object, recalculate the distance instead of using the pickResult + if (!_state.triggeredObject.objectID.isNull() && stylusPickResult->objectID != _state.triggeredObject.objectID) { + glm::vec3 intersection; + glm::vec3 origin = vec3FromVariant(stylusPickResult->pickVariant["position"]); + glm::vec3 direction = -_state.surfaceNormal; + if (_state.triggeredObject.type == ENTITY) { + intersection = RayPick::intersectRayWithEntityXYPlane(_state.triggeredObject.objectID, origin, direction); + } else if (_state.triggeredObject.type == OVERLAY) { + intersection = RayPick::intersectRayWithOverlayXYPlane(_state.triggeredObject.objectID, origin, direction); } + distance = glm::dot(intersection - origin, direction); + } + + float hysteresis = _state.triggering ? TOUCH_HYSTERESIS * sensorScaleFactor : 0.0f; + if (isWithinBounds(distance, TABLET_MIN_TOUCH_DISTANCE * sensorScaleFactor, + TABLET_MAX_TOUCH_DISTANCE * sensorScaleFactor, hysteresis)) { + if (_state.triggeredObject.objectID.isNull()) { + _state.triggeredObject = PickedObject(stylusPickResult->objectID, stylusPickResult->type); + _state.surfaceNormal = stylusPickResult->surfaceNormal; + _state.triggering = true; + } + return true; } -#endif -void StylusPointer::requestTouchFocus(const StylusPickResult& pickResult) { - if (!pickResult) { - return; - } - // send hover events to target if we can. - // record the entity or overlay we are hovering over. - if (!pickResult.overlayID.isNull() && pickResult.overlayID != _hoverOverlay && - getOtherStylus() && pickResult.overlayID != getOtherStylus()->_hoverOverlay) { - _hoverOverlay = pickResult.overlayID; - pickResult.sendHoverEnterEvent(); } + + _state.triggeredObject = PickedObject(); + _state.surfaceNormal = glm::vec3(NAN); + _state.triggering = false; + return false; } -bool StylusPointer::hasTouchFocus(const StylusPickResult& pickResult) { - return (!pickResult.overlayID.isNull() && pickResult.overlayID == _hoverOverlay); +Pointer::PickedObject StylusPointer::getHoveredObject(const PickResultPointer& pickResult) { + auto stylusPickResult = std::static_pointer_cast(pickResult); + if (!stylusPickResult) { + return PickedObject(); + } + return PickedObject(stylusPickResult->objectID, stylusPickResult->type); } -void StylusPointer::relinquishTouchFocus() { - // send hover leave event. - if (!_hoverOverlay.isNull()) { - PointerEvent pointerEvent{ PointerEvent::Move, (uint32_t)(index(_side) + 1) }; - auto& overlays = qApp->getOverlays(); - overlays.sendMouseMoveOnOverlay(_hoverOverlay, pointerEvent); - overlays.sendHoverOverOverlay(_hoverOverlay, pointerEvent); - overlays.sendHoverLeaveOverlay(_hoverOverlay, pointerEvent); - _hoverOverlay = OverlayID(); - } -}; - -void StylusPointer::stealTouchFocus() { - // send hover events to target - if (getOtherStylus() && _state.target.overlayID == getOtherStylus()->_hoverOverlay) { - getOtherStylus()->relinquishTouchFocus(); - } - requestTouchFocus(_state.target); +Pointer::Buttons StylusPointer::getPressedButtons() { + // TODO: custom buttons for styluses + Pointer::Buttons toReturn({ "Primary", "Focus" }); + return toReturn; } -void StylusPointer::stylusTouchingEnter() { - stealTouchFocus(); - _state.target.sendTouchStartEvent(); - DependencyManager::get()->triggerHapticPulse(HAPTIC_STYLUS_STRENGTH, HAPTIC_STYLUS_DURATION, - _sideData.hand); - _touchingEnterTimer = 0; - _touchingEnterPosition = _state.target.position2D; - _deadspotExpired = false; +PointerEvent StylusPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const { + QUuid pickedID; + glm::vec3 intersection, surfaceNormal, direction, origin; + auto stylusPickResult = std::static_pointer_cast(pickResult); + if (stylusPickResult) { + intersection = stylusPickResult->intersection; + surfaceNormal = _state.surfaceNormal; + const QVariantMap& stylusTip = stylusPickResult->pickVariant; + origin = vec3FromVariant(stylusTip["position"]); + direction = -_state.surfaceNormal; + pickedID = stylusPickResult->objectID; + } + + if (pickedID != target.objectID) { + if (target.type == ENTITY) { + intersection = RayPick::intersectRayWithEntityXYPlane(target.objectID, origin, direction); + } else if (target.type == OVERLAY) { + intersection = RayPick::intersectRayWithOverlayXYPlane(target.objectID, origin, direction); + } + } + glm::vec2 pos2D; + if (target.type == ENTITY) { + pos2D = RayPick::projectOntoEntityXYPlane(target.objectID, origin); + } else if (target.type == OVERLAY) { + pos2D = RayPick::projectOntoOverlayXYPlane(target.objectID, origin); + } else if (target.type == HUD) { + pos2D = DependencyManager::get()->calculatePos2DFromHUD(origin); + } + return PointerEvent(pos2D, intersection, surfaceNormal, direction); } -void StylusPointer::stylusTouchingExit() { - if (!_previousState.target) { - return; - } - // special case to handle home button. - if (_previousState.target.overlayID == getHomeButtonID()) { - DependencyManager::get()->sendLocalMessage("home", _previousState.target.overlayID.toString()); - } - - // send touch end event - _state.target.sendTouchEndEvent(); +bool StylusPointer::isWithinBounds(float distance, float min, float max, float hysteresis) { + return (distance == glm::clamp(distance, min - hysteresis, max + hysteresis)); } -void StylusPointer::stylusTouching() { - qDebug() << "QQQ " << __FUNCTION__; - if (_state.target.overlayID.isNull()) { - return; +void StylusPointer::setRenderState(const std::string& state) { + if (state == "events on") { + _renderState = EVENTS_ON; + } else if (state == "events off") { + _renderState = EVENTS_OFF; + } else if (state == "disabled") { + _renderState = DISABLED; } - - if (!_deadspotExpired) { - _deadspotExpired = - (_touchingEnterTimer > POINTER_PRESS_TO_MOVE_DELAY) || - glm::distance2(_state.target.position2D, _touchingEnterPosition) > TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED; - } - - // Only send moves if the target moves more than the deadspot position or if we've timed out the deadspot - if (_deadspotExpired) { - _state.target.sendTouchMoveEvent(); - } -} +} \ No newline at end of file diff --git a/interface/src/raypick/StylusPointer.h b/interface/src/raypick/StylusPointer.h index 5308315187..cc7f2814db 100644 --- a/interface/src/raypick/StylusPointer.h +++ b/interface/src/raypick/StylusPointer.h @@ -8,136 +8,65 @@ #ifndef hifi_StylusPointer_h #define hifi_StylusPointer_h -#include -#include - #include -#include #include #include -#include #include "ui/overlays/Overlay.h" - -class StylusPick : public Pick { - using Side = bilateral::Side; -public: - StylusPick(Side side); - - StylusTip getMathematicalPick() const override; - PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override; - PickResultPointer getEntityIntersection(const StylusTip& pick) override; - PickResultPointer getOverlayIntersection(const StylusTip& pick) override; - PickResultPointer getAvatarIntersection(const StylusTip& pick) override; - PickResultPointer getHUDIntersection(const StylusTip& pick) override; - -private: - const Side _side; - const bool _useFingerInsteadOfStylus{ false }; -}; - -struct SideData; - -struct StylusPickResult : public PickResult { - using Side = bilateral::Side; - // FIXME make into a single ID - OverlayID overlayID; - // FIXME restore entity functionality -#if 0 - EntityItemID entityID; -#endif - StylusTip tip; - float distance{ FLT_MAX }; - vec3 position; - vec2 position2D; - vec3 normal; - vec3 normalizedPosition; - vec3 dimensions; - bool valid{ false }; - - virtual bool doesIntersect() const override; - virtual std::shared_ptr compareAndProcessNewResult(const std::shared_ptr& newRes) override; - virtual bool checkOrFilterAgainstMaxDistance(float maxDistance) override; - - bool isNormalized() const; - bool isNearNormal(float min, float max, float hystersis) const; - bool isNear2D(float border, float hystersis) const; - bool isNear(float min, float max, float border, float hystersis) const; - operator bool() const; - bool hasKeyboardFocus() const; - void setKeyboardFocus() const; - void sendHoverOverEvent() const; - void sendHoverEnterEvent() const; - void sendTouchStartEvent() const; - void sendTouchEndEvent() const; - void sendTouchMoveEvent() const; - -private: - uint32_t deviceId() const; -}; - +#include "StylusPick.h" class StylusPointer : public Pointer { using Parent = Pointer; - using Side = bilateral::Side; using Ptr = std::shared_ptr; public: - StylusPointer(Side side); + StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled); ~StylusPointer(); - void enable() override; - void disable() override; - void update(unsigned int pointerID, float deltaTime) override; + void updateVisuals(const PickResultPointer& pickResult) override; + + // Styluses have three render states: + // default: "events on" -> render and hover/trigger + // "events off" -> render, don't hover/trigger + // "disabled" -> don't render, don't hover/trigger + void setRenderState(const std::string& state) override; + void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override {} + + static OverlayID buildStylusOverlay(const QVariantMap& properties); + +protected: + PickedObject getHoveredObject(const PickResultPointer& pickResult) override; + Buttons getPressedButtons() override; + bool shouldHover(const PickResultPointer& pickResult) override; + bool shouldTrigger(const PickResultPointer& pickResult) override; + + PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const override; private: - - virtual void setRenderState(const std::string& state) override {} - virtual void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) override {} - virtual PickedObject getHoveredObject(const PickResultPointer& pickResult) override { return PickedObject(); } - virtual Buttons getPressedButtons() override { return {}; } - bool shouldHover() override { return true; } - bool shouldTrigger() override { return true; } - virtual PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const override { return PointerEvent(); } - - - StylusPointer* getOtherStylus(); - - void updateStylusTarget(); - void requestTouchFocus(const StylusPickResult& pickResult); - bool hasTouchFocus(const StylusPickResult& pickResult); - void relinquishTouchFocus(); - void stealTouchFocus(); - void stylusTouchingEnter(); - void stylusTouchingExit(); - void stylusTouching(); - void show(); + void show(const StylusTip& tip); void hide(); - struct State { - StylusPickResult target; - bool nearTarget{ false }; - bool touchingTarget{ false }; + struct TriggerState { + PickedObject triggeredObject; + glm::vec3 surfaceNormal { NAN }; + bool hovering { false }; + bool triggering { false }; }; - State _state; - State _previousState; + TriggerState _state; - float _nearHysteresis{ 0.0f }; - float _touchHysteresis{ 0.0f }; - float _hoverHysteresis{ 0.0f }; + enum RenderState { + EVENTS_ON = 0, + EVENTS_OFF, + DISABLED + }; - float _sensorScaleFactor{ 1.0f }; - float _touchingEnterTimer{ 0 }; - vec2 _touchingEnterPosition; - bool _deadspotExpired{ false }; + RenderState _renderState { EVENTS_ON }; - bool _renderingEnabled; - OverlayID _stylusOverlay; - OverlayID _hoverOverlay; - const Side _side; - const SideData& _sideData; + const OverlayID _stylusOverlay; + + static bool isWithinBounds(float distance, float min, float max, float hysteresis); }; #endif // hifi_StylusPointer_h diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index 767721ba7d..e17fb8ec65 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -78,7 +78,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin Buttons sameButtons; const std::string PRIMARY_BUTTON = "Primary"; bool primaryPressed = false; - if (_enabled && shouldTrigger()) { + if (_enabled && shouldTrigger(pickResult)) { buttons = getPressedButtons(); primaryPressed = buttons.find(PRIMARY_BUTTON) != buttons.end(); for (const std::string& button : buttons) { @@ -92,7 +92,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin } // Hover events - bool doHover = shouldHover(); + bool doHover = shouldHover(pickResult); Pointer::PickedObject hoveredObject = getHoveredObject(pickResult); PointerEvent hoveredEvent = buildPointerEvent(hoveredObject, pickResult); hoveredEvent.setType(PointerEvent::Move); diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index 9eeeb5ea7e..0415f00d1e 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -62,8 +62,8 @@ public: virtual void setLength(float length) {} virtual void setLockEndUUID(const QUuid& objectID, bool isOverlay) {} - virtual void update(unsigned int pointerID, float deltaTime); - virtual void updateVisuals(const PickResultPointer& pickResult) {} + void update(unsigned int pointerID, float deltaTime); + virtual void updateVisuals(const PickResultPointer& pickResult) = 0; void generatePointerEvents(unsigned int pointerID, const PickResultPointer& pickResult); struct PickedObject { @@ -87,8 +87,8 @@ protected: virtual PickedObject getHoveredObject(const PickResultPointer& pickResult) = 0; virtual Buttons getPressedButtons() = 0; - virtual bool shouldHover() = 0; - virtual bool shouldTrigger() = 0; + virtual bool shouldHover(const PickResultPointer& pickResult) { return true; } + virtual bool shouldTrigger(const PickResultPointer& pickResult) { return true; } private: PickedObject _prevHoveredObject; diff --git a/libraries/shared/src/RegisteredMetaTypes.h b/libraries/shared/src/RegisteredMetaTypes.h index c4ac7aba14..8bb51c88f6 100644 --- a/libraries/shared/src/RegisteredMetaTypes.h +++ b/libraries/shared/src/RegisteredMetaTypes.h @@ -154,18 +154,30 @@ public: } }; -struct StylusTip : public MathPick { - bilateral::Side side{ bilateral::Side::Invalid }; +class StylusTip : public MathPick { +public: + StylusTip() : position(NAN), velocity(NAN) {} + StylusTip(const QVariantMap& pickVariant) : side(bilateral::Side(pickVariant["side"].toInt())), position(vec3FromVariant(pickVariant["position"])), + orientation(quatFromVariant(pickVariant["orientation"])), velocity(vec3FromVariant(pickVariant["velocity"])) {} + + bilateral::Side side { bilateral::Side::Invalid }; glm::vec3 position; glm::quat orientation; glm::vec3 velocity; - virtual operator bool() const override { return side != bilateral::Side::Invalid; } + + operator bool() const override { return side != bilateral::Side::Invalid; } + + bool operator==(const StylusTip& other) const { + return (side == other.side && position == other.position && orientation == other.orientation && velocity == other.velocity); + } + QVariantMap toVariantMap() const override { - QVariantMap pickRay; - pickRay["position"] = vec3toVariant(position); - pickRay["orientation"] = quatToVariant(orientation); - pickRay["velocity"] = vec3toVariant(velocity); - return pickRay; + QVariantMap stylusTip; + stylusTip["side"] = (int)side; + stylusTip["position"] = vec3toVariant(position); + stylusTip["orientation"] = quatToVariant(orientation); + stylusTip["velocity"] = vec3toVariant(velocity); + return stylusTip; } }; diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 7941ec8d4c..c445895d6c 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -128,16 +128,16 @@ Script.include("/~/system/libraries/utils.js"); LaserPointers.enableLaserPointer(this.laserPointer); LaserPointers.setRenderState(this.laserPointer, this.mode); - if (HMD.tabletID !== this.tabletID || HMD.tabletButtonID !== this.tabletButtonID || HMD.tabletScreenID !== this.tabletScreenID) { + if (HMD.tabletID !== this.tabletID || HMD.homeButtonID !== this.homeButtonID || HMD.tabletScreenID !== this.tabletScreenID) { this.tabletID = HMD.tabletID; - this.tabletButtonID = HMD.tabletButtonID; + this.homeButtonID = HMD.homeButtonID; this.tabletScreenID = HMD.tabletScreenID; - LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.tabletButtonID, HMD.tabletScreenID]); + LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.homeButtonID, HMD.tabletScreenID]); } }; this.pointingAtTablet = function(objectID) { - if (objectID === HMD.tabletScreenID || objectID === HMD.tabletButtonID) { + if (objectID === HMD.tabletScreenID || objectID === HMD.homeButtonID) { return true; } return false; @@ -240,7 +240,7 @@ Script.include("/~/system/libraries/utils.js"); defaultRenderStates: defaultRenderStates }); - LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.tabletButtonID, HMD.tabletScreenID]); + LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.homeButtonID, HMD.tabletScreenID]); } var leftHandInEditMode = new InEditMode(LEFT_HAND); From ef55e3181dd55fc66dbe79b447335c06fed86b1b Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 9 Nov 2017 16:48:52 -0800 Subject: [PATCH 080/292] moveing controllerDispatchaer pointers to pointerUtils.js --- .../controllers/controllerDispatcher.js | 192 ++---------------- .../controllerModules/inEditMode.js | 48 ----- scripts/system/controllers/grab.js | 2 +- scripts/system/libraries/pointersUtils.js | 191 +++++++++++++++++ 4 files changed, 206 insertions(+), 227 deletions(-) create mode 100644 scripts/system/libraries/pointersUtils.js diff --git a/scripts/system/controllers/controllerDispatcher.js b/scripts/system/controllers/controllerDispatcher.js index 401c223992..717e50f8ad 100644 --- a/scripts/system/controllers/controllerDispatcher.js +++ b/scripts/system/controllers/controllerDispatcher.js @@ -20,6 +20,7 @@ controllerDispatcherPluginsNeedSort = false; Script.include("/~/system/libraries/utils.js"); Script.include("/~/system/libraries/controllers.js"); Script.include("/~/system/libraries/controllerDispatcherUtils.js"); +Script.include("/~/system/libraries/pointersUtils.js"); (function() { var NEAR_MAX_RADIUS = 0.1; @@ -34,77 +35,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); PROFILE = true; } - var SEARCH_SPHERE_SIZE = 0.0132; - var dim = {x: SEARCH_SPHERE_SIZE, y: SEARCH_SPHERE_SIZE, z: SEARCH_SPHERE_SIZE}; - var halfPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var halfEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var fullPath = { - type: "line3d", - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - var fullEnd = { - type: "sphere", - dimensions: dim, - solid: true, - color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, - alpha: 0.9, - ignoreRayIntersection: true, - drawInFront: true, // Even when burried inside of something, show it. - visible: true - }; - var holdPath = { - type: "line3d", - color: COLORS_GRAB_DISTANCE_HOLD, - visible: true, - alpha: 1, - solid: true, - glow: 1.0, - lineWidth: 5, - ignoreRayIntersection: true, // always ignore this - drawInFront: true, // Even when burried inside of something, show it. - parentID: MyAvatar.SELF_ID - }; - - var renderStates = [ - {name: "half", path: halfPath, end: halfEnd}, - {name: "full", path: fullPath, end: fullEnd}, - {name: "hold", path: holdPath} - ]; - - var defaultRenderStates = [ - {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: halfPath}, - {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: fullPath}, - {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: holdPath} - ]; - function ControllerDispatcher() { var _this = this; this.lastInterval = Date.now(); @@ -115,6 +45,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.veryhighVarianceCount = 0; this.tabletID = null; this.blacklist = []; + this.pointerManager = new PointerManager(); // a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are // not set to false (not in use), a module cannot start. When a module is using a slot, that module's name @@ -147,39 +78,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } }; - this.enableLaserForPlugin = function(plugin) { - var handLaser = plugin.parameters.handLaser; - if (handLaser !== undefined) { - _this.laserVisibleStatus[handLaser] = true; - } - }; - - this.disableLaserForPlugin = function(plugin) { - var handLaser = plugin.parameters.handLaser; - if (handLaser !== undefined) { - _this.laserVisibleStatus[handLaser] = false; - _this.laserLockStatus[handLaser] = false; - } - }; - - this.lockLaserToTarget = function(laserLockInfo, plugin) { - if (laserLockInfo !== undefined) { - var hand = laserLockInfo.hand; - if (_this.laserVisibleStatus[laserLockInfo.hand]) { - var pointer = (hand === RIGHT_HAND) ? _this.rightControllerPointer : _this.leftControllerPointer; - var targetID = laserLockInfo.targetID; - var targetIsOverlay = laserLockInfo.isOverlay; - Pointers.setLockEndUUID(pointer, targetID, targetIsOverlay); - _this.laserLockStatus[hand] = targetID; - } - } else { - var handLaser = plugin.parameters.handLaser; - if (handLaser !== undefined) { - _this.laserLockStatus[handLaser] = false; - } - } - }; - this.unmarkSlotsForPluginName = function (runningPluginName) { // this is used to free activity-slots when a plugin is deactivated while it's running. for (var activitySlot in _this.activitySlots) { @@ -255,50 +153,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } }; - this.updateRenderStateForVisibleLasers = function() { - // update left hand laser - - var HUD_LASER_OFFSET = 2; - var laserLocked; - if (_this.laserVisibleStatus[LEFT_HAND]) { - laserLocked = _this.laserLockStatus[LEFT_HAND]; - _this.updateLaserRenderState(_this.leftControllerPointer,_this.leftTriggerClicked, _this.leftTriggerValue, laserLocked); - } else { - Pointers.setRenderState(_this.leftControllerPointer, ""); - } - - if (_this.laserVisibleStatus[RIGHT_HAND]) { - laserLocked = _this.laserLockStatus[RIGHT_HAND]; - _this.updateLaserRenderState(_this.rightControllerPointer, _this.rightTriggerClicked, _this.rightTriggerValue, laserLocked); - } else { - Pointers.setRenderState(_this.rightControllerPointer, ""); - } - - if (_this.laserVisibleStatus[LEFT_HAND + HUD_LASER_OFFSET]) { - _this.updateLaserRenderState(_this.leftControllerHudRayPick, _this.leftTriggerClicked, _this.leftTriggerValue, false); - } else { - Pointers.setRenderState(_this.leftControllerHudRayPick, ""); - } - - if (_this.laserVisibleStatus[RIGHT_HAND + HUD_LASER_OFFSET]) { - _this.updateLaserRenderState(_this.rightControllerHudRayPick, _this.rightTriggerClicked, _this.rightTriggerValue, false); - } else { - Pointers.setRenderState(_this.rightControllerHudRayPick, ""); - } - }; - - this.updateLaserRenderState = function(laser, triggerClicked, triggerValue, laserLocked) { - var mode = ""; - if (laserLocked) { - mode = "hold"; - } else if (triggerClicked) { - mode = "full"; - } else if (triggerValue > TRIGGER_ON_VALUE) { - mode = "half"; - } - Pointers.setRenderState(laser, mode); - }; - this.update = function () { if (PROFILE) { Script.beginProfileRange("dispatch.pre"); @@ -518,7 +372,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); } } } - _this.updateRenderStateForVisibleLasers(); + _this.pointerManager.updatePoiniterRenderStates(false, 0); if (PROFILE) { Script.endProfileRange("dispatch.run"); } @@ -543,40 +397,32 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Controller.enableMapping(MAPPING_NAME); - this.leftControllerPointer = Pointers.createPointer(PickType.Ray, { + this.pointerManager.createPointer(false, PickType.Ray, { joint: "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES, - renderStates: renderStates, - defaultRenderStates: defaultRenderStates, triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}], posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true), hover: true }); - this.leftControllerHudRayPick = Pointers.createPointer(PickType.Ray, { - joint: "_CONTROLLER_LEFTHAND", - filter: Picks.PICK_HUD, - maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, - renderStates: renderStates, - defaultRenderStates: defaultRenderStates, - posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true), - triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}], - hover: true - }); - this.rightControllerPointer = Pointers.createPointer(PickType.Ray, { + this.pointerManager.createPointer(false, PickType.Ray, { joint: "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND", filter: Picks.PICK_OVERLAYS | Picks.PICK_ENTITIES, - renderStates: renderStates, - defaultRenderStates: defaultRenderStates, triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true), hover: true }); - this.rightControllerHudRayPick = Pointers.createPointer(PickType.Ray, { + this.pointerManager.createPointer(true, PickType.Ray, { + joint: "_CONTROLLER_LEFTHAND", + filter: Picks.PICK_HUD, + maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, + posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true), + triggers: [{action: Controller.Standard.LTClick, button: "Focus"}, {action: Controller.Standard.LTClick, button: "Primary"}], + hover: true + }); + this.pointerManager.createPointer(true, PickType.Ray, { joint: "_CONTROLLER_RIGHTHAND", filter: Picks.PICK_HUD, maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE, - renderStates: renderStates, - defaultRenderStates: defaultRenderStates, posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true), triggers: [{action: Controller.Standard.RTClick, button: "Focus"}, {action: Controller.Standard.RTClick, button: "Primary"}], hover: true @@ -586,16 +432,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, enabled: true }); - - Pointers.setRenderState(this.leftControllerPointer, ""); - Pointers.setRenderState(this.leftControllerHudRayPick, ""); - Pointers.setRenderState(this.rightControllerPointer, ""); - Pointers.setRenderState(this.rightControllerHudRayPick, ""); - Pointers.enablePointer(this.leftControllerPointer); - Pointers.enablePointer(this.leftControllerHudRayPick); - Pointers.enablePointer(this.rightControllerPointer); - Pointers.enablePointer(this.rightControllerHudRayPick); - this.handleHandMessage = function(channel, message, sender) { var data; if (sender === MyAvatar.sessionUUID) { diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index ff013fc833..d6a23c5436 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -42,32 +42,6 @@ Script.include("/~/system/libraries/utils.js"); return (this.hand === RIGHT_HAND) ? Controller.Standard.RightHand : Controller.Standard.LeftHand; }; -<<<<<<< HEAD -======= - - this.processControllerTriggers = function(controllerData) { - if (controllerData.triggerClicks[this.hand]) { - this.mode = "full"; - } else if (controllerData.triggerValues[this.hand] > TRIGGER_ON_VALUE) { - this.mode = "half"; - } else { - this.mode = "none"; - } - }; - - this.updateLaserPointer = function(controllerData) { - LaserPointers.enableLaserPointer(this.laserPointer); - LaserPointers.setRenderState(this.laserPointer, this.mode); - - if (HMD.tabletID !== this.tabletID || HMD.homeButtonID !== this.homeButtonID || HMD.tabletScreenID !== this.tabletScreenID) { - this.tabletID = HMD.tabletID; - this.homeButtonID = HMD.homeButtonID; - this.tabletScreenID = HMD.tabletScreenID; - LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.homeButtonID, HMD.tabletScreenID]); - } - }; - ->>>>>>> 5a78c9ebfee6685c32abcef652fb6b3b3f7dc348 this.pointingAtTablet = function(objectID) { if (objectID === HMD.tabletScreenID || objectID === HMD.homeButtonID) { return true; @@ -146,26 +120,6 @@ Script.include("/~/system/libraries/utils.js"); this.sendPickData(controllerData); return this.isReady(controllerData); }; -<<<<<<< HEAD -======= - - this.cleanup = function() { - LaserPointers.disableLaserPointer(this.laserPointer); - LaserPointers.removeLaserPointer(this.laserPointer); - }; - - this.laserPointer = LaserPointers.createLaserPointer({ - joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", - filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, - maxDistance: PICK_MAX_DISTANCE, - posOffset: getGrabPointSphereOffset(this.handToController(), true), - renderStates: renderStates, - faceAvatar: true, - defaultRenderStates: defaultRenderStates - }); - - LaserPointers.setIgnoreItems(this.laserPointer, [HMD.tabletID, HMD.homeButtonID, HMD.tabletScreenID]); ->>>>>>> 5a78c9ebfee6685c32abcef652fb6b3b3f7dc348 } var leftHandInEditMode = new InEditMode(LEFT_HAND); @@ -175,8 +129,6 @@ Script.include("/~/system/libraries/utils.js"); enableDispatcherModule("RightHandInEditMode", rightHandInEditMode); function cleanup() { - leftHandInEditMode.cleanup(); - rightHandInEditMode.cleanup(); disableDispatcherModule("LeftHandInEditMode"); disableDispatcherModule("RightHandInEditMode"); } diff --git a/scripts/system/controllers/grab.js b/scripts/system/controllers/grab.js index 7a6b190d44..6d550d981f 100644 --- a/scripts/system/controllers/grab.js +++ b/scripts/system/controllers/grab.js @@ -345,7 +345,7 @@ Grabber.prototype.pressEvent = function(event) { } Pointers.setRenderState(this.mouseRayEntities, "grabbed"); - Pointers.setLockEndUid(this.mouseRayEntities, pickResults.objectID, false); + Pointers.setLockEndUUID(this.mouseRayEntities, pickResults.objectID, false); mouse.startDrag(event); diff --git a/scripts/system/libraries/pointersUtils.js b/scripts/system/libraries/pointersUtils.js new file mode 100644 index 0000000000..d9cca447c6 --- /dev/null +++ b/scripts/system/libraries/pointersUtils.js @@ -0,0 +1,191 @@ +"use strict"; + +// pointerUtils.js +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html + +/* jslint bitwise: true */ + +/* global Script, Entities, Overlays, Controller, Vec3, Quat, getControllerWorldLocation, RayPick, + controllerDispatcherPlugins:true, controllerDispatcherPluginsNeedSort:true, + LEFT_HAND, RIGHT_HAND, NEAR_GRAB_PICK_RADIUS, DEFAULT_SEARCH_SPHERE_DISTANCE, DISPATCHER_PROPERTIES, + getGrabPointSphereOffset, HMD, MyAvatar, Messages, findHandChildEntities, Pointers, PickType, COLORS_GRAB_SEARCHING_HALF_SQUEEZE + COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, Picks, TRIGGER_ON_VALUE +*/ + + +Script.include("/~/system/libraries/controllerDispatcherUtils.js"); +function Pointer(hudLayer, pickType, pointerData) { + this.SEARCH_SPHERE_SIZE = 0.0132; + this.dim = {x: this.SEARCH_SPHERE_SIZE, y: this.SEARCH_SPHERE_SIZE, z: this.SEARCH_SPHERE_SIZE}; + this.halfPath = { + type: "line3d", + color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + drawHUDLayer: hudLayer, + parentID: MyAvatar.SELF_ID + }; + this.halfEnd = { + type: "sphere", + dimensions: this.dim, + solid: true, + color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, + alpha: 0.9, + ignoreRayIntersection: true, + drawInFront: true, // Even when burried inside of something, show it. + drawHUDLayer: hudLayer, + visible: true + }; + this.fullPath = { + type: "line3d", + color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + drawHUDLayer: hudLayer, + parentID: MyAvatar.SELF_ID + }; + this.fullEnd = { + type: "sphere", + dimensions: this.dim, + solid: true, + color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, + alpha: 0.9, + ignoreRayIntersection: true, + drawInFront: true, // Even when burried inside of something, show it. + drawHUDLayer: hudLayer, + visible: true + }; + this.holdPath = { + type: "line3d", + color: COLORS_GRAB_DISTANCE_HOLD, + visible: true, + alpha: 1, + solid: true, + glow: 1.0, + lineWidth: 5, + ignoreRayIntersection: true, // always ignore this + drawInFront: true, // Even when burried inside of something, show it. + drawHUDLayer: hudLayer, + parentID: MyAvatar.SELF_ID + }; + + this.renderStates = [ + {name: "half", path: this.halfPath, end: this.halfEnd}, + {name: "full", path: this.fullPath, end: this.fullEnd}, + {name: "hold", path: this.holdPath} + ]; + + this.defaultRenderStates = [ + {name: "half", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: this.halfPath}, + {name: "full", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: this.fullPath}, + {name: "hold", distance: DEFAULT_SEARCH_SPHERE_DISTANCE, path: this.holdPath} + ]; + + + this.pointerID = null; + this.triggers = []; + this.joint = null; + this.visible = false; + this.locked = false; + + function createPointer(pickType, pointerData) { + if (this.pointerID) { + Pointers.removePointer(this.pointerID); + } + this.pointerID = Pointers.createPointer(pickType, pointerData); + Pointers.setRenderState(this.pointerID, ""); + Pointers.enablePointer(this.pointerID); + } + + this.enable = function() { + }; + + this.disable = function() { + }; + + this.makeVisible = function() { + this.visible = true; + }; + + this.makeInvisible = function() { + this.visible = false; + }; + + this.lockEnd = function(lockData) { + if (lockData !== undefined) { + var hand = lockData.hand; + if (this.visible) { + var targetID = lockData.targetID; + var targetIsOverlay = lockData.isOverlay; + Pointers.setLockEndUUID(this.pointer, targetID, targetIsOverlay); + this.locked = targetID; + } + } else { + this.locked = false; + } + }; + + this.updateRenderState = function(triggerClicked, triggerValue) { + var mode = ""; + if (this.visible) { + if (this.locked) { + mode = "hold"; + } else if (triggerClicked) { + mode = "full"; + } else if (triggerValue > TRIGGER_ON_VALUE) { + mode = "half"; + } + } + + Pointers.setRenderState(this.pointerID, mode); + }; + pointerData.renderStates = this.renderStates; + pointerData.defualtRenderStates = this.defualtRenderStates; + createPointer(pickType, pointerData); +} + + +function PointerManager() { + this.pointers = []; + + this.createPointer = function(hudLayer, pickType, pointerData) { + var pointer = new Pointer(hudLayer, pickType, pointerData); + this.pointers.push(pointer); + }; + + this.makePointerVisible = function(index) { + if (index < this.pointers.length) { + this.pointers[index].makeVisible(); + } + }; + + this.makePointerInvisible = function(index) { + if (index < this.pointers.length) { + this.pointers[index].makeInvisible(); + } + }; + + this.lockPointerEnd = function(index, lockData) { + if (index < this.pointers.length) { + this.pointers[index].lockEnd(lockData); + } + }; + + this.updatePointersRenderState = function(triggerClicked, triggerValue) { + for (var index = 0; index < this.pointers.length; index++) { + this.pointers[index].updateRenderState(triggerClicked, triggerValue); + } + }; +} From c6947dd165691887ac64e0fae778be96af0d6b4e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 9 Nov 2017 18:20:06 -0800 Subject: [PATCH 081/292] some side by side plumbing for NLPackets and NLPacketLists --- libraries/networking/src/NodeList.h | 3 ++ libraries/networking/src/PacketSender.cpp | 38 ++++++++++++---- libraries/networking/src/PacketSender.h | 5 ++- .../octree/src/OctreeEditPacketSender.cpp | 44 +++++++++++++++++-- libraries/octree/src/OctreeEditPacketSender.h | 5 ++- 5 files changed, 80 insertions(+), 15 deletions(-) diff --git a/libraries/networking/src/NodeList.h b/libraries/networking/src/NodeList.h index b3a12153e5..0ebc1f0b22 100644 --- a/libraries/networking/src/NodeList.h +++ b/libraries/networking/src/NodeList.h @@ -40,6 +40,9 @@ const quint64 DOMAIN_SERVER_CHECK_IN_MSECS = 1 * 1000; const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5; +using PacketOrPacketList = std::pair, std::unique_ptr>; +using NodePacketOrPacketListPair = std::pair; + using NodePacketPair = std::pair>; using NodeSharedPacketPair = std::pair>; using NodeSharedReceivedMessagePair = std::pair>; diff --git a/libraries/networking/src/PacketSender.cpp b/libraries/networking/src/PacketSender.cpp index 0cfd67cc4e..01b78585c2 100644 --- a/libraries/networking/src/PacketSender.cpp +++ b/libraries/networking/src/PacketSender.cpp @@ -53,7 +53,19 @@ void PacketSender::queuePacketForSending(const SharedNodePointer& destinationNod _totalBytesQueued += packet->getDataSize(); lock(); - _packets.push_back({destinationNode, std::move(packet)}); + _packets.push_back({destinationNode, PacketOrPacketList { std::move(packet), nullptr} }); + unlock(); + + // Make sure to wake our actual processing thread because we now have packets for it to process. + _hasPackets.wakeAll(); +} + +void PacketSender::queuePacketListForSending(const SharedNodePointer& destinationNode, std::unique_ptr packetList) { + _totalPacketsQueued += packetList->getNumPackets(); + _totalBytesQueued += packetList->getMessageSize(); + + lock(); + _packets.push_back({ destinationNode, PacketOrPacketList { nullptr, std::move(packetList)} }); unlock(); // Make sure to wake our actual processing thread because we now have packets for it to process. @@ -178,7 +190,7 @@ bool PacketSender::nonThreadedProcess() { float averagePacketsPerCall = 0; // might be less than 1, if our caller calls us more frequently than the target PPS - int packetsSentThisCall = 0; + size_t packetsSentThisCall = 0; int packetsToSendThisCall = 0; // Since we're in non-threaded mode, we need to determine how many packets to send per call to process @@ -265,23 +277,31 @@ bool PacketSender::nonThreadedProcess() { while ((packetsSentThisCall < packetsToSendThisCall) && (packetsLeft > 0)) { lock(); - NodePacketPair packetPair = std::move(_packets.front()); + NodePacketOrPacketListPair packetPair = std::move(_packets.front()); _packets.pop_front(); packetsLeft = _packets.size(); unlock(); // send the packet through the NodeList... - DependencyManager::get()->sendUnreliablePacket(*packetPair.second, *packetPair.first); + //PacketOrPacketList packetOrList = packetPair.second; + bool sendAsPacket = packetPair.second.first.get(); + if (sendAsPacket) { + DependencyManager::get()->sendUnreliablePacket(*packetPair.second.first, *packetPair.first); + } else { + DependencyManager::get()->sendPacketList(*packetPair.second.second, *packetPair.first); + } - packetsSentThisCall++; - _packetsOverCheckInterval++; - _totalPacketsSent++; + size_t packetSize = sendAsPacket ? packetPair.second.first->getDataSize() : packetPair.second.second->getMessageSize(); + size_t packetCount = sendAsPacket ? 1 : packetPair.second.second->getNumPackets(); + + packetsSentThisCall += packetCount; + _packetsOverCheckInterval += packetCount; + _totalPacketsSent += packetCount; - int packetSize = packetPair.second->getDataSize(); _totalBytesSent += packetSize; - emit packetSent(packetSize); + emit packetSent(packetSize); // FIXME should include number of packets? _lastSendTime = now; } diff --git a/libraries/networking/src/PacketSender.h b/libraries/networking/src/PacketSender.h index 68faeaca47..fead49df72 100644 --- a/libraries/networking/src/PacketSender.h +++ b/libraries/networking/src/PacketSender.h @@ -39,6 +39,7 @@ public: /// Add packet to outbound queue. void queuePacketForSending(const SharedNodePointer& destinationNode, std::unique_ptr packet); + void queuePacketListForSending(const SharedNodePointer& destinationNode, std::unique_ptr packetList); void setPacketsPerSecond(int packetsPerSecond); int getPacketsPerSecond() const { return _packetsPerSecond; } @@ -99,14 +100,14 @@ protected: SimpleMovingAverage _averageProcessCallTime; private: - std::list _packets; + std::list _packets; quint64 _lastSendTime; bool threadedProcess(); bool nonThreadedProcess(); quint64 _lastPPSCheck; - int _packetsOverCheckInterval; + size_t _packetsOverCheckInterval; quint64 _started; quint64 _totalPacketsSent; diff --git a/libraries/octree/src/OctreeEditPacketSender.cpp b/libraries/octree/src/OctreeEditPacketSender.cpp index f3c9ece9fe..7b612a828c 100644 --- a/libraries/octree/src/OctreeEditPacketSender.cpp +++ b/libraries/octree/src/OctreeEditPacketSender.cpp @@ -115,6 +115,27 @@ void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, std::uniqu }); } +// This method is called when the edit packet layer has determined that it has a fully formed packet destined for +// a known nodeID. +void OctreeEditPacketSender::queuePacketListToNode(const QUuid& nodeUUID, std::unique_ptr packetList) { + + bool wantDebug = false; + DependencyManager::get()->eachNode([&](const SharedNodePointer& node) { + // only send to the NodeTypes that are getMyNodeType() + if (node->getType() == getMyNodeType() + && ((node->getUUID() == nodeUUID) || (nodeUUID.isNull())) + && node->getActiveSocket()) { + + // NOTE: unlike packets, the packet lists don't get rewritten sequence numbers. + + // add packet to history -- we don't keep track of sent PacketLists + //_sentPacketHistories[nodeUUID].packetSent(sequence, *packet); + + queuePacketListForSending(node, std::move(packetList)); + } + }); +} + void OctreeEditPacketSender::processPreServerExistsPackets() { assert(serversExist()); // we should only be here if we have jurisdictions @@ -247,7 +268,7 @@ void OctreeEditPacketSender::queueOctreeEditMessage(PacketType type, QByteArray& }); } if (isMyJurisdiction) { - std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID]; + std::unique_ptr& bufferedPacket = _pendingEditPackets[nodeUUID].first; //only a NLPacket for now if (!bufferedPacket) { bufferedPacket = initializePacket(type, node->getClockSkewUsec()); @@ -291,15 +312,24 @@ void OctreeEditPacketSender::releaseQueuedMessages() { } else { _packetsQueueLock.lock(); for (auto& i : _pendingEditPackets) { - if (i.second) { + if (i.second.first) { // construct a null unique_ptr to an NL packet std::unique_ptr releasedPacket; // swap the null ptr with the packet we want to release - i.second.swap(releasedPacket); + i.second.first.swap(releasedPacket); // move and release the queued packet releaseQueuedPacket(i.first, std::move(releasedPacket)); + } else if (i.second.second) { + // construct a null unique_ptr to an NLPacketList + std::unique_ptr releasedPacketList; + + // swap the null ptr with the NLPacketList we want to release + i.second.second.swap(releasedPacketList); + + // move and release the queued NLPacketList + releaseQueuedPacketList(i.first, std::move(releasedPacketList)); } } @@ -315,6 +345,14 @@ void OctreeEditPacketSender::releaseQueuedPacket(const QUuid& nodeID, std::uniqu _releaseQueuedPacketMutex.unlock(); } +void OctreeEditPacketSender::releaseQueuedPacketList(const QUuid& nodeID, std::unique_ptr packetList) { + _releaseQueuedPacketMutex.lock(); + if (packetList->getMessageSize() > 0 && packetList->getType() != PacketType::Unknown) { + queuePacketListToNode(nodeID, std::move(packetList)); + } + _releaseQueuedPacketMutex.unlock(); +} + std::unique_ptr OctreeEditPacketSender::initializePacket(PacketType type, qint64 nodeClockSkew) { auto newPacket = NLPacket::create(type); diff --git a/libraries/octree/src/OctreeEditPacketSender.h b/libraries/octree/src/OctreeEditPacketSender.h index fd8cc85f91..79c363bec5 100644 --- a/libraries/octree/src/OctreeEditPacketSender.h +++ b/libraries/octree/src/OctreeEditPacketSender.h @@ -87,15 +87,18 @@ protected: bool _shouldSend; void queuePacketToNode(const QUuid& nodeID, std::unique_ptr packet); + void queuePacketListToNode(const QUuid& nodeUUID, std::unique_ptr packetList); + void queuePendingPacketToNodes(std::unique_ptr packet); void queuePacketToNodes(std::unique_ptr packet); std::unique_ptr initializePacket(PacketType type, qint64 nodeClockSkew); void releaseQueuedPacket(const QUuid& nodeUUID, std::unique_ptr packetBuffer); // releases specific queued packet + void releaseQueuedPacketList(const QUuid& nodeID, std::unique_ptr packetList); void processPreServerExistsPackets(); // These are packets which are destined from know servers but haven't been released because they're still too small - std::unordered_map> _pendingEditPackets; + std::unordered_map _pendingEditPackets; // These are packets that are waiting to be processed because we don't yet know if there are servers int _maxPendingMessages; From 608093eee5f27d874597afdea74cd774f7df0831 Mon Sep 17 00:00:00 2001 From: Sam Gateau Date: Fri, 10 Nov 2017 02:55:22 -0800 Subject: [PATCH 082/292] reverting the change in light direction /oritenation --- libraries/model/src/model/Light.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 9c3e0a5282..19da084f84 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -58,7 +58,7 @@ void Light::setOrientation(const glm::quat& orientation) { } void Light::setDirection(const Vec3& direction) { - _lightSchemaBuffer.edit().volume.direction = (_transform.getRotation() * direction); + _lightSchemaBuffer.edit().volume.direction = (direction); } const Vec3& Light::getDirection() const { From 908faa13345797dd37102cf324f3aade3ba9f459 Mon Sep 17 00:00:00 2001 From: beholder Date: Fri, 10 Nov 2017 19:38:07 +0300 Subject: [PATCH 083/292] refactoring: simplify code & fix the issue with menu-es sometimes losing checked state --- interface/resources/qml/desktop/Desktop.qml | 24 +++++++++++-------- .../qml/hifi/tablet/TabletMenuStack.qml | 23 ------------------ 2 files changed, 14 insertions(+), 33 deletions(-) diff --git a/interface/resources/qml/desktop/Desktop.qml b/interface/resources/qml/desktop/Desktop.qml index 847111b8a0..e7c68b2a47 100644 --- a/interface/resources/qml/desktop/Desktop.qml +++ b/interface/resources/qml/desktop/Desktop.qml @@ -51,19 +51,23 @@ FocusScope { // The VR version of the primary menu property var rootMenu: Menu { + id: rootMenuId objectName: "rootMenu" - // for some reasons it is not possible to use just '({})' here as it gets empty when passed to TableRoot/DesktopRoot - property var exclusionGroupsByMenuItem : ListModel {} + property var exclusionGroups: ({}); + property Component exclusiveGroupMaker: Component { + ExclusiveGroup { + } + } - function addExclusionGroup(menuItem, exclusionGroup) - { - exclusionGroupsByMenuItem.append( - { - 'menuItem' : menuItem.toString(), - 'exclusionGroup' : exclusionGroup.toString() - } - ); + function addExclusionGroup(qmlAction, exclusionGroup) { + + var exclusionGroupId = exclusionGroup.toString(); + if(!exclusionGroups[exclusionGroupId]) { + exclusionGroups[exclusionGroupId] = exclusiveGroupMaker.createObject(rootMenuId); + } + + qmlAction.exclusiveGroup = exclusionGroups[exclusionGroupId] } } diff --git a/interface/resources/qml/hifi/tablet/TabletMenuStack.qml b/interface/resources/qml/hifi/tablet/TabletMenuStack.qml index ce4fac3bd5..8cd696a41b 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuStack.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuStack.qml @@ -66,7 +66,6 @@ Item { function toModel(items, newMenu) { var result = modelMaker.createObject(tabletMenu); - var exclusionGroups = {}; for (var i = 0; i < items.length; ++i) { var item = items[i]; @@ -78,28 +77,6 @@ Item { if (item.text !== "Users Online") { result.append({"name": item.text, "item": item}) } - - for(var j = 0; j < tabletMenu.rootMenu.exclusionGroupsByMenuItem.count; ++j) - { - var entry = tabletMenu.rootMenu.exclusionGroupsByMenuItem.get(j); - if(entry.menuItem == item.toString()) - { - var exclusionGroupId = entry.exclusionGroup; - console.debug('item exclusionGroupId: ', exclusionGroupId) - - if(!exclusionGroups[exclusionGroupId]) - { - exclusionGroups[exclusionGroupId] = exclusiveGroupMaker.createObject(newMenu); - console.debug('new exclusion group created: ', exclusionGroups[exclusionGroupId]) - } - - var exclusionGroup = exclusionGroups[exclusionGroupId]; - - item.exclusiveGroup = exclusionGroup - console.debug('item.exclusiveGroup: ', item.exclusiveGroup) - } - } - break; case MenuItemType.Separator: result.append({"name": "", "item": item}) From 87519cd26f0174ce273fc63ee40076bb02132a22 Mon Sep 17 00:00:00 2001 From: beholder Date: Fri, 10 Nov 2017 19:39:51 +0300 Subject: [PATCH 084/292] use conditional bindings to avoid intermediate binding states --- .../qml/hifi/tablet/TabletMenuItem.qml | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml index 11d3cab35e..520841b33f 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml @@ -40,37 +40,29 @@ Item { CheckBox { id: checkbox - // FIXME: Should use radio buttons if source.exclusiveGroup. + width: 20 visible: source !== null ? source.visible && source.type === 1 && source.checkable && !source.exclusiveGroup : false - checked: setChecked() - function setChecked() { - if (!source || source.type !== 1 || !source.checkable) { - return false; - } - // FIXME this works for native QML menus but I don't think it will - // for proxied QML menus - return source.checked; + + Binding on checked { + value: source.checked; + when: source && source.type === 1 && source.checkable && !source.exclusiveGroup; } } RadioButton { id: radiobutton - // FIXME: Should use radio buttons if source.exclusiveGroup. + width: 20 visible: source !== null ? source.visible && source.type === 1 && source.checkable && source.exclusiveGroup : false - checked: setChecked() - function setChecked() { - if (!source || source.type !== 1 || !source.checkable) { - return false; - } - // FIXME this works for native QML menus but I don't think it will - // for proxied QML menus - return source.checked; + + Binding on checked { + value: source.checked; + when: source && source.type === 1 && source.checkable && source.exclusiveGroup; } } } From da49ee8bee498b9d1d9280afbc6ccb325d566d40 Mon Sep 17 00:00:00 2001 From: beholder Date: Fri, 10 Nov 2017 19:42:10 +0300 Subject: [PATCH 085/292] 9032 Current display mode can be deselected in the toolbar/tablet menu --- interface/src/Application.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b21588958e..e35407038b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -7082,6 +7082,7 @@ DisplayPluginPointer Application::getActiveDisplayPlugin() const { return _displayPlugin; } +static const char* exclusionGroupKey = "exclusionGroup"; static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { auto menu = Menu::getInstance(); @@ -7117,6 +7118,8 @@ static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool acti action->setCheckable(true); action->setChecked(active); displayPluginGroup->addAction(action); + + action->setProperty(exclusionGroupKey, QVariant::fromValue(displayPluginGroup)); Q_ASSERT(menu->menuItemExists(MenuOption::OutputMenu, name)); } From cbf05436460d896f46465b4a1e9f627c030b3236 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Fri, 10 Nov 2017 13:22:38 -0800 Subject: [PATCH 086/292] deadspot --- interface/src/raypick/LaserPointer.cpp | 2 +- interface/src/raypick/LaserPointer.h | 2 +- interface/src/raypick/StylusPointer.cpp | 78 +++++++++++++-------- interface/src/raypick/StylusPointer.h | 11 ++- libraries/pointers/src/pointers/Pointer.cpp | 4 +- libraries/pointers/src/pointers/Pointer.h | 2 +- 6 files changed, 64 insertions(+), 35 deletions(-) diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index bd54a24e97..5e0d61f24b 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -289,7 +289,7 @@ RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) { return RenderState(startID, pathID, endID); } -PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const { +PointerEvent LaserPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover) const { QUuid pickedID; glm::vec3 intersection, surfaceNormal, direction, origin; auto rayPickResult = std::static_pointer_cast(pickResult); diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index 4874cadf0a..59be58d4ac 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -70,7 +70,7 @@ public: static RenderState buildRenderState(const QVariantMap& propMap); protected: - PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const override; + PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover = true) const override; PickedObject getHoveredObject(const PickResultPointer& pickResult) override; Pointer::Buttons getPressedButtons() override; diff --git a/interface/src/raypick/StylusPointer.cpp b/interface/src/raypick/StylusPointer.cpp index 80e783cfe4..1a172b8894 100644 --- a/interface/src/raypick/StylusPointer.cpp +++ b/interface/src/raypick/StylusPointer.cpp @@ -17,8 +17,6 @@ #include "PickScriptingInterface.h" #include -using namespace controller; - // TODO: make these configurable per pointer static const float WEB_STYLUS_LENGTH = 0.2f; @@ -30,6 +28,10 @@ static const float TABLET_MAX_TOUCH_DISTANCE = 0.01f; static const float HOVER_HYSTERESIS = 0.01f; static const float TOUCH_HYSTERESIS = 0.02f; +static const float STYLUS_MOVE_DELAY = 0.33f * USECS_PER_SECOND; +static const float TOUCH_PRESS_TO_MOVE_DEADSPOT = 0.0481f; +static const float TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED = TOUCH_PRESS_TO_MOVE_DEADSPOT * TOUCH_PRESS_TO_MOVE_DEADSPOT; + StylusPointer::StylusPointer(const QVariant& props, const OverlayID& stylusOverlay, bool hover, bool enabled) : Pointer(DependencyManager::get()->createStylusPick(props), enabled, hover), _stylusOverlay(stylusOverlay) @@ -115,16 +117,10 @@ bool StylusPointer::shouldTrigger(const PickResultPointer& pickResult) { float distance = stylusPickResult->distance; // If we're triggering on an object, recalculate the distance instead of using the pickResult + glm::vec3 origin = vec3FromVariant(stylusPickResult->pickVariant["position"]); + glm::vec3 direction = -_state.surfaceNormal; if (!_state.triggeredObject.objectID.isNull() && stylusPickResult->objectID != _state.triggeredObject.objectID) { - glm::vec3 intersection; - glm::vec3 origin = vec3FromVariant(stylusPickResult->pickVariant["position"]); - glm::vec3 direction = -_state.surfaceNormal; - if (_state.triggeredObject.type == ENTITY) { - intersection = RayPick::intersectRayWithEntityXYPlane(_state.triggeredObject.objectID, origin, direction); - } else if (_state.triggeredObject.type == OVERLAY) { - intersection = RayPick::intersectRayWithOverlayXYPlane(_state.triggeredObject.objectID, origin, direction); - } - distance = glm::dot(intersection - origin, direction); + distance = glm::dot(findIntersection(_state.triggeredObject, origin, direction) - origin, direction); } float hysteresis = _state.triggering ? TOUCH_HYSTERESIS * sensorScaleFactor : 0.0f; @@ -132,6 +128,9 @@ bool StylusPointer::shouldTrigger(const PickResultPointer& pickResult) { TABLET_MAX_TOUCH_DISTANCE * sensorScaleFactor, hysteresis)) { if (_state.triggeredObject.objectID.isNull()) { _state.triggeredObject = PickedObject(stylusPickResult->objectID, stylusPickResult->type); + _state.intersection = findIntersection(_state.triggeredObject, origin, direction); + _state.triggerPos2D = findPos2D(_state.triggeredObject, origin); + _state.triggerStartTime = usecTimestampNow(); _state.surfaceNormal = stylusPickResult->surfaceNormal; _state.triggering = true; } @@ -140,6 +139,9 @@ bool StylusPointer::shouldTrigger(const PickResultPointer& pickResult) { } _state.triggeredObject = PickedObject(); + _state.intersection = glm::vec3(NAN); + _state.triggerPos2D = glm::vec2(NAN); + _state.triggerStartTime = 0; _state.surfaceNormal = glm::vec3(NAN); _state.triggering = false; return false; @@ -159,34 +161,30 @@ Pointer::Buttons StylusPointer::getPressedButtons() { return toReturn; } -PointerEvent StylusPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const { +PointerEvent StylusPointer::buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover) const { QUuid pickedID; + glm::vec2 pos2D; glm::vec3 intersection, surfaceNormal, direction, origin; auto stylusPickResult = std::static_pointer_cast(pickResult); if (stylusPickResult) { intersection = stylusPickResult->intersection; - surfaceNormal = _state.surfaceNormal; + surfaceNormal = hover ? stylusPickResult->surfaceNormal : _state.surfaceNormal; const QVariantMap& stylusTip = stylusPickResult->pickVariant; origin = vec3FromVariant(stylusTip["position"]); - direction = -_state.surfaceNormal; + direction = -surfaceNormal; + pos2D = findPos2D(target, origin); pickedID = stylusPickResult->objectID; } - if (pickedID != target.objectID) { - if (target.type == ENTITY) { - intersection = RayPick::intersectRayWithEntityXYPlane(target.objectID, origin, direction); - } else if (target.type == OVERLAY) { - intersection = RayPick::intersectRayWithOverlayXYPlane(target.objectID, origin, direction); - } - } - glm::vec2 pos2D; - if (target.type == ENTITY) { - pos2D = RayPick::projectOntoEntityXYPlane(target.objectID, origin); - } else if (target.type == OVERLAY) { - pos2D = RayPick::projectOntoOverlayXYPlane(target.objectID, origin); - } else if (target.type == HUD) { - pos2D = DependencyManager::get()->calculatePos2DFromHUD(origin); + // If we just started triggering and we haven't moved too much, don't update intersection and pos2D + if (!_state.triggeredObject.objectID.isNull() && usecTimestampNow() - _state.triggerStartTime < STYLUS_MOVE_DELAY && + glm::distance2(pos2D, _state.triggerPos2D) < TOUCH_PRESS_TO_MOVE_DEADSPOT_SQUARED) { + pos2D = _state.triggerPos2D; + intersection = _state.intersection; + } else if (pickedID != target.objectID) { + intersection = findIntersection(target, origin, direction); } + return PointerEvent(pos2D, intersection, surfaceNormal, direction); } @@ -203,4 +201,28 @@ void StylusPointer::setRenderState(const std::string& state) { } else if (state == "disabled") { _renderState = DISABLED; } +} + +glm::vec3 StylusPointer::findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction) { + switch (pickedObject.type) { + case ENTITY: + return RayPick::intersectRayWithEntityXYPlane(pickedObject.objectID, origin, direction); + case OVERLAY: + return RayPick::intersectRayWithOverlayXYPlane(pickedObject.objectID, origin, direction); + default: + return glm::vec3(NAN); + } +} + +glm::vec2 StylusPointer::findPos2D(const PickedObject& pickedObject, const glm::vec3& origin) { + switch (pickedObject.type) { + case ENTITY: + return RayPick::projectOntoEntityXYPlane(pickedObject.objectID, origin); + case OVERLAY: + return RayPick::projectOntoOverlayXYPlane(pickedObject.objectID, origin); + case HUD: + return DependencyManager::get()->calculatePos2DFromHUD(origin); + default: + return glm::vec2(NAN); + } } \ No newline at end of file diff --git a/interface/src/raypick/StylusPointer.h b/interface/src/raypick/StylusPointer.h index cc7f2814db..fb2d492798 100644 --- a/interface/src/raypick/StylusPointer.h +++ b/interface/src/raypick/StylusPointer.h @@ -41,7 +41,7 @@ protected: bool shouldHover(const PickResultPointer& pickResult) override; bool shouldTrigger(const PickResultPointer& pickResult) override; - PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const override; + PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover = true) const override; private: void show(const StylusTip& tip); @@ -49,9 +49,13 @@ private: struct TriggerState { PickedObject triggeredObject; + glm::vec3 intersection { NAN }; + glm::vec2 triggerPos2D { NAN }; glm::vec3 surfaceNormal { NAN }; - bool hovering { false }; + quint64 triggerStartTime { 0 }; bool triggering { false }; + + bool hovering { false }; }; TriggerState _state; @@ -67,6 +71,9 @@ private: const OverlayID _stylusOverlay; static bool isWithinBounds(float distance, float min, float max, float hysteresis); + static glm::vec3 findIntersection(const PickedObject& pickedObject, const glm::vec3& origin, const glm::vec3& direction); + static glm::vec2 findPos2D(const PickedObject& pickedObject, const glm::vec3& origin); + }; #endif // hifi_StylusPointer_h diff --git a/libraries/pointers/src/pointers/Pointer.cpp b/libraries/pointers/src/pointers/Pointer.cpp index e17fb8ec65..d5aa13d293 100644 --- a/libraries/pointers/src/pointers/Pointer.cpp +++ b/libraries/pointers/src/pointers/Pointer.cpp @@ -199,7 +199,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin // Trigger continue for (const std::string& button : sameButtons) { - PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); + PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult, false); triggeredEvent.setID(pointerID); triggeredEvent.setType(PointerEvent::Move); triggeredEvent.setButton(chooseButton(button)); @@ -214,7 +214,7 @@ void Pointer::generatePointerEvents(unsigned int pointerID, const PickResultPoin // Trigger end for (const std::string& button : _prevButtons) { - PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult); + PointerEvent triggeredEvent = buildPointerEvent(_triggeredObjects[button], pickResult, false); triggeredEvent.setID(pointerID); triggeredEvent.setType(PointerEvent::Release); triggeredEvent.setButton(chooseButton(button)); diff --git a/libraries/pointers/src/pointers/Pointer.h b/libraries/pointers/src/pointers/Pointer.h index 0415f00d1e..6acbcf9ca0 100644 --- a/libraries/pointers/src/pointers/Pointer.h +++ b/libraries/pointers/src/pointers/Pointer.h @@ -82,7 +82,7 @@ protected: bool _enabled; bool _hover; - virtual PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult) const = 0; + virtual PointerEvent buildPointerEvent(const PickedObject& target, const PickResultPointer& pickResult, bool hover = true) const = 0; virtual PickedObject getHoveredObject(const PickResultPointer& pickResult) = 0; virtual Buttons getPressedButtons() = 0; From 03364c1893a7113574c532a8064460391d29462f Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Fri, 10 Nov 2017 15:34:22 -0800 Subject: [PATCH 087/292] Cleanup DS settings for small screens --- domain-server/resources/web/css/style.css | 22 ++++++++++++++----- .../resources/web/settings/index.shtml | 5 ----- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index fb1e1aa9f5..17dcc06ccb 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -80,11 +80,23 @@ span.port { display: none; } -#setup-sidebar.affix { - /* This overrides a case where going to the bottom of the page, - * then scrolling up, causes `position: relative` to be added to the style - */ - position: fixed !important; +@media (min-width: 768px) { + #setup-sidebar.affix { + /* This overrides a case where going to the bottom of the page, + * then scrolling up, causes `position: relative` to be added to the style + */ + position: fixed !important; + } +} + +@media (max-width: 767px) { + #setup-sidebar.affix { + position: static !important; + } + + #setup-sidebar { + margin-bottom: 20px; + } } #setup-sidebar button { diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index 5a8184db30..d36330375a 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -36,11 +36,6 @@
- - -
-