From a2ca0e84700c76106ac19aa974abc7c50c200bdb Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 10 Feb 2016 17:01:11 -0800 Subject: [PATCH 01/34] initial exploration --- examples/away.js | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/examples/away.js b/examples/away.js index c37e588734..456635f8ab 100644 --- a/examples/away.js +++ b/examples/away.js @@ -90,12 +90,18 @@ hideOverlay(); // MAIN CONTROL var wasMuted, isAway; +var eventMappingName = "io.highfidelity.away"; // goActive on hand controller button events, too. +var eventMapping = Controller.newMapping(eventMappingName); + function goAway() { if (isAway) { return; } isAway = true; print('going "away"'); + Controller.mousePressEvent.connect(goActive); + Controller.keyPressEvent.connect(maybeGoActive); + Controller.enableMapping(eventMappingName); wasMuted = AudioDevice.getMuted(); if (!wasMuted) { AudioDevice.toggleMute(); @@ -110,6 +116,9 @@ function goActive() { } isAway = false; print('going "active"'); + Controller.mousePressEvent.disconnect(goActive); + Controller.keyPressEvent.disconnect(maybeGoActive); + Controller.disableMapping(eventMappingName); // Let hand-controller events through to other scripts. if (!wasMuted) { AudioDevice.toggleMute(); } @@ -117,9 +126,10 @@ function goActive() { stopAwayAnimation(); hideOverlay(); } -Script.scriptEnding.connect(goActive); -Controller.keyPressEvent.connect(function (event) { + +function maybeGoActive(event) { if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) + print('fixme autorepeat'); return; } if (!isAway && (event.text === '.')) { @@ -127,13 +137,26 @@ Controller.keyPressEvent.connect(function (event) { } else { goActive(); } -}); +} var wasHmdActive = false; -Script.update.connect(function () { +function maybeGoAway() { if (HMD.active !== wasHmdActive) { wasHmdActive = !wasHmdActive; if (wasHmdActive) { goAway(); } } +} + +Script.update.connect(maybeGoAway); +// Set up the mapping, but don't enable it until we're actually away. +eventMapping.from(Controller.Standard.LeftPrimaryThumb).to(goActive); +eventMapping.from(Controller.Standard.RightPrimaryThumb).to(goActive); +eventMapping.from(Controller.Standard.LeftSecondaryThumb).to(goActive); +eventMapping.from(Controller.Standard.RightSecondaryThumb).to(goActive); + +Script.scriptEnding.connect(function () { + Script.update.disconnect(maybeGoAway); + goActive(); }); + From f0ca412b29b3cf77fdd5b4d73db53a334a313abd Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 10 Feb 2016 18:22:57 -0800 Subject: [PATCH 02/34] use the existing not mixed count for injector inactivity --- .../src/audio/AudioMixerClientData.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index fa706eb0f6..944ffc382a 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -157,12 +157,16 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() { while (it != _audioStreams.end()) { SharedStreamPointer stream = it->second; - static const int INJECTOR_INACTIVITY_USECS = 5 * USECS_PER_SECOND; + if (stream->popFrames(1, true) > 0) { + stream->updateLastPopOutputLoudnessAndTrailingLoudness(); + } + + static const int INJECTOR_MAX_INACTIVE_BLOCKS = 500; // if we don't have new data for an injected stream in the last INJECTOR_INACTIVITY_MSECS then // we remove the injector from our streams if (stream->getType() == PositionalAudioStream::Injector - && stream->usecsSinceLastPacket() > INJECTOR_INACTIVITY_USECS) { + && stream->getConsecutiveNotMixedCount() > INJECTOR_MAX_INACTIVE_BLOCKS) { // this is an inactive injector, pull it from our streams // first emit that it is finished so that the HRTF objects for this source can be cleaned up @@ -170,12 +174,8 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() { // erase the stream to drop our ref to the shared pointer and remove it it = _audioStreams.erase(it); - + } else { - if (stream->popFrames(1, true) > 0) { - stream->updateLastPopOutputLoudnessAndTrailingLoudness(); - } - ++it; } } From 367e558b19963d9fb3b0646f30dab23966704e4d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 09:30:07 -0800 Subject: [PATCH 03/34] address PR comments for whitespace and constant --- assignment-client/src/audio/AudioMixerClientData.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 944ffc382a..38cb8a174f 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -163,7 +163,7 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() { static const int INJECTOR_MAX_INACTIVE_BLOCKS = 500; - // if we don't have new data for an injected stream in the last INJECTOR_INACTIVITY_MSECS then + // if we don't have new data for an injected stream in the last INJECTOR_MAX_INACTIVE_BLOCKS then // we remove the injector from our streams if (stream->getType() == PositionalAudioStream::Injector && stream->getConsecutiveNotMixedCount() > INJECTOR_MAX_INACTIVE_BLOCKS) { @@ -174,7 +174,6 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend() { // erase the stream to drop our ref to the shared pointer and remove it it = _audioStreams.erase(it); - } else { ++it; } From 27494e54c5b9ad8692dd6a714ecbe45d9f2d04d1 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 11 Feb 2016 12:58:23 -0800 Subject: [PATCH 04/34] use the correct macro for detecting GCC --- libraries/audio/src/AudioHRTF.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index bce95072d9..4eef4ff723 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -143,7 +143,7 @@ static bool cpuSupportsAVX() { return result; } -#elif defined(__GNU__) +#elif defined(__GNUC__) static bool cpuSupportsAVX() { return __builtin_cpu_supports("avx"); From 0d8404e7e8e1d0d51bc4661318fbd0e49f7a7820 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 11 Feb 2016 13:05:47 -0800 Subject: [PATCH 05/34] interact more safely with mappings --- examples/away.js | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/examples/away.js b/examples/away.js index 456635f8ab..05476383df 100644 --- a/examples/away.js +++ b/examples/away.js @@ -19,6 +19,14 @@ var OVERLAY_DATA = { color: {red: 255, green: 255, blue: 255}, alpha: 1 }; +// For the script to receive an event when the user presses a hand-controller button, we need to map +// that button to the handler, which we do at the bottom of this script. However, doing so changes +// the mapping for the user, across all scripts. Therefore, we just enable the mapping when going +// "away", and disable it when going "active". However, this is occuring within a Controller event, so we +// have to wait until the Controller code has finished with all such events, so we delay +// it. Additionally, we may go "away" on startup, and we want to wait until any other such mapping +// have occured, because only the last remapping wins. +var CONTROLLER_REMAPPING_DELAY = 750; // ms // ANIMATION // We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect @@ -97,11 +105,13 @@ function goAway() { if (isAway) { return; } + Script.setTimeout(function () { + if (isAway) { // i.e., unless something changed during the delay. + Controller.enableMapping(eventMappingName); + } + }, CONTROLLER_REMAPPING_DELAY); isAway = true; print('going "away"'); - Controller.mousePressEvent.connect(goActive); - Controller.keyPressEvent.connect(maybeGoActive); - Controller.enableMapping(eventMappingName); wasMuted = AudioDevice.getMuted(); if (!wasMuted) { AudioDevice.toggleMute(); @@ -114,11 +124,13 @@ function goActive() { if (!isAway) { return; } + Script.setTimeout(function () { + if (!isAway) { // i.e., unless something changed during the delay + Controller.disableMapping(eventMappingName); // Let hand-controller events through to other scripts. + } + }, CONTROLLER_REMAPPING_DELAY); isAway = false; print('going "active"'); - Controller.mousePressEvent.disconnect(goActive); - Controller.keyPressEvent.disconnect(maybeGoActive); - Controller.disableMapping(eventMappingName); // Let hand-controller events through to other scripts. if (!wasMuted) { AudioDevice.toggleMute(); } @@ -129,7 +141,6 @@ function goActive() { function maybeGoActive(event) { if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it) - print('fixme autorepeat'); return; } if (!isAway && (event.text === '.')) { @@ -149,6 +160,9 @@ function maybeGoAway() { } Script.update.connect(maybeGoAway); +// These two can be set now and left active as long as the script is running. They do not interfere with other scripts. +Controller.mousePressEvent.connect(goActive); +Controller.keyPressEvent.connect(maybeGoActive); // Set up the mapping, but don't enable it until we're actually away. eventMapping.from(Controller.Standard.LeftPrimaryThumb).to(goActive); eventMapping.from(Controller.Standard.RightPrimaryThumb).to(goActive); @@ -159,4 +173,3 @@ Script.scriptEnding.connect(function () { Script.update.disconnect(maybeGoAway); goActive(); }); - From 7c4e31687c79fe1fb5dc0bea9d1ead993e46085e Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Thu, 11 Feb 2016 13:27:56 -0800 Subject: [PATCH 06/34] simpler/better/more reliable (peek) --- examples/away.js | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/examples/away.js b/examples/away.js index 05476383df..861c642b8d 100644 --- a/examples/away.js +++ b/examples/away.js @@ -19,14 +19,6 @@ var OVERLAY_DATA = { color: {red: 255, green: 255, blue: 255}, alpha: 1 }; -// For the script to receive an event when the user presses a hand-controller button, we need to map -// that button to the handler, which we do at the bottom of this script. However, doing so changes -// the mapping for the user, across all scripts. Therefore, we just enable the mapping when going -// "away", and disable it when going "active". However, this is occuring within a Controller event, so we -// have to wait until the Controller code has finished with all such events, so we delay -// it. Additionally, we may go "away" on startup, and we want to wait until any other such mapping -// have occured, because only the last remapping wins. -var CONTROLLER_REMAPPING_DELAY = 750; // ms // ANIMATION // We currently don't have play/stopAnimation integrated with the animation graph, but we can get the same effect @@ -105,11 +97,6 @@ function goAway() { if (isAway) { return; } - Script.setTimeout(function () { - if (isAway) { // i.e., unless something changed during the delay. - Controller.enableMapping(eventMappingName); - } - }, CONTROLLER_REMAPPING_DELAY); isAway = true; print('going "away"'); wasMuted = AudioDevice.getMuted(); @@ -124,11 +111,6 @@ function goActive() { if (!isAway) { return; } - Script.setTimeout(function () { - if (!isAway) { // i.e., unless something changed during the delay - Controller.disableMapping(eventMappingName); // Let hand-controller events through to other scripts. - } - }, CONTROLLER_REMAPPING_DELAY); isAway = false; print('going "active"'); if (!wasMuted) { @@ -160,16 +142,19 @@ function maybeGoAway() { } Script.update.connect(maybeGoAway); -// These two can be set now and left active as long as the script is running. They do not interfere with other scripts. Controller.mousePressEvent.connect(goActive); Controller.keyPressEvent.connect(maybeGoActive); -// Set up the mapping, but don't enable it until we're actually away. -eventMapping.from(Controller.Standard.LeftPrimaryThumb).to(goActive); -eventMapping.from(Controller.Standard.RightPrimaryThumb).to(goActive); -eventMapping.from(Controller.Standard.LeftSecondaryThumb).to(goActive); -eventMapping.from(Controller.Standard.RightSecondaryThumb).to(goActive); +// Note peek() so as to not interfere with other mappings. +eventMapping.from(Controller.Standard.LeftPrimaryThumb).peek().to(goActive); +eventMapping.from(Controller.Standard.RightPrimaryThumb).peek().to(goActive); +eventMapping.from(Controller.Standard.LeftSecondaryThumb).peek().to(goActive); +eventMapping.from(Controller.Standard.RightSecondaryThumb).peek().to(goActive); +Controller.enableMapping(eventMappingName); Script.scriptEnding.connect(function () { Script.update.disconnect(maybeGoAway); goActive(); + Controller.disableMapping(eventMappingName); + Controller.mousePressEvent.disconnect(goActive); + Controller.keyPressEvent.disconnect(maybeGoActive); }); From aaf8e60de315ac10d31fa0ef5d0b3b36b8b715b1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 15:11:21 -0800 Subject: [PATCH 07/34] delay critical quit messages until just prior to quit --- domain-server/src/DomainServer.cpp | 36 ++++++++++++------- domain-server/src/DomainServer.h | 3 +- .../src/DomainServerSettingsManager.cpp | 11 ++++-- 3 files changed, 34 insertions(+), 16 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d1cb9d4e4a..e30e009520 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -120,6 +120,14 @@ DomainServer::~DomainServer() { DependencyManager::destroy(); } +void DomainServer::queuedQuit(QString quitMessage, int exitCode) { + if (!quitMessage.isEmpty()) { + qCritical() << qPrintable(quitMessage); + } + + QCoreApplication::exit(exitCode); +} + void DomainServer::aboutToQuit() { // clear the log handler so that Qt doesn't call the destructor on LogHandler @@ -164,8 +172,11 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() { qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT; } else if (!certPath.isEmpty() || !keyPath.isEmpty()) { - qDebug() << "Missing certificate or private key. domain-server will now quit."; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + static const QString MISSING_CERT_ERROR_MSG = "Missing certificate or private key. domain-server will now quit."; + static const int MISSING_CERT_ERROR_CODE = 3; + + QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, + Q_ARG(QString, MISSING_CERT_ERROR_MSG), Q_ARG(int, MISSING_CERT_ERROR_CODE)); return false; } @@ -199,8 +210,10 @@ bool DomainServer::optionallySetupOAuth() { || _hostname.isEmpty() || _oauthClientID.isEmpty() || _oauthClientSecret.isEmpty()) { - qDebug() << "Missing OAuth provider URL, hostname, client ID, or client secret. domain-server will now quit."; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + static const QString MISSING_OAUTH_INFO_MSG = "Missing OAuth provider URL, hostname, client ID, or client secret. domain-server will now quit."; + static const int MISSING_OAUTH_INFO_ERROR_CODE = 1542; + QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, + Q_ARG(QString, MISSING_OAUTH_INFO_MSG), Q_ARG(int, MISSING_OAUTH_INFO_ERROR_CODE)); return false; } else { qDebug() << "OAuth will be used to identify clients using provider at" << _oauthProviderURL.toString(); @@ -404,9 +417,13 @@ bool DomainServer::resetAccountManagerAccessToken() { return true; } else { - qDebug() << "Missing OAuth provider URL, but a domain-server feature was required that requires authentication." << - "domain-server will now quit."; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); + static const QString MISSING_OAUTH_PROVIDER_MSG = + QString("Missing OAuth provider URL, but a domain-server feature was required that requires authentication.") + + QString("domain-server will now quit."); + static const int MISSING_OAUTH_PROVIDER_ERROR_CODE = 5323; + QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, + Q_ARG(QString, MISSING_OAUTH_PROVIDER_MSG), + Q_ARG(int, MISSING_OAUTH_PROVIDER_ERROR_CODE)); return false; } @@ -517,11 +534,6 @@ void DomainServer::setupICEHeartbeatForFullNetworking() { } } -void DomainServer::loginFailed() { - qDebug() << "Login to data server has failed. domain-server will now quit"; - QMetaObject::invokeMethod(this, "quit", Qt::QueuedConnection); -} - void DomainServer::parseAssignmentConfigs(QSet& excludedTypes) { // check for configs from the command line, these take precedence const QString ASSIGNMENT_CONFIG_REGEX_STRING = "config-([\\d]+)"; diff --git a/domain-server/src/DomainServer.h b/domain-server/src/DomainServer.h index afdd7bd26e..326ca3e1a8 100644 --- a/domain-server/src/DomainServer.h +++ b/domain-server/src/DomainServer.h @@ -65,7 +65,6 @@ public slots: private slots: void aboutToQuit(); - void loginFailed(); void setupPendingAssignmentCredits(); void sendPendingTransactionsToServer(); @@ -77,6 +76,8 @@ private slots: void handleTempDomainSuccess(QNetworkReply& requestReply); void handleTempDomainError(QNetworkReply& requestReply); + + void queuedQuit(QString quitMessage, int exitCode); private: void setupNodeListAndAssignments(const QUuid& sessionUUID = QUuid::createUuid()); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 98bb63241e..2cf62bd00a 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -62,9 +62,14 @@ DomainServerSettingsManager::DomainServerSettingsManager() : } } - qCritical() << "Did not find settings decription in JSON at" << SETTINGS_DESCRIPTION_RELATIVE_PATH - << "- Unable to continue. domain-server will quit."; - QMetaObject::invokeMethod(QCoreApplication::instance(), "quit", Qt::QueuedConnection); + static const QString MISSING_SETTINGS_DESC_MSG = + QString("Did not find settings decription in JSON at %1 - Unable to continue. domain-server will quit.") + .arg(SETTINGS_DESCRIPTION_RELATIVE_PATH); + static const int MISSING_SETTINGS_DESC_ERROR_CODE = 8912; + + QMetaObject::invokeMethod(QCoreApplication::instance(), "queuedQuit", Qt::QueuedConnection, + Q_ARG(QString, MISSING_SETTINGS_DESC_MSG), + Q_ARG(int, MISSING_SETTINGS_DESC_ERROR_CODE)); } void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer message) { From c4b09c36036afa940e73be95cba8049cb3e6c0d7 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 11 Feb 2016 15:15:50 -0800 Subject: [PATCH 08/34] not supported by Clang --- libraries/audio/src/AudioHRTF.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 4eef4ff723..b56cf87e1e 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -143,7 +143,7 @@ static bool cpuSupportsAVX() { return result; } -#elif defined(__GNUC__) +#elif defined(__GNUC__) && !defined(__clang__) static bool cpuSupportsAVX() { return __builtin_cpu_supports("avx"); From 0f4467c5829a8f3389766dc235c0950f68ab80e3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 15:17:34 -0800 Subject: [PATCH 09/34] cleanup exit codes for queued DS exit --- domain-server/src/DomainServer.cpp | 4 ++-- domain-server/src/DomainServerSettingsManager.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index e30e009520..d68a2cfc8e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -211,7 +211,7 @@ bool DomainServer::optionallySetupOAuth() { || _oauthClientID.isEmpty() || _oauthClientSecret.isEmpty()) { static const QString MISSING_OAUTH_INFO_MSG = "Missing OAuth provider URL, hostname, client ID, or client secret. domain-server will now quit."; - static const int MISSING_OAUTH_INFO_ERROR_CODE = 1542; + static const int MISSING_OAUTH_INFO_ERROR_CODE = 4; QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, Q_ARG(QString, MISSING_OAUTH_INFO_MSG), Q_ARG(int, MISSING_OAUTH_INFO_ERROR_CODE)); return false; @@ -420,7 +420,7 @@ bool DomainServer::resetAccountManagerAccessToken() { static const QString MISSING_OAUTH_PROVIDER_MSG = QString("Missing OAuth provider URL, but a domain-server feature was required that requires authentication.") + QString("domain-server will now quit."); - static const int MISSING_OAUTH_PROVIDER_ERROR_CODE = 5323; + static const int MISSING_OAUTH_PROVIDER_ERROR_CODE = 5; QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection, Q_ARG(QString, MISSING_OAUTH_PROVIDER_MSG), Q_ARG(int, MISSING_OAUTH_PROVIDER_ERROR_CODE)); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index 2cf62bd00a..49ae03ccd4 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -65,7 +65,7 @@ DomainServerSettingsManager::DomainServerSettingsManager() : static const QString MISSING_SETTINGS_DESC_MSG = QString("Did not find settings decription in JSON at %1 - Unable to continue. domain-server will quit.") .arg(SETTINGS_DESCRIPTION_RELATIVE_PATH); - static const int MISSING_SETTINGS_DESC_ERROR_CODE = 8912; + static const int MISSING_SETTINGS_DESC_ERROR_CODE = 6; QMetaObject::invokeMethod(QCoreApplication::instance(), "queuedQuit", Qt::QueuedConnection, Q_ARG(QString, MISSING_SETTINGS_DESC_MSG), From f455e404e3d81dd038b573be99b8a85520850f27 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 15:19:57 -0800 Subject: [PATCH 10/34] add an option for assets path --- domain-server/resources/describe-settings.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 891c586a6a..1a6ca980fe 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -168,7 +168,7 @@ }, { "name": "asset_server", - "label": "Asset Server", + "label": "Asset Server (ATP)", "assignment-types": [3], "settings": [ { @@ -178,6 +178,15 @@ "help": "Assigns an asset-server in your domain to serve files to clients via the ATP protocol (over UDP)", "default": true, "advanced": true + }, + { + "name": "assets_path", + "type": "string", + "label": "Assets Path", + "help": "The path to the directory assets are stored in.
If this path is relative, it will be relative to the application data directory. If you change this path you will need to manually copy any existing assets from the previous directory.", + "placeholder": "assets", + "default": "assets", + "advanced": true } ] }, From 7c0b3953e4d47db6de434aaf3f423183148f68b5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 15:34:43 -0800 Subject: [PATCH 11/34] handle custom path in asset-server for assets --- assignment-client/src/assets/AssetServer.cpp | 50 +++++++++++++++++--- assignment-client/src/assets/AssetServer.h | 2 + 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 8ab53d3b87..443fbff3b1 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -45,25 +45,61 @@ AssetServer::AssetServer(ReceivedMessage& message) : } void AssetServer::run() { + + qDebug() << "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(); + connect(&domainHandler, &DomainHandler::settingsReceived, this, &AssetServer::completeSetup); + connect(&domainHandler, &DomainHandler::settingsReceiveFail, this, &AssetServer::domainSettingsRequestFailed); + ThreadedAssignment::commonInit(ASSET_SERVER_LOGGING_TARGET_NAME, NodeType::AssetServer); +} +void AssetServer::completeSetup() { auto nodeList = DependencyManager::get(); - nodeList->addNodeTypeToInterestSet(NodeType::Agent); - const QString RESOURCES_PATH = "assets"; + auto& domainHandler = nodeList->getDomainHandler(); + const QJsonObject& settingsObject = domainHandler.getSettingsObject(); - _resourcesDirectory = QDir(ServerPathUtils::getDataDirectory()).filePath(RESOURCES_PATH); + static const QString ASSET_SERVER_SETTINGS_KEY = "asset_server"; + auto assetServerObject = settingsObject[ASSET_SERVER_SETTINGS_KEY]; + + // get the path to the asset folder from the domain server settings + static const QString ASSETS_PATH_OPTION = "assets_path"; + auto assetsJSONValue = assetServerObject.toObject()[ASSETS_PATH_OPTION]; + + if (assetsJSONValue.type() != QJsonValue::String) { + qCritical() << "Received an assets path from the domain-server that could not be parsed. Stopping assignment."; + setFinished(true); + return; + } + + auto assetsPathString = assetsJSONValue.toString(); + QDir assetsPath { assetsPathString }; + QString absoluteFilePath = assetsPath.absolutePath(); + + if (assetsPath.isRelative()) { + // if the domain settings passed us a relative path, make an absolute path that is relative to the + // default data directory + absoluteFilePath = ServerPathUtils::getDataFilePath(assetsPathString); + } + + _resourcesDirectory = QDir(absoluteFilePath); qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); bool noExistingAssets = !_resourcesDirectory.exists() \ - || _resourcesDirectory.entryList(QDir::Files).size() == 0; + || _resourcesDirectory.entryList(QDir::Files).size() == 0; if (noExistingAssets) { qDebug() << "Asset resources directory not found, searching for existing asset resources"; QString oldDataDirectory = QCoreApplication::applicationDirPath(); - auto oldResourcesDirectory = QDir(oldDataDirectory).filePath("resources/" + RESOURCES_PATH); + + const QString OLD_RESOURCES_PATH = "assets"; + + auto oldResourcesDirectory = QDir(oldDataDirectory).filePath("resources/" + OLD_RESOURCES_PATH); if (QDir(oldResourcesDirectory).exists()) { @@ -111,10 +147,12 @@ void AssetServer::run() { auto hexHash = hash.toHex(); qDebug() << "\tMoving " << filename << " to " << hexHash; - + file.rename(_resourcesDirectory.absoluteFilePath(hexHash) + "." + fileInfo.suffix()); } } + + nodeList->addNodeTypeToInterestSet(NodeType::Agent); } void AssetServer::handleAssetGetInfo(QSharedPointer message, SharedNodePointer senderNode) { diff --git a/assignment-client/src/assets/AssetServer.h b/assignment-client/src/assets/AssetServer.h index fe83ce92a6..7d6e26af08 100644 --- a/assignment-client/src/assets/AssetServer.h +++ b/assignment-client/src/assets/AssetServer.h @@ -29,6 +29,8 @@ public slots: void run(); private slots: + void completeSetup(); + void handleAssetGetInfo(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetGet(QSharedPointer packet, SharedNodePointer senderNode); void handleAssetUpload(QSharedPointer packetList, SharedNodePointer senderNode); From f117bd586724df4f7bc61bd2d2aebcadd3ee535f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 15:38:50 -0800 Subject: [PATCH 12/34] fix check for string assets path --- assignment-client/src/assets/AssetServer.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 443fbff3b1..556813d335 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -63,13 +63,20 @@ void AssetServer::completeSetup() { const QJsonObject& settingsObject = domainHandler.getSettingsObject(); static const QString ASSET_SERVER_SETTINGS_KEY = "asset_server"; - auto assetServerObject = settingsObject[ASSET_SERVER_SETTINGS_KEY]; + + if (!settingsObject.contains(ASSET_SERVER_SETTINGS_KEY)) { + qCritical() << "Received settings from the domain-server with no asset-server section. Stopping assignment."; + setFinished(true); + return; + } + + auto assetServerObject = settingsObject[ASSET_SERVER_SETTINGS_KEY].toObject(); // get the path to the asset folder from the domain server settings static const QString ASSETS_PATH_OPTION = "assets_path"; - auto assetsJSONValue = assetServerObject.toObject()[ASSETS_PATH_OPTION]; + auto assetsJSONValue = assetServerObject[ASSETS_PATH_OPTION]; - if (assetsJSONValue.type() != QJsonValue::String) { + if (!assetsJSONValue.isString()) { qCritical() << "Received an assets path from the domain-server that could not be parsed. Stopping assignment."; setFinished(true); return; From 8eaea8a7ffff645e7531c970ae84986309674694 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 15:42:35 -0800 Subject: [PATCH 13/34] clarify asset-server migration message --- assignment-client/src/assets/AssetServer.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 556813d335..34cd97eca6 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -97,11 +97,10 @@ void AssetServer::completeSetup() { qDebug() << "Creating resources directory"; _resourcesDirectory.mkpath("."); - bool noExistingAssets = !_resourcesDirectory.exists() \ - || _resourcesDirectory.entryList(QDir::Files).size() == 0; + bool noExistingAssets = !_resourcesDirectory.exists() || _resourcesDirectory.entryList(QDir::Files).size() == 0; if (noExistingAssets) { - qDebug() << "Asset resources directory not found, searching for existing asset resources"; + qDebug() << "Asset resources directory empty, searching for existing asset resources to migrate"; QString oldDataDirectory = QCoreApplication::applicationDirPath(); const QString OLD_RESOURCES_PATH = "assets"; From 8c2d69f865f05b519d61fdb7cf0ed04260aa8a85 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 15:45:35 -0800 Subject: [PATCH 14/34] use breaks in help messages for file paths --- domain-server/resources/describe-settings.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 1a6ca980fe..760b0f7c40 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -183,7 +183,7 @@ "name": "assets_path", "type": "string", "label": "Assets Path", - "help": "The path to the directory assets are stored in.
If this path is relative, it will be relative to the application data directory. If you change this path you will need to manually copy any existing assets from the previous directory.", + "help": "The path to the directory assets are stored in.
If this path is relative, it will be relative to the application data directory.
If you change this path you will need to manually copy any existing assets from the previous directory.", "placeholder": "assets", "default": "assets", "advanced": true @@ -386,7 +386,7 @@ { "name": "persistFilePath", "label": "Entities File Path", - "help": "The path to the file entities are stored in. If this path is relative it will be relative to the application data directory. The filename must end in .json.gz.", + "help": "The path to the file entities are stored in.
If this path is relative it will be relative to the application data directory.
The filename must end in .json.gz.", "placeholder": "models.json.gz", "default": "models.json.gz", "advanced": true From 27d338e81c2c689c958cc554820023324fd71070 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 11 Feb 2016 15:49:13 -0800 Subject: [PATCH 15/34] make any asset path relative to assets dir --- assignment-client/src/assets/AssetServer.cpp | 2 +- domain-server/resources/describe-settings.json | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/assets/AssetServer.cpp b/assignment-client/src/assets/AssetServer.cpp index 34cd97eca6..4ca2439996 100644 --- a/assignment-client/src/assets/AssetServer.cpp +++ b/assignment-client/src/assets/AssetServer.cpp @@ -89,7 +89,7 @@ void AssetServer::completeSetup() { if (assetsPath.isRelative()) { // if the domain settings passed us a relative path, make an absolute path that is relative to the // default data directory - absoluteFilePath = ServerPathUtils::getDataFilePath(assetsPathString); + absoluteFilePath = ServerPathUtils::getDataFilePath("assets/" + assetsPathString); } _resourcesDirectory = QDir(absoluteFilePath); diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 760b0f7c40..014d9f3767 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -184,8 +184,7 @@ "type": "string", "label": "Assets Path", "help": "The path to the directory assets are stored in.
If this path is relative, it will be relative to the application data directory.
If you change this path you will need to manually copy any existing assets from the previous directory.", - "placeholder": "assets", - "default": "assets", + "default": "", "advanced": true } ] From 8a49c4b833bfb212b170c86e65d5432596c532e8 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 11 Feb 2016 16:09:04 -0800 Subject: [PATCH 16/34] use cpuid.h on both GCC and Xcode --- libraries/audio/src/AudioHRTF.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index b56cf87e1e..13735e0a5e 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -143,10 +143,23 @@ static bool cpuSupportsAVX() { return result; } -#elif defined(__GNUC__) && !defined(__clang__) +#elif defined(__GNUC__) + +#include static bool cpuSupportsAVX() { - return __builtin_cpu_supports("avx"); + unsigned int eax, ebx, ecx, edx; + int mask = (1 << 27) | (1 << 28); // OSXSAVE and AVX + + bool result = false; + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && ((ecx & mask) == mask) { + + __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); + if (eax & 0x6) == 0x6) { + result = true; + } + } + return result; } #else From a71222237015f81596c74fc6d52ffd7dc3a563fb Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 11 Feb 2016 16:33:13 -0800 Subject: [PATCH 17/34] fix typos --- libraries/audio/src/AudioHRTF.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 13735e0a5e..7f1136f29d 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -149,11 +149,11 @@ static bool cpuSupportsAVX() { static bool cpuSupportsAVX() { unsigned int eax, ebx, ecx, edx; - int mask = (1 << 27) | (1 << 28); // OSXSAVE and AVX - + unsigned int mask = (1 << 27) | (1 << 28); // OSXSAVE and AVX + bool result = false; - if (__get_cpuid(1, &eax, &ebx, &ecx, &edx) && ((ecx & mask) == mask) { - + if (__get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & mask) == mask)) { + __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); if (eax & 0x6) == 0x6) { result = true; From aef770fcbad123f870e0d210397ac6c9983b0c94 Mon Sep 17 00:00:00 2001 From: Ken Cooke Date: Thu, 11 Feb 2016 16:39:23 -0800 Subject: [PATCH 18/34] fix typo --- libraries/audio/src/AudioHRTF.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioHRTF.cpp b/libraries/audio/src/AudioHRTF.cpp index 7f1136f29d..7fadf073a1 100644 --- a/libraries/audio/src/AudioHRTF.cpp +++ b/libraries/audio/src/AudioHRTF.cpp @@ -155,7 +155,7 @@ static bool cpuSupportsAVX() { if (__get_cpuid(0x1, &eax, &ebx, &ecx, &edx) && ((ecx & mask) == mask)) { __asm__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(0)); - if (eax & 0x6) == 0x6) { + if ((eax & 0x6) == 0x6) { result = true; } } From 111ed65bf88a71ff12f298fae0ce1e7b9fb72421 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 11 Feb 2016 17:18:01 -0800 Subject: [PATCH 19/34] Controller Pose values are relative to Avatar. Pass a InputCalibrationData to each inputPlugin and inputDevice. This contains the most up sensorToWorldMatrix, avatarMat and hmdSensorMatrix. Each input plugin can use this data to transform it's poses into Avatar space before sending it up the chain. This fixes a bug in the handControllerGrab.js script that relied on the hand controller rotation/positions being in the avatar frame. --- interface/src/Application.cpp | 20 ++++---- interface/src/avatar/MyAvatar.cpp | 4 +- .../controllers/src/controllers/Actions.cpp | 2 +- .../controllers/src/controllers/Actions.h | 2 +- libraries/controllers/src/controllers/Input.h | 6 +++ .../controllers/src/controllers/InputDevice.h | 6 +-- .../controllers/src/controllers/Pose.cpp | 9 ++++ libraries/controllers/src/controllers/Pose.h | 2 + .../src/controllers/StandardController.cpp | 2 +- .../src/controllers/StandardController.h | 2 +- .../src/controllers/StateController.cpp | 2 +- .../src/controllers/StateController.h | 2 +- .../src/controllers/UserInputMapper.h | 5 -- .../src/input-plugins/KeyboardMouseDevice.cpp | 6 +-- .../src/input-plugins/KeyboardMouseDevice.h | 4 +- .../src/input-plugins/SpacemouseManager.cpp | 2 +- .../src/input-plugins/SpacemouseManager.h | 2 +- libraries/plugins/src/plugins/InputPlugin.h | 6 ++- libraries/shared/src/GLMHelpers.cpp | 11 ++++- libraries/shared/src/GLMHelpers.h | 3 +- plugins/hifiNeuron/src/NeuronPlugin.cpp | 6 +-- plugins/hifiNeuron/src/NeuronPlugin.h | 6 +-- plugins/hifiSdl2/src/Joystick.cpp | 2 +- plugins/hifiSdl2/src/Joystick.h | 2 +- plugins/hifiSdl2/src/SDL2Manager.cpp | 4 +- plugins/hifiSdl2/src/SDL2Manager.h | 2 +- plugins/hifiSixense/src/SixenseManager.cpp | 23 +++++---- plugins/hifiSixense/src/SixenseManager.h | 6 +-- plugins/openvr/src/ViveControllerManager.cpp | 49 ++++++++++--------- plugins/openvr/src/ViveControllerManager.h | 6 +-- tests/controllers/src/main.cpp | 16 +++++- 31 files changed, 131 insertions(+), 89 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c0416e75da..ded13600be 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3070,13 +3070,18 @@ void Application::update(float deltaTime) { auto myAvatar = getMyAvatar(); auto userInputMapper = DependencyManager::get(); - userInputMapper->setSensorToWorldMat(myAvatar->getSensorToWorldMatrix()); userInputMapper->update(deltaTime); + controller::InputCalibrationData calibrationData = { + myAvatar->getSensorToWorldMatrix(), + createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()), + myAvatar->getHMDSensorMatrix() + }; + bool jointsCaptured = false; for (auto inputPlugin : PluginManager::getInstance()->getInputPlugins()) { if (inputPlugin->isActive()) { - inputPlugin->pluginUpdate(deltaTime, jointsCaptured); + inputPlugin->pluginUpdate(deltaTime, calibrationData, jointsCaptured); if (inputPlugin->isJointController()) { jointsCaptured = true; } @@ -4981,14 +4986,9 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de auto myAvatar = DependencyManager::get()->getMyAvatar(); palm.setActive(pose.isValid()); - // transform from sensor space, to world space, to avatar model space. - glm::mat4 poseMat = createMatFromQuatAndPos(pose.getRotation(), pose.getTranslation() * myAvatar->getScale()); - glm::mat4 sensorToWorldMat = myAvatar->getSensorToWorldMatrix(); - glm::mat4 modelMat = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()); - glm::mat4 objectPose = glm::inverse(modelMat) * sensorToWorldMat * poseMat; - - glm::vec3 position = extractTranslation(objectPose); - glm::quat rotation = glm::quat_cast(objectPose); + // controller pose is in Avatar frame. + glm::vec3 position = pose.getTranslation(); + glm::quat rotation = pose.getRotation(); // Compute current velocity from position change glm::vec3 rawVelocity; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d86af92a55..0f96f67a7d 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1392,7 +1392,7 @@ void MyAvatar::updateOrientation(float deltaTime) { desiredFacing.y = 0.0f; // This is our reference frame, it is captured when the user begins to move. - glm::vec3 referenceFacing = transformVector(_sensorToWorldMatrix, _hoverReferenceCameraFacing); + glm::vec3 referenceFacing = transformVectorFast(_sensorToWorldMatrix, _hoverReferenceCameraFacing); referenceFacing.y = 0.0f; referenceFacing = glm::normalize(referenceFacing); glm::vec3 referenceRight(referenceFacing.z, 0.0f, -referenceFacing.x); @@ -1597,7 +1597,7 @@ void MyAvatar::updatePosition(float deltaTime) { if (!_hoverReferenceCameraFacingIsCaptured && (fabs(_driveKeys[TRANSLATE_Z]) > 0.1f || fabs(_driveKeys[TRANSLATE_X]) > 0.1f)) { _hoverReferenceCameraFacingIsCaptured = true; // transform the camera facing vector into sensor space. - _hoverReferenceCameraFacing = transformVector(glm::inverse(_sensorToWorldMatrix), getHead()->getCameraOrientation() * Vectors::UNIT_Z); + _hoverReferenceCameraFacing = transformVectorFast(glm::inverse(_sensorToWorldMatrix), getHead()->getCameraOrientation() * Vectors::UNIT_Z); } else if (_hoverReferenceCameraFacingIsCaptured && (fabs(_driveKeys[TRANSLATE_Z]) <= 0.1f && fabs(_driveKeys[TRANSLATE_X]) <= 0.1f)) { _hoverReferenceCameraFacingIsCaptured = false; } diff --git a/libraries/controllers/src/controllers/Actions.cpp b/libraries/controllers/src/controllers/Actions.cpp index 7bee5101b1..e6662caa37 100644 --- a/libraries/controllers/src/controllers/Actions.cpp +++ b/libraries/controllers/src/controllers/Actions.cpp @@ -120,7 +120,7 @@ namespace controller { return availableInputs; } - void ActionsDevice::update(float deltaTime, bool jointsCaptured) { + void ActionsDevice::update(float deltaTime, const InputCalibrationData& inpuCalibrationData, bool jointsCaptured) { } void ActionsDevice::focusOutEvent() { diff --git a/libraries/controllers/src/controllers/Actions.h b/libraries/controllers/src/controllers/Actions.h index 812d3b8df3..e77e5e5a93 100644 --- a/libraries/controllers/src/controllers/Actions.h +++ b/libraries/controllers/src/controllers/Actions.h @@ -110,7 +110,7 @@ class ActionsDevice : public QObject, public InputDevice { public: virtual EndpointPointer createEndpoint(const Input& input) const override; virtual Input::NamedVector getAvailableInputs() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; ActionsDevice(); diff --git a/libraries/controllers/src/controllers/Input.h b/libraries/controllers/src/controllers/Input.h index db99e820da..9c7f09d526 100644 --- a/libraries/controllers/src/controllers/Input.h +++ b/libraries/controllers/src/controllers/Input.h @@ -15,6 +15,12 @@ namespace controller { +struct InputCalibrationData { + glm::mat4 sensorToWorldMat; + glm::mat4 avatarMat; + glm::mat4 hmdSensorMat; +}; + enum class ChannelType { UNKNOWN = 0, BUTTON, diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h index 3add7d236f..93247965bc 100644 --- a/libraries/controllers/src/controllers/InputDevice.h +++ b/libraries/controllers/src/controllers/InputDevice.h @@ -52,12 +52,12 @@ public: float getValue(const Input& input) const; float getValue(ChannelType channelType, uint16_t channel) const; Pose getPoseValue(uint16_t channel) const; - + const QString& getName() const { return _name; } // Update call MUST be called once per simulation loop // It takes care of updating the action states and deltas - virtual void update(float deltaTime, bool jointsCaptured) = 0; + virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) = 0; virtual void focusOutEvent() = 0; @@ -101,4 +101,4 @@ private: static float _reticleMoveSpeed; }; -} \ No newline at end of file +} diff --git a/libraries/controllers/src/controllers/Pose.cpp b/libraries/controllers/src/controllers/Pose.cpp index d9641618c1..b86391bbba 100644 --- a/libraries/controllers/src/controllers/Pose.cpp +++ b/libraries/controllers/src/controllers/Pose.cpp @@ -60,5 +60,14 @@ namespace controller { } } + Pose Pose::transform(const glm::mat4& mat) const { + auto rot = glmExtractRotation(mat); + Pose pose(transformPoint(mat, translation), + rot * rotation, + transformVectorFast(mat, velocity), + rot * angularVelocity); + pose.valid = valid; + return pose; + } } diff --git a/libraries/controllers/src/controllers/Pose.h b/libraries/controllers/src/controllers/Pose.h index a8a4452758..47ba59279a 100644 --- a/libraries/controllers/src/controllers/Pose.h +++ b/libraries/controllers/src/controllers/Pose.h @@ -40,6 +40,8 @@ namespace controller { vec3 getVelocity() const { return velocity; } vec3 getAngularVelocity() const { return angularVelocity; } + Pose transform(const glm::mat4& mat) const; + static QScriptValue toScriptValue(QScriptEngine* engine, const Pose& event); static void fromScriptValue(const QScriptValue& object, Pose& event); }; diff --git a/libraries/controllers/src/controllers/StandardController.cpp b/libraries/controllers/src/controllers/StandardController.cpp index e101c5f4ff..5996cad5df 100644 --- a/libraries/controllers/src/controllers/StandardController.cpp +++ b/libraries/controllers/src/controllers/StandardController.cpp @@ -25,7 +25,7 @@ StandardController::StandardController() : InputDevice("Standard") { StandardController::~StandardController() { } -void StandardController::update(float deltaTime, bool jointsCaptured) { +void StandardController::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { } void StandardController::focusOutEvent() { diff --git a/libraries/controllers/src/controllers/StandardController.h b/libraries/controllers/src/controllers/StandardController.h index 57bd0faba5..fee608f822 100644 --- a/libraries/controllers/src/controllers/StandardController.h +++ b/libraries/controllers/src/controllers/StandardController.h @@ -28,7 +28,7 @@ public: virtual EndpointPointer createEndpoint(const Input& input) const override; virtual Input::NamedVector getAvailableInputs() const override; virtual QStringList getDefaultMappingConfigs() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; StandardController(); diff --git a/libraries/controllers/src/controllers/StateController.cpp b/libraries/controllers/src/controllers/StateController.cpp index 6f89c6365c..1d39449e4d 100644 --- a/libraries/controllers/src/controllers/StateController.cpp +++ b/libraries/controllers/src/controllers/StateController.cpp @@ -25,7 +25,7 @@ StateController::StateController() : InputDevice("Application") { StateController::~StateController() { } -void StateController::update(float deltaTime, bool jointsCaptured) {} +void StateController::update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) {} void StateController::focusOutEvent() {} diff --git a/libraries/controllers/src/controllers/StateController.h b/libraries/controllers/src/controllers/StateController.h index 12f3e8b2f1..ed36e4f838 100644 --- a/libraries/controllers/src/controllers/StateController.h +++ b/libraries/controllers/src/controllers/StateController.h @@ -28,7 +28,7 @@ public: // Device functions virtual Input::NamedVector getAvailableInputs() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, const InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; StateController(); diff --git a/libraries/controllers/src/controllers/UserInputMapper.h b/libraries/controllers/src/controllers/UserInputMapper.h index 98a85a2a44..1021032b40 100644 --- a/libraries/controllers/src/controllers/UserInputMapper.h +++ b/libraries/controllers/src/controllers/UserInputMapper.h @@ -97,9 +97,6 @@ namespace controller { // Update means go grab all the device input channels and update the output channel values void update(float deltaTime); - void setSensorToWorldMat(glm::mat4 sensorToWorldMat) { _sensorToWorldMat = sensorToWorldMat; } - glm::mat4 getSensorToWorldMat() { return _sensorToWorldMat; } - const DevicesMap& getDevices() { return _registeredDevices; } uint16 getStandardDeviceID() const { return STANDARD_DEVICE; } InputDevice::Pointer getStandardDevice() { return _registeredDevices[getStandardDeviceID()]; } @@ -131,8 +128,6 @@ namespace controller { std::vector _poseStates = std::vector(toInt(Action::NUM_ACTIONS)); std::vector _lastStandardStates = std::vector(); - glm::mat4 _sensorToWorldMat; - int recordDeviceOfType(const QString& deviceName); QHash _deviceCounts; diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp index 1d7fbbec67..c3d2f7c51c 100755 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.cpp @@ -20,8 +20,8 @@ const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse"; -void KeyboardMouseDevice::pluginUpdate(float deltaTime, bool jointsCaptured) { - _inputDevice->update(deltaTime, jointsCaptured); +void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { + _inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured); // For touch event, we need to check that the last event is not too long ago // Maybe it's a Qt issue, but the touch event sequence (begin, update, end) is not always called properly @@ -36,7 +36,7 @@ void KeyboardMouseDevice::pluginUpdate(float deltaTime, bool jointsCaptured) { } } -void KeyboardMouseDevice::InputDevice::update(float deltaTime, bool jointsCaptured) { +void KeyboardMouseDevice::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { _axisStateMap.clear(); } diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index 6acb2bf041..55ca9a1704 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -70,7 +70,7 @@ public: virtual const QString& getName() const override { return NAME; } virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } - virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override; + virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; void keyPressEvent(QKeyEvent* event); void keyReleaseEvent(QKeyEvent* event); @@ -97,7 +97,7 @@ protected: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; // Let's make it easy for Qt because we assume we love Qt forever diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp index fe90470cb4..d946990319 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.cpp @@ -111,7 +111,7 @@ controller::Input::NamedPair SpacemouseDevice::makePair(SpacemouseDevice::Positi return controller::Input::NamedPair(makeInput(axis), name); } -void SpacemouseDevice::update(float deltaTime, bool jointsCaptured) { +void SpacemouseDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { // the update is done in the SpacemouseManager class. // for windows in the nativeEventFilter the inputmapper is connected or registed or removed when an 3Dconnnexion device is attached or detached // for osx the api will call DeviceAddedHandler or DeviceRemoveHandler when a 3Dconnexion device is attached or detached diff --git a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h index 6253fa7f9d..82c4fa8fb6 100644 --- a/libraries/input-plugins/src/input-plugins/SpacemouseManager.h +++ b/libraries/input-plugins/src/input-plugins/SpacemouseManager.h @@ -214,7 +214,7 @@ public: virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; glm::vec3 cc_position; diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index e9d8ac8d86..b45fa862c1 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -12,12 +12,16 @@ #include "Plugin.h" +namespace controller { + struct InputCalibrationData; +} + class InputPlugin : public Plugin { public: virtual bool isJointController() const = 0; virtual void pluginFocusOutEvent() = 0; - virtual void pluginUpdate(float deltaTime, bool jointsCaptured) = 0; + virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) = 0; }; diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index 7b0f397b07..e9d6591cac 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -407,7 +407,14 @@ glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& p) { return glm::vec3(temp.x / temp.w, temp.y / temp.w, temp.z / temp.w); } -glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& v) { +// does not handle non-uniform scale correctly, but it's faster then transformVectorFull +glm::vec3 transformVectorFast(const glm::mat4& m, const glm::vec3& v) { + glm::mat3 rot(m); + return rot * v; +} + +// handles non-uniform scale. +glm::vec3 transformVectorFull(const glm::mat4& m, const glm::vec3& v) { glm::mat3 rot(m); return glm::inverse(glm::transpose(rot)) * v; } @@ -437,7 +444,7 @@ glm::vec2 getFacingDir2D(const glm::quat& rot) { } glm::vec2 getFacingDir2D(const glm::mat4& m) { - glm::vec3 facing3D = transformVector(m, Vectors::UNIT_NEG_Z); + glm::vec3 facing3D = transformVectorFast(m, Vectors::UNIT_NEG_Z); glm::vec2 facing2D(facing3D.x, facing3D.z); const float ALMOST_ZERO = 0.0001f; if (glm::length(facing2D) < ALMOST_ZERO) { diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 89b924051f..15f3f60cf7 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -215,7 +215,8 @@ glm::mat4 createMatFromQuatAndPos(const glm::quat& q, const glm::vec3& p); glm::quat cancelOutRollAndPitch(const glm::quat& q); glm::mat4 cancelOutRollAndPitch(const glm::mat4& m); glm::vec3 transformPoint(const glm::mat4& m, const glm::vec3& p); -glm::vec3 transformVector(const glm::mat4& m, const glm::vec3& v); +glm::vec3 transformVectorFast(const glm::mat4& m, const glm::vec3& v); +glm::vec3 transformVectorFull(const glm::mat4& m, const glm::vec3& v); // Calculate an orthogonal basis from a primary and secondary axis. // The uAxis, vAxis & wAxis will form an orthognal basis. diff --git a/plugins/hifiNeuron/src/NeuronPlugin.cpp b/plugins/hifiNeuron/src/NeuronPlugin.cpp index a175ce8e06..e2143dbdcf 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.cpp +++ b/plugins/hifiNeuron/src/NeuronPlugin.cpp @@ -498,14 +498,14 @@ void NeuronPlugin::deactivate() { #endif } -void NeuronPlugin::pluginUpdate(float deltaTime, bool jointsCaptured) { +void NeuronPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { std::vector joints; { // lock and copy std::lock_guard guard(_jointsMutex); joints = _joints; } - _inputDevice->update(deltaTime, joints, _prevJoints); + _inputDevice->update(deltaTime, inputCalibrationData, joints, _prevJoints); _prevJoints = joints; } @@ -537,7 +537,7 @@ QString NeuronPlugin::InputDevice::getDefaultMappingConfig() const { return MAPPING_JSON; } -void NeuronPlugin::InputDevice::update(float deltaTime, const std::vector& joints, const std::vector& prevJoints) { +void NeuronPlugin::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const std::vector& joints, const std::vector& prevJoints) { for (size_t i = 0; i < joints.size(); i++) { glm::vec3 linearVel, angularVel; glm::vec3 pos = joints[i].pos; diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index 33c6879f5b..afe8530b07 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -35,7 +35,7 @@ public: virtual void deactivate() override; virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } - virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override; + virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void saveSettings() const override; virtual void loadSettings() override; @@ -56,10 +56,10 @@ protected: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; - virtual void update(float deltaTime, bool jointsCaptured) override {}; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override {}; virtual void focusOutEvent() override {}; - void update(float deltaTime, const std::vector& joints, const std::vector& prevJoints); + void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const std::vector& joints, const std::vector& prevJoints); }; std::shared_ptr _inputDevice { std::make_shared() }; diff --git a/plugins/hifiSdl2/src/Joystick.cpp b/plugins/hifiSdl2/src/Joystick.cpp index b7d69b9406..9d195fd606 100644 --- a/plugins/hifiSdl2/src/Joystick.cpp +++ b/plugins/hifiSdl2/src/Joystick.cpp @@ -39,7 +39,7 @@ void Joystick::closeJoystick() { #endif } -void Joystick::update(float deltaTime, bool jointsCaptured) { +void Joystick::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { for (auto axisState : _axisStateMap) { if (fabsf(axisState.second) < CONTROLLER_THRESHOLD) { _axisStateMap[axisState.first] = 0.0f; diff --git a/plugins/hifiSdl2/src/Joystick.h b/plugins/hifiSdl2/src/Joystick.h index fa50f8eab6..08bf27b960 100644 --- a/plugins/hifiSdl2/src/Joystick.h +++ b/plugins/hifiSdl2/src/Joystick.h @@ -39,7 +39,7 @@ public: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; Joystick() : InputDevice("GamePad") {} diff --git a/plugins/hifiSdl2/src/SDL2Manager.cpp b/plugins/hifiSdl2/src/SDL2Manager.cpp index 7ca49bbd75..58da2c5df0 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.cpp +++ b/plugins/hifiSdl2/src/SDL2Manager.cpp @@ -138,12 +138,12 @@ void SDL2Manager::pluginFocusOutEvent() { #endif } -void SDL2Manager::pluginUpdate(float deltaTime, bool jointsCaptured) { +void SDL2Manager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { #ifdef HAVE_SDL2 if (_isInitialized) { auto userInputMapper = DependencyManager::get(); for (auto joystick : _openJoysticks) { - joystick->update(deltaTime, jointsCaptured); + joystick->update(deltaTime, inputCalibrationData, jointsCaptured); } PerformanceTimer perfTimer("SDL2Manager::update"); diff --git a/plugins/hifiSdl2/src/SDL2Manager.h b/plugins/hifiSdl2/src/SDL2Manager.h index 6506cdccb6..a88e41128d 100644 --- a/plugins/hifiSdl2/src/SDL2Manager.h +++ b/plugins/hifiSdl2/src/SDL2Manager.h @@ -40,7 +40,7 @@ public: virtual void deactivate() override; virtual void pluginFocusOutEvent() override; - virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override; + virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; signals: void joystickAdded(Joystick* joystick); diff --git a/plugins/hifiSixense/src/SixenseManager.cpp b/plugins/hifiSixense/src/SixenseManager.cpp index b23982f948..aad61e4bea 100644 --- a/plugins/hifiSixense/src/SixenseManager.cpp +++ b/plugins/hifiSixense/src/SixenseManager.cpp @@ -132,16 +132,16 @@ void SixenseManager::setSixenseFilter(bool filter) { #endif } -void SixenseManager::pluginUpdate(float deltaTime, bool jointsCaptured) { +void SixenseManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { BAIL_IF_NOT_LOADED - _inputDevice->update(deltaTime, jointsCaptured); + _inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured); if (_inputDevice->_requestReset) { _container->requestReset(); _inputDevice->_requestReset = false; } } -void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) { +void SixenseManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { BAIL_IF_NOT_LOADED #ifdef HAVE_SIXENSE _buttonPressedMap.clear(); @@ -205,7 +205,7 @@ void SixenseManager::InputDevice::update(float deltaTime, bool jointsCaptured) { if (!jointsCaptured) { // Rotation of Palm glm::quat rotation(data->rot_quat[3], data->rot_quat[0], data->rot_quat[1], data->rot_quat[2]); - handlePoseEvent(deltaTime, position, rotation, left); + handlePoseEvent(deltaTime, inputCalibrationData, position, rotation, left); rawPoses[i] = controller::Pose(position, rotation, Vectors::ZERO, Vectors::ZERO); } else { _poseStateMap.clear(); @@ -415,7 +415,7 @@ void SixenseManager::InputDevice::handleButtonEvent(unsigned int buttons, bool l } } -void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left) { +void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const glm::vec3& position, const glm::quat& rotation, bool left) { BAIL_IF_NOT_LOADED #ifdef HAVE_SIXENSE auto hand = left ? controller::StandardPoseChannel::LEFT_HAND : controller::StandardPoseChannel::RIGHT_HAND; @@ -437,7 +437,7 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 pos auto prevPose = _poseStateMap[hand]; // Transform the measured position into body frame. - position = _avatarRotation * (position + _avatarPosition); + vec3 pos = _avatarRotation * (position + _avatarPosition); // From ABOVE the hand canonical axes look like this: // @@ -476,7 +476,7 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 pos // rotation = postOffset * Qsh^ * (measuredRotation * preOffset) * Qsh // // TODO: find a shortcut with fewer rotations. - rotation = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand; + glm::quat rot = _avatarRotation * postOffset * glm::inverse(sixenseToHand) * rotation * preOffset * sixenseToHand; glm::vec3 velocity(0.0f); glm::vec3 angularVelocity(0.0f); @@ -484,11 +484,11 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 pos if (prevPose.isValid() && deltaTime > std::numeric_limits::epsilon()) { auto& samples = _collectedSamples[hand]; - velocity = (position - prevPose.getTranslation()) / deltaTime; + velocity = (pos - prevPose.getTranslation()) / deltaTime; samples.first.addSample(velocity); velocity = samples.first.average; - auto deltaRot = glm::normalize(rotation * glm::conjugate(prevPose.getRotation())); + auto deltaRot = glm::normalize(rot * glm::conjugate(prevPose.getRotation())); auto axis = glm::axis(deltaRot); auto speed = glm::angle(deltaRot) / deltaTime; assert(!glm::isnan(speed)); @@ -500,7 +500,10 @@ void SixenseManager::InputDevice::handlePoseEvent(float deltaTime, glm::vec3 pos _collectedSamples[hand].second.clear(); } - _poseStateMap[hand] = controller::Pose(position, rotation, velocity, angularVelocity); + // transform pose into avatar frame. + glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; + auto avatarPose = controller::Pose(pos, rot, velocity, angularVelocity).transform(controllerToAvatar); + _poseStateMap[hand] = avatarPose; #endif // HAVE_SIXENSE } diff --git a/plugins/hifiSixense/src/SixenseManager.h b/plugins/hifiSixense/src/SixenseManager.h index bbb9774368..fc74b83532 100644 --- a/plugins/hifiSixense/src/SixenseManager.h +++ b/plugins/hifiSixense/src/SixenseManager.h @@ -36,7 +36,7 @@ public: virtual void deactivate() override; virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } - virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override; + virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void saveSettings() const override; virtual void loadSettings() override; @@ -66,11 +66,11 @@ private: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; void handleButtonEvent(unsigned int buttons, bool left); - void handlePoseEvent(float deltaTime, glm::vec3 position, glm::quat rotation, bool left); + void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const glm::vec3& position, const glm::quat& rotation, bool left); void updateCalibration(SixenseControllerData* controllers); friend class SixenseManager; diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index 522c7f9c3d..720a6d48c6 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -102,7 +102,7 @@ void ViveControllerManager::activate() { // vertexBufferPtr->getSize() - sizeof(float) * 2, // sizeof(vr::RenderModel_Vertex_t), // gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::RAW))); - + gpu::Element formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); gpu::Element formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); _texture = gpu::TexturePointer( @@ -205,8 +205,8 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch& } -void ViveControllerManager::pluginUpdate(float deltaTime, bool jointsCaptured) { - _inputDevice->update(deltaTime, jointsCaptured); +void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { + _inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured); auto userInputMapper = DependencyManager::get(); if (_inputDevice->_trackedControllers == 0 && _registeredWithInputMapper) { @@ -222,7 +222,7 @@ void ViveControllerManager::pluginUpdate(float deltaTime, bool jointsCaptured) { } } -void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCaptured) { +void ViveControllerManager::InputDevice::update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) { _poseStateMap.clear(); _buttonPressedMap.clear(); @@ -232,29 +232,29 @@ void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCapt int numTrackedControllers = 0; for (vr::TrackedDeviceIndex_t device = vr::k_unTrackedDeviceIndex_Hmd + 1; - device < vr::k_unMaxTrackedDeviceCount && numTrackedControllers < 2; ++device) { - + device < vr::k_unMaxTrackedDeviceCount && numTrackedControllers < 2; ++device) { + if (!_hmd->IsTrackedDeviceConnected(device)) { continue; } - - if(_hmd->GetTrackedDeviceClass(device) != vr::TrackedDeviceClass_Controller) { + + if (_hmd->GetTrackedDeviceClass(device) != vr::TrackedDeviceClass_Controller) { continue; } if (!_trackedDevicePose[device].bPoseIsValid) { continue; } - + numTrackedControllers++; bool left = numTrackedControllers == 2; - + const mat4& mat = _trackedDevicePoseMat4[device]; - + if (!jointsCaptured) { - handlePoseEvent(mat, numTrackedControllers - 1); + handlePoseEvent(inputCalibrationData, mat, numTrackedControllers - 1); } - + // handle inputs vr::VRControllerState_t controllerState = vr::VRControllerState_t(); if (_hmd->GetControllerState(device, &controllerState)) { @@ -271,7 +271,7 @@ void ViveControllerManager::InputDevice::update(float deltaTime, bool jointsCapt } } } - + _trackedControllers = numTrackedControllers; } @@ -314,7 +314,7 @@ void ViveControllerManager::InputDevice::handleButtonEvent(uint32_t button, bool } } -void ViveControllerManager::InputDevice::handlePoseEvent(const mat4& mat, bool left) { +void ViveControllerManager::InputDevice::handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, bool left) { // When the sensor-to-world rotation is identity the coordinate axes look like this: // // user @@ -342,11 +342,11 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const mat4& mat, bool l // | | | | // - // So when the user is standing in Vive space facing the -zAxis with hands outstretched and palms down + // So when the user is standing in Vive space facing the -zAxis with hands outstretched and palms down // the rotation to align the Vive axes with those of the hands is: // // QviveToHand = halfTurnAboutY * quaterTurnAboutX - + // Due to how the Vive controllers fit into the palm there is an offset that is different for each hand. // You can think of this offset as the inverse of the measured rotation when the hands are posed, such that // the combination (measurement * offset) is identity at this orientation. @@ -384,8 +384,11 @@ void ViveControllerManager::InputDevice::handlePoseEvent(const mat4& mat, bool l position += rotation * (left ? leftTranslationOffset : rightTranslationOffset); rotation = rotation * (left ? leftRotationOffset : rightRotationOffset); - - _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = controller::Pose(position, rotation); + + // transform into avatar frame + glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat; + auto avatarPose = controller::Pose(position, rotation).transform(controllerToAvatar); + _poseStateMap[left ? controller::LEFT_HAND : controller::RIGHT_HAND] = avatarPose; } controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableInputs() const { @@ -436,7 +439,7 @@ QString ViveControllerManager::InputDevice::getDefaultMappingConfig() const { //void ViveControllerManager::assignDefaultInputMapping(UserInputMapper& mapper) { // const float JOYSTICK_MOVE_SPEED = 1.0f; -// +// // // Left Trackpad: Movement, strafing // mapper.addInputChannel(UserInputMapper::LONGITUDINAL_FORWARD, makeInput(AXIS_Y_POS, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); // mapper.addInputChannel(UserInputMapper::LONGITUDINAL_BACKWARD, makeInput(AXIS_Y_NEG, 0), makeInput(TRACKPAD_BUTTON, 0), JOYSTICK_MOVE_SPEED); @@ -446,17 +449,17 @@ QString ViveControllerManager::InputDevice::getDefaultMappingConfig() const { // // Right Trackpad: Vertical movement, zooming // mapper.addInputChannel(UserInputMapper::VERTICAL_UP, makeInput(AXIS_Y_POS, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED); // mapper.addInputChannel(UserInputMapper::VERTICAL_DOWN, makeInput(AXIS_Y_NEG, 1), makeInput(TRACKPAD_BUTTON, 1), JOYSTICK_MOVE_SPEED); -// +// // // Buttons // mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 0)); // mapper.addInputChannel(UserInputMapper::SHIFT, makeInput(BUTTON_A, 1)); -// +// // mapper.addInputChannel(UserInputMapper::ACTION1, makeInput(GRIP_BUTTON, 0)); // mapper.addInputChannel(UserInputMapper::ACTION2, makeInput(GRIP_BUTTON, 1)); // // mapper.addInputChannel(UserInputMapper::LEFT_HAND_CLICK, makeInput(BACK_TRIGGER, 0)); // mapper.addInputChannel(UserInputMapper::RIGHT_HAND_CLICK, makeInput(BACK_TRIGGER, 1)); -// +// // // Hands // mapper.addInputChannel(UserInputMapper::LEFT_HAND, makeInput(LEFT_HAND)); // mapper.addInputChannel(UserInputMapper::RIGHT_HAND, makeInput(RIGHT_HAND)); diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 077aec7fc3..282c8e41a5 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -41,7 +41,7 @@ public: virtual void deactivate() override; virtual void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); } - virtual void pluginUpdate(float deltaTime, bool jointsCaptured) override; + virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; void updateRendering(RenderArgs* args, render::ScenePointer scene, render::PendingChanges pendingChanges); @@ -55,12 +55,12 @@ private: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; virtual QString getDefaultMappingConfig() const override; - virtual void update(float deltaTime, bool jointsCaptured) override; + virtual void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) override; virtual void focusOutEvent() override; void handleButtonEvent(uint32_t button, bool pressed, bool left); void handleAxisEvent(uint32_t axis, float x, float y, bool left); - void handlePoseEvent(const mat4& mat, bool left); + void handlePoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, bool left); int _trackedControllers { 0 }; vr::IVRSystem*& _hmd; diff --git a/tests/controllers/src/main.cpp b/tests/controllers/src/main.cpp index da233d650c..13b6b51d82 100644 --- a/tests/controllers/src/main.cpp +++ b/tests/controllers/src/main.cpp @@ -123,8 +123,14 @@ int main(int argc, char** argv) { float delta = now - last; last = now; + InputCalibrationData calibrationData = { + glm::mat4(), + glm::mat4(), + glm::mat4() + }; + foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { - inputPlugin->pluginUpdate(delta, false); + inputPlugin->pluginUpdate(delta, calibrationData, false); } auto userInputMapper = DependencyManager::get(); @@ -133,6 +139,12 @@ int main(int argc, char** argv) { timer.start(50); { + InputCalibrationData calibrationData = { + glm::mat4(), + glm::mat4(), + glm::mat4() + }; + DependencyManager::set(); foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { QString name = inputPlugin->getName(); @@ -141,7 +153,7 @@ int main(int argc, char** argv) { if (name == KeyboardMouseDevice::NAME) { userInputMapper->registerDevice(std::dynamic_pointer_cast(inputPlugin)->getInputDevice()); } - inputPlugin->pluginUpdate(0, false); + inputPlugin->pluginUpdate(0, calibrationData, false); } rootContext->setContextProperty("Controllers", new MyControllerScriptingInterface()); } From 8bde897cee6149694200b896867c10e77c4a34e2 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Thu, 11 Feb 2016 18:14:42 -0800 Subject: [PATCH 20/34] Application: removed unused myAvatar local variable. --- interface/src/Application.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ded13600be..385e7b93ab 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4983,7 +4983,6 @@ void Application::setPalmData(Hand* hand, const controller::Pose& pose, float de // of this palm manipulation in the Hand class itself. But unfortunately the Hand and Palm don't knbow about // controller::Pose. More work is needed to clean this up. hand->modifyPalm(whichHand, [&](PalmData& palm) { - auto myAvatar = DependencyManager::get()->getMyAvatar(); palm.setActive(pose.isValid()); // controller pose is in Avatar frame. From d516e9da78581ae4e15cb3976dad915a9024fde6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 12 Feb 2016 09:01:54 -0800 Subject: [PATCH 21/34] Only run AO in DEFAULT_RENDER_MODE --- libraries/render-utils/src/AmbientOcclusionEffect.cpp | 5 +++++ libraries/render-utils/src/DeferredLightingEffect.cpp | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/render-utils/src/AmbientOcclusionEffect.cpp b/libraries/render-utils/src/AmbientOcclusionEffect.cpp index 185afade03..aae66f7098 100644 --- a/libraries/render-utils/src/AmbientOcclusionEffect.cpp +++ b/libraries/render-utils/src/AmbientOcclusionEffect.cpp @@ -288,6 +288,11 @@ void AmbientOcclusionEffect::run(const render::SceneContextPointer& sceneContext RenderArgs* args = renderContext->args; + // FIXME: Different render modes should have different tasks + if (args->_renderMode != RenderArgs::DEFAULT_RENDER_MODE) { + return; + } + auto framebufferCache = DependencyManager::get(); auto depthBuffer = framebufferCache->getPrimaryDepthTexture(); auto normalBuffer = framebufferCache->getDeferredNormalTexture(); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 003c309740..d0387cd3d4 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -194,10 +194,11 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo batch.setResourceTexture(DEFERRED_BUFFER_EMISSIVE_UNIT, framebufferCache->getDeferredSpecularTexture()); batch.setResourceTexture(DEFERRED_BUFFER_DEPTH_UNIT, framebufferCache->getPrimaryDepthTexture()); - // need to assign the white texture if ao is off - if (_ambientOcclusionEnabled) { + // FIXME: Different render modes should have different tasks + if (args->_renderMode == RenderArgs::DEFAULT_RENDER_MODE && _ambientOcclusionEnabled) { batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, framebufferCache->getOcclusionTexture()); } else { + // need to assign the white texture if ao is off batch.setResourceTexture(DEFERRED_BUFFER_OBSCURANCE_UNIT, textureCache->getWhiteTexture()); } From 874f74de043632dcca91368aa90c7d4a36c857fd Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Fri, 12 Feb 2016 10:38:50 -0800 Subject: [PATCH 22/34] Fix Quat.lookAt --- libraries/script-engine/src/Quat.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/Quat.cpp b/libraries/script-engine/src/Quat.cpp index 94e53501aa..c0b87c9a5c 100644 --- a/libraries/script-engine/src/Quat.cpp +++ b/libraries/script-engine/src/Quat.cpp @@ -31,7 +31,7 @@ glm::quat Quat::rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { } glm::quat Quat::lookAt(const glm::vec3& eye, const glm::vec3& center, const glm::vec3& up) { - return glm::quat_cast(glm::lookAt(eye, center, up)); + return glm::inverse(glm::quat_cast(glm::lookAt(eye, center, up))); // OpenGL view matrix is inverse of our camera matrix. } glm::quat Quat::lookAtSimple(const glm::vec3& eye, const glm::vec3& center) { From 1160ecb335cc53143af20ea2a16fb905d9ad5d29 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Sun, 31 Jan 2016 22:16:30 -0800 Subject: [PATCH 23/34] improvements in HMD UI behavior --- .../controllers/getHUDLookAtPositionTest.js | 16 +++-- examples/controllers/handControllerGrab.js | 7 ++ .../controllers/reticleHandRotationTest.js | 4 +- .../src/scripting/HMDScriptingInterface.cpp | 34 ++++++++-- .../src/scripting/HMDScriptingInterface.h | 10 +++ interface/src/ui/ApplicationCompositor.cpp | 65 ++++++++++++++----- interface/src/ui/ApplicationCompositor.h | 2 + .../src/controllers/ScriptingInterface.h | 17 +++-- 8 files changed, 119 insertions(+), 36 deletions(-) diff --git a/examples/controllers/getHUDLookAtPositionTest.js b/examples/controllers/getHUDLookAtPositionTest.js index 348b6757b8..cad9c944bf 100644 --- a/examples/controllers/getHUDLookAtPositionTest.js +++ b/examples/controllers/getHUDLookAtPositionTest.js @@ -19,18 +19,20 @@ var cubeSize = 0.03; var cube = Overlays.addOverlay("cube", { position: cubePosition, size: cubeSize, - color: { red: 255, green: 0, blue: 0}, + color: { red: 0, green: 255, blue: 0}, alpha: 1, solid: false }); -var square = Overlays.addOverlay("text", { +var SQUARE_SIZE = 20; + +var square = Overlays.addOverlay("rectangle", { x: 0, y: 0, - width: 20, - height: 20, - color: { red: 255, green: 255, blue: 0}, - backgroundColor: { red: 255, green: 255, blue: 0}, + width: SQUARE_SIZE, + height: SQUARE_SIZE, + color: { red: 0, green: 255, blue: 0}, + backgroundColor: { red: 0, green: 255, blue: 0}, alpha: 1 }); @@ -43,7 +45,7 @@ Script.update.connect(function(deltaTime) { Overlays.editOverlay(cube, { position: lookAt3D }); var lookAt2D = HMD.getHUDLookAtPosition2D(); - Overlays.editOverlay(square, { x: lookAt2D.x, y: lookAt2D.y }); + Overlays.editOverlay(square, { x: lookAt2D.x - (SQUARE_SIZE/2), y: lookAt2D.y - (SQUARE_SIZE/2)}); }); Script.scriptEnding.connect(function(){ diff --git a/examples/controllers/handControllerGrab.js b/examples/controllers/handControllerGrab.js index 908337f643..e213834385 100644 --- a/examples/controllers/handControllerGrab.js +++ b/examples/controllers/handControllerGrab.js @@ -14,6 +14,7 @@ Script.include("../libraries/utils.js"); + // // add lines where the hand ray picking is happening // @@ -722,6 +723,9 @@ function MyController(hand) { this.particleBeamOff(); } this.searchSphereOff(); + + Controller.setReticleVisible(true); + }; this.triggerPress = function(value) { @@ -1018,6 +1022,9 @@ function MyController(hand) { this.overlayLineOn(handPosition, searchSphereLocation, (this.triggerSmoothedGrab() || this.bumperSqueezed()) ? INTERSECT_COLOR : NO_INTERSECT_COLOR); } + + Controller.setReticleVisible(false); + }; this.distanceGrabTimescale = function(mass, distance) { diff --git a/examples/controllers/reticleHandRotationTest.js b/examples/controllers/reticleHandRotationTest.js index a303e5e7b4..a27e6f2c4e 100644 --- a/examples/controllers/reticleHandRotationTest.js +++ b/examples/controllers/reticleHandRotationTest.js @@ -31,8 +31,8 @@ function moveReticleAbsolute(x, y) { var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation"; var mapping = Controller.newMapping(MAPPING_NAME); -mapping.from(Controller.Standard.LT).peek().constrainToInteger().to(Controller.Actions.ReticleClick); -mapping.from(Controller.Standard.RT).peek().constrainToInteger().to(Controller.Actions.ReticleClick); +mapping.from(Controller.Hardware.Hydra.L3).peek().to(Controller.Actions.ReticleClick); +mapping.from(Controller.Hardware.Hydra.R4).peek().to(Controller.Actions.ReticleClick); mapping.enable(); diff --git a/interface/src/scripting/HMDScriptingInterface.cpp b/interface/src/scripting/HMDScriptingInterface.cpp index ab53e6912a..d1572a0aa9 100644 --- a/interface/src/scripting/HMDScriptingInterface.cpp +++ b/interface/src/scripting/HMDScriptingInterface.cpp @@ -20,15 +20,39 @@ HMDScriptingInterface::HMDScriptingInterface() { } +glm::vec3 HMDScriptingInterface::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction) const { + glm::vec3 result { position }; + qApp->getApplicationCompositor().calculateRayUICollisionPoint(position, direction, result); + return result; +} + +glm::vec2 HMDScriptingInterface::overlayFromWorldPoint(const glm::vec3& position) const { + return qApp->getApplicationCompositor().overlayFromSphereSurface(position); +} + +glm::vec2 HMDScriptingInterface::sphericalToOverlay(const glm::vec2 & position) const { + return qApp->getApplicationCompositor().sphericalToOverlay(position); +} + +glm::vec2 HMDScriptingInterface::overlayToSpherical(const glm::vec2 & position) const { + return qApp->getApplicationCompositor().overlayToSpherical(position); +} + +glm::vec2 HMDScriptingInterface::screenToOverlay(const glm::vec2 & position) const { + return qApp->getApplicationCompositor().screenToOverlay(position); +} + +glm::vec2 HMDScriptingInterface::overlayToScreen(const glm::vec2 & position) const { + return qApp->getApplicationCompositor().overlayToScreen(position); +} + + + QScriptValue HMDScriptingInterface::getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine) { glm::vec3 hudIntersection; auto instance = DependencyManager::get(); if (instance->getHUDLookAtPosition3D(hudIntersection)) { - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - glm::vec3 sphereCenter = myAvatar->getDefaultEyePosition(); - glm::vec3 direction = glm::inverse(myAvatar->getOrientation()) * (hudIntersection - sphereCenter); - glm::vec2 polar = glm::vec2(glm::atan(direction.x, -direction.z), glm::asin(direction.y)) * -1.0f; - auto overlayPos = qApp->getApplicationCompositor().sphericalToOverlay(polar); + glm::vec2 overlayPos = qApp->getApplicationCompositor().overlayFromSphereSurface(hudIntersection); return qScriptValueFromValue(engine, overlayPos); } return QScriptValue::NullValue; diff --git a/interface/src/scripting/HMDScriptingInterface.h b/interface/src/scripting/HMDScriptingInterface.h index f07350605f..1245c06575 100644 --- a/interface/src/scripting/HMDScriptingInterface.h +++ b/interface/src/scripting/HMDScriptingInterface.h @@ -25,6 +25,16 @@ class HMDScriptingInterface : public AbstractHMDScriptingInterface, public Depen Q_OBJECT Q_PROPERTY(glm::vec3 position READ getPosition) Q_PROPERTY(glm::quat orientation READ getOrientation) + +public: + Q_INVOKABLE glm::vec3 calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction) const; + Q_INVOKABLE glm::vec2 overlayFromWorldPoint(const glm::vec3& position) const; + + Q_INVOKABLE glm::vec2 sphericalToOverlay(const glm::vec2 & sphericalPos) const; + Q_INVOKABLE glm::vec2 overlayToSpherical(const glm::vec2 & overlayPos) const; + Q_INVOKABLE glm::vec2 screenToOverlay(const glm::vec2 & screenPos) const; + Q_INVOKABLE glm::vec2 overlayToScreen(const glm::vec2 & overlayPos) const; + public: HMDScriptingInterface(); static QScriptValue getHUDLookAtPosition2D(QScriptContext* context, QScriptEngine* engine); diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 5f14d446ff..736b1fffce 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -262,7 +262,6 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int camMat = (headPose * eyeToHead) * camMat; batch.setViewportTransform(renderArgs->_viewport); batch.setViewTransform(camMat); - batch.setProjectionTransform(qApp->getEyeProjection(eye)); #ifdef DEBUG_OVERLAY @@ -282,21 +281,28 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int bindCursorTexture(batch); - //Controller Pointers - glm::mat4 overlayXfm; - _modelTransform.getMatrix(overlayXfm); - //Mouse Pointer - glm::vec2 projection = screenToSpherical(qApp->getTrueMouse()); - mat4 pointerXfm = glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); - mat4 reticleXfm = overlayXfm * pointerXfm; - reticleXfm = glm::scale(reticleXfm, reticleScale); - batch.setModelTransform(reticleXfm); - geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad); + auto controllerScriptingInterface = DependencyManager::get(); + bool reticleVisible = controllerScriptingInterface->getReticleVisible(); + if (reticleVisible) { + glm::mat4 overlayXfm; + _modelTransform.getMatrix(overlayXfm); + + glm::vec2 projection = screenToSpherical(qApp->getTrueMouse()); + + float cursorDepth = controllerScriptingInterface->getReticleDepth(); + mat4 pointerXfm = glm::scale(mat4(), vec3(cursorDepth)) * glm::mat4_cast(quat(vec3(-projection.y, projection.x, 0.0f))) * glm::translate(mat4(), vec3(0, 0, -1)); + mat4 reticleXfm = overlayXfm * pointerXfm; + reticleXfm = glm::scale(reticleXfm, reticleScale); + batch.setModelTransform(reticleXfm); + geometryCache->renderUnitQuad(batch, glm::vec4(1), _reticleQuad); + } }); } +// FIXME - this probably is hella buggy and probably doesn't work correctly +// we should kill it asap. void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const { const glm::vec2 projection = overlayToSpherical(cursorPos); // The overlay space orientation of the mouse coordinates @@ -326,16 +332,22 @@ void ApplicationCompositor::computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& or //Finds the collision point of a world space ray bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const { - MyAvatar* myAvatar = DependencyManager::get()->getMyAvatar(); - glm::quat inverseOrientation = glm::inverse(myAvatar->getOrientation()); + auto displayPlugin = qApp->getActiveDisplayPlugin(); + auto headPose = displayPlugin->getHeadPose(qApp->getFrameCount()); - glm::vec3 relativePosition = inverseOrientation * (position - myAvatar->getDefaultEyePosition()); - glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); + auto myCamera = qApp->getCamera(); + mat4 cameraMat = myCamera->getTransform(); + auto UITransform = cameraMat * glm::inverse(headPose); + auto relativePosition4 = glm::inverse(UITransform) * vec4(position, 1); + auto relativePosition = vec3(relativePosition4) / relativePosition4.w; + auto relativeDirection = glm::inverse(glm::quat_cast(UITransform)) * direction; - float t; - if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getUniformScale(), &t)){ - result = position + direction * t; + float uiRadius = _oculusUIRadius; // * myAvatar->getUniformScale(); // FIXME - how do we want to handle avatar scale + + float instersectionDistance; + if (raySphereIntersect(relativeDirection, relativePosition, uiRadius, &instersectionDistance)){ + result = position + glm::normalize(direction) * instersectionDistance; return true; } @@ -494,6 +506,23 @@ glm::vec2 ApplicationCompositor::overlayToScreen(const glm::vec2& overlayPos) co return sphericalToScreen(overlayToSpherical(overlayPos)); } +glm::vec2 ApplicationCompositor::overlayFromSphereSurface(const glm::vec3& sphereSurfacePoint) const { + + auto displayPlugin = qApp->getActiveDisplayPlugin(); + auto headPose = displayPlugin->getHeadPose(qApp->getFrameCount()); + auto myCamera = qApp->getCamera(); + mat4 cameraMat = myCamera->getTransform(); + auto UITransform = cameraMat * glm::inverse(headPose); + auto relativePosition4 = glm::inverse(UITransform) * vec4(sphereSurfacePoint, 1); + auto relativePosition = vec3(relativePosition4) / relativePosition4.w; + auto center = vec3(0); // center of HUD in HUD space + auto direction = relativePosition - center; // direction to relative position in HUD space + + glm::vec2 polar = glm::vec2(glm::atan(direction.x, -direction.z), glm::asin(direction.y)) * -1.0f; + auto overlayPos = sphericalToOverlay(polar); + return overlayPos; +} + void ApplicationCompositor::updateTooltips() { if (_hoverItemId != _noItemId) { quint64 hoverDuration = usecTimestampNow() - _hoverItemEnterUsecs; diff --git a/interface/src/ui/ApplicationCompositor.h b/interface/src/ui/ApplicationCompositor.h index 8476782550..ae45352e84 100644 --- a/interface/src/ui/ApplicationCompositor.h +++ b/interface/src/ui/ApplicationCompositor.h @@ -62,6 +62,8 @@ public: void computeHmdPickRay(glm::vec2 cursorPos, glm::vec3& origin, glm::vec3& direction) const; uint32_t getOverlayTexture() const; + glm::vec2 overlayFromSphereSurface(const glm::vec3& sphereSurfacePoint) const; + void setCameraBaseTransform(const Transform& transform) { _cameraBaseTransform = transform; } const Transform& getCameraBaseTransform() const { return _cameraBaseTransform; } diff --git a/libraries/controllers/src/controllers/ScriptingInterface.h b/libraries/controllers/src/controllers/ScriptingInterface.h index 52ec52e852..72b6ca78e8 100644 --- a/libraries/controllers/src/controllers/ScriptingInterface.h +++ b/libraries/controllers/src/controllers/ScriptingInterface.h @@ -89,6 +89,12 @@ namespace controller { Q_INVOKABLE QObject* parseMapping(const QString& json); Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl); + Q_INVOKABLE bool getReticleVisible() { return _reticleVisible; } + Q_INVOKABLE void setReticleVisible(bool visible) { _reticleVisible = visible; } + + Q_INVOKABLE float getReticleDepth() { return _reticleDepth; } + Q_INVOKABLE void setReticleDepth(float depth) { _reticleDepth = depth; } + Q_INVOKABLE glm::vec2 getReticlePosition() { return toGlm(QCursor::pos()); } @@ -159,10 +165,13 @@ namespace controller { QVariantMap _actions; QVariantMap _standard; - bool _mouseCaptured{ false }; - bool _touchCaptured{ false }; - bool _wheelCaptured{ false }; - bool _actionsCaptured{ false }; + bool _mouseCaptured { false }; + bool _touchCaptured { false }; + bool _wheelCaptured { false }; + bool _actionsCaptured { false }; + bool _reticleVisible { true }; + + float _reticleDepth { 1.0f }; }; From 28f3e8ba9cf72aa08b76c2f08645c5bc3545274a Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 12 Feb 2016 12:07:23 -0800 Subject: [PATCH 24/34] Don't leave user data pointers around in objects after deletion --- libraries/ui/src/VrMenu.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libraries/ui/src/VrMenu.cpp b/libraries/ui/src/VrMenu.cpp index 2006b22860..d1ef660532 100644 --- a/libraries/ui/src/VrMenu.cpp +++ b/libraries/ui/src/VrMenu.cpp @@ -28,6 +28,11 @@ public: init(menu, qmlObject); } + ~MenuUserData() { + _widget->setUserData(USER_DATA_ID, nullptr); + _qml->setUserData(USER_DATA_ID, nullptr); + } + const QUuid uuid{ QUuid::createUuid() }; static MenuUserData* forObject(QObject* object) { @@ -37,12 +42,17 @@ public: private: MenuUserData(const MenuUserData&); void init(QObject* widgetObject, QObject* qmlObject) { + _widget = widgetObject; + _qml = qmlObject; widgetObject->setUserData(USER_DATA_ID, this); qmlObject->setUserData(USER_DATA_ID, this); qmlObject->setObjectName(uuid.toString()); // Make sure we can find it again in the future Q_ASSERT(VrMenu::_instance->findMenuObject(uuid.toString())); } + + QObject* _widget { nullptr }; + QObject* _qml { nullptr }; }; const int MenuUserData::USER_DATA_ID = QObject::registerUserData(); From d21f9d555adc32d43c0afb8296fdcde5beed60f9 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Fri, 12 Feb 2016 12:37:07 -0800 Subject: [PATCH 25/34] Update NetworkMaterial maps when changing textures --- .../src/model-networking/ModelCache.cpp | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index c4dc7ebccf..2f8e04890c 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -149,23 +149,50 @@ bool NetworkGeometry::isLoadedWithTextures() const { } void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& url) { - - if (_meshes.size() > 0) { auto textureCache = DependencyManager::get(); for (auto&& material : _materials) { + auto networkMaterial = material->_material; + auto oldTextureMaps = networkMaterial->getTextureMaps(); if (material->diffuseTextureName == name) { material->diffuseTexture = textureCache->getTexture(url, DEFAULT_TEXTURE); + + auto diffuseMap = model::TextureMapPointer(new model::TextureMap()); + diffuseMap->setTextureSource(material->diffuseTexture->_textureSource); + diffuseMap->setTextureTransform( + oldTextureMaps[model::MaterialKey::DIFFUSE_MAP]->getTextureTransform()); + + networkMaterial->setTextureMap(model::MaterialKey::DIFFUSE_MAP, diffuseMap); } else if (material->normalTextureName == name) { material->normalTexture = textureCache->getTexture(url); + + auto normalMap = model::TextureMapPointer(new model::TextureMap()); + normalMap->setTextureSource(material->normalTexture->_textureSource); + + networkMaterial->setTextureMap(model::MaterialKey::NORMAL_MAP, normalMap); } else if (material->specularTextureName == name) { material->specularTexture = textureCache->getTexture(url); + + auto glossMap = model::TextureMapPointer(new model::TextureMap()); + glossMap->setTextureSource(material->specularTexture->_textureSource); + + networkMaterial->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap); } else if (material->emissiveTextureName == name) { material->emissiveTexture = textureCache->getTexture(url); + + auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); + lightmapMap->setTextureSource(material->emissiveTexture->_textureSource); + lightmapMap->setTextureTransform( + oldTextureMaps[model::MaterialKey::LIGHTMAP_MAP]->getTextureTransform()); + glm::vec2 oldOffsetScale = + oldTextureMaps[model::MaterialKey::LIGHTMAP_MAP]->getLightmapOffsetScale(); + lightmapMap->setLightmapOffsetScale(oldOffsetScale.x, oldOffsetScale.y); + + networkMaterial->setTextureMap(model::MaterialKey::LIGHTMAP_MAP, lightmapMap); } } } else { - qCWarning(modelnetworking) << "Ignoring setTextureWirthNameToURL() geometry not ready." << name << url; + qCWarning(modelnetworking) << "Ignoring setTextureWithNameToURL() geometry not ready." << name << url; } _isLoadedWithTextures = false; } @@ -374,7 +401,6 @@ void NetworkGeometry::modelParseError(int error, QString str) { _resource = nullptr; } - const NetworkMaterial* NetworkGeometry::getShapeMaterial(int shapeID) { if ((shapeID >= 0) && (shapeID < (int)_shapes.size())) { int materialID = _shapes[shapeID]->_materialID; From c469fc6a29a4ec727786c74005378e12f64284e9 Mon Sep 17 00:00:00 2001 From: "James B. Pollack" Date: Fri, 12 Feb 2016 14:30:21 -0800 Subject: [PATCH 26/34] hide hyperlink property for web entities --- examples/html/entityProperties.html | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 71f2450da1..d8e5451ff8 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -308,6 +308,11 @@ allSections.push(elWebSections); var elWebSourceURL = document.getElementById("property-web-source-url"); + + var elHyperlinkHref = document.getElementById("property-hyperlink-href"); + var elHyperlinkDescription = document.getElementById("property-hyperlink-description"); + var elHyperlinkSections = document.querySelectorAll(".hyperlink-section"); + var elParticleSections = document.querySelectorAll(".particle-section"); allSections.push(elParticleSections); var elParticleIsEmitting = document.getElementById("property-particle-is-emitting"); @@ -370,9 +375,6 @@ var elYTextureURL = document.getElementById("property-y-texture-url"); var elZTextureURL = document.getElementById("property-z-texture-url"); - var elHyperlinkHref = document.getElementById("property-hyperlink-href"); - var elHyperlinkDescription = document.getElementById("property-hyperlink-description"); - var elPreviewCameraButton = document.getElementById("preview-camera-button"); if (window.EventBridge !== undefined) { @@ -492,8 +494,12 @@ for (var j = 0; j < allSections[i].length; j++) { allSections[i][j].style.display = 'none'; } + } + + for (var i = 0; i < elHyperlinkSections.length; i++) { + elHyperlinkSections[i].style.display = 'block'; } - + if (properties.type == "Box" || properties.type == "Sphere" || properties.type == "ParticleEffect") { elColorSection.style.display = 'block'; elColorRed.value = properties.color.red; @@ -526,6 +532,9 @@ for (var i = 0; i < elWebSections.length; i++) { elWebSections[i].style.display = 'block'; } + for (var i = 0; i < elHyperlinkSections.length; i++) { + elHyperlinkSections[i].style.display = 'none'; + } elWebSourceURL.value = properties.sourceUrl; } else if (properties.type == "Text") { @@ -1158,17 +1167,17 @@ -
+ -
+ -
+