mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-19 20:08:10 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into dont-think-during-mouse-move
This commit is contained in:
commit
e4aa4823f9
42 changed files with 1097 additions and 506 deletions
|
@ -17,8 +17,8 @@
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
#include <SharedUtil.h>
|
|
||||||
#include <HifiConfigVariantMap.h>
|
#include <HifiConfigVariantMap.h>
|
||||||
|
#include <SharedUtil.h>
|
||||||
#include <ShutdownEventListener.h>
|
#include <ShutdownEventListener.h>
|
||||||
|
|
||||||
#include "Assignment.h"
|
#include "Assignment.h"
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
{
|
{
|
||||||
"label": "Places / Paths",
|
"label": "Places / Paths",
|
||||||
"html_id": "places_paths",
|
"html_id": "places_paths",
|
||||||
|
"restart": false,
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
"name": "paths",
|
"name": "paths",
|
||||||
|
@ -75,6 +76,7 @@
|
||||||
{
|
{
|
||||||
"name": "descriptors",
|
"name": "descriptors",
|
||||||
"label": "Description",
|
"label": "Description",
|
||||||
|
"restart": false,
|
||||||
"help": "This data will be queryable from your server. It may be collected by High Fidelity and used to share your domain with others.",
|
"help": "This data will be queryable from your server. It may be collected by High Fidelity and used to share your domain with others.",
|
||||||
"settings": [
|
"settings": [
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,11 +2,11 @@ $(document).ready(function(){
|
||||||
// setup the underscore templates
|
// setup the underscore templates
|
||||||
var nodeTemplate = _.template($('#nodes-template').html());
|
var nodeTemplate = _.template($('#nodes-template').html());
|
||||||
var queuedTemplate = _.template($('#queued-template').html());
|
var queuedTemplate = _.template($('#queued-template').html());
|
||||||
|
|
||||||
// setup a function to grab the assignments
|
// setup a function to grab the assignments
|
||||||
function getNodesAndAssignments() {
|
function getNodesAndAssignments() {
|
||||||
$.getJSON("nodes.json", function(json){
|
$.getJSON("nodes.json", function(json){
|
||||||
|
|
||||||
json.nodes.sort(function(a, b){
|
json.nodes.sort(function(a, b){
|
||||||
if (a.type === b.type) {
|
if (a.type === b.type) {
|
||||||
if (a.uptime < b.uptime) {
|
if (a.uptime < b.uptime) {
|
||||||
|
@ -16,36 +16,50 @@ $(document).ready(function(){
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.type === "agent" && b.type !== "agent") {
|
if (a.type === "agent" && b.type !== "agent") {
|
||||||
return 1;
|
return 1;
|
||||||
} else if (b.type === "agent" && a.type !== "agent") {
|
} else if (b.type === "agent" && a.type !== "agent") {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.type > b.type) {
|
if (a.type > b.type) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a.type < b.type) {
|
if (a.type < b.type) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#nodes-table tbody').html(nodeTemplate(json));
|
$('#nodes-table tbody').html(nodeTemplate(json));
|
||||||
|
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||||
|
// we assume a 401 means the DS has restarted
|
||||||
|
// and no longer has our OAuth produced uuid
|
||||||
|
// so just reload and re-auth
|
||||||
|
if (jqXHR.status == 401) {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
$.getJSON("assignments.json", function(json){
|
$.getJSON("assignments.json", function(json){
|
||||||
$('#assignments-table tbody').html(queuedTemplate(json));
|
$('#assignments-table tbody').html(queuedTemplate(json));
|
||||||
|
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||||
|
// we assume a 401 means the DS has restarted
|
||||||
|
// and no longer has our OAuth produced uuid
|
||||||
|
// so just reload and re-auth
|
||||||
|
if (jqXHR.status == 401) {
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// do the first GET on page load
|
// do the first GET on page load
|
||||||
getNodesAndAssignments();
|
getNodesAndAssignments();
|
||||||
// grab the new assignments JSON every two seconds
|
// grab the new assignments JSON every two seconds
|
||||||
var getNodesAndAssignmentsInterval = setInterval(getNodesAndAssignments, 2000);
|
var getNodesAndAssignmentsInterval = setInterval(getNodesAndAssignments, 2000);
|
||||||
|
|
||||||
// hook the node delete to the X button
|
// hook the node delete to the X button
|
||||||
$(document.body).on('click', '.glyphicon-remove', function(){
|
$(document.body).on('click', '.glyphicon-remove', function(){
|
||||||
// fire off a delete for this node
|
// fire off a delete for this node
|
||||||
|
@ -57,10 +71,10 @@ $(document).ready(function(){
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document.body).on('click', '#kill-all-btn', function() {
|
$(document.body).on('click', '#kill-all-btn', function() {
|
||||||
var confirmed_kill = confirm("Are you sure?");
|
var confirmed_kill = confirm("Are you sure?");
|
||||||
|
|
||||||
if (confirmed_kill == true) {
|
if (confirmed_kill == true) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url: "/nodes/",
|
url: "/nodes/",
|
||||||
|
|
|
@ -40,11 +40,11 @@
|
||||||
#include <LogHandler.h>
|
#include <LogHandler.h>
|
||||||
#include <PathUtils.h>
|
#include <PathUtils.h>
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
|
#include <Trace.h>
|
||||||
|
#include <StatTracker.h>
|
||||||
|
|
||||||
#include "DomainServerNodeData.h"
|
#include "DomainServerNodeData.h"
|
||||||
#include "NodeConnectionData.h"
|
#include "NodeConnectionData.h"
|
||||||
#include <Trace.h>
|
|
||||||
#include <StatTracker.h>
|
|
||||||
|
|
||||||
int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
||||||
|
|
||||||
|
@ -162,8 +162,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
||||||
|
|
||||||
_gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request
|
_gatekeeper.preloadAllowedUserPublicKeys(); // so they can connect on first request
|
||||||
|
|
||||||
|
//send signal to DomainMetadata when descriptors changed
|
||||||
_metadata = new DomainMetadata(this);
|
_metadata = new DomainMetadata(this);
|
||||||
|
connect(&_settingsManager, &DomainServerSettingsManager::settingsUpdated,
|
||||||
|
_metadata, &DomainMetadata::descriptorsChanged);
|
||||||
|
|
||||||
qDebug() << "domain-server is running";
|
qDebug() << "domain-server is running";
|
||||||
static const QString AC_SUBNET_WHITELIST_SETTING_PATH = "security.ac_subnet_whitelist";
|
static const QString AC_SUBNET_WHITELIST_SETTING_PATH = "security.ac_subnet_whitelist";
|
||||||
|
@ -1972,7 +1974,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
||||||
return _settingsManager.handleAuthenticatedHTTPRequest(connection, url);
|
return _settingsManager.handleAuthenticatedHTTPRequest(connection, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString HIFI_SESSION_COOKIE_KEY = "DS_WEB_SESSION_UUID";
|
static const QString HIFI_SESSION_COOKIE_KEY = "DS_WEB_SESSION_UUID";
|
||||||
|
static const QString STATE_QUERY_KEY = "state";
|
||||||
|
|
||||||
bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url, bool skipSubHandler) {
|
bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &url, bool skipSubHandler) {
|
||||||
qDebug() << "HTTPS request received at" << url.toString();
|
qDebug() << "HTTPS request received at" << url.toString();
|
||||||
|
@ -1983,10 +1986,9 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
|
||||||
const QString CODE_QUERY_KEY = "code";
|
const QString CODE_QUERY_KEY = "code";
|
||||||
QString authorizationCode = codeURLQuery.queryItemValue(CODE_QUERY_KEY);
|
QString authorizationCode = codeURLQuery.queryItemValue(CODE_QUERY_KEY);
|
||||||
|
|
||||||
const QString STATE_QUERY_KEY = "state";
|
|
||||||
QUuid stateUUID = QUuid(codeURLQuery.queryItemValue(STATE_QUERY_KEY));
|
QUuid stateUUID = QUuid(codeURLQuery.queryItemValue(STATE_QUERY_KEY));
|
||||||
|
|
||||||
if (!authorizationCode.isEmpty() && !stateUUID.isNull()) {
|
if (!authorizationCode.isEmpty() && !stateUUID.isNull() && _webAuthenticationStateSet.remove(stateUUID)) {
|
||||||
// fire off a request with this code and state to get an access token for the user
|
// fire off a request with this code and state to get an access token for the user
|
||||||
|
|
||||||
const QString OAUTH_TOKEN_REQUEST_PATH = "/oauth/token";
|
const QString OAUTH_TOKEN_REQUEST_PATH = "/oauth/token";
|
||||||
|
@ -2004,47 +2006,83 @@ bool DomainServer::handleHTTPSRequest(HTTPSConnection* connection, const QUrl &u
|
||||||
tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
tokenRequest.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
|
||||||
QNetworkReply* tokenReply = NetworkAccessManager::getInstance().post(tokenRequest, tokenPostBody.toLocal8Bit());
|
QNetworkReply* tokenReply = NetworkAccessManager::getInstance().post(tokenRequest, tokenPostBody.toLocal8Bit());
|
||||||
|
connect(tokenReply, &QNetworkReply::finished, this, &DomainServer::tokenGrantFinished);
|
||||||
|
|
||||||
if (_webAuthenticationStateSet.remove(stateUUID)) {
|
// add this connection to our list of pending connections so that we can hold the response
|
||||||
// this is a web user who wants to auth to access web interface
|
_pendingOAuthConnections.insert(stateUUID, connection);
|
||||||
// we hold the response back to them until we get their profile information
|
|
||||||
// and can decide if they are let in or not
|
|
||||||
|
|
||||||
QEventLoop loop;
|
// set the state UUID on the reply so that we can associate the response with the connection later
|
||||||
connect(tokenReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
tokenReply->setProperty(STATE_QUERY_KEY.toLocal8Bit(), stateUUID);
|
||||||
|
|
||||||
// start the loop for the token request
|
return true;
|
||||||
loop.exec();
|
} else {
|
||||||
|
connection->respond(HTTPConnection::StatusCode400);
|
||||||
|
|
||||||
QNetworkReply* profileReply = profileRequestGivenTokenReply(tokenReply);
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// stop the loop once the profileReply is complete
|
HTTPSConnection* DomainServer::connectionFromReplyWithState(QNetworkReply* reply) {
|
||||||
connect(profileReply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
// grab the UUID state property from the reply
|
||||||
|
QUuid stateUUID = reply->property(STATE_QUERY_KEY.toLocal8Bit()).toUuid();
|
||||||
|
|
||||||
// restart the loop for the profile request
|
if (!stateUUID.isNull()) {
|
||||||
loop.exec();
|
return _pendingOAuthConnections.take(stateUUID);
|
||||||
|
} else {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DomainServer::tokenGrantFinished() {
|
||||||
|
auto tokenReply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
|
if (tokenReply) {
|
||||||
|
if (tokenReply->error() == QNetworkReply::NoError) {
|
||||||
|
// now that we have a token for this profile, send off a profile request
|
||||||
|
QNetworkReply* profileReply = profileRequestGivenTokenReply(tokenReply);
|
||||||
|
|
||||||
|
// forward along the state UUID that we kept with the token request
|
||||||
|
profileReply->setProperty(STATE_QUERY_KEY.toLocal8Bit(), tokenReply->property(STATE_QUERY_KEY.toLocal8Bit()));
|
||||||
|
|
||||||
|
connect(profileReply, &QNetworkReply::finished, this, &DomainServer::profileRequestFinished);
|
||||||
|
} else {
|
||||||
|
// the token grant failed, send back a 500 (assuming the connection is still around)
|
||||||
|
auto connection = connectionFromReplyWithState(tokenReply);
|
||||||
|
|
||||||
|
if (connection) {
|
||||||
|
connection->respond(HTTPConnection::StatusCode500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tokenReply->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DomainServer::profileRequestFinished() {
|
||||||
|
|
||||||
|
auto profileReply = qobject_cast<QNetworkReply*>(sender());
|
||||||
|
|
||||||
|
if (profileReply) {
|
||||||
|
auto connection = connectionFromReplyWithState(profileReply);
|
||||||
|
|
||||||
|
if (connection) {
|
||||||
|
if (profileReply->error() == QNetworkReply::NoError) {
|
||||||
// call helper method to get cookieHeaders
|
// call helper method to get cookieHeaders
|
||||||
Headers cookieHeaders = setupCookieHeadersFromProfileReply(profileReply);
|
Headers cookieHeaders = setupCookieHeadersFromProfileReply(profileReply);
|
||||||
|
|
||||||
connection->respond(HTTPConnection::StatusCode302, QByteArray(),
|
connection->respond(HTTPConnection::StatusCode302, QByteArray(),
|
||||||
HTTPConnection::DefaultContentType, cookieHeaders);
|
HTTPConnection::DefaultContentType, cookieHeaders);
|
||||||
|
|
||||||
delete tokenReply;
|
} else {
|
||||||
delete profileReply;
|
// the profile request failed, send back a 500 (assuming the connection is still around)
|
||||||
|
connection->respond(HTTPConnection::StatusCode500);
|
||||||
// we've redirected the user back to our homepage
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// respond with a 200 code indicating that login is complete
|
profileReply->deleteLater();
|
||||||
connection->respond(HTTPConnection::StatusCode200);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2104,22 +2142,31 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
||||||
// the user does not have allowed username or role, return 401
|
// the user does not have allowed username or role, return 401
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
// re-direct this user to OAuth page
|
static const QByteArray REQUESTED_WITH_HEADER = "X-Requested-With";
|
||||||
|
static const QString XML_REQUESTED_WITH = "XMLHttpRequest";
|
||||||
|
|
||||||
// generate a random state UUID to use
|
if (connection->requestHeaders().value(REQUESTED_WITH_HEADER) == XML_REQUESTED_WITH) {
|
||||||
QUuid stateUUID = QUuid::createUuid();
|
// unauthorized XHR requests get a 401 and not a 302, since there isn't an XHR
|
||||||
|
// path to OAuth authorize
|
||||||
|
connection->respond(HTTPConnection::StatusCode401, UNAUTHENTICATED_BODY);
|
||||||
|
} else {
|
||||||
|
// re-direct this user to OAuth page
|
||||||
|
|
||||||
// add it to the set so we can handle the callback from the OAuth provider
|
// generate a random state UUID to use
|
||||||
_webAuthenticationStateSet.insert(stateUUID);
|
QUuid stateUUID = QUuid::createUuid();
|
||||||
|
|
||||||
QUrl authURL = oauthAuthorizationURL(stateUUID);
|
// add it to the set so we can handle the callback from the OAuth provider
|
||||||
|
_webAuthenticationStateSet.insert(stateUUID);
|
||||||
|
|
||||||
Headers redirectHeaders;
|
QUrl authURL = oauthAuthorizationURL(stateUUID);
|
||||||
|
|
||||||
redirectHeaders.insert("Location", authURL.toEncoded());
|
Headers redirectHeaders;
|
||||||
|
|
||||||
connection->respond(HTTPConnection::StatusCode302,
|
redirectHeaders.insert("Location", authURL.toEncoded());
|
||||||
QByteArray(), HTTPConnection::DefaultContentType, redirectHeaders);
|
|
||||||
|
connection->respond(HTTPConnection::StatusCode302,
|
||||||
|
QByteArray(), HTTPConnection::DefaultContentType, redirectHeaders);
|
||||||
|
}
|
||||||
|
|
||||||
// we don't know about this user yet, so they are not yet authenticated
|
// we don't know about this user yet, so they are not yet authenticated
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -111,6 +111,9 @@ private slots:
|
||||||
void updateDownstreamNodes();
|
void updateDownstreamNodes();
|
||||||
void updateUpstreamNodes();
|
void updateUpstreamNodes();
|
||||||
|
|
||||||
|
void tokenGrantFinished();
|
||||||
|
void profileRequestFinished();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void iceServerChanged();
|
void iceServerChanged();
|
||||||
void userConnected();
|
void userConnected();
|
||||||
|
@ -178,6 +181,8 @@ private:
|
||||||
|
|
||||||
void updateReplicationNodes(ReplicationServerDirection direction);
|
void updateReplicationNodes(ReplicationServerDirection direction);
|
||||||
|
|
||||||
|
HTTPSConnection* connectionFromReplyWithState(QNetworkReply* reply);
|
||||||
|
|
||||||
SubnetList _acSubnetWhitelist;
|
SubnetList _acSubnetWhitelist;
|
||||||
|
|
||||||
std::vector<QString> _replicatedUsernames;
|
std::vector<QString> _replicatedUsernames;
|
||||||
|
@ -235,6 +240,8 @@ private:
|
||||||
|
|
||||||
bool _sendICEServerAddressToMetaverseAPIInProgress { false };
|
bool _sendICEServerAddressToMetaverseAPIInProgress { false };
|
||||||
bool _sendICEServerAddressToMetaverseAPIRedo { false };
|
bool _sendICEServerAddressToMetaverseAPIRedo { false };
|
||||||
|
|
||||||
|
QHash<QUuid, QPointer<HTTPSConnection>> _pendingOAuthConnections;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1198,6 +1198,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
static const QString SECURITY_ROOT_KEY = "security";
|
static const QString SECURITY_ROOT_KEY = "security";
|
||||||
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
||||||
static const QString BROADCASTING_KEY = "broadcasting";
|
static const QString BROADCASTING_KEY = "broadcasting";
|
||||||
|
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
|
||||||
|
|
||||||
auto& settingsVariant = _configMap.getConfig();
|
auto& settingsVariant = _configMap.getConfig();
|
||||||
bool needRestart = false;
|
bool needRestart = false;
|
||||||
|
@ -1249,7 +1250,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
|
|
||||||
if (!matchingDescriptionObject.isEmpty()) {
|
if (!matchingDescriptionObject.isEmpty()) {
|
||||||
updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject);
|
updateSetting(rootKey, rootValue, *thisMap, matchingDescriptionObject);
|
||||||
if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY) {
|
if (rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != SETTINGS_PATHS_KEY ) {
|
||||||
needRestart = true;
|
needRestart = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -1265,7 +1266,7 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
||||||
if (!matchingDescriptionObject.isEmpty()) {
|
if (!matchingDescriptionObject.isEmpty()) {
|
||||||
const QJsonValue& settingValue = rootValue.toObject()[settingKey];
|
const QJsonValue& settingValue = rootValue.toObject()[settingKey];
|
||||||
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
|
updateSetting(settingKey, settingValue, *thisMap, matchingDescriptionObject);
|
||||||
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY)
|
if ((rootKey != SECURITY_ROOT_KEY && rootKey != BROADCASTING_KEY && rootKey != DESCRIPTION_ROOT_KEY)
|
||||||
|| settingKey == AC_SUBNET_WHITELIST_KEY) {
|
|| settingKey == AC_SUBNET_WHITELIST_KEY) {
|
||||||
needRestart = true;
|
needRestart = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,36 +34,32 @@
|
||||||
{ "from": "Vive.RSCenter", "to": "Standard.RightPrimaryThumb" },
|
{ "from": "Vive.RSCenter", "to": "Standard.RightPrimaryThumb" },
|
||||||
{ "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" },
|
{ "from": "Vive.RightApplicationMenu", "to": "Standard.RightSecondaryThumb" },
|
||||||
|
|
||||||
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand", "when": [ "Application.InHMD" ] },
|
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand"},
|
||||||
{ "from": "Vive.RightHand", "to": "Standard.RightHand", "when": [ "Application.InHMD" ] },
|
{ "from": "Vive.RightHand", "to": "Standard.RightHand"},
|
||||||
|
|
||||||
{
|
{
|
||||||
"from": "Vive.LeftFoot", "to" : "Standard.LeftFoot",
|
"from": "Vive.LeftFoot", "to" : "Standard.LeftFoot",
|
||||||
"filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}],
|
"filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}]
|
||||||
"when": [ "Application.InHMD" ]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"from": "Vive.RightFoot", "to" : "Standard.RightFoot",
|
"from": "Vive.RightFoot", "to" : "Standard.RightFoot",
|
||||||
"filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}],
|
"filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}]
|
||||||
"when": [ "Application.InHMD" ]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"from": "Vive.Hips", "to" : "Standard.Hips",
|
"from": "Vive.Hips", "to" : "Standard.Hips",
|
||||||
"filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}],
|
"filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}]
|
||||||
"when": [ "Application.InHMD" ]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"from": "Vive.Spine2", "to" : "Standard.Spine2",
|
"from": "Vive.Spine2", "to" : "Standard.Spine2",
|
||||||
"filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}],
|
"filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}]
|
||||||
"when": [ "Application.InHMD" ]
|
|
||||||
},
|
},
|
||||||
|
|
||||||
{ "from": "Vive.Head", "to" : "Standard.Head", "when": [ "Application.InHMD" ] },
|
{ "from": "Vive.Head", "to" : "Standard.Head"},
|
||||||
|
|
||||||
{ "from": "Vive.RightArm", "to" : "Standard.RightArm", "when": [ "Application.InHMD" ] },
|
{ "from": "Vive.RightArm", "to" : "Standard.RightArm"},
|
||||||
{ "from": "Vive.LeftArm", "to" : "Standard.LeftArm", "when": [ "Application.InHMD" ] }
|
{ "from": "Vive.LeftArm", "to" : "Standard.LeftArm"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
BIN
interface/resources/images/calibration-help.png
Normal file
BIN
interface/resources/images/calibration-help.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
64
interface/resources/qml/controls-uit/ImageMessageBox.qml
Normal file
64
interface/resources/qml/controls-uit/ImageMessageBox.qml
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// ImageMessageBox.qml
|
||||||
|
//
|
||||||
|
// Created by Dante Ruiz on 7/5/2017
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
import QtQuick 2.5
|
||||||
|
import QtQuick.Controls 1.4
|
||||||
|
import "../styles-uit"
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: imageBox
|
||||||
|
visible: false
|
||||||
|
anchors.fill: parent
|
||||||
|
property alias source: image.source
|
||||||
|
property alias imageWidth: image.width
|
||||||
|
property alias imageHeight: image.height
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: "black"
|
||||||
|
opacity: 0.3
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: image
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
HiFiGlyphs {
|
||||||
|
id: closeGlyphButton
|
||||||
|
text: hifi.glyphs.close
|
||||||
|
size: 25
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: 15
|
||||||
|
right: parent.right
|
||||||
|
rightMargin: 15
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
onEntered: {
|
||||||
|
parent.text = hifi.glyphs.closeInverted;
|
||||||
|
}
|
||||||
|
|
||||||
|
onExited: {
|
||||||
|
parent.text = hifi.glyphs.close;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
imageBox.visible = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -65,7 +65,7 @@ Rectangle {
|
||||||
|
|
||||||
HiFiGlyphs {
|
HiFiGlyphs {
|
||||||
id: image
|
id: image
|
||||||
text: hifi.glyphs.avatar1
|
text: hifi.glyphs.avatarTPose
|
||||||
size: 190
|
size: 190
|
||||||
color: hifi.colors.white
|
color: hifi.colors.white
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ import "../../controls-uit" as HifiControls
|
||||||
StackView {
|
StackView {
|
||||||
id: stack
|
id: stack
|
||||||
initialItem: inputConfiguration
|
initialItem: inputConfiguration
|
||||||
|
property alias messageVisible: imageMessageBox.visible
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: inputConfiguration
|
id: inputConfiguration
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -26,6 +27,15 @@ StackView {
|
||||||
|
|
||||||
property var pluginSettings: null
|
property var pluginSettings: null
|
||||||
|
|
||||||
|
HifiControls.ImageMessageBox {
|
||||||
|
id: imageMessageBox
|
||||||
|
anchors.fill: parent
|
||||||
|
z: 2000
|
||||||
|
imageWidth: 442
|
||||||
|
imageHeight: 670
|
||||||
|
source: "../../../images/calibration-help.png"
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: inputConfiguration.width
|
width: inputConfiguration.width
|
||||||
height: 1
|
height: 1
|
||||||
|
@ -167,7 +177,7 @@ StackView {
|
||||||
loader.item.pluginName = box.currentText;
|
loader.item.pluginName = box.currentText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loader.item.hasOwnProperty("displayInformation")) {
|
if (loader.item.hasOwnProperty("displayInformation")) {
|
||||||
loader.item.displayConfiguration();
|
loader.item.displayConfiguration();
|
||||||
}
|
}
|
||||||
|
@ -183,20 +193,20 @@ StackView {
|
||||||
return InputConfiguration.activeInputPlugins();
|
return InputConfiguration.activeInputPlugins();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
changeSource();
|
changeSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeSource() {
|
function changeSource() {
|
||||||
loader.source = "";
|
loader.source = "";
|
||||||
var source = "";
|
var source = "";
|
||||||
if (box.currentText == "Vive") {
|
if (box.currentText == "Vive") {
|
||||||
source = InputConfiguration.configurationLayout("OpenVR");
|
source = InputConfiguration.configurationLayout("OpenVR");
|
||||||
} else {
|
} else {
|
||||||
source = InputConfiguration.configurationLayout(box.currentText);
|
source = InputConfiguration.configurationLayout(box.currentText);
|
||||||
}
|
}
|
||||||
|
|
||||||
loader.source = source;
|
loader.source = source;
|
||||||
if (source === "") {
|
if (source === "") {
|
||||||
box.label = "(not configurable)";
|
box.label = "(not configurable)";
|
||||||
|
@ -204,14 +214,14 @@ StackView {
|
||||||
box.label = "";
|
box.label = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: timer
|
id: timer
|
||||||
repeat: false
|
repeat: false
|
||||||
interval: 300
|
interval: 300
|
||||||
onTriggered: initialize()
|
onTriggered: initialize()
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
timer.start();
|
timer.start();
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,9 +50,12 @@ Rectangle {
|
||||||
readonly property int apply: 1
|
readonly property int apply: 1
|
||||||
readonly property int applyAndCalibrate: 2
|
readonly property int applyAndCalibrate: 2
|
||||||
readonly property int calibrate: 3
|
readonly property int calibrate: 3
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mouseArea
|
id: mouseArea
|
||||||
|
@ -64,6 +67,7 @@ Rectangle {
|
||||||
mouse.accepted = false;
|
mouse.accepted = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
color: hifi.colors.baseGray
|
color: hifi.colors.baseGray
|
||||||
|
|
||||||
RalewayBold {
|
RalewayBold {
|
||||||
|
@ -146,6 +150,7 @@ Rectangle {
|
||||||
label: "Y: offset"
|
label: "Y: offset"
|
||||||
minimumValue: -10
|
minimumValue: -10
|
||||||
stepSize: 0.0254
|
stepSize: 0.0254
|
||||||
|
value: -0.05
|
||||||
colorScheme: hifi.colorSchemes.dark
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
|
@ -161,15 +166,16 @@ Rectangle {
|
||||||
minimumValue: -10
|
minimumValue: -10
|
||||||
stepSize: 0.0254
|
stepSize: 0.0254
|
||||||
decimals: 4
|
decimals: 4
|
||||||
|
value: -0.05
|
||||||
colorScheme: hifi.colorSchemes.dark
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
sendConfigurationSettings();
|
sendConfigurationSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RalewayBold {
|
RalewayBold {
|
||||||
id: hands
|
id: hands
|
||||||
|
|
||||||
|
@ -245,7 +251,7 @@ Rectangle {
|
||||||
anchors.left: openVrConfiguration.left
|
anchors.left: openVrConfiguration.left
|
||||||
anchors.leftMargin: leftMargin + 10
|
anchors.leftMargin: leftMargin + 10
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
HifiControls.SpinBox {
|
HifiControls.SpinBox {
|
||||||
id: handYOffset
|
id: handYOffset
|
||||||
decimals: 4
|
decimals: 4
|
||||||
|
@ -269,7 +275,7 @@ Rectangle {
|
||||||
stepSize: 0.0254
|
stepSize: 0.0254
|
||||||
decimals: 4
|
decimals: 4
|
||||||
colorScheme: hifi.colorSchemes.dark
|
colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
sendConfigurationSettings();
|
sendConfigurationSettings();
|
||||||
}
|
}
|
||||||
|
@ -290,6 +296,52 @@ Rectangle {
|
||||||
anchors.leftMargin: leftMargin
|
anchors.leftMargin: leftMargin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RalewayRegular {
|
||||||
|
id: info
|
||||||
|
|
||||||
|
text: "See Recommended Tracker Placement"
|
||||||
|
color: hifi.colors.blueHighlight
|
||||||
|
size: 10
|
||||||
|
anchors {
|
||||||
|
left: additional.right
|
||||||
|
leftMargin: 10
|
||||||
|
verticalCenter: additional.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: selected
|
||||||
|
color: hifi.colors.blueHighlight
|
||||||
|
|
||||||
|
width: info.width
|
||||||
|
height: 1
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: info.bottom
|
||||||
|
topMargin: 1
|
||||||
|
left: info.left
|
||||||
|
right: info.right
|
||||||
|
}
|
||||||
|
|
||||||
|
visible: false
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent;
|
||||||
|
hoverEnabled: true
|
||||||
|
|
||||||
|
onEntered: {
|
||||||
|
selected.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onExited: {
|
||||||
|
selected.visible = false;
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
stack.messageVisible = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: feetConfig
|
id: feetConfig
|
||||||
anchors.top: additional.bottom
|
anchors.top: additional.bottom
|
||||||
|
@ -379,6 +431,7 @@ Rectangle {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
hipBox.checked = true;
|
hipBox.checked = true;
|
||||||
feetBox.checked = true;
|
feetBox.checked = true;
|
||||||
|
shoulderBox.checked = false;
|
||||||
}
|
}
|
||||||
sendConfigurationSettings();
|
sendConfigurationSettings();
|
||||||
}
|
}
|
||||||
|
@ -416,6 +469,7 @@ Rectangle {
|
||||||
if (checked) {
|
if (checked) {
|
||||||
hipBox.checked = true;
|
hipBox.checked = true;
|
||||||
feetBox.checked = true;
|
feetBox.checked = true;
|
||||||
|
chestBox.checked = false;
|
||||||
}
|
}
|
||||||
sendConfigurationSettings();
|
sendConfigurationSettings();
|
||||||
}
|
}
|
||||||
|
@ -463,7 +517,7 @@ Rectangle {
|
||||||
anchors.leftMargin: leftMargin
|
anchors.leftMargin: leftMargin
|
||||||
|
|
||||||
radius: hifi.buttons.radius
|
radius: hifi.buttons.radius
|
||||||
|
|
||||||
gradient: Gradient {
|
gradient: Gradient {
|
||||||
GradientStop {
|
GradientStop {
|
||||||
position: 0.2
|
position: 0.2
|
||||||
|
@ -479,7 +533,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GradientStop {
|
GradientStop {
|
||||||
position: 1.0
|
position: 1.0
|
||||||
color: {
|
color: {
|
||||||
|
@ -495,10 +549,10 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
HiFiGlyphs {
|
HiFiGlyphs {
|
||||||
id: glyphButton
|
id: glyphButton
|
||||||
color: enabled ? hifi.buttons.textColor[calibrationButton.color]
|
color: enabled ? hifi.buttons.textColor[calibrationButton.color]
|
||||||
|
@ -512,7 +566,7 @@ Rectangle {
|
||||||
bottomMargin: 1
|
bottomMargin: 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RalewayBold {
|
RalewayBold {
|
||||||
id: calibrationText
|
id: calibrationText
|
||||||
font.capitalization: Font.AllUppercase
|
font.capitalization: Font.AllUppercase
|
||||||
|
@ -527,7 +581,7 @@ Rectangle {
|
||||||
topMargin: 7
|
topMargin: 7
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
@ -549,19 +603,19 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPressed: {
|
onPressed: {
|
||||||
calibrationButton.pressed = true;
|
calibrationButton.pressed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onReleased: {
|
onReleased: {
|
||||||
calibrationButton.pressed = false;
|
calibrationButton.pressed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onEntered: {
|
onEntered: {
|
||||||
calibrationButton.hovered = true;
|
calibrationButton.hovered = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
onExited: {
|
||||||
calibrationButton.hovered = false;
|
calibrationButton.hovered = false;
|
||||||
}
|
}
|
||||||
|
@ -642,6 +696,57 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Separator {
|
||||||
|
id: advanceSeperator
|
||||||
|
width: parent.width
|
||||||
|
anchors.top: timeToCalibrate.bottom
|
||||||
|
anchors.topMargin: 10
|
||||||
|
}
|
||||||
|
|
||||||
|
RalewayBold {
|
||||||
|
id: advanceSettings
|
||||||
|
|
||||||
|
text: "Advanced Settings"
|
||||||
|
size: 12
|
||||||
|
|
||||||
|
color: hifi.colors.white
|
||||||
|
|
||||||
|
anchors.top: advanceSeperator.bottom
|
||||||
|
anchors.topMargin: 10
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: leftMargin
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HifiControls.CheckBox {
|
||||||
|
id: viveInDesktop
|
||||||
|
width: 15
|
||||||
|
height: 15
|
||||||
|
boxRadius: 7
|
||||||
|
|
||||||
|
anchors.top: advanceSettings.bottom
|
||||||
|
anchors.topMargin: 5
|
||||||
|
anchors.left: openVrConfiguration.left
|
||||||
|
anchors.leftMargin: leftMargin + 10
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
sendConfigurationSettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RalewayBold {
|
||||||
|
id: viveDesktopText
|
||||||
|
size: 10
|
||||||
|
text: "Use Vive devices in desktop mode"
|
||||||
|
color: hifi.colors.white
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
left: viveInDesktop.right
|
||||||
|
leftMargin: 5
|
||||||
|
verticalCenter: viveInDesktop.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
id: numberAnimation
|
id: numberAnimation
|
||||||
target: openVrConfiguration
|
target: openVrConfiguration
|
||||||
|
@ -667,14 +772,14 @@ Rectangle {
|
||||||
calibratingScreen = screen.createObject();
|
calibratingScreen = screen.createObject();
|
||||||
stack.push(calibratingScreen);
|
stack.push(calibratingScreen);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status["calibrated"]) {
|
if (status["calibrated"]) {
|
||||||
calibrationScreen.success();
|
calibrationScreen.success();
|
||||||
|
|
||||||
if (status["UI"]) {
|
if (status["UI"]) {
|
||||||
logAction("mocap_ui_success", status);
|
logAction("mocap_ui_success", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (!status["calibrated"]) {
|
} else if (!status["calibrated"]) {
|
||||||
calibrationScreen.failure();
|
calibrationScreen.failure();
|
||||||
|
|
||||||
|
@ -728,6 +833,7 @@ Rectangle {
|
||||||
|
|
||||||
var HmdHead = settings["HMDHead"];
|
var HmdHead = settings["HMDHead"];
|
||||||
var viveController = settings["handController"];
|
var viveController = settings["handController"];
|
||||||
|
var desktopMode = settings["desktopMode"];
|
||||||
|
|
||||||
if (HmdHead) {
|
if (HmdHead) {
|
||||||
headBox.checked = true;
|
headBox.checked = true;
|
||||||
|
@ -745,6 +851,8 @@ Rectangle {
|
||||||
handBox.checked = false;
|
handBox.checked = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
viveInDesktop.checked = desktopMode;
|
||||||
|
|
||||||
initializeButtonState();
|
initializeButtonState();
|
||||||
updateCalibrationText();
|
updateCalibrationText();
|
||||||
|
|
||||||
|
@ -786,11 +894,11 @@ Rectangle {
|
||||||
var handOverride = handSetting["override"];
|
var handOverride = handSetting["override"];
|
||||||
|
|
||||||
var settingsChanged = false;
|
var settingsChanged = false;
|
||||||
|
|
||||||
if (lastConfiguration["bodyConfiguration"] !== bodySetting) {
|
if (lastConfiguration["bodyConfiguration"] !== bodySetting) {
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var lastHead = lastConfiguration["headConfiguration"];
|
var lastHead = lastConfiguration["headConfiguration"];
|
||||||
if (lastHead["override"] !== headOverride) {
|
if (lastHead["override"] !== headOverride) {
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
|
@ -800,13 +908,13 @@ Rectangle {
|
||||||
if (lastHand["override"] !== handOverride) {
|
if (lastHand["override"] !== handOverride) {
|
||||||
settingsChanged = true;
|
settingsChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingsChanged) {
|
if (settingsChanged) {
|
||||||
if ((!handOverride) && (!headOverride) && (bodySetting === "None")) {
|
if ((!handOverride) && (!headOverride) && (bodySetting === "None")) {
|
||||||
state = buttonState.apply;
|
state = buttonState.apply;
|
||||||
} else {
|
} else {
|
||||||
state = buttonState.applyAndCalibrate;
|
state = buttonState.applyAndCalibrate;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (state == buttonState.apply) {
|
if (state == buttonState.apply) {
|
||||||
state = buttonState.disabled;
|
state = buttonState.disabled;
|
||||||
|
@ -814,7 +922,7 @@ Rectangle {
|
||||||
state = buttonState.calibrate;
|
state = buttonState.calibrate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lastConfiguration = settings;
|
lastConfiguration = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,7 +939,7 @@ Rectangle {
|
||||||
state = buttonState.disabled;
|
state = buttonState.disabled;
|
||||||
} else {
|
} else {
|
||||||
state = buttonState.calibrate;
|
state = buttonState.calibrate;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateCalibrationButton() {
|
function updateCalibrationButton() {
|
||||||
|
@ -897,11 +1005,12 @@ Rectangle {
|
||||||
"Y": handYOffset.value,
|
"Y": handYOffset.value,
|
||||||
"Z": handZOffset.value
|
"Z": handZOffset.value
|
||||||
}
|
}
|
||||||
|
|
||||||
var settingsObject = {
|
var settingsObject = {
|
||||||
"bodyConfiguration": trackerConfiguration,
|
"bodyConfiguration": trackerConfiguration,
|
||||||
"headConfiguration": headObject,
|
"headConfiguration": headObject,
|
||||||
"handConfiguration": handObject
|
"handConfiguration": handObject,
|
||||||
|
"desktopMode": viveInDesktop.checked
|
||||||
}
|
}
|
||||||
|
|
||||||
return settingsObject;
|
return settingsObject;
|
||||||
|
|
|
@ -94,10 +94,20 @@ StackView {
|
||||||
property bool keyboardEnabled: false
|
property bool keyboardEnabled: false
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
propagateComposedEvents: true
|
||||||
|
onPressed: {
|
||||||
|
parent.forceActiveFocus();
|
||||||
|
addressBarDialog.keyboardEnabled = false;
|
||||||
|
mouse.accepted = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
right: parent.right
|
right: parent.right
|
||||||
left: parent.left
|
left: parent.left
|
||||||
|
@ -227,9 +237,9 @@ StackView {
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent;
|
anchors.fill: parent;
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!addressLine.focus || !HMD.active) {
|
addressLine.focus = true;
|
||||||
addressLine.focus = true;
|
addressLine.forceActiveFocus();
|
||||||
addressLine.forceActiveFocus();
|
if (HMD.active) {
|
||||||
addressBarDialog.keyboardEnabled = HMD.active;
|
addressBarDialog.keyboardEnabled = HMD.active;
|
||||||
}
|
}
|
||||||
tabletRoot.playButtonClickSound();
|
tabletRoot.playButtonClickSound();
|
||||||
|
|
|
@ -52,8 +52,10 @@ Windows.ScrollingWindow {
|
||||||
|
|
||||||
// used to receive messages from interface script
|
// used to receive messages from interface script
|
||||||
function fromScript(message) {
|
function fromScript(message) {
|
||||||
if (loader.item.hasOwnProperty("fromScript")) {
|
if (loader.item !== null) {
|
||||||
loader.item.fromScript(message);
|
if (loader.item.hasOwnProperty("fromScript")) {
|
||||||
|
loader.item.fromScript(message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -336,5 +336,6 @@ Item {
|
||||||
readonly property string source: "\ue01c"
|
readonly property string source: "\ue01c"
|
||||||
readonly property string playback_play: "\ue01d"
|
readonly property string playback_play: "\ue01d"
|
||||||
readonly property string stop_square: "\ue01e"
|
readonly property string stop_square: "\ue01e"
|
||||||
|
readonly property string avatarTPose: "\ue01f"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <QtCore/QCommandLineParser>
|
#include <QtCore/QCommandLineParser>
|
||||||
#include <QtCore/QMimeData>
|
#include <QtCore/QMimeData>
|
||||||
#include <QtCore/QThreadPool>
|
#include <QtCore/QThreadPool>
|
||||||
|
#include <QtConcurrent/QtConcurrentRun>
|
||||||
|
|
||||||
#include <QtGui/QScreen>
|
#include <QtGui/QScreen>
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
|
@ -480,6 +481,12 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
||||||
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
|
static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset";
|
||||||
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
|
bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET);
|
||||||
bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt);
|
||||||
|
// get dir to use for cache
|
||||||
|
static const auto CACHE_SWITCH = "--cache";
|
||||||
|
QString cacheDir = getCmdOption(argc, const_cast<const char**>(argv), CACHE_SWITCH);
|
||||||
|
if (!cacheDir.isEmpty()) {
|
||||||
|
qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir);
|
||||||
|
}
|
||||||
|
|
||||||
Setting::init();
|
Setting::init();
|
||||||
|
|
||||||
|
@ -945,58 +952,68 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
// Make sure we don't time out during slow operations at startup
|
// Make sure we don't time out during slow operations at startup
|
||||||
updateHeartbeat();
|
updateHeartbeat();
|
||||||
|
|
||||||
|
|
||||||
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
|
|
||||||
// The value will be 0 if the user blew away settings this session, which is both a feature and a bug.
|
|
||||||
static const QString TESTER = "HIFI_TESTER";
|
|
||||||
auto gpuIdent = GPUIdent::getInstance();
|
|
||||||
auto glContextData = getGLContextData();
|
|
||||||
QJsonObject properties = {
|
|
||||||
{ "version", applicationVersion() },
|
|
||||||
{ "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) },
|
|
||||||
{ "previousSessionCrashed", _previousSessionCrashed },
|
|
||||||
{ "previousSessionRuntime", sessionRunTime.get() },
|
|
||||||
{ "cpu_architecture", QSysInfo::currentCpuArchitecture() },
|
|
||||||
{ "kernel_type", QSysInfo::kernelType() },
|
|
||||||
{ "kernel_version", QSysInfo::kernelVersion() },
|
|
||||||
{ "os_type", QSysInfo::productType() },
|
|
||||||
{ "os_version", QSysInfo::productVersion() },
|
|
||||||
{ "gpu_name", gpuIdent->getName() },
|
|
||||||
{ "gpu_driver", gpuIdent->getDriver() },
|
|
||||||
{ "gpu_memory", static_cast<qint64>(gpuIdent->getMemory()) },
|
|
||||||
{ "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) },
|
|
||||||
{ "gl_version", glContextData["version"] },
|
|
||||||
{ "gl_vender", glContextData["vendor"] },
|
|
||||||
{ "gl_sl_version", glContextData["sl_version"] },
|
|
||||||
{ "gl_renderer", glContextData["renderer"] },
|
|
||||||
{ "ideal_thread_count", QThread::idealThreadCount() }
|
|
||||||
};
|
|
||||||
auto macVersion = QSysInfo::macVersion();
|
|
||||||
if (macVersion != QSysInfo::MV_None) {
|
|
||||||
properties["os_osx_version"] = QSysInfo::macVersion();
|
|
||||||
}
|
|
||||||
auto windowsVersion = QSysInfo::windowsVersion();
|
|
||||||
if (windowsVersion != QSysInfo::WV_None) {
|
|
||||||
properties["os_win_version"] = QSysInfo::windowsVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessorInfo procInfo;
|
|
||||||
if (getProcessorInfo(procInfo)) {
|
|
||||||
properties["processor_core_count"] = procInfo.numProcessorCores;
|
|
||||||
properties["logical_processor_count"] = procInfo.numLogicalProcessors;
|
|
||||||
properties["processor_l1_cache_count"] = procInfo.numProcessorCachesL1;
|
|
||||||
properties["processor_l2_cache_count"] = procInfo.numProcessorCachesL2;
|
|
||||||
properties["processor_l3_cache_count"] = procInfo.numProcessorCachesL3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add firstRun flag from settings to launch event
|
|
||||||
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
||||||
properties["first_run"] = firstRun.get();
|
|
||||||
|
|
||||||
// add the user's machine ID to the launch event
|
// once the settings have been loaded, check if we need to flip the default for UserActivityLogger
|
||||||
properties["machine_fingerprint"] = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint());
|
auto& userActivityLogger = UserActivityLogger::getInstance();
|
||||||
|
if (!userActivityLogger.isDisabledSettingSet()) {
|
||||||
|
// the user activity logger is opt-out for Interface
|
||||||
|
// but it's defaulted to disabled for other targets
|
||||||
|
// so we need to enable it here if it has never been disabled by the user
|
||||||
|
userActivityLogger.disable(false);
|
||||||
|
}
|
||||||
|
|
||||||
UserActivityLogger::getInstance().logAction("launch", properties);
|
if (userActivityLogger.isEnabled()) {
|
||||||
|
// sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value.
|
||||||
|
// The value will be 0 if the user blew away settings this session, which is both a feature and a bug.
|
||||||
|
static const QString TESTER = "HIFI_TESTER";
|
||||||
|
auto gpuIdent = GPUIdent::getInstance();
|
||||||
|
auto glContextData = getGLContextData();
|
||||||
|
QJsonObject properties = {
|
||||||
|
{ "version", applicationVersion() },
|
||||||
|
{ "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) },
|
||||||
|
{ "previousSessionCrashed", _previousSessionCrashed },
|
||||||
|
{ "previousSessionRuntime", sessionRunTime.get() },
|
||||||
|
{ "cpu_architecture", QSysInfo::currentCpuArchitecture() },
|
||||||
|
{ "kernel_type", QSysInfo::kernelType() },
|
||||||
|
{ "kernel_version", QSysInfo::kernelVersion() },
|
||||||
|
{ "os_type", QSysInfo::productType() },
|
||||||
|
{ "os_version", QSysInfo::productVersion() },
|
||||||
|
{ "gpu_name", gpuIdent->getName() },
|
||||||
|
{ "gpu_driver", gpuIdent->getDriver() },
|
||||||
|
{ "gpu_memory", static_cast<qint64>(gpuIdent->getMemory()) },
|
||||||
|
{ "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) },
|
||||||
|
{ "gl_version", glContextData["version"] },
|
||||||
|
{ "gl_vender", glContextData["vendor"] },
|
||||||
|
{ "gl_sl_version", glContextData["sl_version"] },
|
||||||
|
{ "gl_renderer", glContextData["renderer"] },
|
||||||
|
{ "ideal_thread_count", QThread::idealThreadCount() }
|
||||||
|
};
|
||||||
|
auto macVersion = QSysInfo::macVersion();
|
||||||
|
if (macVersion != QSysInfo::MV_None) {
|
||||||
|
properties["os_osx_version"] = QSysInfo::macVersion();
|
||||||
|
}
|
||||||
|
auto windowsVersion = QSysInfo::windowsVersion();
|
||||||
|
if (windowsVersion != QSysInfo::WV_None) {
|
||||||
|
properties["os_win_version"] = QSysInfo::windowsVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessorInfo procInfo;
|
||||||
|
if (getProcessorInfo(procInfo)) {
|
||||||
|
properties["processor_core_count"] = procInfo.numProcessorCores;
|
||||||
|
properties["logical_processor_count"] = procInfo.numLogicalProcessors;
|
||||||
|
properties["processor_l1_cache_count"] = procInfo.numProcessorCachesL1;
|
||||||
|
properties["processor_l2_cache_count"] = procInfo.numProcessorCachesL2;
|
||||||
|
properties["processor_l3_cache_count"] = procInfo.numProcessorCachesL3;
|
||||||
|
}
|
||||||
|
|
||||||
|
properties["first_run"] = firstRun.get();
|
||||||
|
|
||||||
|
// add the user's machine ID to the launch event
|
||||||
|
properties["machine_fingerprint"] = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint());
|
||||||
|
|
||||||
|
userActivityLogger.logAction("launch", properties);
|
||||||
|
}
|
||||||
|
|
||||||
// Tell our entity edit sender about our known jurisdictions
|
// Tell our entity edit sender about our known jurisdictions
|
||||||
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
|
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
|
||||||
|
@ -1218,8 +1235,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
||||||
settingsTimer->stop();
|
settingsTimer->stop();
|
||||||
// Delete it (this will trigger the thread destruction
|
// Delete it (this will trigger the thread destruction
|
||||||
settingsTimer->deleteLater();
|
settingsTimer->deleteLater();
|
||||||
// Mark the settings thread as finished, so we know we can safely save in the main application
|
// Mark the settings thread as finished, so we know we can safely save in the main application
|
||||||
// shutdown code
|
// shutdown code
|
||||||
_settingsGuard.trigger();
|
_settingsGuard.trigger();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2164,48 +2181,74 @@ void Application::paintGL() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto displayPlugin = getActiveDisplayPlugin();
|
DisplayPluginPointer displayPlugin;
|
||||||
// FIXME not needed anymore?
|
{
|
||||||
_offscreenContext->makeCurrent();
|
PROFILE_RANGE(render, "/getActiveDisplayPlugin");
|
||||||
|
displayPlugin = getActiveDisplayPlugin();
|
||||||
|
}
|
||||||
|
|
||||||
// If a display plugin loses it's underlying support, it
|
{
|
||||||
// needs to be able to signal us to not use it
|
PROFILE_RANGE(render, "/offscreenMakeCurrent");
|
||||||
if (!displayPlugin->beginFrameRender(_frameCount)) {
|
// FIXME not needed anymore?
|
||||||
_inPaint = false;
|
_offscreenContext->makeCurrent();
|
||||||
updateDisplayMode();
|
}
|
||||||
return;
|
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/pluginBeginFrameRender");
|
||||||
|
// If a display plugin loses it's underlying support, it
|
||||||
|
// needs to be able to signal us to not use it
|
||||||
|
if (!displayPlugin->beginFrameRender(_frameCount)) {
|
||||||
|
_inPaint = false;
|
||||||
|
updateDisplayMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the avatar with a fresh HMD pose
|
// update the avatar with a fresh HMD pose
|
||||||
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
|
{
|
||||||
|
PROFILE_RANGE(render, "/updateAvatar");
|
||||||
|
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
|
||||||
|
}
|
||||||
|
|
||||||
auto lodManager = DependencyManager::get<LODManager>();
|
auto lodManager = DependencyManager::get<LODManager>();
|
||||||
|
|
||||||
|
RenderArgs renderArgs;
|
||||||
{
|
{
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
PROFILE_RANGE(render, "/buildFrustrumAndArgs");
|
||||||
_viewFrustum.calculate();
|
{
|
||||||
}
|
QMutexLocker viewLocker(&_viewMutex);
|
||||||
RenderArgs renderArgs(_gpuContext, getEntities(), lodManager->getOctreeSizeScale(),
|
_viewFrustum.calculate();
|
||||||
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
|
}
|
||||||
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
renderArgs = RenderArgs(_gpuContext, getEntities(), lodManager->getOctreeSizeScale(),
|
||||||
{
|
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
||||||
renderArgs.setViewFrustum(_viewFrustum);
|
{
|
||||||
|
QMutexLocker viewLocker(&_viewMutex);
|
||||||
|
renderArgs.setViewFrustum(_viewFrustum);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
{
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
PROFILE_RANGE(render, "/resizeGL");
|
||||||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
||||||
resizeGL();
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
|
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||||
_gpuContext->beginFrame(getHMDSensorPose());
|
resizeGL();
|
||||||
// Reset the gpu::Context Stages
|
}
|
||||||
// Back to the default framebuffer;
|
|
||||||
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) {
|
|
||||||
batch.resetStages();
|
|
||||||
});
|
|
||||||
|
|
||||||
{
|
{
|
||||||
|
PROFILE_RANGE(render, "/gpuContextReset");
|
||||||
|
_gpuContext->beginFrame(getHMDSensorPose());
|
||||||
|
// Reset the gpu::Context Stages
|
||||||
|
// Back to the default framebuffer;
|
||||||
|
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) {
|
||||||
|
batch.resetStages();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/renderOverlay");
|
||||||
PerformanceTimer perfTimer("renderOverlay");
|
PerformanceTimer perfTimer("renderOverlay");
|
||||||
// NOTE: There is no batch associated with this renderArgs
|
// NOTE: There is no batch associated with this renderArgs
|
||||||
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||||
|
@ -2216,114 +2259,127 @@ void Application::paintGL() {
|
||||||
|
|
||||||
glm::vec3 boomOffset;
|
glm::vec3 boomOffset;
|
||||||
{
|
{
|
||||||
PerformanceTimer perfTimer("CameraUpdates");
|
PROFILE_RANGE(render, "/updateCamera");
|
||||||
|
{
|
||||||
|
PerformanceTimer perfTimer("CameraUpdates");
|
||||||
|
|
||||||
auto myAvatar = getMyAvatar();
|
auto myAvatar = getMyAvatar();
|
||||||
boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
|
boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
|
||||||
|
|
||||||
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
|
Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN);
|
||||||
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN));
|
Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN));
|
||||||
cameraMenuChanged();
|
cameraMenuChanged();
|
||||||
}
|
|
||||||
|
|
||||||
// The render mode is default or mirror if the camera is in mirror mode, assigned further below
|
|
||||||
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
|
||||||
|
|
||||||
// Always use the default eye position, not the actual head eye position.
|
|
||||||
// Using the latter will cause the camera to wobble with idle animations,
|
|
||||||
// or with changes from the face tracker
|
|
||||||
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
|
||||||
if (isHMDMode()) {
|
|
||||||
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
|
||||||
_myCamera.setPosition(extractTranslation(camMat));
|
|
||||||
_myCamera.setOrientation(glm::quat_cast(camMat));
|
|
||||||
} else {
|
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
|
|
||||||
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
|
|
||||||
}
|
}
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
|
||||||
if (isHMDMode()) {
|
|
||||||
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
|
||||||
_myCamera.setOrientation(glm::normalize(glm::quat_cast(hmdWorldMat)));
|
|
||||||
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
|
|
||||||
myAvatar->getOrientation() * boomOffset);
|
|
||||||
} else {
|
|
||||||
_myCamera.setOrientation(myAvatar->getHead()->getOrientation());
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
|
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
|
||||||
+ _myCamera.getOrientation() * boomOffset);
|
|
||||||
} else {
|
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
|
||||||
+ myAvatar->getOrientation() * boomOffset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
|
||||||
if (isHMDMode()) {
|
|
||||||
auto mirrorBodyOrientation = myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f));
|
|
||||||
|
|
||||||
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix());
|
// The render mode is default or mirror if the camera is in mirror mode, assigned further below
|
||||||
// Mirror HMD yaw and roll
|
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||||
glm::vec3 mirrorHmdEulers = glm::eulerAngles(hmdRotation);
|
|
||||||
mirrorHmdEulers.y = -mirrorHmdEulers.y;
|
|
||||||
mirrorHmdEulers.z = -mirrorHmdEulers.z;
|
|
||||||
glm::quat mirrorHmdRotation = glm::quat(mirrorHmdEulers);
|
|
||||||
|
|
||||||
glm::quat worldMirrorRotation = mirrorBodyOrientation * mirrorHmdRotation;
|
// Always use the default eye position, not the actual head eye position.
|
||||||
|
// Using the latter will cause the camera to wobble with idle animations,
|
||||||
_myCamera.setOrientation(worldMirrorRotation);
|
// or with changes from the face tracker
|
||||||
|
if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
|
||||||
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
|
|
||||||
// Mirror HMD lateral offsets
|
|
||||||
hmdOffset.x = -hmdOffset.x;
|
|
||||||
|
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
|
||||||
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
|
|
||||||
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
|
|
||||||
+ mirrorBodyOrientation * hmdOffset);
|
|
||||||
} else {
|
|
||||||
_myCamera.setOrientation(myAvatar->getWorldAlignedOrientation()
|
|
||||||
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
|
||||||
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
|
|
||||||
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
|
||||||
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
|
||||||
}
|
|
||||||
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) {
|
|
||||||
EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer();
|
|
||||||
if (cameraEntity != nullptr) {
|
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix());
|
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||||
_myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation);
|
_myCamera.setPosition(extractTranslation(camMat));
|
||||||
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
|
_myCamera.setOrientation(glm::quat_cast(camMat));
|
||||||
_myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset));
|
|
||||||
} else {
|
} else {
|
||||||
_myCamera.setOrientation(cameraEntity->getRotation());
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
|
||||||
_myCamera.setPosition(cameraEntity->getPosition());
|
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
|
||||||
|
}
|
||||||
|
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||||
|
if (isHMDMode()) {
|
||||||
|
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||||
|
_myCamera.setOrientation(glm::normalize(glm::quat_cast(hmdWorldMat)));
|
||||||
|
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
|
||||||
|
myAvatar->getOrientation() * boomOffset);
|
||||||
|
} else {
|
||||||
|
_myCamera.setOrientation(myAvatar->getHead()->getOrientation());
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
|
||||||
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
|
+ _myCamera.getOrientation() * boomOffset);
|
||||||
|
} else {
|
||||||
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
|
+ myAvatar->getOrientation() * boomOffset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
|
if (isHMDMode()) {
|
||||||
|
auto mirrorBodyOrientation = myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f));
|
||||||
|
|
||||||
|
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix());
|
||||||
|
// Mirror HMD yaw and roll
|
||||||
|
glm::vec3 mirrorHmdEulers = glm::eulerAngles(hmdRotation);
|
||||||
|
mirrorHmdEulers.y = -mirrorHmdEulers.y;
|
||||||
|
mirrorHmdEulers.z = -mirrorHmdEulers.z;
|
||||||
|
glm::quat mirrorHmdRotation = glm::quat(mirrorHmdEulers);
|
||||||
|
|
||||||
|
glm::quat worldMirrorRotation = mirrorBodyOrientation * mirrorHmdRotation;
|
||||||
|
|
||||||
|
_myCamera.setOrientation(worldMirrorRotation);
|
||||||
|
|
||||||
|
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
|
||||||
|
// Mirror HMD lateral offsets
|
||||||
|
hmdOffset.x = -hmdOffset.x;
|
||||||
|
|
||||||
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
|
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
|
||||||
|
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
|
||||||
|
+ mirrorBodyOrientation * hmdOffset);
|
||||||
|
} else {
|
||||||
|
_myCamera.setOrientation(myAvatar->getWorldAlignedOrientation()
|
||||||
|
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
||||||
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
|
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
|
||||||
|
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
||||||
|
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
||||||
|
}
|
||||||
|
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
||||||
|
} else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) {
|
||||||
|
EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer();
|
||||||
|
if (cameraEntity != nullptr) {
|
||||||
|
if (isHMDMode()) {
|
||||||
|
glm::quat hmdRotation = extractRotation(myAvatar->getHMDSensorMatrix());
|
||||||
|
_myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation);
|
||||||
|
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
|
||||||
|
_myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset));
|
||||||
|
} else {
|
||||||
|
_myCamera.setOrientation(cameraEntity->getRotation());
|
||||||
|
_myCamera.setPosition(cameraEntity->getPosition());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// Update camera position
|
||||||
// Update camera position
|
if (!isHMDMode()) {
|
||||||
if (!isHMDMode()) {
|
_myCamera.update(1.0f / _frameCounter.rate());
|
||||||
_myCamera.update(1.0f / _frameCounter.rate());
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform());
|
{
|
||||||
|
PROFILE_RANGE(render, "/updateCompositor");
|
||||||
|
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform());
|
||||||
|
}
|
||||||
|
|
||||||
// Primary rendering pass
|
gpu::FramebufferPointer finalFramebuffer;
|
||||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
QSize finalFramebufferSize;
|
||||||
const QSize size = framebufferCache->getFrameBufferSize();
|
{
|
||||||
// Final framebuffer that will be handled to the display-plugin
|
PROFILE_RANGE(render, "/getOutputFramebuffer");
|
||||||
auto finalFramebuffer = framebufferCache->getFramebuffer();
|
// Primary rendering pass
|
||||||
|
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||||
|
finalFramebufferSize = framebufferCache->getFrameBufferSize();
|
||||||
|
// Final framebuffer that will be handled to the display-plugin
|
||||||
|
finalFramebuffer = framebufferCache->getFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(render, "/mainRender");
|
PROFILE_RANGE(render, "/mainRender");
|
||||||
PerformanceTimer perfTimer("mainRender");
|
PerformanceTimer perfTimer("mainRender");
|
||||||
renderArgs._boomOffset = boomOffset;
|
renderArgs._boomOffset = boomOffset;
|
||||||
|
// FIXME is this ever going to be different from the size previously set in the render args
|
||||||
|
// in the overlay render?
|
||||||
// Viewport is assigned to the size of the framebuffer
|
// Viewport is assigned to the size of the framebuffer
|
||||||
renderArgs._viewport = ivec4(0, 0, size.width(), size.height());
|
renderArgs._viewport = ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height());
|
||||||
if (displayPlugin->isStereo()) {
|
if (displayPlugin->isStereo()) {
|
||||||
// Stereo modes will typically have a larger projection matrix overall,
|
// Stereo modes will typically have a larger projection matrix overall,
|
||||||
// so we ask for the 'mono' projection matrix, which for stereo and HMD
|
// so we ask for the 'mono' projection matrix, which for stereo and HMD
|
||||||
|
@ -3623,6 +3679,133 @@ bool Application::shouldPaint(float nsecsElapsed) {
|
||||||
#include <TCHAR.h>
|
#include <TCHAR.h>
|
||||||
#include <pdh.h>
|
#include <pdh.h>
|
||||||
#pragma comment(lib, "pdh.lib")
|
#pragma comment(lib, "pdh.lib")
|
||||||
|
#pragma comment(lib, "ntdll.lib")
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
enum SYSTEM_INFORMATION_CLASS {
|
||||||
|
SystemBasicInformation = 0,
|
||||||
|
SystemProcessorPerformanceInformation = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
|
||||||
|
LARGE_INTEGER IdleTime;
|
||||||
|
LARGE_INTEGER KernelTime;
|
||||||
|
LARGE_INTEGER UserTime;
|
||||||
|
LARGE_INTEGER DpcTime;
|
||||||
|
LARGE_INTEGER InterruptTime;
|
||||||
|
ULONG InterruptCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SYSTEM_BASIC_INFORMATION {
|
||||||
|
ULONG Reserved;
|
||||||
|
ULONG TimerResolution;
|
||||||
|
ULONG PageSize;
|
||||||
|
ULONG NumberOfPhysicalPages;
|
||||||
|
ULONG LowestPhysicalPageNumber;
|
||||||
|
ULONG HighestPhysicalPageNumber;
|
||||||
|
ULONG AllocationGranularity;
|
||||||
|
ULONG_PTR MinimumUserModeAddress;
|
||||||
|
ULONG_PTR MaximumUserModeAddress;
|
||||||
|
ULONG_PTR ActiveProcessorsAffinityMask;
|
||||||
|
CCHAR NumberOfProcessors;
|
||||||
|
};
|
||||||
|
|
||||||
|
NTSYSCALLAPI NTSTATUS NTAPI NtQuerySystemInformation(
|
||||||
|
_In_ SYSTEM_INFORMATION_CLASS SystemInformationClass,
|
||||||
|
_Out_writes_bytes_opt_(SystemInformationLength) PVOID SystemInformation,
|
||||||
|
_In_ ULONG SystemInformationLength,
|
||||||
|
_Out_opt_ PULONG ReturnLength
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
template <typename T>
|
||||||
|
NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, T& t) {
|
||||||
|
return NtQuerySystemInformation(SystemInformationClass, &t, (ULONG)sizeof(T), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
NTSTATUS NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, std::vector<T>& t) {
|
||||||
|
return NtQuerySystemInformation(SystemInformationClass, t.data(), (ULONG)(sizeof(T) * t.size()), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void updateValueAndDelta(std::pair<T, T>& pair, T newValue) {
|
||||||
|
auto& value = pair.first;
|
||||||
|
auto& delta = pair.second;
|
||||||
|
delta = (value != 0) ? newValue - value : 0;
|
||||||
|
value = newValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MyCpuInfo {
|
||||||
|
using ValueAndDelta = std::pair<LONGLONG, LONGLONG>;
|
||||||
|
std::string name;
|
||||||
|
ValueAndDelta kernel { 0, 0 };
|
||||||
|
ValueAndDelta user { 0, 0 };
|
||||||
|
ValueAndDelta idle { 0, 0 };
|
||||||
|
float kernelUsage { 0.0f };
|
||||||
|
float userUsage { 0.0f };
|
||||||
|
|
||||||
|
void update(const SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION& cpuInfo) {
|
||||||
|
updateValueAndDelta(kernel, cpuInfo.KernelTime.QuadPart);
|
||||||
|
updateValueAndDelta(user, cpuInfo.UserTime.QuadPart);
|
||||||
|
updateValueAndDelta(idle, cpuInfo.IdleTime.QuadPart);
|
||||||
|
auto totalTime = kernel.second + user.second + idle.second;
|
||||||
|
if (totalTime != 0) {
|
||||||
|
kernelUsage = (FLOAT)kernel.second / totalTime;
|
||||||
|
userUsage = (FLOAT)user.second / totalTime;
|
||||||
|
} else {
|
||||||
|
kernelUsage = userUsage = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
void updateCpuInformation() {
|
||||||
|
static std::once_flag once;
|
||||||
|
static SYSTEM_BASIC_INFORMATION systemInfo {};
|
||||||
|
static SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION cpuTotals;
|
||||||
|
static std::vector<SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION> cpuInfos;
|
||||||
|
static std::vector<MyCpuInfo> myCpuInfos;
|
||||||
|
static MyCpuInfo myCpuTotals;
|
||||||
|
std::call_once(once, [&] {
|
||||||
|
NtQuerySystemInformation( SystemBasicInformation, systemInfo);
|
||||||
|
cpuInfos.resize(systemInfo.NumberOfProcessors);
|
||||||
|
myCpuInfos.resize(systemInfo.NumberOfProcessors);
|
||||||
|
for (size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) {
|
||||||
|
myCpuInfos[i].name = "cpu." + std::to_string(i);
|
||||||
|
}
|
||||||
|
myCpuTotals.name = "cpu.total";
|
||||||
|
});
|
||||||
|
NtQuerySystemInformation(SystemProcessorPerformanceInformation, cpuInfos);
|
||||||
|
|
||||||
|
// Zero the CPU totals.
|
||||||
|
memset(&cpuTotals, 0, sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION));
|
||||||
|
for (size_t i = 0; i < systemInfo.NumberOfProcessors; ++i) {
|
||||||
|
auto& cpuInfo = cpuInfos[i];
|
||||||
|
// KernelTime includes IdleTime.
|
||||||
|
cpuInfo.KernelTime.QuadPart -= cpuInfo.IdleTime.QuadPart;
|
||||||
|
|
||||||
|
// Update totals
|
||||||
|
cpuTotals.IdleTime.QuadPart += cpuInfo.IdleTime.QuadPart;
|
||||||
|
cpuTotals.KernelTime.QuadPart += cpuInfo.KernelTime.QuadPart;
|
||||||
|
cpuTotals.UserTime.QuadPart += cpuInfo.UserTime.QuadPart;
|
||||||
|
|
||||||
|
// Update friendly structure
|
||||||
|
auto& myCpuInfo = myCpuInfos[i];
|
||||||
|
myCpuInfo.update(cpuInfo);
|
||||||
|
PROFILE_COUNTER(app, myCpuInfo.name.c_str(), {
|
||||||
|
{ "kernel", myCpuInfo.kernelUsage },
|
||||||
|
{ "user", myCpuInfo.userUsage }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
myCpuTotals.update(cpuTotals);
|
||||||
|
PROFILE_COUNTER(app, myCpuTotals.name.c_str(), {
|
||||||
|
{ "kernel", myCpuTotals.kernelUsage },
|
||||||
|
{ "user", myCpuTotals.userUsage }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;
|
static ULARGE_INTEGER lastCPU, lastSysCPU, lastUserCPU;
|
||||||
static int numProcessors;
|
static int numProcessors;
|
||||||
|
@ -3675,6 +3858,26 @@ void getCpuUsage(vec3& systemAndUser) {
|
||||||
systemAndUser.z = (float)counterVal.doubleValue;
|
systemAndUser.z = (float)counterVal.doubleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setupCpuMonitorThread() {
|
||||||
|
initCpuUsage();
|
||||||
|
auto cpuMonitorThread = QThread::currentThread();
|
||||||
|
|
||||||
|
QTimer* timer = new QTimer();
|
||||||
|
timer->setInterval(50);
|
||||||
|
QObject::connect(timer, &QTimer::timeout, [] {
|
||||||
|
updateCpuInformation();
|
||||||
|
vec3 kernelUserAndSystem;
|
||||||
|
getCpuUsage(kernelUserAndSystem);
|
||||||
|
PROFILE_COUNTER(app, "cpuProcess", { { "system", kernelUserAndSystem.x }, { "user", kernelUserAndSystem.y } });
|
||||||
|
PROFILE_COUNTER(app, "cpuSystem", { { "system", kernelUserAndSystem.z } });
|
||||||
|
});
|
||||||
|
QObject::connect(cpuMonitorThread, &QThread::finished, [=] {
|
||||||
|
timer->deleteLater();
|
||||||
|
cpuMonitorThread->deleteLater();
|
||||||
|
});
|
||||||
|
timer->start();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -3695,15 +3898,17 @@ void Application::idle(float nsecsElapsed) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
|
// If tracing is enabled then monitor the CPU in a separate thread
|
||||||
static std::once_flag once;
|
static std::once_flag once;
|
||||||
std::call_once(once, [] {
|
std::call_once(once, [&] {
|
||||||
initCpuUsage();
|
if (trace_app().isDebugEnabled()) {
|
||||||
|
QThread* cpuMonitorThread = new QThread(qApp);
|
||||||
|
cpuMonitorThread->setObjectName("cpuMonitorThread");
|
||||||
|
QObject::connect(cpuMonitorThread, &QThread::started, [this] { setupCpuMonitorThread(); });
|
||||||
|
QObject::connect(qApp, &QCoreApplication::aboutToQuit, cpuMonitorThread, &QThread::quit);
|
||||||
|
cpuMonitorThread->start();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
vec3 kernelUserAndSystem;
|
|
||||||
getCpuUsage(kernelUserAndSystem);
|
|
||||||
PROFILE_COUNTER(app, "cpuProcess", { { "system", kernelUserAndSystem.x }, { "user", kernelUserAndSystem.y } });
|
|
||||||
PROFILE_COUNTER(app, "cpuSystem", { { "system", kernelUserAndSystem.z } });
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -299,7 +299,6 @@ public:
|
||||||
void setAvatarOverrideUrl(const QUrl& url, bool save);
|
void setAvatarOverrideUrl(const QUrl& url, bool save);
|
||||||
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
|
QUrl getAvatarOverrideUrl() { return _avatarOverrideUrl; }
|
||||||
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
|
bool getSaveAvatarOverrideUrl() { return _saveAvatarOverrideUrl; }
|
||||||
void setCacheOverrideDir(const QString& dirName) { _cacheDir = dirName; }
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void svoImportRequested(const QString& url);
|
void svoImportRequested(const QString& url);
|
||||||
|
@ -691,6 +690,5 @@ private:
|
||||||
QUrl _avatarOverrideUrl;
|
QUrl _avatarOverrideUrl;
|
||||||
bool _saveAvatarOverrideUrl { false };
|
bool _saveAvatarOverrideUrl { false };
|
||||||
|
|
||||||
QString _cacheDir;
|
|
||||||
};
|
};
|
||||||
#endif // hifi_Application_h
|
#endif // hifi_Application_h
|
||||||
|
|
|
@ -319,7 +319,7 @@ Menu::Menu() {
|
||||||
QString("../../hifi/tablet/TabletLodPreferences.qml"), "LodPreferencesDialog");
|
QString("../../hifi/tablet/TabletLodPreferences.qml"), "LodPreferencesDialog");
|
||||||
});
|
});
|
||||||
|
|
||||||
action = addActionToQMenuAndActionHash(settingsMenu, "Controller Settings");
|
action = addActionToQMenuAndActionHash(settingsMenu, "Controller Settings...");
|
||||||
connect(action, &QAction::triggered, [] {
|
connect(action, &QAction::triggered, [] {
|
||||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||||
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
auto hmd = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
|
|
@ -1634,7 +1634,8 @@ void MyAvatar::prepareForPhysicsSimulation() {
|
||||||
_characterController.setParentVelocity(parentVelocity);
|
_characterController.setParentVelocity(parentVelocity);
|
||||||
|
|
||||||
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
||||||
if (qApp->isHMDMode()) {
|
auto headPose = getHeadControllerPoseInAvatarFrame();
|
||||||
|
if (headPose.isValid()) {
|
||||||
_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput());
|
_follow.prePhysicsUpdate(*this, deriveBodyFromHMDSensor(), _bodySensorMatrix, hasDriveInput());
|
||||||
} else {
|
} else {
|
||||||
_follow.deactivate();
|
_follow.deactivate();
|
||||||
|
|
|
@ -101,7 +101,7 @@ int main(int argc, const char* argv[]) {
|
||||||
if (allowMultipleInstances) {
|
if (allowMultipleInstances) {
|
||||||
instanceMightBeRunning = false;
|
instanceMightBeRunning = false;
|
||||||
}
|
}
|
||||||
// this needs to be done here in main, as the mechanism for setting the
|
// this needs to be done here in main, as the mechanism for setting the
|
||||||
// scripts directory appears not to work. See the bug report
|
// scripts directory appears not to work. See the bug report
|
||||||
// https://highfidelity.fogbugz.com/f/cases/5759/Issues-changing-scripts-directory-in-ScriptsEngine
|
// https://highfidelity.fogbugz.com/f/cases/5759/Issues-changing-scripts-directory-in-ScriptsEngine
|
||||||
if (parser.isSet(overrideScriptsPathOption)) {
|
if (parser.isSet(overrideScriptsPathOption)) {
|
||||||
|
@ -111,20 +111,6 @@ int main(int argc, const char* argv[]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser.isSet(overrideAppLocalDataPathOption)) {
|
|
||||||
// get dir to use for cache
|
|
||||||
QString cacheDir = parser.value(overrideAppLocalDataPathOption);
|
|
||||||
if (!cacheDir.isEmpty()) {
|
|
||||||
// tell everyone to use the right cache location
|
|
||||||
//
|
|
||||||
// this handles data8 and prepared
|
|
||||||
DependencyManager::get<ResourceManager>()->setCacheDir(cacheDir);
|
|
||||||
|
|
||||||
// this does the ktx_cache
|
|
||||||
PathUtils::getAppLocalDataPath(cacheDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instanceMightBeRunning) {
|
if (instanceMightBeRunning) {
|
||||||
// Try to connect and send message to existing interface instance
|
// Try to connect and send message to existing interface instance
|
||||||
QLocalSocket socket;
|
QLocalSocket socket;
|
||||||
|
|
|
@ -67,19 +67,14 @@ void Overlays::init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Overlays::update(float deltatime) {
|
void Overlays::update(float deltatime) {
|
||||||
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
|
|
||||||
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
|
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&_mutex);
|
QMutexLocker locker(&_mutex);
|
||||||
overlaysHUD = _overlaysHUD;
|
foreach(const auto& thisOverlay, _overlaysHUD) {
|
||||||
overlaysWorld = _overlaysWorld;
|
thisOverlay->update(deltatime);
|
||||||
}
|
}
|
||||||
|
foreach(const auto& thisOverlay, _overlaysWorld) {
|
||||||
foreach(const auto& thisOverlay, overlaysHUD) {
|
thisOverlay->update(deltatime);
|
||||||
thisOverlay->update(deltatime);
|
}
|
||||||
}
|
|
||||||
foreach(const auto& thisOverlay, overlaysWorld) {
|
|
||||||
thisOverlay->update(deltatime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanupOverlaysToDelete();
|
cleanupOverlaysToDelete();
|
||||||
|
@ -119,14 +114,8 @@ void Overlays::renderHUD(RenderArgs* renderArgs) {
|
||||||
int height = size.y;
|
int height = size.y;
|
||||||
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);
|
mat4 legacyProjection = glm::ortho<float>(0, width, height, 0, -1000, 1000);
|
||||||
|
|
||||||
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
|
QMutexLocker locker(&_mutex);
|
||||||
{
|
foreach(Overlay::Pointer thisOverlay, _overlaysHUD) {
|
||||||
QMutexLocker locker(&_mutex);
|
|
||||||
overlaysHUD = _overlaysHUD;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
foreach(Overlay::Pointer thisOverlay, overlaysHUD) {
|
|
||||||
|
|
||||||
// Reset all batch pipeline settings between overlay
|
// Reset all batch pipeline settings between overlay
|
||||||
geometryCache->useSimpleDrawPipeline(batch);
|
geometryCache->useSimpleDrawPipeline(batch);
|
||||||
|
@ -318,6 +307,7 @@ void Overlays::deleteOverlay(OverlayID id) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
_overlaysToDelete.push_back(overlayToDelete);
|
_overlaysToDelete.push_back(overlayToDelete);
|
||||||
emit overlayDeleted(id);
|
emit overlayDeleted(id);
|
||||||
}
|
}
|
||||||
|
@ -400,36 +390,22 @@ OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 pointCopy = point;
|
|
||||||
if (!_enabled) {
|
if (!_enabled) {
|
||||||
return UNKNOWN_OVERLAY_ID;
|
return UNKNOWN_OVERLAY_ID;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<OverlayID, Overlay::Pointer> overlaysHUD;
|
QMutexLocker locker(&_mutex);
|
||||||
{
|
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysHUD);
|
||||||
QMutexLocker locker(&_mutex);
|
|
||||||
overlaysHUD = _overlaysHUD;
|
|
||||||
}
|
|
||||||
QMapIterator<OverlayID, Overlay::Pointer> i(overlaysHUD);
|
|
||||||
|
|
||||||
const float LARGE_NEGATIVE_FLOAT = -9999999;
|
|
||||||
glm::vec3 origin(pointCopy.x, pointCopy.y, LARGE_NEGATIVE_FLOAT);
|
|
||||||
glm::vec3 direction(0, 0, 1);
|
|
||||||
glm::vec3 thisSurfaceNormal;
|
|
||||||
unsigned int bestStackOrder = 0;
|
unsigned int bestStackOrder = 0;
|
||||||
OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID;
|
OverlayID bestOverlayID = UNKNOWN_OVERLAY_ID;
|
||||||
|
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
i.next();
|
i.next();
|
||||||
OverlayID thisID = i.key();
|
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
|
||||||
if (!i.value()->is3D()) {
|
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
|
||||||
auto thisOverlay = std::dynamic_pointer_cast<Overlay2D>(i.value());
|
thisOverlay->getBoundingRect().contains(point.x, point.y, false)) {
|
||||||
if (thisOverlay && thisOverlay->getVisible() && thisOverlay->isLoaded() &&
|
if (thisOverlay->getStackOrder() > bestStackOrder) {
|
||||||
thisOverlay->getBoundingRect().contains(pointCopy.x, pointCopy.y, false)) {
|
bestOverlayID = i.key();
|
||||||
if (thisOverlay->getStackOrder() > bestStackOrder) {
|
bestStackOrder = thisOverlay->getStackOrder();
|
||||||
bestOverlayID = thisID;
|
|
||||||
bestStackOrder = thisOverlay->getStackOrder();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -498,14 +474,9 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionInternal(const PickR
|
||||||
float bestDistance = std::numeric_limits<float>::max();
|
float bestDistance = std::numeric_limits<float>::max();
|
||||||
bool bestIsFront = false;
|
bool bestIsFront = false;
|
||||||
|
|
||||||
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
|
QMutexLocker locker(&_mutex);
|
||||||
{
|
|
||||||
QMutexLocker locker(&_mutex);
|
|
||||||
overlaysWorld = _overlaysWorld;
|
|
||||||
}
|
|
||||||
|
|
||||||
RayToOverlayIntersectionResult result;
|
RayToOverlayIntersectionResult result;
|
||||||
QMapIterator<OverlayID, Overlay::Pointer> i(overlaysWorld);
|
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
i.next();
|
i.next();
|
||||||
OverlayID thisID = i.key();
|
OverlayID thisID = i.key();
|
||||||
|
@ -636,22 +607,16 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlay::Pointer thisOverlay;
|
Overlay::Pointer thisOverlay = getOverlay(id);
|
||||||
{
|
|
||||||
QMutexLocker locker(&_mutex);
|
|
||||||
thisOverlay = _overlaysHUD[id];
|
|
||||||
}
|
|
||||||
if (thisOverlay) {
|
if (thisOverlay) {
|
||||||
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
|
if (thisOverlay->is3D()) {
|
||||||
return textOverlay->textSize(text);
|
if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) {
|
||||||
}
|
return text3dOverlay->textSize(text);
|
||||||
} else {
|
}
|
||||||
{
|
} else {
|
||||||
QMutexLocker locker(&_mutex);
|
if (auto textOverlay = std::dynamic_pointer_cast<TextOverlay>(thisOverlay)) {
|
||||||
thisOverlay = _overlaysWorld[id];
|
return textOverlay->textSize(text);
|
||||||
}
|
}
|
||||||
if (auto text3dOverlay = std::dynamic_pointer_cast<Text3DOverlay>(thisOverlay)) {
|
|
||||||
return text3dOverlay->textSize(text);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return QSizeF(0.0f, 0.0f);
|
return QSizeF(0.0f, 0.0f);
|
||||||
|
@ -995,13 +960,8 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QMap<OverlayID, Overlay::Pointer> overlaysWorld;
|
QMutexLocker locker(&_mutex);
|
||||||
{
|
QMapIterator<OverlayID, Overlay::Pointer> i(_overlaysWorld);
|
||||||
QMutexLocker locker(&_mutex);
|
|
||||||
overlaysWorld = _overlaysWorld;
|
|
||||||
}
|
|
||||||
|
|
||||||
QMapIterator<OverlayID, Overlay::Pointer> i(overlaysWorld);
|
|
||||||
int checked = 0;
|
int checked = 0;
|
||||||
while (i.hasNext()) {
|
while (i.hasNext()) {
|
||||||
checked++;
|
checked++;
|
||||||
|
|
|
@ -198,11 +198,7 @@ gpu::TexturePointer TextureCache::getTextureByHash(const std::string& hash) {
|
||||||
std::unique_lock<std::mutex> lock(_texturesByHashesMutex);
|
std::unique_lock<std::mutex> lock(_texturesByHashesMutex);
|
||||||
weakPointer = _texturesByHashes[hash];
|
weakPointer = _texturesByHashes[hash];
|
||||||
}
|
}
|
||||||
auto result = weakPointer.lock();
|
return weakPointer.lock();
|
||||||
if (result) {
|
|
||||||
qCWarning(modelnetworking) << "QQQ Returning live texture for hash " << hash.c_str();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::TexturePointer TextureCache::cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture) {
|
gpu::TexturePointer TextureCache::cacheTextureByHash(const std::string& hash, const gpu::TexturePointer& texture) {
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#include <QtScript/QScriptEngine>
|
#include <QtScript/QScriptEngine>
|
||||||
#include <QtNetwork/QNetworkDiskCache>
|
#include <QtNetwork/QNetworkDiskCache>
|
||||||
|
|
||||||
|
#include <shared/GlobalAppProperties.h>
|
||||||
|
|
||||||
#include "AssetRequest.h"
|
#include "AssetRequest.h"
|
||||||
#include "AssetUpload.h"
|
#include "AssetUpload.h"
|
||||||
#include "AssetUtils.h"
|
#include "AssetUtils.h"
|
||||||
|
@ -31,11 +33,12 @@
|
||||||
|
|
||||||
MessageID AssetClient::_currentID = 0;
|
MessageID AssetClient::_currentID = 0;
|
||||||
|
|
||||||
AssetClient::AssetClient(const QString& cacheDir) : _cacheDir(cacheDir) {
|
AssetClient::AssetClient() {
|
||||||
|
_cacheDir = qApp->property(hifi::properties::APP_LOCAL_DATA_PATH).toString();
|
||||||
setCustomDeleter([](Dependency* dependency){
|
setCustomDeleter([](Dependency* dependency){
|
||||||
static_cast<AssetClient*>(dependency)->deleteLater();
|
static_cast<AssetClient*>(dependency)->deleteLater();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
auto& packetReceiver = nodeList->getPacketReceiver();
|
auto& packetReceiver = nodeList->getPacketReceiver();
|
||||||
|
|
||||||
|
@ -105,7 +108,7 @@ void AssetClient::handleAssetMappingOperationReply(QSharedPointer<ReceivedMessag
|
||||||
|
|
||||||
MessageID messageID;
|
MessageID messageID;
|
||||||
message->readPrimitive(&messageID);
|
message->readPrimitive(&messageID);
|
||||||
|
|
||||||
AssetServerError error;
|
AssetServerError error;
|
||||||
message->readPrimitive(&error);
|
message->readPrimitive(&error);
|
||||||
|
|
||||||
|
@ -132,13 +135,13 @@ void AssetClient::handleAssetMappingOperationReply(QSharedPointer<ReceivedMessag
|
||||||
bool haveAssetServer() {
|
bool haveAssetServer() {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
if (!assetServer) {
|
if (!assetServer) {
|
||||||
qCWarning(asset_client) << "Could not complete AssetClient operation "
|
qCWarning(asset_client) << "Could not complete AssetClient operation "
|
||||||
<< "since you are not currently connected to an asset-server.";
|
<< "since you are not currently connected to an asset-server.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,14 +223,14 @@ MessageID AssetClient::getAsset(const QString& hash, DataOffset start, DataOffse
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
if (assetServer) {
|
if (assetServer) {
|
||||||
|
|
||||||
auto messageID = ++_currentID;
|
auto messageID = ++_currentID;
|
||||||
|
|
||||||
auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(start) + sizeof(end);
|
auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH + sizeof(start) + sizeof(end);
|
||||||
auto packet = NLPacket::create(PacketType::AssetGet, payloadSize, true);
|
auto packet = NLPacket::create(PacketType::AssetGet, payloadSize, true);
|
||||||
|
|
||||||
qCDebug(asset_client) << "Requesting data from" << start << "to" << end << "of" << hash << "from asset-server.";
|
qCDebug(asset_client) << "Requesting data from" << start << "to" << end << "of" << hash << "from asset-server.";
|
||||||
|
|
||||||
packet->writePrimitive(messageID);
|
packet->writePrimitive(messageID);
|
||||||
|
|
||||||
packet->write(QByteArray::fromHex(hash.toLatin1()));
|
packet->write(QByteArray::fromHex(hash.toLatin1()));
|
||||||
|
@ -254,10 +257,10 @@ MessageID AssetClient::getAssetInfo(const QString& hash, GetInfoCallback callbac
|
||||||
|
|
||||||
if (assetServer) {
|
if (assetServer) {
|
||||||
auto messageID = ++_currentID;
|
auto messageID = ++_currentID;
|
||||||
|
|
||||||
auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH;
|
auto payloadSize = sizeof(messageID) + SHA256_HASH_LENGTH;
|
||||||
auto packet = NLPacket::create(PacketType::AssetGetInfo, payloadSize, true);
|
auto packet = NLPacket::create(PacketType::AssetGetInfo, payloadSize, true);
|
||||||
|
|
||||||
packet->writePrimitive(messageID);
|
packet->writePrimitive(messageID);
|
||||||
packet->write(QByteArray::fromHex(hash.toLatin1()));
|
packet->write(QByteArray::fromHex(hash.toLatin1()));
|
||||||
|
|
||||||
|
@ -278,7 +281,7 @@ void AssetClient::handleAssetGetInfoReply(QSharedPointer<ReceivedMessage> messag
|
||||||
MessageID messageID;
|
MessageID messageID;
|
||||||
message->readPrimitive(&messageID);
|
message->readPrimitive(&messageID);
|
||||||
auto assetHash = message->read(SHA256_HASH_LENGTH);
|
auto assetHash = message->read(SHA256_HASH_LENGTH);
|
||||||
|
|
||||||
AssetServerError error;
|
AssetServerError error;
|
||||||
message->readPrimitive(&error);
|
message->readPrimitive(&error);
|
||||||
|
|
||||||
|
@ -367,7 +370,7 @@ void AssetClient::handleAssetGetReply(QSharedPointer<ReceivedMessage> message, S
|
||||||
callbacks.completeCallback(true, error, message->readAll());
|
callbacks.completeCallback(true, error, message->readAll());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
messageCallbackMap.erase(requestIt);
|
messageCallbackMap.erase(requestIt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -478,7 +481,7 @@ MessageID AssetClient::getAllAssetMappings(MappingOperationCallback callback) {
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
if (assetServer) {
|
if (assetServer) {
|
||||||
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
||||||
|
|
||||||
|
@ -501,7 +504,7 @@ MessageID AssetClient::getAllAssetMappings(MappingOperationCallback callback) {
|
||||||
MessageID AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) {
|
MessageID AssetClient::deleteAssetMappings(const AssetPathList& paths, MappingOperationCallback callback) {
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
if (assetServer) {
|
if (assetServer) {
|
||||||
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
||||||
|
|
||||||
|
@ -532,7 +535,7 @@ MessageID AssetClient::setAssetMapping(const QString& path, const AssetHash& has
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
if (assetServer) {
|
if (assetServer) {
|
||||||
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
auto packetList = NLPacketList::create(PacketType::AssetMappingOperation, QByteArray(), true, true);
|
||||||
|
|
||||||
|
@ -644,7 +647,7 @@ MessageID AssetClient::uploadAsset(const QByteArray& data, UploadResultCallback
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
SharedNodePointer assetServer = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||||
|
|
||||||
if (assetServer) {
|
if (assetServer) {
|
||||||
auto packetList = NLPacketList::create(PacketType::AssetUpload, QByteArray(), true, true);
|
auto packetList = NLPacketList::create(PacketType::AssetUpload, QByteArray(), true, true);
|
||||||
|
|
||||||
|
@ -682,7 +685,7 @@ void AssetClient::handleAssetUploadReply(QSharedPointer<ReceivedMessage> message
|
||||||
} else {
|
} else {
|
||||||
auto hash = message->read(SHA256_HASH_LENGTH);
|
auto hash = message->read(SHA256_HASH_LENGTH);
|
||||||
hashString = hash.toHex();
|
hashString = hash.toHex();
|
||||||
|
|
||||||
qCDebug(asset_client) << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString;
|
qCDebug(asset_client) << "Successfully uploaded asset to asset-server - SHA256 hash is " << hashString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,7 +49,7 @@ using ProgressCallback = std::function<void(qint64 totalReceived, qint64 total)>
|
||||||
class AssetClient : public QObject, public Dependency {
|
class AssetClient : public QObject, public Dependency {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
AssetClient(const QString& cacheDir="");
|
AssetClient();
|
||||||
|
|
||||||
Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path);
|
Q_INVOKABLE GetMappingRequest* createGetMappingRequest(const AssetPath& path);
|
||||||
Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest();
|
Q_INVOKABLE GetAllMappingsRequest* createGetAllMappingsRequest();
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
ResourceManager::ResourceManager() {
|
ResourceManager::ResourceManager() {
|
||||||
_thread.setObjectName("Resource Manager Thread");
|
_thread.setObjectName("Resource Manager Thread");
|
||||||
|
|
||||||
auto assetClient = DependencyManager::set<AssetClient>(_cacheDir);
|
auto assetClient = DependencyManager::set<AssetClient>();
|
||||||
assetClient->moveToThread(&_thread);
|
assetClient->moveToThread(&_thread);
|
||||||
QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init);
|
QObject::connect(&_thread, &QThread::started, assetClient.data(), &AssetClient::init);
|
||||||
|
|
||||||
|
@ -160,7 +160,3 @@ bool ResourceManager::resourceExists(const QUrl& url) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ResourceManager::setCacheDir(const QString& cacheDir) {
|
|
||||||
// TODO: check for existence?
|
|
||||||
_cacheDir = cacheDir;
|
|
||||||
}
|
|
||||||
|
|
|
@ -59,7 +59,6 @@ private:
|
||||||
PrefixMap _prefixMap;
|
PrefixMap _prefixMap;
|
||||||
QMutex _prefixMapLock;
|
QMutex _prefixMapLock;
|
||||||
|
|
||||||
QString _cacheDir;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,6 +33,7 @@ public:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
bool isEnabled() { return !_disabled.get(); }
|
bool isEnabled() { return !_disabled.get(); }
|
||||||
|
bool isDisabledSettingSet() const { return _disabled.isSet(); }
|
||||||
|
|
||||||
void disable(bool disable);
|
void disable(bool disable);
|
||||||
void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters());
|
void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters());
|
||||||
|
@ -53,7 +54,7 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UserActivityLogger();
|
UserActivityLogger();
|
||||||
Setting::Handle<bool> _disabled { "UserActivityLoggerDisabled", false };
|
Setting::Handle<bool> _disabled { "UserActivityLoggerDisabled", true };
|
||||||
|
|
||||||
QElapsedTimer _timer;
|
QElapsedTimer _timer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1821,7 +1821,7 @@ void ScriptEngine::include(const QStringList& includeFiles, QScriptValue callbac
|
||||||
clearExceptions();
|
clearExceptions();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scriptWarningMessage("Script.include() skipping evaluation of previously included url:" + url.toString());
|
scriptPrintedMessage("Script.include() skipping evaluation of previously included url:" + url.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "PathUtils.h"
|
#include "PathUtils.h"
|
||||||
#include <QtCore/QStandardPaths>
|
#include <QtCore/QStandardPaths>
|
||||||
#include <mutex> // std::once
|
#include <mutex> // std::once
|
||||||
|
#include "shared/GlobalAppProperties.h"
|
||||||
|
|
||||||
const QString& PathUtils::resourcesPath() {
|
const QString& PathUtils::resourcesPath() {
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
|
@ -34,12 +35,8 @@ QString PathUtils::getAppDataPath() {
|
||||||
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/";
|
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PathUtils::getAppLocalDataPath(const QString& overridePath /* = "" */) {
|
QString PathUtils::getAppLocalDataPath() {
|
||||||
static QString overriddenPath = "";
|
QString overriddenPath = qApp->property(hifi::properties::APP_LOCAL_DATA_PATH).toString();
|
||||||
// set the overridden path if one was passed in
|
|
||||||
if (!overridePath.isEmpty()) {
|
|
||||||
overriddenPath = overridePath;
|
|
||||||
}
|
|
||||||
// return overridden path if set
|
// return overridden path if set
|
||||||
if (!overriddenPath.isEmpty()) {
|
if (!overriddenPath.isEmpty()) {
|
||||||
return overriddenPath;
|
return overriddenPath;
|
||||||
|
|
|
@ -28,7 +28,7 @@ public:
|
||||||
static const QString& resourcesPath();
|
static const QString& resourcesPath();
|
||||||
|
|
||||||
static QString getAppDataPath();
|
static QString getAppDataPath();
|
||||||
static QString getAppLocalDataPath(const QString& overridePath = "");
|
static QString getAppLocalDataPath();
|
||||||
|
|
||||||
static QString getAppDataFilePath(const QString& filename);
|
static QString getAppDataFilePath(const QString& filename);
|
||||||
static QString getAppLocalDataFilePath(const QString& filename);
|
static QString getAppLocalDataFilePath(const QString& filename);
|
||||||
|
|
|
@ -107,6 +107,7 @@ namespace Setting {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isSet() const {
|
bool isSet() const {
|
||||||
|
maybeInit();
|
||||||
return _isSet;
|
return _isSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,10 +17,6 @@ void moveToNewNamedThread(QObject* object, const QString& name, std::function<vo
|
||||||
QThread* thread = new QThread();
|
QThread* thread = new QThread();
|
||||||
thread->setObjectName(name);
|
thread->setObjectName(name);
|
||||||
|
|
||||||
if (priority != QThread::InheritPriority) {
|
|
||||||
thread->setPriority(priority);
|
|
||||||
}
|
|
||||||
|
|
||||||
QString tempName = name;
|
QString tempName = name;
|
||||||
QObject::connect(thread, &QThread::started, [startCallback] {
|
QObject::connect(thread, &QThread::started, [startCallback] {
|
||||||
startCallback();
|
startCallback();
|
||||||
|
@ -32,6 +28,9 @@ void moveToNewNamedThread(QObject* object, const QString& name, std::function<vo
|
||||||
// put the object on the thread
|
// put the object on the thread
|
||||||
object->moveToThread(thread);
|
object->moveToThread(thread);
|
||||||
thread->start();
|
thread->start();
|
||||||
|
if (priority != QThread::InheritPriority) {
|
||||||
|
thread->setPriority(priority);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void moveToNewNamedThread(QObject* object, const QString& name, QThread::Priority priority) {
|
void moveToNewNamedThread(QObject* object, const QString& name, QThread::Priority priority) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace hifi { namespace properties {
|
||||||
const char* TEST = "com.highfidelity.test";
|
const char* TEST = "com.highfidelity.test";
|
||||||
const char* TRACING = "com.highfidelity.tracing";
|
const char* TRACING = "com.highfidelity.tracing";
|
||||||
const char* HMD = "com.highfidelity.hmd";
|
const char* HMD = "com.highfidelity.hmd";
|
||||||
|
const char* APP_LOCAL_DATA_PATH = "com.highfidelity.appLocalDataPath";
|
||||||
|
|
||||||
namespace gl {
|
namespace gl {
|
||||||
const char* BACKEND = "com.highfidelity.gl.backend";
|
const char* BACKEND = "com.highfidelity.gl.backend";
|
||||||
|
|
|
@ -19,6 +19,7 @@ namespace hifi { namespace properties {
|
||||||
extern const char* TEST;
|
extern const char* TEST;
|
||||||
extern const char* TRACING;
|
extern const char* TRACING;
|
||||||
extern const char* HMD;
|
extern const char* HMD;
|
||||||
|
extern const char* APP_LOCAL_DATA_PATH;
|
||||||
|
|
||||||
namespace gl {
|
namespace gl {
|
||||||
extern const char* BACKEND;
|
extern const char* BACKEND;
|
||||||
|
|
|
@ -82,6 +82,12 @@ struct PoseData {
|
||||||
angularVelocities[i] = transformVectorFast(resetMat, toGlm(vrPoses[i].vAngularVelocity));
|
angularVelocities[i] = transformVectorFast(resetMat, toGlm(vrPoses[i].vAngularVelocity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void resetToInvalid() {
|
||||||
|
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {
|
||||||
|
vrPoses[i].bPoseIsValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME remove once OpenVR header is updated
|
// FIXME remove once OpenVR header is updated
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#include <GLMHelpers.h>
|
#include <GLMHelpers.h>
|
||||||
#include <glm/ext.hpp>
|
#include <glm/ext.hpp>
|
||||||
#include <glm/gtc/quaternion.hpp>
|
#include <glm/gtc/quaternion.hpp>
|
||||||
|
#include <ui-plugins/PluginContainer.h>
|
||||||
|
#include <plugins/DisplayPlugin.h>
|
||||||
|
|
||||||
#include <controllers/UserInputMapper.h>
|
#include <controllers/UserInputMapper.h>
|
||||||
#include <Plugins/InputConfiguration.h>
|
#include <Plugins/InputConfiguration.h>
|
||||||
|
@ -60,11 +62,6 @@ static const int SECOND_FOOT = 1;
|
||||||
static const int HIP = 2;
|
static const int HIP = 2;
|
||||||
static const int CHEST = 3;
|
static const int CHEST = 3;
|
||||||
|
|
||||||
static float HEAD_PUCK_Y_OFFSET = -0.0254f;
|
|
||||||
static float HEAD_PUCK_Z_OFFSET = -0.152f;
|
|
||||||
static float HAND_PUCK_Y_OFFSET = -0.0508f;
|
|
||||||
static float HAND_PUCK_Z_OFFSET = 0.0254f;
|
|
||||||
|
|
||||||
const char* ViveControllerManager::NAME { "OpenVR" };
|
const char* ViveControllerManager::NAME { "OpenVR" };
|
||||||
|
|
||||||
const std::map<vr::ETrackingResult, QString> TRACKING_RESULT_TO_STRING = {
|
const std::map<vr::ETrackingResult, QString> TRACKING_RESULT_TO_STRING = {
|
||||||
|
@ -121,6 +118,29 @@ static QString deviceTrackingResultToString(vr::ETrackingResult trackingResult)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static glm::mat4 calculateResetMat() {
|
||||||
|
auto chaperone = vr::VRChaperone();
|
||||||
|
if (chaperone) {
|
||||||
|
float const UI_RADIUS = 1.0f;
|
||||||
|
float const UI_HEIGHT = 1.6f;
|
||||||
|
float const UI_Z_OFFSET = 0.5;
|
||||||
|
|
||||||
|
float xSize, zSize;
|
||||||
|
chaperone->GetPlayAreaSize(&xSize, &zSize);
|
||||||
|
glm::vec3 uiPos(0.0f, UI_HEIGHT, UI_RADIUS - (0.5f * zSize) - UI_Z_OFFSET);
|
||||||
|
|
||||||
|
return glm::inverse(createMatFromQuatAndPos(glm::quat(), uiPos));
|
||||||
|
}
|
||||||
|
return glm::mat4();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ViveControllerManager::isDesktopMode() {
|
||||||
|
if (_container) {
|
||||||
|
return !_container->getActiveDisplayPlugin()->isHmd();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void ViveControllerManager::calibrate() {
|
void ViveControllerManager::calibrate() {
|
||||||
if (isSupported()) {
|
if (isSupported()) {
|
||||||
_inputDevice->calibrateNextFrame();
|
_inputDevice->calibrateNextFrame();
|
||||||
|
@ -141,13 +161,21 @@ bool ViveControllerManager::isSupported() const {
|
||||||
|
|
||||||
void ViveControllerManager::setConfigurationSettings(const QJsonObject configurationSettings) {
|
void ViveControllerManager::setConfigurationSettings(const QJsonObject configurationSettings) {
|
||||||
if (isSupported()) {
|
if (isSupported()) {
|
||||||
|
if (configurationSettings.contains("desktopMode")) {
|
||||||
|
_desktopMode = configurationSettings["desktopMode"].toBool();
|
||||||
|
if (!_desktopMode) {
|
||||||
|
_resetMatCalculated = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
_inputDevice->configureCalibrationSettings(configurationSettings);
|
_inputDevice->configureCalibrationSettings(configurationSettings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QJsonObject ViveControllerManager::configurationSettings() {
|
QJsonObject ViveControllerManager::configurationSettings() {
|
||||||
if (isSupported()) {
|
if (isSupported()) {
|
||||||
return _inputDevice->configurationSettings();
|
QJsonObject configurationSettings = _inputDevice->configurationSettings();
|
||||||
|
configurationSettings["desktopMode"] = _desktopMode;
|
||||||
|
return configurationSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
return QJsonObject();
|
return QJsonObject();
|
||||||
|
@ -218,6 +246,18 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDesktopMode() && _desktopMode) {
|
||||||
|
if (!_resetMatCalculated) {
|
||||||
|
_resetMat = calculateResetMat();
|
||||||
|
_resetMatCalculated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, 0, _nextSimPoseData.vrPoses, vr::k_unMaxTrackedDeviceCount);
|
||||||
|
_nextSimPoseData.update(_resetMat);
|
||||||
|
} else if (isDesktopMode()) {
|
||||||
|
_nextSimPoseData.resetToInvalid();
|
||||||
|
}
|
||||||
|
|
||||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||||
handleOpenVrEvents();
|
handleOpenVrEvents();
|
||||||
if (openVrQuitRequested()) {
|
if (openVrQuitRequested()) {
|
||||||
|
@ -344,8 +384,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso
|
||||||
bool overrideHead = headObject["override"].toBool();
|
bool overrideHead = headObject["override"].toBool();
|
||||||
if (overrideHead) {
|
if (overrideHead) {
|
||||||
_headConfig = HeadConfig::Puck;
|
_headConfig = HeadConfig::Puck;
|
||||||
HEAD_PUCK_Y_OFFSET = headObject["Y"].toDouble();
|
_headPuckYOffset = headObject["Y"].toDouble();
|
||||||
HEAD_PUCK_Z_OFFSET = headObject["Z"].toDouble();
|
_headPuckZOffset = headObject["Z"].toDouble();
|
||||||
} else {
|
} else {
|
||||||
_headConfig = HeadConfig::HMD;
|
_headConfig = HeadConfig::HMD;
|
||||||
}
|
}
|
||||||
|
@ -354,8 +394,8 @@ void ViveControllerManager::InputDevice::configureCalibrationSettings(const QJso
|
||||||
bool overrideHands = handsObject["override"].toBool();
|
bool overrideHands = handsObject["override"].toBool();
|
||||||
if (overrideHands) {
|
if (overrideHands) {
|
||||||
_handConfig = HandConfig::Pucks;
|
_handConfig = HandConfig::Pucks;
|
||||||
HAND_PUCK_Y_OFFSET = handsObject["Y"].toDouble();
|
_handPuckYOffset = handsObject["Y"].toDouble();
|
||||||
HAND_PUCK_Z_OFFSET = handsObject["Z"].toDouble();
|
_handPuckZOffset = handsObject["Z"].toDouble();
|
||||||
} else {
|
} else {
|
||||||
_handConfig = HandConfig::HandController;
|
_handConfig = HandConfig::HandController;
|
||||||
}
|
}
|
||||||
|
@ -389,7 +429,7 @@ void ViveControllerManager::InputDevice::emitCalibrationStatus() {
|
||||||
status["hand_pucks"] = (_handConfig == HandConfig::Pucks);
|
status["hand_pucks"] = (_handConfig == HandConfig::Pucks);
|
||||||
status["puckCount"] = (int)_validTrackedObjects.size();
|
status["puckCount"] = (int)_validTrackedObjects.size();
|
||||||
status["UI"] = _calibrate;
|
status["UI"] = _calibrate;
|
||||||
|
|
||||||
emit inputConfiguration->calibrationStatus(status);
|
emit inputConfiguration->calibrationStatus(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -426,7 +466,9 @@ void ViveControllerManager::InputDevice::handleTrackedObject(uint32_t deviceInde
|
||||||
// transform into avatar frame
|
// transform into avatar frame
|
||||||
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
|
glm::mat4 controllerToAvatar = glm::inverse(inputCalibrationData.avatarMat) * inputCalibrationData.sensorToWorldMat;
|
||||||
_poseStateMap[poseIndex] = pose.transform(controllerToAvatar);
|
_poseStateMap[poseIndex] = pose.transform(controllerToAvatar);
|
||||||
_validTrackedObjects.push_back(std::make_pair(poseIndex, _poseStateMap[poseIndex]));
|
|
||||||
|
// but _validTrackedObjects remain in sensor frame
|
||||||
|
_validTrackedObjects.push_back(std::make_pair(poseIndex, pose));
|
||||||
} else {
|
} else {
|
||||||
controller::Pose invalidPose;
|
controller::Pose invalidPose;
|
||||||
_poseStateMap[poseIndex] = invalidPose;
|
_poseStateMap[poseIndex] = invalidPose;
|
||||||
|
@ -440,7 +482,7 @@ void ViveControllerManager::InputDevice::sendUserActivityData(QString activity)
|
||||||
{"head_puck", (_headConfig == HeadConfig::Puck) ? true : false},
|
{"head_puck", (_headConfig == HeadConfig::Puck) ? true : false},
|
||||||
{"hand_pucks", (_handConfig == HandConfig::Pucks) ? true : false}
|
{"hand_pucks", (_handConfig == HandConfig::Pucks) ? true : false}
|
||||||
};
|
};
|
||||||
|
|
||||||
UserActivityLogger::getInstance().logAction(activity, jsonData);
|
UserActivityLogger::getInstance().logAction(activity, jsonData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -473,12 +515,13 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr
|
||||||
glm::mat4 defaultToReferenceMat = glm::mat4();
|
glm::mat4 defaultToReferenceMat = glm::mat4();
|
||||||
if (_headConfig == HeadConfig::HMD) {
|
if (_headConfig == HeadConfig::HMD) {
|
||||||
defaultToReferenceMat = calculateDefaultToReferenceForHmd(inputCalibration);
|
defaultToReferenceMat = calculateDefaultToReferenceForHmd(inputCalibration);
|
||||||
} else if (_headConfig == HeadConfig::Puck) {
|
} else if (_headConfig == HeadConfig::Puck) {
|
||||||
|
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
|
||||||
defaultToReferenceMat = calculateDefaultToReferenceForHeadPuck(inputCalibration);
|
defaultToReferenceMat = calculateDefaultToReferenceForHeadPuck(inputCalibration);
|
||||||
}
|
}
|
||||||
|
|
||||||
_config = _preferedConfig;
|
_config = _preferedConfig;
|
||||||
|
|
||||||
bool headConfigured = configureHead(defaultToReferenceMat, inputCalibration);
|
bool headConfigured = configureHead(defaultToReferenceMat, inputCalibration);
|
||||||
bool handsConfigured = configureHands(defaultToReferenceMat, inputCalibration);
|
bool handsConfigured = configureHands(defaultToReferenceMat, inputCalibration);
|
||||||
bool bodyConfigured = configureBody(defaultToReferenceMat, inputCalibration);
|
bool bodyConfigured = configureBody(defaultToReferenceMat, inputCalibration);
|
||||||
|
@ -668,63 +711,67 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// defaultToReferenceMat is an offset from avatar space to sensor space.
|
||||||
|
// it aligns the default center-eye in avatar space with the hmd in sensor space.
|
||||||
|
//
|
||||||
|
// * E_a is the the default center-of-the-eyes transform in avatar space.
|
||||||
|
// * E_s is the the hmd eye-center transform in sensor space, with roll and pitch removed.
|
||||||
|
// * D is the defaultReferenceMat.
|
||||||
|
//
|
||||||
|
// E_s = D * E_a =>
|
||||||
|
// D = E_s * inverse(E_a)
|
||||||
|
//
|
||||||
glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHmd(const controller::InputCalibrationData& inputCalibration) {
|
glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHmd(const controller::InputCalibrationData& inputCalibration) {
|
||||||
// convert the hmd head from sensor space to avatar space
|
|
||||||
glm::mat4 hmdSensorFlippedMat = inputCalibration.hmdSensorMat * Matrices::Y_180;
|
|
||||||
glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat;
|
|
||||||
glm::mat4 hmdAvatarMat = sensorToAvatarMat * hmdSensorFlippedMat;
|
|
||||||
|
|
||||||
// cancel the roll and pitch for the hmd head
|
// the center-eye transform in avatar space.
|
||||||
glm::quat hmdRotation = cancelOutRollAndPitch(glmExtractRotation(hmdAvatarMat));
|
glm::mat4 E_a = inputCalibration.defaultCenterEyeMat;
|
||||||
glm::vec3 hmdTranslation = extractTranslation(hmdAvatarMat);
|
|
||||||
glm::mat4 currentHmd = createMatFromQuatAndPos(hmdRotation, hmdTranslation);
|
|
||||||
|
|
||||||
// calculate the offset from the centerOfEye to defaultHeadMat
|
// the center-eye transform in sensor space.
|
||||||
glm::mat4 defaultHeadOffset = glm::inverse(inputCalibration.defaultCenterEyeMat) * inputCalibration.defaultHeadMat;
|
glm::mat4 E_s = inputCalibration.hmdSensorMat * Matrices::Y_180; // the Y_180 is to convert hmd from -z forward to z forward.
|
||||||
|
|
||||||
glm::mat4 currentHead = currentHmd * defaultHeadOffset;
|
// cancel out roll and pitch on E_s
|
||||||
|
glm::quat rot = cancelOutRollAndPitch(glmExtractRotation(E_s));
|
||||||
|
glm::vec3 trans = extractTranslation(E_s);
|
||||||
|
E_s = createMatFromQuatAndPos(rot, trans);
|
||||||
|
|
||||||
// calculate the defaultToRefrenceXform
|
return E_s * glm::inverse(E_a);
|
||||||
glm::mat4 defaultToReferenceMat = currentHead * glm::inverse(inputCalibration.defaultHeadMat);
|
|
||||||
|
|
||||||
return defaultToReferenceMat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// defaultToReferenceMat is an offset from avatar space to sensor space.
|
||||||
|
// It aligns the default center-of-the-eyes transform in avatar space with the head-puck in sensor space.
|
||||||
|
// The offset from the center-of-the-eyes to the head-puck can be configured via _headPuckYOffset and _headPuckZOffset,
|
||||||
|
// These values are exposed in the configuration UI.
|
||||||
|
//
|
||||||
|
// * E_a is the the default center-eye transform in avatar space.
|
||||||
|
// * E_s is the the head-puck center-eye transform in sensor space, with roll and pitch removed.
|
||||||
|
// * D is the defaultReferenceMat.
|
||||||
|
//
|
||||||
|
// E_s = D * E_a =>
|
||||||
|
// D = E_s * inverse(E_a)
|
||||||
|
//
|
||||||
glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration) {
|
glm::mat4 ViveControllerManager::InputDevice::calculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration) {
|
||||||
glm::mat4 avatarToSensorMat = glm::inverse(inputCalibration.sensorToWorldMat) * inputCalibration.avatarMat;
|
|
||||||
glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat;
|
// the center-eye transform in avatar space.
|
||||||
|
glm::mat4 E_a = inputCalibration.defaultCenterEyeMat;
|
||||||
|
|
||||||
|
// calculate the center-eye transform in sensor space, via the head-puck
|
||||||
size_t headPuckIndex = _validTrackedObjects.size() - 1;
|
size_t headPuckIndex = _validTrackedObjects.size() - 1;
|
||||||
controller::Pose headPuckPose = _validTrackedObjects[headPuckIndex].second;
|
controller::Pose headPuckPose = _validTrackedObjects[headPuckIndex].second;
|
||||||
glm::mat4 headPuckAvatarMat = createMatFromQuatAndPos(headPuckPose.getRotation(), headPuckPose.getTranslation()) * Matrices::Y_180;
|
|
||||||
glm::vec3 headPuckTranslation = extractTranslation(headPuckAvatarMat);
|
|
||||||
glm::vec3 headPuckZAxis = cancelOutRollAndPitch(glmExtractRotation(headPuckAvatarMat)) * glm::vec3(0.0f, 0.0f, 1.0f);
|
|
||||||
glm::vec3 worldUp = glm::vec3(0.0f, 1.0f, 0.0f);
|
|
||||||
|
|
||||||
// check that the head puck z axis is not parrallel to the world up
|
// AJT: TODO: handle case were forward is parallel with UNIT_Y.
|
||||||
const float EPSILON = 1.0e-4f;
|
glm::vec3 forward = headPuckPose.rotation * -Vectors::UNIT_Z;
|
||||||
glm::vec3 zAxis = glmExtractRotation(headPuckAvatarMat) * glm::vec3(0.0f, 0.0f, 1.0f);
|
glm::vec3 x = glm::normalize(glm::cross(Vectors::UNIT_Y, forward));
|
||||||
if (fabsf(fabsf(glm::dot(glm::normalize(worldUp), glm::normalize(zAxis))) - 1.0f) < EPSILON) {
|
glm::vec3 z = glm::normalize(glm::cross(x, Vectors::UNIT_Y));
|
||||||
headPuckZAxis = glm::vec3(1.0f, 0.0f, 0.0f);
|
glm::mat3 centerEyeRotMat(x, Vectors::UNIT_Y, z);
|
||||||
}
|
glm::vec3 centerEyeTrans = headPuckPose.translation + centerEyeRotMat * glm::vec3(0.0f, _headPuckYOffset, _headPuckZOffset);
|
||||||
|
|
||||||
glm::vec3 yPrime = glm::vec3(0.0f, 1.0f, 0.0f);
|
glm::mat4 E_s(glm::vec4(centerEyeRotMat[0], 0.0f),
|
||||||
glm::vec3 xPrime = glm::normalize(glm::cross(worldUp, headPuckZAxis));
|
glm::vec4(centerEyeRotMat[1], 0.0f),
|
||||||
glm::vec3 zPrime = glm::normalize(glm::cross(xPrime, yPrime));
|
glm::vec4(centerEyeRotMat[2], 0.0f),
|
||||||
glm::mat4 newHeadPuck = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
|
glm::vec4(centerEyeTrans, 1.0f));
|
||||||
glm::vec4(zPrime, 0.0f), glm::vec4(headPuckTranslation, 1.0f));
|
|
||||||
|
|
||||||
glm::mat4 headPuckOffset = glm::mat4(glm::vec4(1.0f, 0.0f, 0.0f, 0.0f), glm::vec4(0.0f, 1.0f, 0.0f, 0.0f),
|
return E_s * glm::inverse(E_a);
|
||||||
glm::vec4(0.0f, 0.0f, 1.0f, 0.0f), glm::vec4(0.0f, HEAD_PUCK_Y_OFFSET, HEAD_PUCK_Z_OFFSET, 1.0f));
|
|
||||||
|
|
||||||
glm::mat4 finalHeadPuck = newHeadPuck * headPuckOffset;
|
|
||||||
|
|
||||||
glm::mat4 defaultHeadOffset = glm::inverse(inputCalibration.defaultCenterEyeMat) * inputCalibration.defaultHeadMat;
|
|
||||||
|
|
||||||
glm::mat4 currentHead = finalHeadPuck * defaultHeadOffset;
|
|
||||||
|
|
||||||
// calculate the defaultToRefrenceXform
|
|
||||||
glm::mat4 defaultToReferenceMat = currentHead * glm::inverse(inputCalibration.defaultHeadMat);
|
|
||||||
return defaultToReferenceMat;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPseudoButton, int xPseudoButton, int yPseudoButton) {
|
void ViveControllerManager::InputDevice::partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPseudoButton, int xPseudoButton, int yPseudoButton) {
|
||||||
|
@ -912,12 +959,12 @@ void ViveControllerManager::InputDevice::calibrateLeftHand(glm::mat4& defaultToR
|
||||||
|
|
||||||
glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
|
glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
|
||||||
glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||||
|
|
||||||
|
|
||||||
glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET);
|
|
||||||
|
glm::vec3 translationOffset = glm::vec3(0.0f, _handPuckYOffset, _handPuckZOffset);
|
||||||
glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat);
|
glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat);
|
||||||
glm::quat finalRotation = glmExtractRotation(newHandMat);
|
glm::quat finalRotation = glmExtractRotation(newHandMat);
|
||||||
|
|
||||||
glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation;
|
glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation;
|
||||||
|
|
||||||
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
||||||
|
@ -942,13 +989,13 @@ void ViveControllerManager::InputDevice::calibrateRightHand(glm::mat4& defaultTo
|
||||||
glm::vec3 yPrime = glm::normalize(glm::cross(zPrime, xPrime));
|
glm::vec3 yPrime = glm::normalize(glm::cross(zPrime, xPrime));
|
||||||
glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
|
glm::mat4 newHandMat = glm::mat4(glm::vec4(xPrime, 0.0f), glm::vec4(yPrime, 0.0f),
|
||||||
glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
glm::vec4(zPrime, 0.0f), glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
glm::vec3 translationOffset = glm::vec3(0.0f, HAND_PUCK_Y_OFFSET, HAND_PUCK_Z_OFFSET);
|
|
||||||
|
glm::vec3 translationOffset = glm::vec3(0.0f, _handPuckYOffset, _handPuckZOffset);
|
||||||
glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat);
|
glm::quat initialRotation = glmExtractRotation(handPoseAvatarMat);
|
||||||
glm::quat finalRotation = glmExtractRotation(newHandMat);
|
glm::quat finalRotation = glmExtractRotation(newHandMat);
|
||||||
|
|
||||||
glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation;
|
glm::quat rotationOffset = glm::inverse(initialRotation) * finalRotation;
|
||||||
|
|
||||||
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
glm::mat4 offsetMat = createMatFromQuatAndPos(rotationOffset, translationOffset);
|
||||||
|
@ -965,7 +1012,7 @@ void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToRefer
|
||||||
auto& secondFoot = _validTrackedObjects[SECOND_FOOT];
|
auto& secondFoot = _validTrackedObjects[SECOND_FOOT];
|
||||||
controller::Pose& firstFootPose = firstFoot.second;
|
controller::Pose& firstFootPose = firstFoot.second;
|
||||||
controller::Pose& secondFootPose = secondFoot.second;
|
controller::Pose& secondFootPose = secondFoot.second;
|
||||||
|
|
||||||
if (determineLimbOrdering(firstFootPose, secondFootPose, headXAxis, headPosition)) {
|
if (determineLimbOrdering(firstFootPose, secondFootPose, headXAxis, headPosition)) {
|
||||||
calibrateFoot(defaultToReferenceMat, inputCalibration, firstFoot, true);
|
calibrateFoot(defaultToReferenceMat, inputCalibration, firstFoot, true);
|
||||||
calibrateFoot(defaultToReferenceMat, inputCalibration, secondFoot, false);
|
calibrateFoot(defaultToReferenceMat, inputCalibration, secondFoot, false);
|
||||||
|
@ -1030,13 +1077,8 @@ void ViveControllerManager::InputDevice::calibrateShoulders(glm::mat4& defaultTo
|
||||||
void ViveControllerManager::InputDevice::calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
void ViveControllerManager::InputDevice::calibrateHead(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
|
||||||
size_t headIndex = _validTrackedObjects.size() - 1;
|
size_t headIndex = _validTrackedObjects.size() - 1;
|
||||||
const PuckPosePair& head = _validTrackedObjects[headIndex];
|
const PuckPosePair& head = _validTrackedObjects[headIndex];
|
||||||
|
|
||||||
// assume the person is wearing the head puck on his/her forehead
|
|
||||||
glm::mat4 defaultHeadOffset = glm::inverse(inputCalibration.defaultCenterEyeMat) * inputCalibration.defaultHeadMat;
|
|
||||||
controller::Pose newHead = head.second.postTransform(defaultHeadOffset);
|
|
||||||
|
|
||||||
_jointToPuckMap[controller::HEAD] = head.first;
|
_jointToPuckMap[controller::HEAD] = head.first;
|
||||||
_pucksOffset[head.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHeadMat, newHead);
|
_pucksOffset[head.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHeadMat, head.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ViveControllerManager::InputDevice::configToString(Config config) {
|
QString ViveControllerManager::InputDevice::configToString(Config config) {
|
||||||
|
|
|
@ -152,7 +152,7 @@ private:
|
||||||
HandController,
|
HandController,
|
||||||
Pucks
|
Pucks
|
||||||
};
|
};
|
||||||
|
|
||||||
Config _config { Config::None };
|
Config _config { Config::None };
|
||||||
Config _preferedConfig { Config::None };
|
Config _preferedConfig { Config::None };
|
||||||
HeadConfig _headConfig { HeadConfig::HMD };
|
HeadConfig _headConfig { HeadConfig::HMD };
|
||||||
|
@ -177,6 +177,10 @@ private:
|
||||||
float _leftHapticDuration { 0.0f };
|
float _leftHapticDuration { 0.0f };
|
||||||
float _rightHapticStrength { 0.0f };
|
float _rightHapticStrength { 0.0f };
|
||||||
float _rightHapticDuration { 0.0f };
|
float _rightHapticDuration { 0.0f };
|
||||||
|
float _headPuckYOffset { -0.05f };
|
||||||
|
float _headPuckZOffset { -0.05f };
|
||||||
|
float _handPuckYOffset { 0.0f };
|
||||||
|
float _handPuckZOffset { 0.0f };
|
||||||
bool _triggersPressedHandled { false };
|
bool _triggersPressedHandled { false };
|
||||||
bool _calibrated { false };
|
bool _calibrated { false };
|
||||||
bool _timeTilCalibrationSet { false };
|
bool _timeTilCalibrationSet { false };
|
||||||
|
@ -190,9 +194,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
|
||||||
|
bool isDesktopMode();
|
||||||
bool _registeredWithInputMapper { false };
|
bool _registeredWithInputMapper { false };
|
||||||
bool _modelLoaded { false };
|
bool _modelLoaded { false };
|
||||||
|
bool _resetMatCalculated { false };
|
||||||
|
bool _desktopMode { false };
|
||||||
|
glm::mat4 _resetMat { glm::mat4() };
|
||||||
model::Geometry _modelGeometry;
|
model::Geometry _modelGeometry;
|
||||||
gpu::TexturePointer _texture;
|
gpu::TexturePointer _texture;
|
||||||
|
|
||||||
|
|
116
scripts/system/controllers/godView.js
Normal file
116
scripts/system/controllers/godView.js
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
"use strict";
|
||||||
|
//
|
||||||
|
// godView.js
|
||||||
|
// scripts/system/
|
||||||
|
//
|
||||||
|
// Created by Brad Hefta-Gaub on 1 Jun 2017
|
||||||
|
// Copyright 2017 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
/* globals HMD, Script, Menu, Tablet, Camera */
|
||||||
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
|
var godView = false;
|
||||||
|
|
||||||
|
var GOD_CAMERA_OFFSET = -1; // 1 meter below the avatar
|
||||||
|
var GOD_VIEW_HEIGHT = 300; // 300 meter above the ground
|
||||||
|
var ABOVE_GROUND_DROP = 2;
|
||||||
|
var MOVE_BY = 1;
|
||||||
|
|
||||||
|
function moveTo(position) {
|
||||||
|
if (godView) {
|
||||||
|
MyAvatar.position = position;
|
||||||
|
Camera.position = Vec3.sum(MyAvatar.position, {x:0, y: GOD_CAMERA_OFFSET, z: 0});
|
||||||
|
} else {
|
||||||
|
MyAvatar.position = position;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyPressEvent(event) {
|
||||||
|
if (godView) {
|
||||||
|
switch(event.text) {
|
||||||
|
case "UP":
|
||||||
|
moveTo(Vec3.sum(MyAvatar.position, {x:0.0, y: 0, z: -1 * MOVE_BY}));
|
||||||
|
break;
|
||||||
|
case "DOWN":
|
||||||
|
moveTo(Vec3.sum(MyAvatar.position, {x:0, y: 0, z: MOVE_BY}));
|
||||||
|
break;
|
||||||
|
case "LEFT":
|
||||||
|
moveTo(Vec3.sum(MyAvatar.position, {x:-1 * MOVE_BY, y: 0, z: 0}));
|
||||||
|
break;
|
||||||
|
case "RIGHT":
|
||||||
|
moveTo(Vec3.sum(MyAvatar.position, {x:MOVE_BY, y: 0, z: 0}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mousePress(event) {
|
||||||
|
if (godView) {
|
||||||
|
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||||
|
var pointingAt = Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction,300));
|
||||||
|
var moveToPosition = { x: pointingAt.x, y: MyAvatar.position.y, z: pointingAt.z };
|
||||||
|
moveTo(moveToPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var oldCameraMode = Camera.mode;
|
||||||
|
|
||||||
|
function startGodView() {
|
||||||
|
if (!godView) {
|
||||||
|
oldCameraMode = Camera.mode;
|
||||||
|
MyAvatar.position = Vec3.sum(MyAvatar.position, {x:0, y: GOD_VIEW_HEIGHT, z: 0});
|
||||||
|
Camera.mode = "independent";
|
||||||
|
Camera.position = Vec3.sum(MyAvatar.position, {x:0, y: GOD_CAMERA_OFFSET, z: 0});
|
||||||
|
Camera.orientation = Quat.fromPitchYawRollDegrees(-90,0,0);
|
||||||
|
godView = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function endGodView() {
|
||||||
|
if (godView) {
|
||||||
|
Camera.mode = oldCameraMode;
|
||||||
|
MyAvatar.position = Vec3.sum(MyAvatar.position, {x:0, y: (-1 * GOD_VIEW_HEIGHT) + ABOVE_GROUND_DROP, z: 0});
|
||||||
|
godView = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var button;
|
||||||
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
|
||||||
|
function onClicked() {
|
||||||
|
if (godView) {
|
||||||
|
endGodView();
|
||||||
|
} else {
|
||||||
|
startGodView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
button = tablet.addButton({
|
||||||
|
icon: "icons/tablet-icons/switch-desk-i.svg", // FIXME - consider a better icon from Alan
|
||||||
|
text: "God View"
|
||||||
|
});
|
||||||
|
|
||||||
|
button.clicked.connect(onClicked);
|
||||||
|
Controller.keyPressEvent.connect(keyPressEvent);
|
||||||
|
Controller.mousePressEvent.connect(mousePress);
|
||||||
|
|
||||||
|
|
||||||
|
Script.scriptEnding.connect(function () {
|
||||||
|
if (godView) {
|
||||||
|
endGodView();
|
||||||
|
}
|
||||||
|
button.clicked.disconnect(onClicked);
|
||||||
|
if (tablet) {
|
||||||
|
tablet.removeButton(button);
|
||||||
|
}
|
||||||
|
Controller.keyPressEvent.disconnect(keyPressEvent);
|
||||||
|
Controller.mousePressEvent.disconnect(mousePress);
|
||||||
|
});
|
||||||
|
|
||||||
|
}()); // END LOCAL_SCOPE
|
|
@ -20,7 +20,9 @@ var blastShareText = "Blast to my Connections",
|
||||||
hifiShareText = "Share to Snaps Feed",
|
hifiShareText = "Share to Snaps Feed",
|
||||||
hifiAlreadySharedText = "Already Shared to Snaps Feed",
|
hifiAlreadySharedText = "Already Shared to Snaps Feed",
|
||||||
facebookShareText = "Share to Facebook",
|
facebookShareText = "Share to Facebook",
|
||||||
twitterShareText = "Share to Twitter";
|
twitterShareText = "Share to Twitter",
|
||||||
|
shareButtonLabelTextActive = "SHARE:",
|
||||||
|
shareButtonLabelTextInactive = "SHARE";
|
||||||
|
|
||||||
function fileExtensionMatches(filePath, extension) {
|
function fileExtensionMatches(filePath, extension) {
|
||||||
return filePath.split('.').pop().toLowerCase() === extension;
|
return filePath.split('.').pop().toLowerCase() === extension;
|
||||||
|
@ -138,6 +140,8 @@ function selectImageToShare(selectedID, isSelected) {
|
||||||
var imageContainer = document.getElementById(selectedID),
|
var imageContainer = document.getElementById(selectedID),
|
||||||
image = document.getElementById(selectedID + 'img'),
|
image = document.getElementById(selectedID + 'img'),
|
||||||
shareBar = document.getElementById(selectedID + "shareBar"),
|
shareBar = document.getElementById(selectedID + "shareBar"),
|
||||||
|
showShareButtonsDots = document.getElementById(selectedID + "showShareButtonsDots"),
|
||||||
|
showShareButtonsLabel = document.getElementById(selectedID + "showShareButtonsLabel"),
|
||||||
shareButtonsDiv = document.getElementById(selectedID + "shareButtonsDiv"),
|
shareButtonsDiv = document.getElementById(selectedID + "shareButtonsDiv"),
|
||||||
shareBarHelp = document.getElementById(selectedID + "shareBarHelp"),
|
shareBarHelp = document.getElementById(selectedID + "shareBarHelp"),
|
||||||
showShareButtonsButtonDiv = document.getElementById(selectedID + "showShareButtonsButtonDiv"),
|
showShareButtonsButtonDiv = document.getElementById(selectedID + "showShareButtonsButtonDiv"),
|
||||||
|
@ -156,6 +160,9 @@ function selectImageToShare(selectedID, isSelected) {
|
||||||
shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.45)";
|
shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.45)";
|
||||||
shareBar.style.pointerEvents = "initial";
|
shareBar.style.pointerEvents = "initial";
|
||||||
|
|
||||||
|
showShareButtonsDots.style.visibility = "hidden";
|
||||||
|
showShareButtonsLabel.innerHTML = shareButtonLabelTextActive;
|
||||||
|
|
||||||
shareButtonsDiv.style.visibility = "visible";
|
shareButtonsDiv.style.visibility = "visible";
|
||||||
shareBarHelp.style.visibility = "visible";
|
shareBarHelp.style.visibility = "visible";
|
||||||
|
|
||||||
|
@ -176,6 +183,9 @@ function selectImageToShare(selectedID, isSelected) {
|
||||||
shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.0)";
|
shareBar.style.backgroundColor = "rgba(0, 0, 0, 0.0)";
|
||||||
shareBar.style.pointerEvents = "none";
|
shareBar.style.pointerEvents = "none";
|
||||||
|
|
||||||
|
showShareButtonsDots.style.visibility = "visible";
|
||||||
|
showShareButtonsLabel.innerHTML = shareButtonLabelTextInactive;
|
||||||
|
|
||||||
shareButtonsDiv.style.visibility = "hidden";
|
shareButtonsDiv.style.visibility = "hidden";
|
||||||
shareBarHelp.style.visibility = "hidden";
|
shareBarHelp.style.visibility = "hidden";
|
||||||
}
|
}
|
||||||
|
@ -185,6 +195,7 @@ function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabl
|
||||||
shareBarHelpID = parentID + "shareBarHelp",
|
shareBarHelpID = parentID + "shareBarHelp",
|
||||||
shareButtonsDivID = parentID + "shareButtonsDiv",
|
shareButtonsDivID = parentID + "shareButtonsDiv",
|
||||||
showShareButtonsButtonDivID = parentID + "showShareButtonsButtonDiv",
|
showShareButtonsButtonDivID = parentID + "showShareButtonsButtonDiv",
|
||||||
|
showShareButtonsDotsID = parentID + "showShareButtonsDots",
|
||||||
showShareButtonsLabelID = parentID + "showShareButtonsLabel",
|
showShareButtonsLabelID = parentID + "showShareButtonsLabel",
|
||||||
blastToConnectionsButtonID = parentID + "blastToConnectionsButton",
|
blastToConnectionsButtonID = parentID + "blastToConnectionsButton",
|
||||||
shareWithEveryoneButtonID = parentID + "shareWithEveryoneButton",
|
shareWithEveryoneButtonID = parentID + "shareWithEveryoneButton",
|
||||||
|
@ -199,8 +210,8 @@ function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabl
|
||||||
if (canShare) {
|
if (canShare) {
|
||||||
shareBarInnerHTML = '<div class="shareControlsHelp" id="' + shareBarHelpID + '" style="visibility:hidden;' + ((canBlast && blastButtonDisabled || !canBlast && hifiButtonDisabled) ? "background-color:#000;opacity:0.5;" : "") + '"></div>' +
|
shareBarInnerHTML = '<div class="shareControlsHelp" id="' + shareBarHelpID + '" style="visibility:hidden;' + ((canBlast && blastButtonDisabled || !canBlast && hifiButtonDisabled) ? "background-color:#000;opacity:0.5;" : "") + '"></div>' +
|
||||||
'<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
|
'<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
|
||||||
'<label id="' + showShareButtonsLabelID + '">SHARE</label>' +
|
'<label id="' + showShareButtonsLabelID + '">' + shareButtonLabelTextInactive + '</label>' +
|
||||||
'<span class="showShareButtonDots">' +
|
'<span id="' + showShareButtonsDotsID + '" class="showShareButtonDots">' +
|
||||||
'' +
|
'' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
|
@ -217,7 +228,7 @@ function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabl
|
||||||
document.getElementById(parentID + 'img').onclick = function () { selectImageToShare(parentID, true); };
|
document.getElementById(parentID + 'img').onclick = function () { selectImageToShare(parentID, true); };
|
||||||
} else {
|
} else {
|
||||||
shareBarInnerHTML = '<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
|
shareBarInnerHTML = '<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
|
||||||
'<label id="' + showShareButtonsLabelID + '">SHARE</label>' +
|
'<label id="' + showShareButtonsLabelID + '">' + shareButtonLabelTextInactive + '</label>' +
|
||||||
'<span class="showShareButtonDots">' +
|
'<span class="showShareButtonDots">' +
|
||||||
'' +
|
'' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
|
@ -230,7 +241,7 @@ function createShareBar(parentID, isLoggedIn, canShare, isGif, blastButtonDisabl
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shareBarInnerHTML = '<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
|
shareBarInnerHTML = '<div class="showShareButtonsButtonDiv inactive" id="' + showShareButtonsButtonDivID + '" onclick="selectImageToShare(' + parentID + ', true)">' +
|
||||||
'<label id="' + showShareButtonsLabelID + '">SHARE</label>' +
|
'<label id="' + showShareButtonsLabelID + '">' + shareButtonLabelTextInactive + '</label>' +
|
||||||
'<span class="showShareButtonDots">' +
|
'<span class="showShareButtonDots">' +
|
||||||
'' +
|
'' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
|
|
|
@ -482,10 +482,10 @@ function populateNearbyUserList(selectData, oldAudioData) {
|
||||||
isPresent: true,
|
isPresent: true,
|
||||||
isReplicated: avatar.isReplicated
|
isReplicated: avatar.isReplicated
|
||||||
};
|
};
|
||||||
|
// Everyone needs to see admin status. Username and fingerprint returns default constructor output if the requesting user isn't an admin.
|
||||||
|
Users.requestUsernameFromID(id);
|
||||||
if (id) {
|
if (id) {
|
||||||
addAvatarNode(id); // No overlay for ourselves
|
addAvatarNode(id); // No overlay for ourselves
|
||||||
// Everyone needs to see admin status. Username and fingerprint returns default constructor output if the requesting user isn't an admin.
|
|
||||||
Users.requestUsernameFromID(id);
|
|
||||||
avatarsOfInterest[id] = true;
|
avatarsOfInterest[id] = true;
|
||||||
} else {
|
} else {
|
||||||
// Return our username from the Account API
|
// Return our username from the Account API
|
||||||
|
|
|
@ -42,7 +42,6 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
|
||||||
const QCommandLineOption listenPortOption("listenPort", "listen port", QString::number(INVALID_PORT));
|
const QCommandLineOption listenPortOption("listenPort", "listen port", QString::number(INVALID_PORT));
|
||||||
parser.addOption(listenPortOption);
|
parser.addOption(listenPortOption);
|
||||||
|
|
||||||
|
|
||||||
if (!parser.parse(QCoreApplication::arguments())) {
|
if (!parser.parse(QCoreApplication::arguments())) {
|
||||||
qCritical() << parser.errorText() << endl;
|
qCritical() << parser.errorText() << endl;
|
||||||
parser.showHelp();
|
parser.showHelp();
|
||||||
|
@ -66,6 +65,7 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
|
||||||
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtInfoMsg, false);
|
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtInfoMsg, false);
|
||||||
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtWarningMsg, false);
|
const_cast<QLoggingCategory*>(&shared())->setEnabled(QtWarningMsg, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
QString domainServerAddress = "127.0.0.1:40103";
|
QString domainServerAddress = "127.0.0.1:40103";
|
||||||
if (parser.isSet(domainAddressOption)) {
|
if (parser.isSet(domainAddressOption)) {
|
||||||
|
@ -90,14 +90,16 @@ ACClientApp::ACClientApp(int argc, char* argv[]) :
|
||||||
|
|
||||||
|
|
||||||
auto nodeList = DependencyManager::get<NodeList>();
|
auto nodeList = DependencyManager::get<NodeList>();
|
||||||
// start the nodeThread so its event loop is running
|
|
||||||
nodeList->startThread();
|
|
||||||
|
|
||||||
// setup a timer for domain-server check ins
|
// setup a timer for domain-server check ins
|
||||||
QTimer* domainCheckInTimer = new QTimer(nodeList.data());
|
QTimer* domainCheckInTimer = new QTimer(nodeList.data());
|
||||||
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
|
connect(domainCheckInTimer, &QTimer::timeout, nodeList.data(), &NodeList::sendDomainServerCheckIn);
|
||||||
domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
|
domainCheckInTimer->start(DOMAIN_SERVER_CHECK_IN_MSECS);
|
||||||
|
|
||||||
|
// start the nodeThread so its event loop is running
|
||||||
|
// (must happen after the checkin timer is created with the nodelist as it's parent)
|
||||||
|
nodeList->startThread();
|
||||||
|
|
||||||
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
const DomainHandler& domainHandler = nodeList->getDomainHandler();
|
||||||
|
|
||||||
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
|
||||||
|
|
Loading…
Reference in a new issue