From 5e2870ac5f249da597b9f312bce5b9648103e50c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 09:30:08 -0700 Subject: [PATCH 01/17] require a distinction between master config and user config --- domain-server/src/DomainServer.cpp | 4 +- .../src/DomainServerSettingsManager.cpp | 23 +++------- .../src/DomainServerSettingsManager.h | 10 ++-- libraries/shared/src/HifiConfigVariantMap.cpp | 46 +++++++++---------- libraries/shared/src/HifiConfigVariantMap.h | 22 +++++++-- 5 files changed, 52 insertions(+), 53 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index b1ed765be6..d347cb088f 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -48,7 +48,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : _sessionAuthenticationHash(), _webAuthenticationStateSet(), _cookieSessionHash(), - _settingsManager() + _settingsManager(arguments()) { LogUtils::init(); @@ -57,8 +57,6 @@ DomainServer::DomainServer(int argc, char* argv[]) : setApplicationName("domain-server"); QSettings::setDefaultFormat(QSettings::IniFormat); - _settingsManager.loadSettingsMap(arguments()); - installNativeEventFilter(&_shutdownEventListener); connect(&_shutdownEventListener, SIGNAL(receivedCloseEvent()), SLOT(quit())); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index d9b1d4d8d6..ae5a815e92 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -26,9 +26,9 @@ const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings.json"; -DomainServerSettingsManager::DomainServerSettingsManager() : +DomainServerSettingsManager::DomainServerSettingsManager(const QStringList& argumentList) : _descriptionArray(), - _settingsMap() + _configMap(argumentList) { // load the description object from the settings description QFile descriptionFile(QCoreApplication::applicationDirPath() + SETTINGS_DESCRIPTION_RELATIVE_PATH); @@ -37,13 +37,6 @@ DomainServerSettingsManager::DomainServerSettingsManager() : _descriptionArray = QJsonDocument::fromJson(descriptionFile.readAll()).array(); } -void DomainServerSettingsManager::loadSettingsMap(const QStringList& argumentList) { - _settingsMap = HifiConfigVariantMap::mergeMasterConfigWithUserConfig(argumentList); - - // figure out where we are supposed to persist our settings to - _settingsFilepath = HifiConfigVariantMap::userConfigFilepath(argumentList); -} - const QString SETTINGS_PATH = "/settings.json"; bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connection, const QUrl &url) { @@ -76,7 +69,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection QJsonObject postedObject = postedDocument.object(); // we recurse one level deep below each group for the appropriate setting - recurseJSONObjectAndOverwriteSettings(postedObject, _settingsMap, _descriptionArray); + recurseJSONObjectAndOverwriteSettings(postedObject, _configMap.getUserConfig(), _descriptionArray); // store whatever the current _settingsMap is to file persistToFile(); @@ -99,6 +92,7 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection rootObject[SETTINGS_RESPONSE_DESCRIPTION_KEY] = _descriptionArray; rootObject[SETTINGS_RESPONSE_VALUE_KEY] = responseObjectForType("", true); + connection->respond(HTTPConnection::StatusCode200, QJsonDocument(rootObject).toJson(), "application/json"); } @@ -145,7 +139,8 @@ QJsonObject DomainServerSettingsManager::responseObjectForType(const QString& ty // we need to check if the settings map has a value for this setting QVariant variantValue; - QVariant settingsMapGroupValue = _settingsMap.value(groupObject[DESCRIPTION_NAME_KEY].toString()); + QVariant settingsMapGroupValue = _configMap.getMergedConfig() + .value(groupObject[DESCRIPTION_NAME_KEY].toString()); if (!settingsMapGroupValue.isNull()) { variantValue = settingsMapGroupValue.toMap().value(settingName); @@ -239,10 +234,6 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ } } -QByteArray DomainServerSettingsManager::getJSONSettingsMap() const { - return QJsonDocument::fromVariant(_settingsMap).toJson(); -} - void DomainServerSettingsManager::persistToFile() { // make sure we have the dir the settings file is supposed to live in @@ -255,7 +246,7 @@ void DomainServerSettingsManager::persistToFile() { QFile settingsFile(_settingsFilepath); if (settingsFile.open(QIODevice::WriteOnly)) { - settingsFile.write(getJSONSettingsMap()); + settingsFile.write(QJsonDocument::fromVariant(_configMap.getUserConfig()).toJson()); } else { qCritical("Could not write to JSON settings file. Unable to persist settings."); } diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 29b773a354..4b884dfd5b 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -15,19 +15,17 @@ #include #include +#include #include class DomainServerSettingsManager : public QObject { Q_OBJECT public: - DomainServerSettingsManager(); + DomainServerSettingsManager(const QStringList& argumentList); bool handlePublicHTTPRequest(HTTPConnection* connection, const QUrl& url); bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url); - void loadSettingsMap(const QStringList& argumentList); - - QByteArray getJSONSettingsMap() const; - QVariantMap& getSettingsMap() { return _settingsMap; } + QVariantMap& getSettingsMap() { return _configMap.getMergedConfig(); } private: QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false); void recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, QVariantMap& settingsVariant, @@ -35,7 +33,7 @@ private: void persistToFile(); QJsonArray _descriptionArray; - QVariantMap _settingsMap; + HifiConfigVariantMap _configMap; QString _settingsFilepath; }; diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index d3626e0249..fabb185a35 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -87,43 +87,46 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL return mergedMap; } -QVariantMap HifiConfigVariantMap::mergeMasterConfigWithUserConfig(const QStringList& argumentList) { +HifiConfigVariantMap::HifiConfigVariantMap(const QStringList& argumentList) : + _masterConfigPath(), + _userConfigPath(), + _masterConfig(), + _userConfig(), + _mergedConfig() +{ // check if there is a master config file const QString MASTER_CONFIG_FILE_OPTION = "--master-config"; - QVariantMap configVariantMap; - int masterConfigIndex = argumentList.indexOf(MASTER_CONFIG_FILE_OPTION); if (masterConfigIndex != -1) { QString masterConfigFilepath = argumentList[masterConfigIndex + 1]; - mergeMapWithJSONFile(configVariantMap, masterConfigFilepath); + loadMapFromJSONFile(_masterConfig, masterConfigFilepath); } - // merge the existing configVariantMap with the user config file - mergeMapWithJSONFile(configVariantMap, userConfigFilepath(argumentList)); - - return configVariantMap; -} - -QString HifiConfigVariantMap::userConfigFilepath(const QStringList& argumentList) { - // we've loaded up the master config file, now fill in anything it didn't have with the user config file + // load the user config const QString USER_CONFIG_FILE_OPTION = "--user-config"; int userConfigIndex = argumentList.indexOf(USER_CONFIG_FILE_OPTION); QString userConfigFilepath; if (userConfigIndex != -1) { - userConfigFilepath = argumentList[userConfigIndex + 1]; + _userConfigPath = argumentList[userConfigIndex + 1]; } else { - userConfigFilepath = QString("%1/%2/%3/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), - QCoreApplication::organizationName(), - QCoreApplication::applicationName()); + _userConfigPath = QString("%1%2/%3/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), + QCoreApplication::organizationName(), + QCoreApplication::applicationName()); } - return userConfigFilepath; + loadMapFromJSONFile(_userConfig, _userConfigPath); + + // the merged config is initially matched to the master config + _mergedConfig = _masterConfig; + + // then we merge in anything missing from the user config + addMissingValuesToExistingMap(_mergedConfig, _userConfig); } -void HifiConfigVariantMap::mergeMapWithJSONFile(QVariantMap& existingMap, const QString& filename) { +void HifiConfigVariantMap::loadMapFromJSONFile(QVariantMap& existingMap, const QString& filename) { QFile configFile(filename); if (configFile.exists()) { @@ -131,12 +134,7 @@ void HifiConfigVariantMap::mergeMapWithJSONFile(QVariantMap& existingMap, const configFile.open(QIODevice::ReadOnly); QJsonDocument configDocument = QJsonDocument::fromJson(configFile.readAll()); - - if (existingMap.isEmpty()) { - existingMap = configDocument.toVariant().toMap(); - } else { - addMissingValuesToExistingMap(existingMap, configDocument.toVariant().toMap()); - } + existingMap = configDocument.toVariant().toMap(); } else { qDebug() << "Could not find JSON config file at" << filename; diff --git a/libraries/shared/src/HifiConfigVariantMap.h b/libraries/shared/src/HifiConfigVariantMap.h index b1b6b55aa2..12cc05d2e9 100644 --- a/libraries/shared/src/HifiConfigVariantMap.h +++ b/libraries/shared/src/HifiConfigVariantMap.h @@ -17,11 +17,25 @@ class HifiConfigVariantMap { public: static QVariantMap mergeCLParametersWithJSONConfig(const QStringList& argumentList); - static QVariantMap mergeMasterConfigWithUserConfig(const QStringList& argumentList); - static QString userConfigFilepath(const QStringList& argumentList); + + HifiConfigVariantMap(const QStringList& argumentList); + + const QVariantMap& getMasterConfig() const { return _masterConfig; } + QVariantMap& getUserConfig() { return _userConfig; } + QVariantMap& getMergedConfig() { return _mergedConfig; } + + const QString& userConfigFilepath() const { return _userConfigPath; } private: - static void mergeMapWithJSONFile(QVariantMap& existingMap, const QString& filename); - static void addMissingValuesToExistingMap(QVariantMap& existingMap, const QVariantMap& newMap); + QString _masterConfigPath; + QString _userConfigPath; + + QVariantMap _masterConfig; + QVariantMap _userConfig; + QVariantMap _mergedConfig; + + QVariantMap mergeMasterConfigWithUserConfig(const QStringList& argumentList); + void loadMapFromJSONFile(QVariantMap& existingMap, const QString& filename); + void addMissingValuesToExistingMap(QVariantMap& existingMap, const QVariantMap& newMap); }; const QVariant* valueForKeyPath(QVariantMap& variantMap, const QString& keyPath); From ec0805acc53af942a1a78eb39b1bd72eb6f0ecbf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 09:34:04 -0700 Subject: [PATCH 02/17] add locked settings to json return for auth'ed settings --- domain-server/src/DomainServerSettingsManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index ae5a815e92..e262d4e8a4 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -87,10 +87,12 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection // setup a JSON Object with descriptions and non-omitted settings const QString SETTINGS_RESPONSE_DESCRIPTION_KEY = "descriptions"; const QString SETTINGS_RESPONSE_VALUE_KEY = "values"; + const QString SETTINGS_RESPONSE_LOCKED_VALUES_KEY = "locked"; QJsonObject rootObject; rootObject[SETTINGS_RESPONSE_DESCRIPTION_KEY] = _descriptionArray; rootObject[SETTINGS_RESPONSE_VALUE_KEY] = responseObjectForType("", true); + rootObject[SETTINGS_RESPONSE_LOCKED_VALUES_KEY] = QJsonDocument::fromVariant(_configMap.getMasterConfig()).object(); connection->respond(HTTPConnection::StatusCode200, QJsonDocument(rootObject).toJson(), "application/json"); From 58b03c7ef2e54820404090a8ed82118e5415e885 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 09:53:27 -0700 Subject: [PATCH 03/17] disable form inputs for values set by master config --- domain-server/resources/describe-settings.json | 2 +- domain-server/resources/web/js/settings.js | 12 ++++++++---- domain-server/resources/web/settings/index.shtml | 6 ++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 8fb7bddb89..19c293b610 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -116,7 +116,7 @@ "advanced": true }, { - "name": "I-print-stream-stats", + "name": "print-stream-stats", "type": "checkbox", "label": "Print Stream Stats:", "help": "audio upstream and downstream stats of each agent printed to audio-mixer stdout", diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 8bb02e6e94..2d079e9a7c 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -3,9 +3,11 @@ var Settings = { }; var viewHelpers = { - getFormGroup: function(groupName, setting, values, isAdvanced) { + getFormGroup: function(groupName, setting, values, isAdvanced, isLocked) { setting_id = groupName + "_" + setting.name + console.log(setting.name + " in " + groupName + " is " + isLocked) + form_group = "
" if (_.has(values, groupName) && _.has(values[groupName], setting.name)) { @@ -18,9 +20,10 @@ var viewHelpers = { if (setting.type === 'checkbox') { form_group += "" - form_group += "
" + form_group += "
" form_group += ""; form_group += "
" } else { @@ -29,7 +32,7 @@ var viewHelpers = { form_group += ""; form_group += "" + "' value='" + setting_value + "'" + (isLocked ? " disabled" : "") + "/>" form_group += "" + setting.help + "" } @@ -101,6 +104,7 @@ function reloadSettings() { $('#panels').html(Settings.panelsTemplate(data)) Settings.initialValues = form2js('settings-form', "_", false, cleanupFormValues, true); + $('[data-target=tooltip]').tooltip() }); } diff --git a/domain-server/resources/web/settings/index.shtml b/domain-server/resources/web/settings/index.shtml index 54fbb02eca..2f0cdf6537 100644 --- a/domain-server/resources/web/settings/index.shtml +++ b/domain-server/resources/web/settings/index.shtml @@ -38,10 +38,12 @@
<% split_settings = _.partition(group.settings, function(value, index) { return !value.advanced }) %> <% _.each(split_settings[0], function(setting) { %> - <%= getFormGroup(group.name, setting, values, false) %> + <%= getFormGroup(group.name, setting, values, false, + (_.has(locked, group.name) && _.has(locked[group.name], setting.name))) %> <% }); %> <% _.each(split_settings[1], function(setting) { %> - <%= getFormGroup(group.name, setting, values, true) %> + <%= getFormGroup(group.name, setting, values, true, + (_.has(locked, group.name) && _.has(locked[group.name], setting.name))) %> <% }); %>
From 46258ae78f78abde987c49e59350d2ca278edb9c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 10:02:01 -0700 Subject: [PATCH 04/17] add a tooltip to say why locked settings cannot be changed --- domain-server/resources/web/css/style.css | 4 ++++ domain-server/resources/web/js/settings.js | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/domain-server/resources/web/css/style.css b/domain-server/resources/web/css/style.css index cef30b5782..a75b1a23ae 100644 --- a/domain-server/resources/web/css/style.css +++ b/domain-server/resources/web/css/style.css @@ -52,6 +52,10 @@ span.port { color: red; } +.locked { + color: blue; +} + .advanced-setting { display: none; } diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index 2d079e9a7c..3313bce06d 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -18,8 +18,13 @@ var viewHelpers = { setting_value = "" } + label_class = 'control-label' + if (isLocked) { + label_class += ' locked' + } + if (setting.type === 'checkbox') { - form_group += "" + form_group += "" form_group += "
" form_group += ""; + form_group += ""; form_group += "" @@ -104,7 +109,12 @@ function reloadSettings() { $('#panels').html(Settings.panelsTemplate(data)) Settings.initialValues = form2js('settings-form', "_", false, cleanupFormValues, true); - $('[data-target=tooltip]').tooltip() + + // add tooltip to locked settings + $('label.locked').tooltip({ + placement: 'right', + title: 'This setting is in the master config file and cannot be changed' + }) }); } From bd4a32551b723d1fe5290f108beb4856ba8c9782 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 10:09:33 -0700 Subject: [PATCH 05/17] fix for settings save without organization --- domain-server/src/DomainServer.cpp | 4 +++- .../src/DomainServerSettingsManager.cpp | 12 +++++++---- .../src/DomainServerSettingsManager.h | 5 +++-- libraries/shared/src/HifiConfigVariantMap.cpp | 20 ++++++++++--------- libraries/shared/src/HifiConfigVariantMap.h | 8 ++++---- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index d347cb088f..4f048a2ec9 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -48,7 +48,7 @@ DomainServer::DomainServer(int argc, char* argv[]) : _sessionAuthenticationHash(), _webAuthenticationStateSet(), _cookieSessionHash(), - _settingsManager(arguments()) + _settingsManager() { LogUtils::init(); @@ -57,6 +57,8 @@ DomainServer::DomainServer(int argc, char* argv[]) : setApplicationName("domain-server"); QSettings::setDefaultFormat(QSettings::IniFormat); + _settingsManager.setupConfigMap(arguments()); + installNativeEventFilter(&_shutdownEventListener); connect(&_shutdownEventListener, SIGNAL(receivedCloseEvent()), SLOT(quit())); diff --git a/domain-server/src/DomainServerSettingsManager.cpp b/domain-server/src/DomainServerSettingsManager.cpp index e262d4e8a4..fc36a97a25 100644 --- a/domain-server/src/DomainServerSettingsManager.cpp +++ b/domain-server/src/DomainServerSettingsManager.cpp @@ -26,9 +26,9 @@ const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings.json"; -DomainServerSettingsManager::DomainServerSettingsManager(const QStringList& argumentList) : +DomainServerSettingsManager::DomainServerSettingsManager() : _descriptionArray(), - _configMap(argumentList) + _configMap() { // load the description object from the settings description QFile descriptionFile(QCoreApplication::applicationDirPath() + SETTINGS_DESCRIPTION_RELATIVE_PATH); @@ -37,6 +37,10 @@ DomainServerSettingsManager::DomainServerSettingsManager(const QStringList& argu _descriptionArray = QJsonDocument::fromJson(descriptionFile.readAll()).array(); } +void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) { + _configMap.loadMasterAndUserConfig(argumentList); +} + const QString SETTINGS_PATH = "/settings.json"; bool DomainServerSettingsManager::handlePublicHTTPRequest(HTTPConnection* connection, const QUrl &url) { @@ -239,13 +243,13 @@ void DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ void DomainServerSettingsManager::persistToFile() { // make sure we have the dir the settings file is supposed to live in - QFileInfo settingsFileInfo(_settingsFilepath); + QFileInfo settingsFileInfo(_configMap.getUserConfigFilename()); if (!settingsFileInfo.dir().exists()) { settingsFileInfo.dir().mkpath("."); } - QFile settingsFile(_settingsFilepath); + QFile settingsFile(_configMap.getUserConfigFilename()); if (settingsFile.open(QIODevice::WriteOnly)) { settingsFile.write(QJsonDocument::fromVariant(_configMap.getUserConfig()).toJson()); diff --git a/domain-server/src/DomainServerSettingsManager.h b/domain-server/src/DomainServerSettingsManager.h index 4b884dfd5b..b60cb32dfd 100644 --- a/domain-server/src/DomainServerSettingsManager.h +++ b/domain-server/src/DomainServerSettingsManager.h @@ -21,10 +21,12 @@ class DomainServerSettingsManager : public QObject { Q_OBJECT public: - DomainServerSettingsManager(const QStringList& argumentList); + DomainServerSettingsManager(); bool handlePublicHTTPRequest(HTTPConnection* connection, const QUrl& url); bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url); + void setupConfigMap(const QStringList& argumentList); + QVariantMap& getSettingsMap() { return _configMap.getMergedConfig(); } private: QJsonObject responseObjectForType(const QString& typeValue, bool isAuthenticated = false); @@ -34,7 +36,6 @@ private: QJsonArray _descriptionArray; HifiConfigVariantMap _configMap; - QString _settingsFilepath; }; #endif // hifi_DomainServerSettingsManager_h \ No newline at end of file diff --git a/libraries/shared/src/HifiConfigVariantMap.cpp b/libraries/shared/src/HifiConfigVariantMap.cpp index fabb185a35..648f15648a 100644 --- a/libraries/shared/src/HifiConfigVariantMap.cpp +++ b/libraries/shared/src/HifiConfigVariantMap.cpp @@ -87,13 +87,16 @@ QVariantMap HifiConfigVariantMap::mergeCLParametersWithJSONConfig(const QStringL return mergedMap; } -HifiConfigVariantMap::HifiConfigVariantMap(const QStringList& argumentList) : - _masterConfigPath(), - _userConfigPath(), +HifiConfigVariantMap::HifiConfigVariantMap() : + _userConfigFilename(), _masterConfig(), _userConfig(), _mergedConfig() { + +} + +void HifiConfigVariantMap::loadMasterAndUserConfig(const QStringList& argumentList) { // check if there is a master config file const QString MASTER_CONFIG_FILE_OPTION = "--master-config"; @@ -108,16 +111,15 @@ HifiConfigVariantMap::HifiConfigVariantMap(const QStringList& argumentList) : const QString USER_CONFIG_FILE_OPTION = "--user-config"; int userConfigIndex = argumentList.indexOf(USER_CONFIG_FILE_OPTION); - QString userConfigFilepath; if (userConfigIndex != -1) { - _userConfigPath = argumentList[userConfigIndex + 1]; + _userConfigFilename = argumentList[userConfigIndex + 1]; } else { - _userConfigPath = QString("%1%2/%3/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), - QCoreApplication::organizationName(), - QCoreApplication::applicationName()); + _userConfigFilename = QString("%1/%2/%3/config.json").arg(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation), + QCoreApplication::organizationName(), + QCoreApplication::applicationName()); } - loadMapFromJSONFile(_userConfig, _userConfigPath); + loadMapFromJSONFile(_userConfig, _userConfigFilename); // the merged config is initially matched to the master config _mergedConfig = _masterConfig; diff --git a/libraries/shared/src/HifiConfigVariantMap.h b/libraries/shared/src/HifiConfigVariantMap.h index 12cc05d2e9..99a58d731e 100644 --- a/libraries/shared/src/HifiConfigVariantMap.h +++ b/libraries/shared/src/HifiConfigVariantMap.h @@ -18,16 +18,16 @@ class HifiConfigVariantMap { public: static QVariantMap mergeCLParametersWithJSONConfig(const QStringList& argumentList); - HifiConfigVariantMap(const QStringList& argumentList); + HifiConfigVariantMap(); + void loadMasterAndUserConfig(const QStringList& argumentList); const QVariantMap& getMasterConfig() const { return _masterConfig; } QVariantMap& getUserConfig() { return _userConfig; } QVariantMap& getMergedConfig() { return _mergedConfig; } - const QString& userConfigFilepath() const { return _userConfigPath; } + const QString& getUserConfigFilename() const { return _userConfigFilename; } private: - QString _masterConfigPath; - QString _userConfigPath; + QString _userConfigFilename; QVariantMap _masterConfig; QVariantMap _userConfig; From eb7ee361683258f4a265904fbd0aaa68378f3928 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 10:29:40 -0700 Subject: [PATCH 06/17] use two dashes for url as command line option --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0fd7ae96d1..c00b83b53d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -304,8 +304,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : connect(&addressManager, &AddressManager::possibleDomainChangeRequired, this, &Application::changeDomainHostname); - // when -url in command line, teleport to location - addressManager.handleLookupString(getCmdOption(argc, constArgv, "-url")); + // when --url in command line, teleport to location + addressManager.handleLookupString(getCmdOption(argc, constArgv, "--url")); _settings = new QSettings(this); _numChangedSettings = 0; From f7a17b7deca5128638eeb6412d73b985bac83e53 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 12:58:01 -0700 Subject: [PATCH 07/17] dynamically load sixense lib on OS X to make avoiding hid_init crash easier --- interface/CMakeLists.txt | 5 +- interface/src/Application.cpp | 22 +- interface/src/Application.h | 2 - interface/src/Menu.cpp | 21 +- interface/src/Menu.h | 2 + interface/src/devices/SixenseManager.cpp | 363 ++++++++++++++--------- interface/src/devices/SixenseManager.h | 21 +- interface/src/ui/ApplicationOverlay.cpp | 2 +- 8 files changed, 276 insertions(+), 162 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index a2a832afe0..ddc034801b 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -137,8 +137,9 @@ foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) set(${${EXTERNAL}_UPPERCASE}_LIBRARIES ${${${EXTERNAL}_UPPERCASE}_LIBRARY}) endif () - target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES}) - + if (NOT APPLE OR NOT ${${EXTERNAL}_UPPERCASE} MATCHES "SIXENSE") + target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES}) + endif () endif () endforeach() diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0fd7ae96d1..a5d9c89033 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -182,7 +182,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _lastNackTime(usecTimestampNow()), _lastSendDownstreamAudioStats(usecTimestampNow()) { - // read the ApplicationInfo.ini file for Name/Version/Domain information QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); @@ -381,12 +380,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _particleEditSender.setPacketsPerSecond(3000); // super high!! _entityEditSender.setPacketsPerSecond(3000); // super high!! - // Set the sixense filtering - _sixenseManager.setFilter(Menu::getInstance()->isOptionChecked(MenuOption::FilterSixense)); - - // Set hand controller velocity filtering - _sixenseManager.setLowVelocityFilter(Menu::getInstance()->isOptionChecked(MenuOption::LowVelocityFilter)); - checkVersion(); _overlays.init(_glWidget); // do this before scripts load @@ -1484,7 +1477,7 @@ void Application::setRenderVoxels(bool voxelRender) { } void Application::setLowVelocityFilter(bool lowVelocityFilter) { - getSixenseManager()->setLowVelocityFilter(lowVelocityFilter); + SixenseManager::getInstance().setLowVelocityFilter(lowVelocityFilter); } void Application::doKillLocalVoxels() { @@ -1798,6 +1791,17 @@ void Application::init() { _audio.setReceivedAudioStreamSettings(Menu::getInstance()->getReceivedAudioStreamSettings()); qDebug("Loaded settings"); + +#ifdef __APPLE__ + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseEnabled)) { + // on OS X we only setup sixense if the user wants it on - this allows running without the hid_init crash + // if hydra support is temporarily not required + Menu::getInstance()->toggleSixense(true); + } +#else + // setup sixense + Menu::getInstance()->toggleSixense(true); +#endif // initialize our face trackers after loading the menu settings _faceshift.init(); @@ -2174,7 +2178,7 @@ void Application::update(float deltaTime) { DeviceTracker::updateAll(); updateFaceshift(); updateVisage(); - _sixenseManager.update(deltaTime); + SixenseManager::getInstance().update(deltaTime); JoystickScriptingInterface::getInstance().update(); _prioVR.update(deltaTime); diff --git a/interface/src/Application.h b/interface/src/Application.h index f8710bae7b..e50039a20e 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -219,7 +219,6 @@ public: DdeFaceTracker* getDDE() { return &_dde; } CaraFaceTracker* getCara() { return &_cara; } FaceTracker* getActiveFaceTracker(); - SixenseManager* getSixenseManager() { return &_sixenseManager; } PrioVR* getPrioVR() { return &_prioVR; } BandwidthMeter* getBandwidthMeter() { return &_bandwidthMeter; } QUndoStack* getUndoStack() { return &_undoStack; } @@ -510,7 +509,6 @@ private: CaraFaceTracker _cara; DdeFaceTracker _dde; - SixenseManager _sixenseManager; PrioVR _prioVR; Camera _myCamera; // My view onto the world diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8f7b2be43b..1da85aad16 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -431,11 +431,18 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); QMenu* sixenseOptionsMenu = handOptionsMenu->addMenu("Sixense"); +#ifdef __APPLE__ + addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, + MenuOption::SixenseEnabled, + 0, true, + this, + SLOT(toggleSixense(bool))); +#endif addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::FilterSixense, 0, true, - appInstance->getSixenseManager(), + &SixenseManager::getInstance(), SLOT(setFilter(bool))); addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::LowVelocityFilter, @@ -1134,6 +1141,18 @@ void Menu::editAnimations() { } } +void Menu::toggleSixense(bool shouldEnable) { + SixenseManager& sixenseManager = SixenseManager::getInstance(); + + if (shouldEnable && !sixenseManager.isInitialized()) { + sixenseManager.initialize(); + sixenseManager.setFilter(isOptionChecked(MenuOption::FilterSixense)); + sixenseManager.setLowVelocityFilter(isOptionChecked(MenuOption::LowVelocityFilter)); + } + + sixenseManager.setIsEnabled(shouldEnable); +} + void Menu::changePrivateKey() { // setup the dialog QInputDialog privateKeyDialog(Application::getInstance()->getWindow()); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b267ab8b2c..c47c04e177 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -186,6 +186,7 @@ public slots: void pasteToVoxel(); void toggleLoginMenuItem(); + void toggleSixense(bool shouldEnable); QMenu* addMenu(const QString& menuName); void removeMenu(const QString& menuName); @@ -448,6 +449,7 @@ namespace MenuOption { const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowIKConstraints = "Show IK Constraints"; const QString SimpleShadows = "Simple"; + const QString SixenseEnabled = "Enable Hydra Support"; const QString SixenseMouseInput = "Enable Sixense Mouse Input"; const QString SixenseLasers = "Enable Sixense UI Lasers"; const QString StandOnNearbyFloors = "Stand on nearby floors"; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 417b0619f8..14b598f58c 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -30,23 +30,28 @@ const int CALIBRATION_STATE_COMPLETE = 4; const float NECK_X = 0.25f; // meters const float NECK_Y = 0.3f; // meters const float NECK_Z = 0.3f; // meters + +#ifdef __APPLE__ +typedef int (*SixenseBaseFunction)(); +typedef int (*SixenseTakeIntFunction)(int); +typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData*); #endif -SixenseManager::SixenseManager() { -#ifdef HAVE_SIXENSE - _lastMovement = 0; - _amountMoved = glm::vec3(0.0f); - _lowVelocityFilter = false; - - _calibrationState = CALIBRATION_STATE_IDLE; - // By default we assume the _neckBase (in orb frame) is as high above the orb - // as the "torso" is below it. - _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); - - sixenseInit(); - #endif - _hydrasConnected = false; + +SixenseManager& SixenseManager::getInstance() { + static SixenseManager sharedInstance; + return sharedInstance; +} + +SixenseManager::SixenseManager() : +#ifdef __APPLE__ + _sixenseLibrary(NULL), +#endif + _isInitialized(false), + _isEnabled(true), + _hydrasConnected(false) +{ _triggerPressed[0] = false; _bumperPressed[0] = false; _oldX[0] = -1; @@ -58,155 +63,223 @@ SixenseManager::SixenseManager() { } SixenseManager::~SixenseManager() { + + if (_isInitialized) { +#ifdef __APPLE__ + SixenseBaseFunction sixenseExit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseExit"); +#endif + + sixenseExit(); + } + +#ifdef __APPLE__ + delete _sixenseLibrary; +#endif +} + +void SixenseManager::initialize() { #ifdef HAVE_SIXENSE - sixenseExit(); + + if (!_isInitialized) { + _lastMovement = 0; + _amountMoved = glm::vec3(0.0f); + _lowVelocityFilter = false; + + _calibrationState = CALIBRATION_STATE_IDLE; + // By default we assume the _neckBase (in orb frame) is as high above the orb + // as the "torso" is below it. + _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); + +#ifdef __APPLE__ + + if (!_sixenseLibrary) { + _sixenseLibrary = new QLibrary("libsixense_x64.dylib"); + } + + SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit"); +#endif + + sixenseInit(); + + _isInitialized = true; + } + #endif } void SixenseManager::setFilter(bool filter) { #ifdef HAVE_SIXENSE - if (filter) { - sixenseSetFilterEnabled(1); - } else { - sixenseSetFilterEnabled(0); + + if (_isInitialized) { +#ifdef __APPLE__ + SixenseTakeIntFunction sixenseSetFilterEnabled = (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseSetFilterEnabled"); +#endif + + if (filter) { + sixenseSetFilterEnabled(1); + } else { + sixenseSetFilterEnabled(0); + } } + #endif } void SixenseManager::update(float deltaTime) { #ifdef HAVE_SIXENSE - // if the controllers haven't been moved in a while, disable - const unsigned int MOVEMENT_DISABLE_SECONDS = 3; - if (usecTimestampNow() - _lastMovement > (MOVEMENT_DISABLE_SECONDS * USECS_PER_SECOND)) { - Hand* hand = Application::getInstance()->getAvatar()->getHand(); - for (std::vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { - it->setActive(false); - } - _lastMovement = usecTimestampNow(); - } - - if (sixenseGetNumActiveControllers() == 0) { - _hydrasConnected = false; - return; - } - - PerformanceTimer perfTimer("sixense"); - if (!_hydrasConnected) { - _hydrasConnected = true; - UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); - } - MyAvatar* avatar = Application::getInstance()->getAvatar(); - Hand* hand = avatar->getHand(); - - int maxControllers = sixenseGetMaxControllers(); - - // we only support two controllers - sixenseControllerData controllers[2]; - - int numActiveControllers = 0; - for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) { - if (!sixenseIsControllerEnabled(i)) { - continue; - } - sixenseControllerData* data = controllers + numActiveControllers; - ++numActiveControllers; - sixenseGetNewestData(i, data); - - // Set palm position and normal based on Hydra position/orientation - - // Either find a palm matching the sixense controller, or make a new one - PalmData* palm; - bool foundHand = false; - for (size_t j = 0; j < hand->getNumPalms(); j++) { - if (hand->getPalms()[j].getSixenseID() == data->controller_index) { - palm = &(hand->getPalms()[j]); - foundHand = true; + if (_isInitialized && _isEnabled) { + // if the controllers haven't been moved in a while, disable + const unsigned int MOVEMENT_DISABLE_SECONDS = 3; + if (usecTimestampNow() - _lastMovement > (MOVEMENT_DISABLE_SECONDS * USECS_PER_SECOND)) { + Hand* hand = Application::getInstance()->getAvatar()->getHand(); + for (std::vector::iterator it = hand->getPalms().begin(); it != hand->getPalms().end(); it++) { + it->setActive(false); } - } - if (!foundHand) { - PalmData newPalm(hand); - hand->getPalms().push_back(newPalm); - palm = &(hand->getPalms()[hand->getNumPalms() - 1]); - palm->setSixenseID(data->controller_index); - qDebug("Found new Sixense controller, ID %i", data->controller_index); - } - - palm->setActive(true); - - // Read controller buttons and joystick into the hand - palm->setControllerButtons(data->buttons); - palm->setTrigger(data->trigger); - palm->setJoystick(data->joystick_x, data->joystick_y); - - - // Emulate the mouse so we can use scripts - if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { - emulateMouse(palm, numActiveControllers - 1); - } - - // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. - glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); - position *= METERS_PER_MILLIMETER; - - // Transform the measured position into body frame. - glm::vec3 neck = _neckBase; - // Zeroing y component of the "neck" effectively raises the measured position a little bit. - neck.y = 0.f; - position = _orbRotation * (position - neck); - - // Rotation of Palm - glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); - rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * _orbRotation * rotation; - - // Compute current velocity from position change - glm::vec3 rawVelocity; - if (deltaTime > 0.f) { - rawVelocity = (position - palm->getRawPosition()) / deltaTime; - } else { - rawVelocity = glm::vec3(0.0f); - } - palm->setRawVelocity(rawVelocity); // meters/sec - - // adjustment for hydra controllers fit into hands - float sign = (i == 0) ? -1.0f : 1.0f; - rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); - - if (_lowVelocityFilter) { - // Use a velocity sensitive filter to damp small motions and preserve large ones with - // no latency. - float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f); - position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter); - rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter); - palm->setRawPosition(position); - palm->setRawRotation(rotation); - } else { - palm->setRawPosition(position); - palm->setRawRotation(rotation); - } - - // use the velocity to determine whether there's any movement (if the hand isn't new) - const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f; - _amountMoved += rawVelocity * deltaTime; - if (glm::length(_amountMoved) > MOVEMENT_DISTANCE_THRESHOLD && foundHand) { _lastMovement = usecTimestampNow(); - _amountMoved = glm::vec3(0.0f); } - // Store the one fingertip in the palm structure so we can track velocity - const float FINGER_LENGTH = 0.3f; // meters - const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); - const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR; - glm::vec3 oldTipPosition = palm->getTipRawPosition(); - if (deltaTime > 0.f) { - palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime); - } else { - palm->setTipVelocity(glm::vec3(0.f)); +#ifdef __APPLE__ + SixenseBaseFunction sixenseGetNumActiveControllers = + (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetNumActiveControllers"); +#endif + + if (sixenseGetNumActiveControllers() == 0) { + _hydrasConnected = false; + return; + } + + PerformanceTimer perfTimer("sixense"); + if (!_hydrasConnected) { + _hydrasConnected = true; + UserActivityLogger::getInstance().connectedDevice("spatial_controller", "hydra"); + } + MyAvatar* avatar = Application::getInstance()->getAvatar(); + Hand* hand = avatar->getHand(); + +#ifdef __APPLE__ + SixenseBaseFunction sixenseGetMaxControllers = + (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseGetMaxControllers"); +#endif + + int maxControllers = sixenseGetMaxControllers(); + + // we only support two controllers + sixenseControllerData controllers[2]; + +#ifdef __APPLE__ + SixenseTakeIntFunction sixenseIsControllerEnabled = + (SixenseTakeIntFunction) _sixenseLibrary->resolve("sixenseIsControllerEnabled"); + + SixenseTakeIntAndSixenseControllerData sixenseGetNewestData = + (SixenseTakeIntAndSixenseControllerData) _sixenseLibrary->resolve("sixenseGetNewestData"); +#endif + + int numActiveControllers = 0; + for (int i = 0; i < maxControllers && numActiveControllers < 2; i++) { + if (!sixenseIsControllerEnabled(i)) { + continue; + } + sixenseControllerData* data = controllers + numActiveControllers; + ++numActiveControllers; + sixenseGetNewestData(i, data); + + // Set palm position and normal based on Hydra position/orientation + + // Either find a palm matching the sixense controller, or make a new one + PalmData* palm; + bool foundHand = false; + for (size_t j = 0; j < hand->getNumPalms(); j++) { + if (hand->getPalms()[j].getSixenseID() == data->controller_index) { + palm = &(hand->getPalms()[j]); + foundHand = true; + } + } + if (!foundHand) { + PalmData newPalm(hand); + hand->getPalms().push_back(newPalm); + palm = &(hand->getPalms()[hand->getNumPalms() - 1]); + palm->setSixenseID(data->controller_index); + qDebug("Found new Sixense controller, ID %i", data->controller_index); + } + + palm->setActive(true); + + // Read controller buttons and joystick into the hand + palm->setControllerButtons(data->buttons); + palm->setTrigger(data->trigger); + palm->setJoystick(data->joystick_x, data->joystick_y); + + + // Emulate the mouse so we can use scripts + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { + emulateMouse(palm, numActiveControllers - 1); + } + + // NOTE: Sixense API returns pos data in millimeters but we IMMEDIATELY convert to meters. + glm::vec3 position(data->pos[0], data->pos[1], data->pos[2]); + position *= METERS_PER_MILLIMETER; + + // Transform the measured position into body frame. + glm::vec3 neck = _neckBase; + // Zeroing y component of the "neck" effectively raises the measured position a little bit. + neck.y = 0.f; + position = _orbRotation * (position - neck); + + // Rotation of Palm + glm::quat rotation(data->rot_quat[3], -data->rot_quat[0], data->rot_quat[1], -data->rot_quat[2]); + rotation = glm::angleAxis(PI, glm::vec3(0.f, 1.f, 0.f)) * _orbRotation * rotation; + + // Compute current velocity from position change + glm::vec3 rawVelocity; + if (deltaTime > 0.f) { + rawVelocity = (position - palm->getRawPosition()) / deltaTime; + } else { + rawVelocity = glm::vec3(0.0f); + } + palm->setRawVelocity(rawVelocity); // meters/sec + + // adjustment for hydra controllers fit into hands + float sign = (i == 0) ? -1.0f : 1.0f; + rotation *= glm::angleAxis(sign * PI/4.0f, glm::vec3(0.0f, 0.0f, 1.0f)); + + if (_lowVelocityFilter) { + // Use a velocity sensitive filter to damp small motions and preserve large ones with + // no latency. + float velocityFilter = glm::clamp(1.0f - glm::length(rawVelocity), 0.0f, 1.0f); + position = palm->getRawPosition() * velocityFilter + position * (1.0f - velocityFilter); + rotation = safeMix(palm->getRawRotation(), rotation, 1.0f - velocityFilter); + palm->setRawPosition(position); + palm->setRawRotation(rotation); + } else { + palm->setRawPosition(position); + palm->setRawRotation(rotation); + } + + // use the velocity to determine whether there's any movement (if the hand isn't new) + const float MOVEMENT_DISTANCE_THRESHOLD = 0.003f; + _amountMoved += rawVelocity * deltaTime; + if (glm::length(_amountMoved) > MOVEMENT_DISTANCE_THRESHOLD && foundHand) { + _lastMovement = usecTimestampNow(); + _amountMoved = glm::vec3(0.0f); + } + + // Store the one fingertip in the palm structure so we can track velocity + const float FINGER_LENGTH = 0.3f; // meters + const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, FINGER_LENGTH); + const glm::vec3 newTipPosition = position + rotation * FINGER_VECTOR; + glm::vec3 oldTipPosition = palm->getTipRawPosition(); + if (deltaTime > 0.f) { + palm->setTipVelocity((newTipPosition - oldTipPosition) / deltaTime); + } else { + palm->setTipVelocity(glm::vec3(0.f)); + } + palm->setTipPosition(newTipPosition); + } + + if (numActiveControllers == 2) { + updateCalibration(controllers); } - palm->setTipPosition(newTipPosition); - } - if (numActiveControllers == 2) { - updateCalibration(controllers); } #endif // HAVE_SIXENSE } diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h index 664c102f76..1954ac91bc 100644 --- a/interface/src/devices/SixenseManager.h +++ b/interface/src/devices/SixenseManager.h @@ -18,6 +18,11 @@ #include #include #include "sixense.h" + +#ifdef __APPLE__ + #include +#endif + #endif const unsigned int BUTTON_0 = 1U << 0; // the skinny button between 1 and 2 @@ -38,9 +43,12 @@ const bool DEFAULT_INVERT_SIXENSE_MOUSE_BUTTONS = false; class SixenseManager : public QObject { Q_OBJECT public: + static SixenseManager& getInstance(); - SixenseManager(); - ~SixenseManager(); + void initialize(); + bool isInitialized() const { return _isInitialized; } + + void setIsEnabled(bool isEnabled) { _isEnabled = isEnabled; } void update(float deltaTime); float getCursorPixelRangeMult() const; @@ -51,6 +59,9 @@ public slots: void setLowVelocityFilter(bool lowVelocityFilter) { _lowVelocityFilter = lowVelocityFilter; }; private: + SixenseManager(); + ~SixenseManager(); + #ifdef HAVE_SIXENSE void updateCalibration(const sixenseControllerData* controllers); void emulateMouse(PalmData* palm, int index); @@ -72,7 +83,13 @@ private: glm::vec3 _reachForward; float _lastDistance; +#ifdef __APPLE__ + QLibrary* _sixenseLibrary; #endif + +#endif + bool _isInitialized; + bool _isEnabled; bool _hydrasConnected; quint64 _lastMovement; glm::vec3 _amountMoved; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index df7c2d2289..d8d2213d8f 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -671,7 +671,7 @@ void ApplicationOverlay::renderControllerPointers() { float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); // Get the pixel range over which the xAngle and yAngle are scaled - float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMult(); + float cursorRange = glWidget->width() * SixenseManager::getInstance().getCursorPixelRangeMult(); mouseX = (glWidget->width() / 2.0f + cursorRange * xAngle); mouseY = (glWidget->height() / 2.0f + cursorRange * yAngle); From db0bfd53ae4758a0a601f07200b08dd9d0f74a93 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 12:58:40 -0700 Subject: [PATCH 08/17] make the sixense library name a constant --- interface/src/devices/SixenseManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 14b598f58c..5068427db8 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -93,7 +93,8 @@ void SixenseManager::initialize() { #ifdef __APPLE__ if (!_sixenseLibrary) { - _sixenseLibrary = new QLibrary("libsixense_x64.dylib"); + const QString SIXENSE_LIBRARY_NAME = "libsixense_x64.dylib"; + _sixenseLibrary = new QLibrary(SIXENSE_LIBRARY_NAME); } SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit"); From 1f4c0b6340ab1282066c67f8b3f5ada401d278a2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 13:09:25 -0700 Subject: [PATCH 09/17] wrap sixenseExit call in HAVE_SIXENSE ifdef --- interface/src/devices/SixenseManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 5068427db8..7823d6e840 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -63,6 +63,7 @@ SixenseManager::SixenseManager() : } SixenseManager::~SixenseManager() { +#ifdef HAVE_SIXENSE_ if (_isInitialized) { #ifdef __APPLE__ @@ -75,6 +76,8 @@ SixenseManager::~SixenseManager() { #ifdef __APPLE__ delete _sixenseLibrary; #endif + +#endif } void SixenseManager::initialize() { From 3fbf14168657e52d162a0242dcada9e812375337 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 13:14:25 -0700 Subject: [PATCH 10/17] handle avatar location changes after avatar position has been reloaded --- interface/src/Application.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c00b83b53d..261411b5fb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -303,9 +303,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // connect to the domainChangeRequired signal on AddressManager connect(&addressManager, &AddressManager::possibleDomainChangeRequired, this, &Application::changeDomainHostname); - - // when --url in command line, teleport to location - addressManager.handleLookupString(getCmdOption(argc, constArgv, "--url")); _settings = new QSettings(this); _numChangedSettings = 0; @@ -1796,6 +1793,13 @@ void Application::init() { Menu::getInstance()->loadSettings(); _audio.setReceivedAudioStreamSettings(Menu::getInstance()->getReceivedAudioStreamSettings()); + + // when --url in command line, teleport to location + const QString HIFI_URL_COMMAND_LINE_KEY = "--url"; + int urlIndex = arguments().indexOf(HIFI_URL_COMMAND_LINE_KEY); + if (urlIndex != -1) { + AddressManager::getInstance().handleLookupString(arguments().value(urlIndex + 1)); + } qDebug("Loaded settings"); From a847c2d80d70ec74383b2afd94c57a543bd2b6f8 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 13:15:28 -0700 Subject: [PATCH 11/17] move url handling to after settings load debug --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 261411b5fb..e0c03584bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1793,6 +1793,8 @@ void Application::init() { Menu::getInstance()->loadSettings(); _audio.setReceivedAudioStreamSettings(Menu::getInstance()->getReceivedAudioStreamSettings()); + + qDebug() << "Loaded settings"; // when --url in command line, teleport to location const QString HIFI_URL_COMMAND_LINE_KEY = "--url"; @@ -1801,8 +1803,6 @@ void Application::init() { AddressManager::getInstance().handleLookupString(arguments().value(urlIndex + 1)); } - qDebug("Loaded settings"); - // initialize our face trackers after loading the menu settings _faceshift.init(); _faceplus.init(); From 72ff908bd3fb125e2c16ee63325e953ee3e22aba Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 29 Sep 2014 14:37:11 -0700 Subject: [PATCH 12/17] Fix for metavoxel crashes on Windows. I was expecting the scope of a temporary object to last until the next line; turns out VC++ can destroy it in the middle of evaluating the line. --- interface/src/MetavoxelSystem.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index b993d5243e..e8a70a2419 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -1204,7 +1204,8 @@ int PointAugmentVisitor::visit(MetavoxelInfo& info) { _points.swap(swapPoints); buffer = new PointBuffer(swapPoints); } - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); + BufferDataPointer pointer(buffer); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); } return STOP_RECURSION; } @@ -1219,7 +1220,8 @@ bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { _points.swap(swapPoints); buffer = new PointBuffer(swapPoints); } - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); + BufferDataPointer pointer(buffer); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); return true; } @@ -1446,7 +1448,8 @@ int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) { _data->guide(_fetchVisitor); } } - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); + BufferDataPointer pointer(buffer); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); return STOP_RECURSION; } @@ -1505,7 +1508,8 @@ int HeightfieldUpdateVisitor::visit(MetavoxelInfo& info) { buffer->getHeight(), buffer->getColor(), buffer->getMaterial(), buffer->getMaterials()); _fetchVisitor.init(newBuffer); _data->guide(_fetchVisitor); - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(newBuffer))); + BufferDataPointer pointer(newBuffer); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); return STOP_RECURSION; } @@ -2078,7 +2082,8 @@ int VoxelAugmentVisitor::visit(MetavoxelInfo& info) { buffer = new VoxelBuffer(vertices, indices, material->getMaterials()); } - info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); + BufferDataPointer pointer(buffer); + info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(pointer)); return STOP_RECURSION; } From 4c617c6d5562ff709815463c9e0eefcece06da2c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 29 Sep 2014 14:51:45 -0700 Subject: [PATCH 13/17] Stop using the emissive color for glow. --- interface/src/renderer/Model.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 858d8c9239..55eefb0bde 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1335,11 +1335,7 @@ void Model::renderMeshes(RenderMode mode, bool translucent, float alphaThreshold } else { glm::vec4 diffuse = glm::vec4(part.diffuseColor, part.opacity); if (!(translucent && alphaThreshold == 0.0f)) { - float emissive = (part.emissiveColor.r + part.emissiveColor.g + part.emissiveColor.b) / 3.0f; - diffuse.a = qMax(Application::getInstance()->getGlowEffect()->getIntensity(), emissive); - glAlphaFunc(GL_EQUAL, diffuse.a); - diffuse = glm::vec4(qMax(diffuse.r, part.emissiveColor.r), qMax(diffuse.g, part.emissiveColor.g), - qMax(diffuse.b, part.emissiveColor.b), diffuse.a); + glAlphaFunc(GL_EQUAL, diffuse.a = Application::getInstance()->getGlowEffect()->getIntensity()); } glm::vec4 specular = glm::vec4(part.specularColor, 1.0f); glMaterialfv(GL_FRONT, GL_AMBIENT, (const float*)&diffuse); From c16ab0a19fa388afc2f8b31cd8ca6e653c231a1c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 15:27:45 -0700 Subject: [PATCH 14/17] remove definition for an unused method --- libraries/shared/src/HifiConfigVariantMap.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/HifiConfigVariantMap.h b/libraries/shared/src/HifiConfigVariantMap.h index 99a58d731e..6bdeb15589 100644 --- a/libraries/shared/src/HifiConfigVariantMap.h +++ b/libraries/shared/src/HifiConfigVariantMap.h @@ -33,7 +33,6 @@ private: QVariantMap _userConfig; QVariantMap _mergedConfig; - QVariantMap mergeMasterConfigWithUserConfig(const QStringList& argumentList); void loadMapFromJSONFile(QVariantMap& existingMap, const QString& filename); void addMissingValuesToExistingMap(QVariantMap& existingMap, const QVariantMap& newMap); }; From 2fbd249d9f3da191a30dc94dd0b7c1912fcdb11f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 16:38:10 -0700 Subject: [PATCH 15/17] fix reset password link for LoginDialog --- interface/src/ui/LoginDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 57e02689c1..6583e170d3 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -21,7 +21,7 @@ #include "LoginDialog.h" -const QString FORGOT_PASSWORD_URL = "https://data.highfidelity.io/password/new"; +const QString FORGOT_PASSWORD_URL = "https://data.highfidelity.io/users/password/new"; LoginDialog::LoginDialog(QWidget* parent) : FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP), From f047c2dff09fd586b9d7f790a1e56c1881768127 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 17:08:06 -0700 Subject: [PATCH 16/17] have OS X hydra support be disabled by default --- interface/src/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 1da85aad16..d2ae9160ad 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -434,7 +434,7 @@ Menu::Menu() : #ifdef __APPLE__ addCheckableActionToQMenuAndActionHash(sixenseOptionsMenu, MenuOption::SixenseEnabled, - 0, true, + 0, false, this, SLOT(toggleSixense(bool))); #endif From e512b05e621293f75bcbab45f104f0918c373e91 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 29 Sep 2014 17:28:50 -0700 Subject: [PATCH 17/17] add extra debug for hydra library initialization --- interface/src/devices/SixenseManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 7823d6e840..28b125b6da 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -100,6 +100,8 @@ void SixenseManager::initialize() { _sixenseLibrary = new QLibrary(SIXENSE_LIBRARY_NAME); } + qDebug() << "Initializing sixense library for hydra support - libsixense_x64.dylib load state is" + << _sixenseLibrary->isLoaded(); SixenseBaseFunction sixenseInit = (SixenseBaseFunction) _sixenseLibrary->resolve("sixenseInit"); #endif