mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
Merge branch 'vive-ui' into feature/equip-hotspots
This commit is contained in:
commit
eabb8d08c0
100 changed files with 1572 additions and 588 deletions
|
@ -13,13 +13,13 @@ We no longer require install of qt5 via our [homebrew formulas repository](https
|
|||
Assuming you've installed OpenSSL or Qt 5 using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR and QT_CMAKE_PREFIX_PATH so CMake can find your installations.
|
||||
For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
|
||||
|
||||
export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2d_1
|
||||
export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2h_1/
|
||||
|
||||
For Qt 5.5.1 installed via homebrew, set QT_CMAKE_PREFIX_PATH as follows.
|
||||
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt5/5.5.1_2/lib/cmake
|
||||
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt55/5.5.1/lib/cmake
|
||||
|
||||
Not that these use the versions from homebrew formulae at the time of this writing, and the version in the path will likely change.
|
||||
Note that these use the versions from homebrew formulae at the time of this writing, and the version in the path will likely change.
|
||||
|
||||
###Xcode
|
||||
If Xcode is your editor of choice, you can ask CMake to generate Xcode project files instead of Unix Makefiles.
|
||||
|
|
4
cmake/externals/neuron/CMakeLists.txt
vendored
4
cmake/externals/neuron/CMakeLists.txt
vendored
|
@ -4,8 +4,8 @@ set(EXTERNAL_NAME neuron)
|
|||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
|
||||
set(NEURON_URL "https://s3.amazonaws.com/hifi-public/dependencies/neuron_datareader_b.12.zip")
|
||||
set(NEURON_URL_MD5 "0ab54ca04c9cc8094e0fa046c226e574")
|
||||
set(NEURON_URL "https://s3.amazonaws.com/hifi-public/dependencies/neuron_datareader_b.12.2.zip")
|
||||
set(NEURON_URL_MD5 "84273ad2200bf86a9279d1f412a822ca")
|
||||
|
||||
ExternalProject_Add(${EXTERNAL_NAME}
|
||||
URL ${NEURON_URL}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"version": 1.4,
|
||||
"version": 1.5,
|
||||
"settings": [
|
||||
{
|
||||
"name": "metaverse",
|
||||
|
@ -116,6 +116,7 @@
|
|||
"name": "hosts",
|
||||
"label": "Hosts",
|
||||
"type": "table",
|
||||
"can_add_new_rows": true,
|
||||
"help": "Usernames of hosts who can reliably show your domain to new visitors.",
|
||||
"numbered": false,
|
||||
"columns": [
|
||||
|
@ -130,6 +131,7 @@
|
|||
"name": "tags",
|
||||
"label": "Tags",
|
||||
"type": "table",
|
||||
"can_add_new_rows": true,
|
||||
"help": "Common categories under which your domain falls.",
|
||||
"numbered": false,
|
||||
"columns": [
|
||||
|
@ -139,6 +141,218 @@
|
|||
"can_set": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Operating Hours",
|
||||
"help": "\"Open\" domains can be searched using their operating hours. Hours are entered in the local timezone, selected below.",
|
||||
|
||||
"name": "weekday_hours",
|
||||
"caption": "Weekday Hours (Monday-Friday)",
|
||||
"type": "table",
|
||||
"can_add_new_rows": false,
|
||||
"columns": [
|
||||
{
|
||||
"name": "open",
|
||||
"label": "Opening Time",
|
||||
"type": "time",
|
||||
"default": "00:00",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"name": "close",
|
||||
"label": "Closing Time",
|
||||
"type": "time",
|
||||
"default": "23:59",
|
||||
"editable": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "weekend_hours",
|
||||
"label": "Weekend Hours (Saturday/Sunday)",
|
||||
"type": "table",
|
||||
"can_add_new_rows": false,
|
||||
"columns": [
|
||||
{
|
||||
"name": "open",
|
||||
"label": "Opening Time",
|
||||
"type": "time",
|
||||
"default": "00:00",
|
||||
"editable": true
|
||||
},
|
||||
{
|
||||
"name": "close",
|
||||
"label": "Closing Time",
|
||||
"type": "time",
|
||||
"default": "23:59",
|
||||
"editable": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Time Zone",
|
||||
"name": "utc_offset",
|
||||
"caption": "Time Zone",
|
||||
"help": "This server's time zone. Used to define your server's operating hours.",
|
||||
"type": "select",
|
||||
"options": [
|
||||
{
|
||||
"value": "-12",
|
||||
"label": "UTC-12:00"
|
||||
},
|
||||
{
|
||||
"value": "-11",
|
||||
"label": "UTC-11:00"
|
||||
},
|
||||
{
|
||||
"value": "-10",
|
||||
"label": "UTC-10:00"
|
||||
},
|
||||
{
|
||||
"value": "-9.5",
|
||||
"label": "UTC-09:30"
|
||||
},
|
||||
{
|
||||
"value": "-9",
|
||||
"label": "UTC-09:00"
|
||||
},
|
||||
{
|
||||
"value": "-8",
|
||||
"label": "UTC-08:00"
|
||||
},
|
||||
{
|
||||
"value": "-7",
|
||||
"label": "UTC-07:00"
|
||||
},
|
||||
{
|
||||
"value": "-6",
|
||||
"label": "UTC-06:00"
|
||||
},
|
||||
{
|
||||
"value": "-5",
|
||||
"label": "UTC-05:00"
|
||||
},
|
||||
{
|
||||
"value": "-4",
|
||||
"label": "UTC-04:00"
|
||||
},
|
||||
{
|
||||
"value": "-3.5",
|
||||
"label": "UTC-03:30"
|
||||
},
|
||||
{
|
||||
"value": "-3",
|
||||
"label": "UTC-03:00"
|
||||
},
|
||||
{
|
||||
"value": "-2",
|
||||
"label": "UTC-02:00"
|
||||
},
|
||||
{
|
||||
"value": "-1",
|
||||
"label": "UTC-01:00"
|
||||
},
|
||||
{
|
||||
"value": "",
|
||||
"label": "UTC±00:00"
|
||||
},
|
||||
{
|
||||
"value": "1",
|
||||
"label": "UTC+01:00"
|
||||
},
|
||||
{
|
||||
"value": "2",
|
||||
"label": "UTC+02:00"
|
||||
},
|
||||
{
|
||||
"value": "3",
|
||||
"label": "UTC+03:00"
|
||||
},
|
||||
{
|
||||
"value": "3.5",
|
||||
"label": "UTC+03:30"
|
||||
},
|
||||
{
|
||||
"value": "4",
|
||||
"label": "UTC+04:00"
|
||||
},
|
||||
{
|
||||
"value": "4.5",
|
||||
"label": "UTC+04:30"
|
||||
},
|
||||
{
|
||||
"value": "5",
|
||||
"label": "UTC+05:00"
|
||||
},
|
||||
{
|
||||
"value": "5.5",
|
||||
"label": "UTC+05:30"
|
||||
},
|
||||
{
|
||||
"value": "5.75",
|
||||
"label": "UTC+05:45"
|
||||
},
|
||||
{
|
||||
"value": "6",
|
||||
"label": "UTC+06:00"
|
||||
},
|
||||
{
|
||||
"value": "6.5",
|
||||
"label": "UTC+06:30"
|
||||
},
|
||||
{
|
||||
"value": "7",
|
||||
"label": "UTC+07:00"
|
||||
},
|
||||
{
|
||||
"value": "8",
|
||||
"label": "UTC+08:00"
|
||||
},
|
||||
{
|
||||
"value": "8.5",
|
||||
"label": "UTC+08:30"
|
||||
},
|
||||
{
|
||||
"value": "8.75",
|
||||
"label": "UTC+08:45"
|
||||
},
|
||||
{
|
||||
"value": "9",
|
||||
"label": "UTC+09:00"
|
||||
},
|
||||
{
|
||||
"value": "9.5",
|
||||
"label": "UTC+09:30"
|
||||
},
|
||||
{
|
||||
"value": "10",
|
||||
"label": "UTC+10:00"
|
||||
},
|
||||
{
|
||||
"value": "10.5",
|
||||
"label": "UTC+10:30"
|
||||
},
|
||||
{
|
||||
"value": "11",
|
||||
"label": "UTC+11:00"
|
||||
},
|
||||
{
|
||||
"value": "12",
|
||||
"label": "UTC+12:00"
|
||||
},
|
||||
{
|
||||
"value": "12.75",
|
||||
"label": "UTC+12:45"
|
||||
},
|
||||
{
|
||||
"value": "13",
|
||||
"label": "UTC+13:00"
|
||||
},
|
||||
{
|
||||
"value": "14",
|
||||
"label": "UTC+14:00"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
@ -243,6 +243,16 @@ $(document).ready(function(){
|
|||
}
|
||||
});
|
||||
|
||||
$('#' + Settings.FORM_ID).on('change', 'input.table-time', function() {
|
||||
// Bootstrap switches in table: set the changed data attribute for all rows in table.
|
||||
var row = $(this).closest('tr');
|
||||
if (row.hasClass("value-row")) { // Don't set attribute on input row switches prior to it being added to table.
|
||||
row.find('td.' + Settings.DATA_COL_CLASS + ' input').attr('data-changed', true);
|
||||
updateDataChangedForSiblingRows(row, true);
|
||||
badgeSidebarForDifferences($(this));
|
||||
}
|
||||
});
|
||||
|
||||
$('.advanced-toggle').click(function(){
|
||||
Settings.showAdvanced = !Settings.showAdvanced
|
||||
var advancedSelector = $('.' + Settings.ADVANCED_CLASS)
|
||||
|
@ -987,7 +997,7 @@ function makeTable(setting, keypath, setting_value, isLocked) {
|
|||
html += "<td class='key'>" + rowIndexOrName + "</td>"
|
||||
}
|
||||
|
||||
var isNonDeletableRow = false;
|
||||
var isNonDeletableRow = !setting.can_add_new_rows;
|
||||
|
||||
_.each(setting.columns, function(col) {
|
||||
|
||||
|
@ -1007,6 +1017,10 @@ function makeTable(setting, keypath, setting_value, isLocked) {
|
|||
html += "<td class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>"
|
||||
+ "<input type='checkbox' class='form-control table-checkbox' "
|
||||
+ "name='" + colName + "'" + (colValue ? " checked" : "") + " /></td>";
|
||||
} else if (isArray && col.type === "time" && col.editable) {
|
||||
html += "<td class='" + Settings.DATA_COL_CLASS + "'name='" + col.name + "'>"
|
||||
+ "<input type='time' class='form-control table-time' "
|
||||
+ "name='" + colName + "' value='" + (colValue || col.default || "00:00") + "' /></td>";
|
||||
} else {
|
||||
// Use a hidden input so that the values are posted.
|
||||
html += "<td class='" + Settings.DATA_COL_CLASS + "' name='" + colName + "'>"
|
||||
|
@ -1196,15 +1210,21 @@ function addTableRow(add_glyphicon) {
|
|||
// Hide inputs
|
||||
var input = $(element).find("input")
|
||||
var isCheckbox = false;
|
||||
var isTime = false;
|
||||
if (input.hasClass("table-checkbox")) {
|
||||
input = $(input).parent();
|
||||
isCheckbox = true;
|
||||
} else if (input.hasClass("table-time")) {
|
||||
input = $(input).parent();
|
||||
isTime = true;
|
||||
}
|
||||
|
||||
var val = input.val();
|
||||
if (isCheckbox) {
|
||||
val = $(input).find("input").is(':checked');
|
||||
// don't hide the checkbox
|
||||
val = $(input).find("input").is(':checked');
|
||||
} else if (isTime) {
|
||||
// don't hide the time
|
||||
} else {
|
||||
input.attr("type", "hidden")
|
||||
}
|
||||
|
|
|
@ -10,16 +10,18 @@
|
|||
|
||||
#include "DomainMetadata.h"
|
||||
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <AccountManager.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <LimitedNodeList.h>
|
||||
|
||||
#include "DomainServer.h"
|
||||
#include "DomainServerNodeData.h"
|
||||
|
||||
const QString DomainMetadata::USERS = "users";
|
||||
const QString DomainMetadata::USERS_NUM_TOTAL = "num_users";
|
||||
const QString DomainMetadata::USERS_NUM_ANON = "num_anon_users";
|
||||
const QString DomainMetadata::USERS_HOSTNAMES = "user_hostnames";
|
||||
const QString DomainMetadata::Users::NUM_TOTAL = "num_users";
|
||||
const QString DomainMetadata::Users::NUM_ANON = "num_anon_users";
|
||||
const QString DomainMetadata::Users::HOSTNAMES = "user_hostnames";
|
||||
// users metadata will appear as (JSON):
|
||||
// { "num_users": Number,
|
||||
// "num_anon_users": Number,
|
||||
|
@ -27,26 +29,30 @@ const QString DomainMetadata::USERS_HOSTNAMES = "user_hostnames";
|
|||
// }
|
||||
|
||||
const QString DomainMetadata::DESCRIPTORS = "descriptors";
|
||||
const QString DomainMetadata::DESCRIPTORS_DESCRIPTION = "description";
|
||||
const QString DomainMetadata::DESCRIPTORS_CAPACITY = "capacity"; // parsed from security
|
||||
const QString DomainMetadata::DESCRIPTORS_RESTRICTION = "restriction"; // parsed from ACL
|
||||
const QString DomainMetadata::DESCRIPTORS_MATURITY = "maturity";
|
||||
const QString DomainMetadata::DESCRIPTORS_HOSTS = "hosts";
|
||||
const QString DomainMetadata::DESCRIPTORS_TAGS = "tags";
|
||||
const QString DomainMetadata::Descriptors::DESCRIPTION = "description";
|
||||
const QString DomainMetadata::Descriptors::CAPACITY = "capacity"; // parsed from security
|
||||
const QString DomainMetadata::Descriptors::RESTRICTION = "restriction"; // parsed from ACL
|
||||
const QString DomainMetadata::Descriptors::MATURITY = "maturity";
|
||||
const QString DomainMetadata::Descriptors::HOSTS = "hosts";
|
||||
const QString DomainMetadata::Descriptors::TAGS = "tags";
|
||||
const QString DomainMetadata::Descriptors::HOURS = "hours";
|
||||
const QString DomainMetadata::Descriptors::Hours::WEEKDAY = "weekday";
|
||||
const QString DomainMetadata::Descriptors::Hours::WEEKEND = "weekend";
|
||||
const QString DomainMetadata::Descriptors::Hours::UTC_OFFSET = "utc_offset";
|
||||
const QString DomainMetadata::Descriptors::Hours::OPEN = "open";
|
||||
const QString DomainMetadata::Descriptors::Hours::CLOSE = "close";
|
||||
// descriptors metadata will appear as (JSON):
|
||||
// { "capacity": Number,
|
||||
// TODO: "hours": String, // UTF-8 representation of the week, split into 15" segments
|
||||
// { "description": String, // capped description
|
||||
// "capacity": Number,
|
||||
// "restriction": String, // enum of either open, hifi, or acl
|
||||
// "maturity": String, // enum corresponding to ESRB ratings
|
||||
// "hosts": [ String ], // capped list of usernames
|
||||
// "description": String, // capped description
|
||||
// TODO: "img": {
|
||||
// "src": String,
|
||||
// "type": String,
|
||||
// "size": Number,
|
||||
// "updated_at": Number,
|
||||
// },
|
||||
// "tags": [ String ], // capped list of tags
|
||||
// "hours": {
|
||||
// "utc_offset": Number,
|
||||
// "weekday": [ { "open": Time, "close": Time } ],
|
||||
// "weekend": [ { "open": Time, "close": Time } ],
|
||||
// }
|
||||
// }
|
||||
|
||||
// metadata will appear as (JSON):
|
||||
|
@ -54,36 +60,167 @@ const QString DomainMetadata::DESCRIPTORS_TAGS = "tags";
|
|||
//
|
||||
// it is meant to be sent to and consumed by an external API
|
||||
|
||||
DomainMetadata::DomainMetadata() {
|
||||
_metadata[USERS] = {};
|
||||
_metadata[DESCRIPTORS] = {};
|
||||
DomainMetadata::DomainMetadata(QObject* domainServer) : QObject(domainServer) {
|
||||
// set up the structure necessary for casting during parsing (see parseHours, esp.)
|
||||
_metadata[USERS] = QVariantMap {};
|
||||
_metadata[DESCRIPTORS] = QVariantMap { {
|
||||
Descriptors::HOURS, QVariantMap {
|
||||
{ Descriptors::Hours::WEEKDAY, QVariantList {
|
||||
QVariantList{ QVariant{}, QVariant{} } }
|
||||
},
|
||||
{ Descriptors::Hours::WEEKEND, QVariantList {
|
||||
QVariantList{ QVariant{}, QVariant{} } }
|
||||
}
|
||||
}
|
||||
} };
|
||||
|
||||
assert(dynamic_cast<DomainServer*>(domainServer));
|
||||
DomainServer* server = static_cast<DomainServer*>(domainServer);
|
||||
|
||||
// update the metadata when a user (dis)connects
|
||||
connect(server, &DomainServer::userConnected, this, &DomainMetadata::usersChanged);
|
||||
connect(server, &DomainServer::userDisconnected, this, &DomainMetadata::usersChanged);
|
||||
|
||||
// update the metadata when security changes
|
||||
connect(&server->_settingsManager, &DomainServerSettingsManager::updateNodePermissions,
|
||||
this, static_cast<void(DomainMetadata::*)()>(&DomainMetadata::securityChanged));
|
||||
|
||||
// initialize the descriptors
|
||||
securityChanged(false);
|
||||
descriptorsChanged();
|
||||
}
|
||||
|
||||
void DomainMetadata::setDescriptors(QVariantMap& settings) {
|
||||
QJsonObject DomainMetadata::get() {
|
||||
maybeUpdateUsers();
|
||||
return QJsonObject::fromVariantMap(_metadata);
|
||||
}
|
||||
|
||||
QJsonObject DomainMetadata::get(const QString& group) {
|
||||
maybeUpdateUsers();
|
||||
return QJsonObject::fromVariantMap(_metadata[group].toMap());
|
||||
}
|
||||
|
||||
// merge delta into target
|
||||
// target should be of the form [ OpenTime, CloseTime ],
|
||||
// delta should be of the form [ { open: Time, close: Time } ]
|
||||
void parseHours(QVariant delta, QVariant& target) {
|
||||
using Hours = DomainMetadata::Descriptors::Hours;
|
||||
|
||||
assert(target.canConvert<QVariantList>());
|
||||
auto& targetList = *static_cast<QVariantList*>(target.data());
|
||||
|
||||
// if/when multiple ranges are allowed, this list will need to be iterated
|
||||
assert(targetList[0].canConvert<QVariantList>());
|
||||
auto& hours = *static_cast<QVariantList*>(targetList[0].data());
|
||||
|
||||
auto deltaHours = delta.toList()[0].toMap();
|
||||
if (deltaHours.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// merge delta into base
|
||||
static const int OPEN_INDEX = 0;
|
||||
static const int CLOSE_INDEX = 1;
|
||||
auto open = deltaHours.find(Hours::OPEN);
|
||||
if (open != deltaHours.end()) {
|
||||
hours[OPEN_INDEX] = open.value();
|
||||
}
|
||||
assert(hours[OPEN_INDEX].canConvert<QString>());
|
||||
auto close = deltaHours.find(Hours::CLOSE);
|
||||
if (close != deltaHours.end()) {
|
||||
hours[CLOSE_INDEX] = close.value();
|
||||
}
|
||||
assert(hours[CLOSE_INDEX].canConvert<QString>());
|
||||
}
|
||||
|
||||
void DomainMetadata::descriptorsChanged() {
|
||||
// get descriptors
|
||||
assert(_metadata[DESCRIPTORS].canConvert<QVariantMap>());
|
||||
auto& state = *static_cast<QVariantMap*>(_metadata[DESCRIPTORS].data());
|
||||
auto settings = static_cast<DomainServer*>(parent())->_settingsManager.getSettingsMap();
|
||||
auto descriptors = settings[DESCRIPTORS].toMap();
|
||||
|
||||
// copy simple descriptors (description/maturity)
|
||||
state[Descriptors::DESCRIPTION] = descriptors[Descriptors::DESCRIPTION];
|
||||
state[Descriptors::MATURITY] = descriptors[Descriptors::MATURITY];
|
||||
|
||||
// copy array descriptors (hosts/tags)
|
||||
state[Descriptors::HOSTS] = descriptors[Descriptors::HOSTS].toList();
|
||||
state[Descriptors::TAGS] = descriptors[Descriptors::TAGS].toList();
|
||||
|
||||
// parse capacity
|
||||
const QString CAPACITY = "security.maximum_user_capacity";
|
||||
const QVariant* capacityVariant = valueForKeyPath(settings, CAPACITY);
|
||||
unsigned int capacity = capacityVariant ? capacityVariant->toUInt() : 0;
|
||||
state[Descriptors::CAPACITY] = capacity;
|
||||
|
||||
// TODO: Keep parity with ACL development.
|
||||
const QString RESTRICTION = "security.restricted_access";
|
||||
const QString RESTRICTION_OPEN = "open";
|
||||
// const QString RESTRICTION_HIFI = "hifi";
|
||||
const QString RESTRICTION_ACL = "acl";
|
||||
const QVariant* isRestrictedVariant = valueForKeyPath(settings, RESTRICTION);
|
||||
bool isRestricted = isRestrictedVariant ? isRestrictedVariant->toBool() : false;
|
||||
QString restriction = isRestricted ? RESTRICTION_ACL : RESTRICTION_OPEN;
|
||||
|
||||
QVariantMap descriptors = settings[DESCRIPTORS].toMap();
|
||||
descriptors[DESCRIPTORS_CAPACITY] = capacity;
|
||||
descriptors[DESCRIPTORS_RESTRICTION] = restriction;
|
||||
_metadata[DESCRIPTORS] = descriptors;
|
||||
// parse operating hours
|
||||
const QString WEEKDAY_HOURS = "weekday_hours";
|
||||
const QString WEEKEND_HOURS = "weekend_hours";
|
||||
const QString UTC_OFFSET = "utc_offset";
|
||||
assert(state[Descriptors::HOURS].canConvert<QVariantMap>());
|
||||
auto& hours = *static_cast<QVariantMap*>(state[Descriptors::HOURS].data());
|
||||
parseHours(descriptors.take(WEEKDAY_HOURS), hours[Descriptors::Hours::WEEKDAY]);
|
||||
parseHours(descriptors.take(WEEKEND_HOURS), hours[Descriptors::Hours::WEEKEND]);
|
||||
hours[Descriptors::Hours::UTC_OFFSET] = descriptors.take(UTC_OFFSET);
|
||||
|
||||
#if DEV_BUILD || PR_BUILD
|
||||
qDebug() << "Domain metadata descriptors set:" << descriptors;
|
||||
qDebug() << "Domain metadata descriptors set:" << QJsonObject::fromVariantMap(_metadata[DESCRIPTORS].toMap());
|
||||
#endif
|
||||
|
||||
sendDescriptors();
|
||||
}
|
||||
|
||||
void DomainMetadata::securityChanged(bool send) {
|
||||
// get descriptors
|
||||
assert(_metadata[DESCRIPTORS].canConvert<QVariantMap>());
|
||||
auto& state = *static_cast<QVariantMap*>(_metadata[DESCRIPTORS].data());
|
||||
|
||||
const QString RESTRICTION_OPEN = "open";
|
||||
const QString RESTRICTION_ANON = "anon";
|
||||
const QString RESTRICTION_HIFI = "hifi";
|
||||
const QString RESTRICTION_ACL = "acl";
|
||||
|
||||
QString restriction;
|
||||
|
||||
const auto& settingsManager = static_cast<DomainServer*>(parent())->_settingsManager;
|
||||
bool hasAnonymousAccess =
|
||||
settingsManager.getStandardPermissionsForName(NodePermissions::standardNameAnonymous).canConnectToDomain;
|
||||
bool hasHifiAccess =
|
||||
settingsManager.getStandardPermissionsForName(NodePermissions::standardNameLoggedIn).canConnectToDomain;
|
||||
if (hasAnonymousAccess) {
|
||||
restriction = hasHifiAccess ? RESTRICTION_OPEN : RESTRICTION_ANON;
|
||||
} else if (hasHifiAccess) {
|
||||
restriction = RESTRICTION_HIFI;
|
||||
} else {
|
||||
restriction = RESTRICTION_ACL;
|
||||
}
|
||||
|
||||
state[Descriptors::RESTRICTION] = restriction;
|
||||
|
||||
#if DEV_BUILD || PR_BUILD
|
||||
qDebug() << "Domain metadata restriction set:" << restriction;
|
||||
#endif
|
||||
|
||||
if (send) {
|
||||
sendDescriptors();
|
||||
}
|
||||
}
|
||||
|
||||
void DomainMetadata::usersChanged() {
|
||||
++_tic;
|
||||
|
||||
#if DEV_BUILD || PR_BUILD
|
||||
qDebug() << "Domain metadata users change detected";
|
||||
#endif
|
||||
}
|
||||
|
||||
void DomainMetadata::updateUsers() {
|
||||
void DomainMetadata::maybeUpdateUsers() {
|
||||
if (_lastTic == _tic) {
|
||||
return;
|
||||
}
|
||||
_lastTic = _tic;
|
||||
|
||||
static const QString DEFAULT_HOSTNAME = "*";
|
||||
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
@ -112,21 +249,32 @@ void DomainMetadata::updateUsers() {
|
|||
}
|
||||
});
|
||||
|
||||
QVariantMap users = {
|
||||
{ USERS_NUM_TOTAL, numConnected },
|
||||
{ USERS_NUM_ANON, numConnectedAnonymously },
|
||||
{ USERS_HOSTNAMES, userHostnames }};
|
||||
_metadata[USERS] = users;
|
||||
assert(_metadata[USERS].canConvert<QVariantMap>());
|
||||
auto& users = *static_cast<QVariantMap*>(_metadata[USERS].data());
|
||||
users[Users::NUM_TOTAL] = numConnected;
|
||||
users[Users::NUM_ANON] = numConnectedAnonymously;
|
||||
users[Users::HOSTNAMES] = userHostnames;
|
||||
|
||||
#if DEV_BUILD || PR_BUILD
|
||||
qDebug() << "Domain metadata users updated:" << users;
|
||||
qDebug() << "Domain metadata users set:" << QJsonObject::fromVariantMap(_metadata[USERS].toMap());
|
||||
#endif
|
||||
}
|
||||
|
||||
void DomainMetadata::usersChanged() {
|
||||
++_tic;
|
||||
void DomainMetadata::sendDescriptors() {
|
||||
QString domainUpdateJSON = QString("{\"domain\":%1}").arg(QString(QJsonDocument(get(DESCRIPTORS)).toJson(QJsonDocument::Compact)));
|
||||
const QUuid& domainID = DependencyManager::get<LimitedNodeList>()->getSessionUUID();
|
||||
if (!domainID.isNull()) {
|
||||
static const QString DOMAIN_UPDATE = "/api/v1/domains/%1";
|
||||
QString path { DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)) };
|
||||
DependencyManager::get<AccountManager>()->sendRequest(path,
|
||||
AccountManagerAuth::Required,
|
||||
QNetworkAccessManager::PutOperation,
|
||||
JSONCallbackParameters(),
|
||||
domainUpdateJSON.toUtf8());
|
||||
|
||||
#if DEV_BUILD || PR_BUILD
|
||||
qDebug() << "Domain metadata users change detected";
|
||||
qDebug() << "Domain metadata sent to" << path;
|
||||
qDebug() << "Domain metadata update:" << domainUpdateJSON;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,46 +19,56 @@
|
|||
class DomainMetadata : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using Tic = uint32_t;
|
||||
|
||||
static const QString USERS;
|
||||
static const QString USERS_NUM_TOTAL;
|
||||
static const QString USERS_NUM_ANON;
|
||||
static const QString USERS_HOSTNAMES;
|
||||
class Users {
|
||||
public:
|
||||
static const QString NUM_TOTAL;
|
||||
static const QString NUM_ANON;
|
||||
static const QString HOSTNAMES;
|
||||
};
|
||||
|
||||
static const QString DESCRIPTORS;
|
||||
static const QString DESCRIPTORS_DESCRIPTION;
|
||||
static const QString DESCRIPTORS_CAPACITY;
|
||||
static const QString DESCRIPTORS_HOURS;
|
||||
static const QString DESCRIPTORS_RESTRICTION;
|
||||
static const QString DESCRIPTORS_MATURITY;
|
||||
static const QString DESCRIPTORS_HOSTS;
|
||||
static const QString DESCRIPTORS_TAGS;
|
||||
static const QString DESCRIPTORS_IMG;
|
||||
static const QString DESCRIPTORS_IMG_SRC;
|
||||
static const QString DESCRIPTORS_IMG_TYPE;
|
||||
static const QString DESCRIPTORS_IMG_SIZE;
|
||||
static const QString DESCRIPTORS_IMG_UPDATED_AT;
|
||||
class Descriptors {
|
||||
public:
|
||||
static const QString DESCRIPTION;
|
||||
static const QString CAPACITY;
|
||||
static const QString RESTRICTION;
|
||||
static const QString MATURITY;
|
||||
static const QString HOSTS;
|
||||
static const QString TAGS;
|
||||
static const QString HOURS;
|
||||
class Hours {
|
||||
public:
|
||||
static const QString WEEKDAY;
|
||||
static const QString WEEKEND;
|
||||
static const QString UTC_OFFSET;
|
||||
static const QString OPEN;
|
||||
static const QString CLOSE;
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
DomainMetadata();
|
||||
DomainMetadata(QObject* domainServer);
|
||||
DomainMetadata() = delete;
|
||||
|
||||
// Returns the last set metadata
|
||||
// If connected users have changed, metadata may need to be updated
|
||||
// this should be checked by storing tic = getTic() between calls
|
||||
// and testing it for equality before the next get (tic == getTic())
|
||||
QJsonObject get() { return QJsonObject::fromVariantMap(_metadata); }
|
||||
QJsonObject getUsers() { return QJsonObject::fromVariantMap(_metadata[USERS].toMap()); }
|
||||
QJsonObject getDescriptors() { return QJsonObject::fromVariantMap(_metadata[DESCRIPTORS].toMap()); }
|
||||
|
||||
uint32_t getTic() { return _tic; }
|
||||
|
||||
void setDescriptors(QVariantMap& settings);
|
||||
void updateUsers();
|
||||
// Get cached metadata
|
||||
QJsonObject get();
|
||||
QJsonObject get(const QString& group);
|
||||
|
||||
public slots:
|
||||
void descriptorsChanged();
|
||||
void securityChanged(bool send);
|
||||
void securityChanged() { securityChanged(true); }
|
||||
void usersChanged();
|
||||
|
||||
protected:
|
||||
void maybeUpdateUsers();
|
||||
void sendDescriptors();
|
||||
|
||||
QVariantMap _metadata;
|
||||
uint32_t _lastTic{ (uint32_t)-1 };
|
||||
uint32_t _tic{ 0 };
|
||||
};
|
||||
|
||||
|
|
|
@ -94,10 +94,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
qRegisterMetaType<DomainServerWebSessionData>("DomainServerWebSessionData");
|
||||
qRegisterMetaTypeStreamOperators<DomainServerWebSessionData>("DomainServerWebSessionData");
|
||||
|
||||
// update the metadata when a user (dis)connects
|
||||
connect(this, &DomainServer::userConnected, &_metadata, &DomainMetadata::usersChanged);
|
||||
connect(this, &DomainServer::userDisconnected, &_metadata, &DomainMetadata::usersChanged);
|
||||
|
||||
// make sure we hear about newly connected nodes from our gatekeeper
|
||||
connect(&_gatekeeper, &DomainGatekeeper::connectedNode, this, &DomainServer::handleConnectedNode);
|
||||
|
||||
|
@ -124,8 +120,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
optionallyGetTemporaryName(args);
|
||||
}
|
||||
|
||||
// update the metadata with current descriptors
|
||||
_metadata.setDescriptors(_settingsManager.getSettingsMap());
|
||||
_metadata = new DomainMetadata(this);
|
||||
}
|
||||
|
||||
DomainServer::~DomainServer() {
|
||||
|
@ -1101,14 +1096,11 @@ void DomainServer::sendHeartbeatToMetaverse(const QString& networkAddress) {
|
|||
NodePermissions anonymousPermissions = _settingsManager.getPermissionsForName(NodePermissions::standardNameAnonymous);
|
||||
domainObject[RESTRICTED_ACCESS_FLAG] = !anonymousPermissions.canConnectToDomain;
|
||||
|
||||
// Add the metadata to the heartbeat
|
||||
static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat";
|
||||
auto tic = _metadata.getTic();
|
||||
if (_metadataTic != tic) {
|
||||
_metadataTic = tic;
|
||||
_metadata.updateUsers();
|
||||
if (_metadata) {
|
||||
// Add the metadata to the heartbeat
|
||||
static const QString DOMAIN_HEARTBEAT_KEY = "heartbeat";
|
||||
domainObject[DOMAIN_HEARTBEAT_KEY] = _metadata->get(DomainMetadata::USERS);
|
||||
}
|
||||
domainObject[DOMAIN_HEARTBEAT_KEY] = _metadata.getUsers();
|
||||
|
||||
QString domainUpdateJSON = QString("{\"domain\":%1}").arg(QString(QJsonDocument(domainObject).toJson(QJsonDocument::Compact)));
|
||||
|
||||
|
|
|
@ -172,13 +172,12 @@ private:
|
|||
|
||||
DomainServerSettingsManager _settingsManager;
|
||||
|
||||
DomainMetadata _metadata;
|
||||
uint32_t _metadataTic{ 0 };
|
||||
|
||||
HifiSockAddr _iceServerSocket;
|
||||
std::unique_ptr<NLPacket> _iceServerHeartbeatPacket;
|
||||
|
||||
QTimer* _iceHeartbeatTimer { nullptr }; // this looks like it dangles when created but it's parented to the DomainServer
|
||||
// These will be parented to this, they are not dangling
|
||||
DomainMetadata* _metadata { nullptr };
|
||||
QTimer* _iceHeartbeatTimer { nullptr };
|
||||
|
||||
QList<QHostAddress> _iceServerAddresses;
|
||||
QSet<QHostAddress> _failedIceServerAddresses;
|
||||
|
@ -190,6 +189,7 @@ private:
|
|||
bool _hasAccessToken { false };
|
||||
|
||||
friend class DomainGatekeeper;
|
||||
friend class DomainMetadata;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QUrlQuery>
|
||||
|
||||
#include <QTimeZone>
|
||||
|
||||
#include <Assignment.h>
|
||||
#include <HifiConfigVariantMap.h>
|
||||
#include <HTTPConnection.h>
|
||||
|
@ -69,7 +71,7 @@ DomainServerSettingsManager::DomainServerSettingsManager() :
|
|||
}
|
||||
|
||||
static const QString MISSING_SETTINGS_DESC_MSG =
|
||||
QString("Did not find settings decription in JSON at %1 - Unable to continue. domain-server will quit.\n%2 at %3")
|
||||
QString("Did not find settings description in JSON at %1 - Unable to continue. domain-server will quit.\n%2 at %3")
|
||||
.arg(SETTINGS_DESCRIPTION_RELATIVE_PATH).arg(parseError.errorString()).arg(parseError.offset);
|
||||
static const int MISSING_SETTINGS_DESC_ERROR_CODE = 6;
|
||||
|
||||
|
@ -241,7 +243,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
|||
}
|
||||
|
||||
QList<QHash<QString, NodePermissionsPointer>> permissionsSets;
|
||||
permissionsSets << _standardAgentPermissions << _agentPermissions;
|
||||
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get();
|
||||
foreach (auto permissionsSet, permissionsSets) {
|
||||
foreach (QString userName, permissionsSet.keys()) {
|
||||
if (onlyEditorsAreRezzers) {
|
||||
|
@ -258,6 +260,27 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
|||
_standardAgentPermissions.clear();
|
||||
_agentPermissions.clear();
|
||||
}
|
||||
|
||||
if (oldVersion < 1.5) {
|
||||
// This was prior to operating hours, so add default hours
|
||||
static const QString WEEKDAY_HOURS{ "descriptors.weekday_hours" };
|
||||
static const QString WEEKEND_HOURS{ "descriptors.weekend_hours" };
|
||||
static const QString UTC_OFFSET{ "descriptors.utc_offset" };
|
||||
|
||||
QVariant* weekdayHours = valueForKeyPath(_configMap.getUserConfig(), WEEKDAY_HOURS, true);
|
||||
QVariant* weekendHours = valueForKeyPath(_configMap.getUserConfig(), WEEKEND_HOURS, true);
|
||||
QVariant* utcOffset = valueForKeyPath(_configMap.getUserConfig(), UTC_OFFSET, true);
|
||||
|
||||
*weekdayHours = QVariantList { QVariantMap{ { "open", QVariant("00:00") }, { "close", QVariant("23:59") } } };
|
||||
*weekendHours = QVariantList { QVariantMap{ { "open", QVariant("00:00") }, { "close", QVariant("23:59") } } };
|
||||
*utcOffset = QVariant(QTimeZone::systemTimeZone().offsetFromUtc(QDateTime::currentDateTime()) / (float)3600);
|
||||
|
||||
// write the new settings to file
|
||||
persistToFile();
|
||||
|
||||
// reload the master and user config so the merged config is correct
|
||||
_configMap.loadMasterAndUserConfig(_argumentList);
|
||||
}
|
||||
}
|
||||
|
||||
unpackPermissions();
|
||||
|
@ -267,7 +290,7 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
|||
}
|
||||
|
||||
void DomainServerSettingsManager::packPermissionsForMap(QString mapName,
|
||||
QHash<QString, NodePermissionsPointer> agentPermissions,
|
||||
NodePermissionsMap& agentPermissions,
|
||||
QString keyPath) {
|
||||
QVariant* security = valueForKeyPath(_configMap.getUserConfig(), "security");
|
||||
if (!security || !security->canConvert(QMetaType::QVariantMap)) {
|
||||
|
@ -378,7 +401,7 @@ void DomainServerSettingsManager::unpackPermissions() {
|
|||
#ifdef WANT_DEBUG
|
||||
qDebug() << "--------------- permissions ---------------------";
|
||||
QList<QHash<QString, NodePermissionsPointer>> permissionsSets;
|
||||
permissionsSets << _standardAgentPermissions << _agentPermissions;
|
||||
permissionsSets << _standardAgentPermissions.get() << _agentPermissions.get();
|
||||
foreach (auto permissionSet, permissionsSets) {
|
||||
QHashIterator<QString, NodePermissionsPointer> i(permissionSet);
|
||||
while (i.hasNext()) {
|
||||
|
|
|
@ -72,11 +72,11 @@ private:
|
|||
|
||||
friend class DomainServer;
|
||||
|
||||
void packPermissionsForMap(QString mapName, QHash<QString, NodePermissionsPointer> agentPermissions, QString keyPath);
|
||||
void packPermissionsForMap(QString mapName, NodePermissionsMap& agentPermissions, QString keyPath);
|
||||
void packPermissions();
|
||||
void unpackPermissions();
|
||||
QHash<QString, NodePermissionsPointer> _standardAgentPermissions; // anonymous, logged-in, localhost
|
||||
QHash<QString, NodePermissionsPointer> _agentPermissions; // specific account-names
|
||||
NodePermissionsMap _standardAgentPermissions; // anonymous, logged-in, localhost
|
||||
NodePermissionsMap _agentPermissions; // specific account-names
|
||||
};
|
||||
|
||||
#endif // hifi_DomainServerSettingsManager_h
|
||||
|
|
|
@ -139,7 +139,7 @@ link_hifi_libraries(shared octree gpu gl gpu-gl procedural model render
|
|||
recording fbx networking model-networking entities avatars
|
||||
audio audio-client animation script-engine physics
|
||||
render-utils entities-renderer ui auto-updater
|
||||
controllers plugins display-plugins input-plugins steamworks-wrapper)
|
||||
controllers plugins ui-plugins display-plugins input-plugins steamworks-wrapper)
|
||||
|
||||
# include the binary directory of render-utils for shader includes
|
||||
target_include_directories(${TARGET_NAME} PRIVATE "${CMAKE_BINARY_DIR}/libraries/render-utils")
|
||||
|
|
|
@ -65,7 +65,7 @@ FocusScope {
|
|||
|
||||
var oldChildren = expectedChildren;
|
||||
var newChildren = d.getRepositionChildren();
|
||||
if (oldRecommendedRect != Qt.rect(0,0,0,0)
|
||||
if (oldRecommendedRect != Qt.rect(0,0,0,0) && oldRecommendedRect != Qt.rect(0,0,1,1)
|
||||
&& (oldRecommendedRect != newRecommendedRect
|
||||
|| oldChildren != newChildren)
|
||||
) {
|
||||
|
@ -297,6 +297,9 @@ FocusScope {
|
|||
|
||||
onPinnedChanged: {
|
||||
if (pinned) {
|
||||
nullFocus.focus = true;
|
||||
nullFocus.forceActiveFocus();
|
||||
|
||||
// recalculate our non-pinned children
|
||||
hiddenChildren = d.findMatchingChildren(desktop, function(child){
|
||||
return !d.isTopLevelWindow(child) && child.visible && !child.pinned;
|
||||
|
@ -478,6 +481,8 @@ FocusScope {
|
|||
|
||||
FocusHack { id: focusHack; }
|
||||
|
||||
FocusScope { id: nullFocus; }
|
||||
|
||||
Rectangle {
|
||||
id: focusDebugger;
|
||||
objectName: "focusDebugger"
|
||||
|
|
|
@ -614,12 +614,6 @@ ModalWindow {
|
|||
readOnly: !root.saveDialog
|
||||
activeFocusOnTab: !readOnly
|
||||
onActiveFocusChanged: if (activeFocus) { selectAll(); }
|
||||
onTextChanged: {
|
||||
if (root.saveDialog && text !== "") {
|
||||
fileTableView.selection.clear();
|
||||
fileTableView.currentRow = -1;
|
||||
}
|
||||
}
|
||||
onAccepted: okAction.trigger();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,12 @@ import QtQuick.Controls 1.4
|
|||
import QtWebEngine 1.1;
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
import "../desktop"
|
||||
import "../desktop" as OriginalDesktop
|
||||
import ".."
|
||||
import "."
|
||||
import "./toolbars"
|
||||
|
||||
Desktop {
|
||||
OriginalDesktop.Desktop {
|
||||
id: desktop
|
||||
|
||||
MouseArea {
|
||||
|
@ -54,12 +54,13 @@ Desktop {
|
|||
WebEngine.settings.localContentCanAccessRemoteUrls = true;
|
||||
|
||||
var sysToolbar = desktop.getToolbar("com.highfidelity.interface.toolbar.system");
|
||||
//toolbars[sysToolbar.objectName] = sysToolbar
|
||||
var toggleHudButton = sysToolbar.addButton({
|
||||
objectName: "hudToggle",
|
||||
imageURL: "../../../icons/hud-01.svg",
|
||||
visible: true,
|
||||
|
||||
pinned: true,
|
||||
});
|
||||
|
||||
toggleHudButton.yOffset = Qt.binding(function(){
|
||||
return desktop.pinned ? 50 : 0
|
||||
});
|
||||
|
|
|
@ -7,14 +7,16 @@ import "."
|
|||
|
||||
Window {
|
||||
id: window
|
||||
frame: ToolFrame { }
|
||||
frame: ToolFrame {
|
||||
horizontalSpacers: horizontal
|
||||
verticalSpacers: !horizontal
|
||||
}
|
||||
hideBackground: true
|
||||
resizable: false
|
||||
destroyOnCloseButton: false
|
||||
destroyOnHidden: false
|
||||
closable: false
|
||||
shown: true
|
||||
pinned: true
|
||||
width: content.width
|
||||
height: content.height
|
||||
visible: true
|
||||
|
@ -32,54 +34,77 @@ Window {
|
|||
}
|
||||
|
||||
onHorizontalChanged: {
|
||||
var oldParent = horizontal ? column : row;
|
||||
var newParent = horizontal ? row : column;
|
||||
var move = [];
|
||||
|
||||
var i;
|
||||
for (i in oldParent.children) {
|
||||
var child = oldParent.children[i];
|
||||
if (child.spacer) {
|
||||
continue;
|
||||
}
|
||||
move.push(oldParent.children[i]);
|
||||
}
|
||||
for (i in move) {
|
||||
move[i].parent = newParent;
|
||||
for (var i in buttons) {
|
||||
var child = buttons[i];
|
||||
child.parent = newParent;
|
||||
if (horizontal) {
|
||||
move[i].y = 0
|
||||
child.y = 0
|
||||
} else {
|
||||
move[i].x = 0
|
||||
child.x = 0
|
||||
}
|
||||
}
|
||||
fixSpacers();
|
||||
}
|
||||
|
||||
Item {
|
||||
id: content
|
||||
implicitHeight: horizontal ? row.height : column.height
|
||||
implicitWidth: horizontal ? row.width : column.width
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: 6
|
||||
visible: window.horizontal
|
||||
Rectangle{ readonly property bool spacer: true; id: rowSpacer1; width: 1; height: row.height }
|
||||
Rectangle{ readonly property bool spacer: true; id: rowSpacer2; width: 1; height: row.height }
|
||||
Rectangle{ readonly property bool spacer: true; id: rowSpacer3; width: 1; height: row.height }
|
||||
Rectangle{ readonly property bool spacer: true; id: rowSpacer4; width: 1; height: row.height }
|
||||
}
|
||||
|
||||
Column {
|
||||
id: column
|
||||
spacing: 6
|
||||
visible: !window.horizontal
|
||||
Rectangle{ readonly property bool spacer: true; id: colSpacer1; width: column.width; height: 1 }
|
||||
Rectangle{ readonly property bool spacer: true; id: colSpacer2; width: column.width; height: 1 }
|
||||
Rectangle{ readonly property bool spacer: true; id: colSpacer3; width: column.width; height: 1 }
|
||||
Rectangle{ readonly property bool spacer: true; id: colSpacer4; width: column.width; height: 1 }
|
||||
}
|
||||
|
||||
Component { id: toolbarButtonBuilder; ToolbarButton { } }
|
||||
|
||||
Connections {
|
||||
target: desktop
|
||||
onPinnedChanged: {
|
||||
if (!window.pinned) {
|
||||
return;
|
||||
}
|
||||
var newPinned = desktop.pinned;
|
||||
for (var i in buttons) {
|
||||
var child = buttons[i];
|
||||
if (desktop.pinned) {
|
||||
if (!child.pinned) {
|
||||
child.visible = false;
|
||||
}
|
||||
} else {
|
||||
child.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function findButtonIndex(name) {
|
||||
if (!name) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (var i in buttons) {
|
||||
var child = buttons[i];
|
||||
if (child.objectName === name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
function findButton(name) {
|
||||
var index = findButtonIndex(name);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
return buttons[index];
|
||||
}
|
||||
|
||||
function addButton(properties) {
|
||||
|
@ -88,30 +113,39 @@ Window {
|
|||
// If a name is specified, then check if there's an existing button with that name
|
||||
// and return it if so. This will allow multiple clients to listen to a single button,
|
||||
// and allow scripts to be idempotent so they don't duplicate buttons if they're reloaded
|
||||
if (properties.objectName) {
|
||||
for (var i in buttons) {
|
||||
var child = buttons[i];
|
||||
if (child.objectName === properties.objectName) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
var result = findButton(properties.objectName);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
properties.toolbar = this;
|
||||
var result = toolbarButtonBuilder.createObject(container, properties);
|
||||
properties.opacity = 0;
|
||||
result = toolbarButtonBuilder.createObject(container, properties);
|
||||
buttons.push(result);
|
||||
fixSpacers();
|
||||
result.opacity = 1;
|
||||
updatePinned();
|
||||
return result;
|
||||
}
|
||||
|
||||
function fixSpacers() {
|
||||
colSpacer3.parent = null
|
||||
colSpacer4.parent = null
|
||||
rowSpacer3.parent = null
|
||||
rowSpacer4.parent = null
|
||||
colSpacer3.parent = column
|
||||
colSpacer4.parent = column
|
||||
rowSpacer3.parent = row
|
||||
rowSpacer4.parent = row
|
||||
function removeButton(name) {
|
||||
var index = findButtonIndex(name);
|
||||
if (index < -1) {
|
||||
console.warn("Tried to remove non-existent button " + name);
|
||||
return;
|
||||
}
|
||||
buttons[index].destroy();
|
||||
buttons.splice(index, 1);
|
||||
updatePinned();
|
||||
}
|
||||
|
||||
function updatePinned() {
|
||||
var newPinned = false;
|
||||
for (var i in buttons) {
|
||||
var child = buttons[i];
|
||||
if (child.pinned) {
|
||||
newPinned = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pinned = newPinned;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,11 +7,40 @@ Item {
|
|||
property alias alpha: button.opacity
|
||||
property var subImage;
|
||||
property int yOffset: 0
|
||||
property int buttonState: 0
|
||||
property var toolbar;
|
||||
property real size: 50 // toolbar ? toolbar.buttonSize : 50
|
||||
width: size; height: size
|
||||
property bool pinned: false
|
||||
clip: true
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: 150
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
|
||||
property alias fadeTargetProperty: button.opacity
|
||||
|
||||
onFadeTargetPropertyChanged: {
|
||||
visible = (fadeTargetProperty !== 0.0);
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if ((!visible && fadeTargetProperty != 0.0) || (visible && fadeTargetProperty == 0.0)) {
|
||||
var target = visible;
|
||||
visible = !visible;
|
||||
fadeTargetProperty = target ? 1.0 : 0.0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onButtonStateChanged: {
|
||||
yOffset = size * buttonState
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (subImage) {
|
||||
if (subImage.y) {
|
||||
|
@ -30,10 +59,7 @@ Item {
|
|||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
console.log("Clicked on button " + image.source + " named " + button.objectName)
|
||||
button.clicked();
|
||||
}
|
||||
onClicked: button.clicked();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ Item {
|
|||
height: 1.66 * window.height
|
||||
x: (window.width - width) / 2
|
||||
y: window.height / 2 - 0.375 * height
|
||||
visible: gradientsSupported && window && window.focus && pane.visible
|
||||
visible: gradientsSupported && window && window.focus && window.content.visible
|
||||
gradient: Gradient {
|
||||
// GradientStop position 0.5 is at full circumference of circle that fits inside the square.
|
||||
GradientStop { position: 0.0; color: "#ff000000" } // black, 100% opacity
|
||||
|
|
|
@ -16,20 +16,67 @@ import "../styles-uit"
|
|||
|
||||
Frame {
|
||||
HifiConstants { id: hifi }
|
||||
property bool horizontalSpacers: false
|
||||
property bool verticalSpacers: false
|
||||
|
||||
Rectangle {
|
||||
// Dialog frame
|
||||
id: frameContent
|
||||
readonly property int frameMargin: 6
|
||||
readonly property int frameMarginLeft: frameMargin
|
||||
readonly property int frameMarginRight: frameMargin
|
||||
readonly property int frameMarginTop: frameMargin
|
||||
readonly property int frameMarginBottom: frameMargin
|
||||
readonly property int frameMarginLeft: frameMargin + (horizontalSpacers ? 12 : 0)
|
||||
readonly property int frameMarginRight: frameMargin + (horizontalSpacers ? 12 : 0)
|
||||
readonly property int frameMarginTop: frameMargin + (verticalSpacers ? 12 : 0)
|
||||
readonly property int frameMarginBottom: frameMargin + (verticalSpacers ? 12 : 0)
|
||||
|
||||
Rectangle {
|
||||
visible: horizontalSpacers
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 8
|
||||
height: window.height
|
||||
color: "gray";
|
||||
radius: 4
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: horizontalSpacers
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 6
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 8
|
||||
height: window.height
|
||||
color: "gray";
|
||||
radius: 4
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: verticalSpacers
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 6
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: 8
|
||||
width: window.width
|
||||
color: "gray";
|
||||
radius: 4
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: verticalSpacers
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 6
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
height: 8
|
||||
width: window.width
|
||||
color: "gray";
|
||||
radius: 4
|
||||
}
|
||||
|
||||
anchors {
|
||||
topMargin: -frameMargin
|
||||
leftMargin: -frameMargin
|
||||
rightMargin: -frameMargin
|
||||
bottomMargin: -frameMargin
|
||||
leftMargin: -frameMarginLeft
|
||||
rightMargin: -frameMarginRight
|
||||
topMargin: -frameMarginTop
|
||||
bottomMargin: -frameMarginBottom
|
||||
}
|
||||
anchors.fill: parent
|
||||
color: hifi.colors.baseGrayHighlight40
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
#include <input-plugins/InputPlugin.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
#include <controllers/StateController.h>
|
||||
#include <UserActivityLoggerScriptingInterface.h>
|
||||
#include <LogHandler.h>
|
||||
#include <MainWindow.h>
|
||||
#include <MessagesClient.h>
|
||||
|
@ -83,7 +84,6 @@
|
|||
#include <PerfStat.h>
|
||||
#include <PhysicsEngine.h>
|
||||
#include <PhysicsHelpers.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <RenderableWebEntityItem.h>
|
||||
#include <RenderShadowTask.h>
|
||||
|
@ -119,7 +119,6 @@
|
|||
#include "InterfaceLogging.h"
|
||||
#include "LODManager.h"
|
||||
#include "ModelPackager.h"
|
||||
#include "PluginContainerProxy.h"
|
||||
#include "scripting/AccountScriptingInterface.h"
|
||||
#include "scripting/AssetMappingsScriptingInterface.h"
|
||||
#include "scripting/AudioDeviceScriptingInterface.h"
|
||||
|
@ -152,6 +151,8 @@
|
|||
#include "InterfaceParentFinder.h"
|
||||
|
||||
#include "FrameTimingsScriptingInterface.h"
|
||||
#include <GPUIdent.h>
|
||||
#include <gl/GLHelpers.h>
|
||||
|
||||
// On Windows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||
// FIXME seems to be broken.
|
||||
|
@ -439,7 +440,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::set<HMDScriptingInterface>();
|
||||
DependencyManager::set<ResourceScriptingInterface>();
|
||||
DependencyManager::set<ToolbarScriptingInterface>();
|
||||
|
||||
DependencyManager::set<UserActivityLoggerScriptingInterface>();
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
DependencyManager::set<SpeechRecognizer>();
|
||||
|
@ -466,7 +467,6 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
// continuing to overburden Application.cpp
|
||||
Cube3DOverlay* _keyboardFocusHighlight{ nullptr };
|
||||
int _keyboardFocusHighlightID{ -1 };
|
||||
PluginContainer* _pluginContainer;
|
||||
|
||||
|
||||
// FIXME hack access to the internal share context for the Chromium helper
|
||||
|
@ -506,6 +506,11 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
_maxOctreePPS(maxOctreePacketsPerSecond.get()),
|
||||
_lastFaceTrackerUpdate(0)
|
||||
{
|
||||
|
||||
|
||||
PluginContainer* pluginContainer = dynamic_cast<PluginContainer*>(this); // set the container for any plugins that care
|
||||
PluginManager::getInstance()->setContainer(pluginContainer);
|
||||
|
||||
// FIXME this may be excessively conservative. On the other hand
|
||||
// maybe I'm used to having an 8-core machine
|
||||
// Perhaps find the ideal thread count and subtract 2 or 3
|
||||
|
@ -523,7 +528,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
|
||||
_entityClipboard->createRootElement();
|
||||
|
||||
_pluginContainer = new PluginContainerProxy();
|
||||
#ifdef Q_OS_WIN
|
||||
installNativeEventFilter(&MyNativeEventFilter::getInstance());
|
||||
#endif
|
||||
|
@ -674,10 +678,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
accountManager->setIsAgent(true);
|
||||
accountManager->setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL);
|
||||
|
||||
// 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.
|
||||
UserActivityLogger::getInstance().launch(applicationVersion(), _previousSessionCrashed, sessionRunTime.get());
|
||||
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
// use our MyAvatar position and quat for address manager path
|
||||
|
@ -767,6 +767,39 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
// Make sure we don't time out during slow operations at startup
|
||||
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.
|
||||
auto gpuIdent = GPUIdent::getInstance();
|
||||
auto glContextData = getGLContextData();
|
||||
QJsonObject properties = {
|
||||
{ "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["slVersion"] },
|
||||
{ "gl_renderer", glContextData["renderer"] }
|
||||
};
|
||||
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();
|
||||
}
|
||||
UserActivityLogger::getInstance().logAction("launch", properties);
|
||||
|
||||
|
||||
// Tell our entity edit sender about our known jurisdictions
|
||||
_entityEditSender.setServerJurisdictions(&_entityServerJurisdictions);
|
||||
_entityEditSender.setMyAvatar(getMyAvatar());
|
||||
|
@ -1062,6 +1095,89 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
}
|
||||
});
|
||||
|
||||
// Add periodic checks to send user activity data
|
||||
static int CHECK_NEARBY_AVATARS_INTERVAL_MS = 10000;
|
||||
static int SEND_STATS_INTERVAL_MS = 10000;
|
||||
static int NEARBY_AVATAR_RADIUS_METERS = 10;
|
||||
|
||||
// Periodically send fps as a user activity event
|
||||
QTimer* sendStatsTimer = new QTimer(this);
|
||||
sendStatsTimer->setInterval(SEND_STATS_INTERVAL_MS);
|
||||
connect(sendStatsTimer, &QTimer::timeout, this, [this]() {
|
||||
QJsonObject properties = {};
|
||||
MemoryInfo memInfo;
|
||||
if (getMemoryInfo(memInfo)) {
|
||||
properties["system_memory_total"] = static_cast<qint64>(memInfo.totalMemoryBytes);
|
||||
properties["system_memory_used"] = static_cast<qint64>(memInfo.usedMemoryBytes);
|
||||
properties["process_memory_used"] = static_cast<qint64>(memInfo.processUsedMemoryBytes);
|
||||
}
|
||||
|
||||
auto displayPlugin = qApp->getActiveDisplayPlugin();
|
||||
|
||||
properties["fps"] = _frameCounter.rate();
|
||||
properties["present_rate"] = displayPlugin->presentRate();
|
||||
properties["new_frame_present_rate"] = displayPlugin->newFramePresentRate();
|
||||
properties["dropped_frame_rate"] = displayPlugin->droppedFrameRate();
|
||||
properties["sim_rate"] = getAverageSimsPerSecond();
|
||||
properties["avatar_sim_rate"] = getAvatarSimrate();
|
||||
|
||||
auto bandwidthRecorder = DependencyManager::get<BandwidthRecorder>();
|
||||
properties["packet_rate_in"] = bandwidthRecorder->getCachedTotalAverageInputPacketsPerSecond();
|
||||
properties["packet_rate_out"] = bandwidthRecorder->getCachedTotalAverageOutputPacketsPerSecond();
|
||||
properties["kbps_in"] = bandwidthRecorder->getCachedTotalAverageInputKilobitsPerSecond();
|
||||
properties["kbps_out"] = bandwidthRecorder->getCachedTotalAverageOutputKilobitsPerSecond();
|
||||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
SharedNodePointer entityServerNode = nodeList->soloNodeOfType(NodeType::EntityServer);
|
||||
SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
|
||||
SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);
|
||||
SharedNodePointer assetServerNode = nodeList->soloNodeOfType(NodeType::AssetServer);
|
||||
SharedNodePointer messagesMixerNode = nodeList->soloNodeOfType(NodeType::MessagesMixer);
|
||||
properties["entity_ping"] = entityServerNode ? entityServerNode->getPingMs() : -1;
|
||||
properties["audio_ping"] = audioMixerNode ? audioMixerNode->getPingMs() : -1;
|
||||
properties["avatar_ping"] = avatarMixerNode ? avatarMixerNode->getPingMs() : -1;
|
||||
properties["asset_ping"] = assetServerNode ? assetServerNode->getPingMs() : -1;
|
||||
properties["messages_ping"] = messagesMixerNode ? messagesMixerNode->getPingMs() : -1;
|
||||
|
||||
auto loadingRequests = ResourceCache::getLoadingRequests();
|
||||
properties["active_downloads"] = loadingRequests.size();
|
||||
properties["pending_downloads"] = ResourceCache::getPendingRequestCount();
|
||||
|
||||
properties["throttled"] = _displayPlugin ? _displayPlugin->isThrottled() : false;
|
||||
|
||||
UserActivityLogger::getInstance().logAction("stats", properties);
|
||||
});
|
||||
sendStatsTimer->start();
|
||||
|
||||
|
||||
// Periodically check for count of nearby avatars
|
||||
static int lastCountOfNearbyAvatars = -1;
|
||||
QTimer* checkNearbyAvatarsTimer = new QTimer(this);
|
||||
checkNearbyAvatarsTimer->setInterval(CHECK_NEARBY_AVATARS_INTERVAL_MS);
|
||||
connect(checkNearbyAvatarsTimer, &QTimer::timeout, this, [this]() {
|
||||
auto avatarManager = DependencyManager::get<AvatarManager>();
|
||||
int nearbyAvatars = avatarManager->numberOfAvatarsInRange(avatarManager->getMyAvatar()->getPosition(),
|
||||
NEARBY_AVATAR_RADIUS_METERS) - 1;
|
||||
if (nearbyAvatars != lastCountOfNearbyAvatars) {
|
||||
lastCountOfNearbyAvatars = nearbyAvatars;
|
||||
UserActivityLogger::getInstance().logAction("nearby_avatars", { { "count", nearbyAvatars } });
|
||||
}
|
||||
});
|
||||
checkNearbyAvatarsTimer->start();
|
||||
|
||||
// Track user activity event when we receive a mute packet
|
||||
auto onMutedByMixer = []() {
|
||||
UserActivityLogger::getInstance().logAction("received_mute_packet");
|
||||
};
|
||||
connect(DependencyManager::get<AudioClient>().data(), &AudioClient::mutedByMixer, this, onMutedByMixer);
|
||||
|
||||
// Track when the address bar is opened
|
||||
auto onAddressBarToggled = [this]() {
|
||||
// Record time
|
||||
UserActivityLogger::getInstance().logAction("opened_address_bar", { { "uptime_ms", _sessionRunTimer.elapsed() } });
|
||||
};
|
||||
connect(DependencyManager::get<DialogsManager>().data(), &DialogsManager::addressBarToggled, this, onAddressBarToggled);
|
||||
|
||||
// Make sure we don't time out during slow operations at startup
|
||||
updateHeartbeat();
|
||||
|
||||
|
@ -2037,9 +2153,9 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
case Qt::Key_Return:
|
||||
if (isOption) {
|
||||
if (_window->isFullScreen()) {
|
||||
_pluginContainer->unsetFullscreen();
|
||||
unsetFullscreen();
|
||||
} else {
|
||||
_pluginContainer->setFullscreen(nullptr);
|
||||
setFullscreen(nullptr);
|
||||
}
|
||||
} else {
|
||||
Menu::getInstance()->triggerOption(MenuOption::AddressBar);
|
||||
|
@ -2953,7 +3069,6 @@ void Application::loadSettings() {
|
|||
//DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false);
|
||||
|
||||
Menu::getInstance()->loadSettings();
|
||||
|
||||
// If there is a preferred plugin, we probably messed it up with the menu settings, so fix it.
|
||||
auto pluginManager = PluginManager::getInstance();
|
||||
auto plugins = pluginManager->getPreferredDisplayPlugins();
|
||||
|
@ -4578,6 +4693,8 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
|
||||
scriptEngine->registerGlobalObject("ScriptDiscoveryService", DependencyManager::get<ScriptEngines>().data());
|
||||
scriptEngine->registerGlobalObject("Reticle", getApplicationCompositor().getReticleInterface());
|
||||
|
||||
scriptEngine->registerGlobalObject("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
}
|
||||
|
||||
bool Application::canAcceptURL(const QString& urlString) const {
|
||||
|
@ -5180,6 +5297,11 @@ void Application::updateDisplayMode() {
|
|||
return;
|
||||
}
|
||||
|
||||
UserActivityLogger::getInstance().logAction("changed_display_mode", {
|
||||
{ "previous_display_mode", _displayPlugin ? _displayPlugin->getName() : "" },
|
||||
{ "display_mode", newDisplayPlugin ? newDisplayPlugin->getName() : "" }
|
||||
});
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
|
||||
// Make the switch atomic from the perspective of other threads
|
||||
|
@ -5310,3 +5432,49 @@ void Application::showDesktop() {
|
|||
CompositorHelper& Application::getApplicationCompositor() const {
|
||||
return *DependencyManager::get<CompositorHelper>();
|
||||
}
|
||||
|
||||
|
||||
// virtual functions required for PluginContainer
|
||||
ui::Menu* Application::getPrimaryMenu() {
|
||||
auto appMenu = _window->menuBar();
|
||||
auto uiMenu = dynamic_cast<ui::Menu*>(appMenu);
|
||||
return uiMenu;
|
||||
}
|
||||
|
||||
void Application::showDisplayPluginsTools(bool show) {
|
||||
DependencyManager::get<DialogsManager>()->hmdTools(show);
|
||||
}
|
||||
|
||||
GLWidget* Application::getPrimaryWidget() {
|
||||
return _glWidget;
|
||||
}
|
||||
|
||||
MainWindow* Application::getPrimaryWindow() {
|
||||
return getWindow();
|
||||
}
|
||||
|
||||
QOpenGLContext* Application::getPrimaryContext() {
|
||||
return _glWidget->context()->contextHandle();
|
||||
}
|
||||
|
||||
bool Application::makeRenderingContextCurrent() {
|
||||
return _offscreenContext->makeCurrent();
|
||||
}
|
||||
|
||||
void Application::releaseSceneTexture(const gpu::TexturePointer& texture) {
|
||||
Q_ASSERT(QThread::currentThread() == thread());
|
||||
auto& framebufferMap = _lockedFramebufferMap;
|
||||
Q_ASSERT(framebufferMap.contains(texture));
|
||||
auto framebufferPointer = framebufferMap[texture];
|
||||
framebufferMap.remove(texture);
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
framebufferCache->releaseFramebuffer(framebufferPointer);
|
||||
}
|
||||
|
||||
void Application::releaseOverlayTexture(const gpu::TexturePointer& texture) {
|
||||
_applicationOverlay.releaseOverlay(texture);
|
||||
}
|
||||
|
||||
bool Application::isForeground() const {
|
||||
return _isForeground && !_window->isMinimized();
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <PhysicsEngine.h>
|
||||
#include <plugins/Forward.h>
|
||||
#include <plugins/DisplayPlugin.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <ScriptEngine.h>
|
||||
#include <ShapeManager.h>
|
||||
#include <SimpleMovingAverage.h>
|
||||
|
@ -86,14 +87,32 @@ class Application;
|
|||
#endif
|
||||
#define qApp (static_cast<Application*>(QCoreApplication::instance()))
|
||||
|
||||
class Application : public QApplication, public AbstractViewStateInterface, public AbstractScriptingServicesInterface, public AbstractUriHandler {
|
||||
class Application : public QApplication,
|
||||
public AbstractViewStateInterface,
|
||||
public AbstractScriptingServicesInterface,
|
||||
public AbstractUriHandler,
|
||||
public PluginContainer {
|
||||
Q_OBJECT
|
||||
|
||||
// TODO? Get rid of those
|
||||
friend class OctreePacketProcessor;
|
||||
friend class PluginContainerProxy;
|
||||
|
||||
public:
|
||||
|
||||
// virtual functions required for PluginContainer
|
||||
virtual ui::Menu* getPrimaryMenu() override;
|
||||
virtual void requestReset() override { resetSensors(true); }
|
||||
virtual void showDisplayPluginsTools(bool show) override;
|
||||
virtual GLWidget* getPrimaryWidget() override;
|
||||
virtual MainWindow* getPrimaryWindow() override;
|
||||
virtual QOpenGLContext* getPrimaryContext() override;
|
||||
virtual bool makeRenderingContextCurrent() override;
|
||||
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override;
|
||||
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override;
|
||||
virtual bool isForeground() const override;
|
||||
|
||||
virtual DisplayPluginPointer getActiveDisplayPlugin() const override;
|
||||
|
||||
enum Event {
|
||||
Present = DisplayPlugin::Present,
|
||||
Paint = Present + 1,
|
||||
|
@ -163,7 +182,6 @@ public:
|
|||
|
||||
Overlays& getOverlays() { return _overlays; }
|
||||
|
||||
bool isForeground() const { return _isForeground; }
|
||||
|
||||
size_t getFrameCount() const { return _frameCount; }
|
||||
float getFps() const { return _frameCounter.rate(); }
|
||||
|
@ -185,8 +203,6 @@ public:
|
|||
|
||||
void setActiveDisplayPlugin(const QString& pluginName);
|
||||
|
||||
DisplayPluginPointer getActiveDisplayPlugin() const;
|
||||
|
||||
FileLogger* getLogger() const { return _logger; }
|
||||
|
||||
glm::vec2 getViewportDimensions() const;
|
||||
|
@ -195,6 +211,8 @@ public:
|
|||
|
||||
float getRenderResolutionScale() const;
|
||||
|
||||
qint64 getCurrentSessionRuntime() const { return _sessionRunTimer.elapsed(); }
|
||||
|
||||
bool isAboutToQuit() const { return _aboutToQuit; }
|
||||
|
||||
// the isHMDMode is true whenever we use the interface from an HMD and not a standard flat display
|
||||
|
|
|
@ -80,7 +80,8 @@ void DiscoverabilityManager::updateLocation() {
|
|||
locationObject.insert(FRIENDS_ONLY_KEY_IN_LOCATION, (_mode.get() == Discoverability::Friends));
|
||||
|
||||
// if we have a session ID add it now, otherwise add a null value
|
||||
rootObject[SESSION_ID_KEY] = _sessionID.isEmpty() ? QJsonValue() : _sessionID;
|
||||
auto sessionID = accountManager->getSessionID();
|
||||
rootObject[SESSION_ID_KEY] = sessionID.isNull() ? QJsonValue() : sessionID.toString();
|
||||
|
||||
JSONCallbackParameters callbackParameters;
|
||||
callbackParameters.jsonCallbackReceiver = this;
|
||||
|
@ -110,11 +111,8 @@ void DiscoverabilityManager::updateLocation() {
|
|||
callbackParameters.jsonCallbackMethod = "handleHeartbeatResponse";
|
||||
|
||||
QJsonObject heartbeatObject;
|
||||
if (!_sessionID.isEmpty()) {
|
||||
heartbeatObject[SESSION_ID_KEY] = _sessionID;
|
||||
} else {
|
||||
heartbeatObject[SESSION_ID_KEY] = QJsonValue();
|
||||
}
|
||||
auto sessionID = accountManager->getSessionID();
|
||||
heartbeatObject[SESSION_ID_KEY] = sessionID.isNull() ? QJsonValue() : sessionID.toString();
|
||||
|
||||
accountManager->sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Optional,
|
||||
QNetworkAccessManager::PutOperation, callbackParameters,
|
||||
|
@ -126,11 +124,11 @@ void DiscoverabilityManager::handleHeartbeatResponse(QNetworkReply& requestReply
|
|||
auto dataObject = AccountManager::dataObjectFromResponse(requestReply);
|
||||
|
||||
if (!dataObject.isEmpty()) {
|
||||
_sessionID = dataObject[SESSION_ID_KEY].toString();
|
||||
auto sessionID = dataObject[SESSION_ID_KEY].toString();
|
||||
|
||||
// give that session ID to the account manager
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->setSessionID(_sessionID);
|
||||
accountManager->setSessionID(sessionID);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@ private:
|
|||
DiscoverabilityManager();
|
||||
|
||||
Setting::Handle<int> _mode;
|
||||
QString _sessionID;
|
||||
QJsonObject _lastLocationObject;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
#include "PluginContainerProxy.h"
|
||||
|
||||
#include <QtGui/QScreen>
|
||||
#include <QtGui/QWindow>
|
||||
|
||||
#include <plugins/Plugin.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <FramebufferCache.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
#include "GLCanvas.h"
|
||||
#include "ui/DialogsManager.h"
|
||||
|
||||
#include <gl/OffscreenGLCanvas.h>
|
||||
#include <QtGui/QOpenGLContext>
|
||||
|
||||
PluginContainerProxy::PluginContainerProxy() {
|
||||
}
|
||||
|
||||
PluginContainerProxy::~PluginContainerProxy() {
|
||||
}
|
||||
|
||||
ui::Menu* PluginContainerProxy::getPrimaryMenu() {
|
||||
auto appMenu = qApp->_window->menuBar();
|
||||
auto uiMenu = dynamic_cast<ui::Menu*>(appMenu);
|
||||
return uiMenu;
|
||||
}
|
||||
|
||||
bool PluginContainerProxy::isForeground() {
|
||||
return qApp->isForeground() && !qApp->getWindow()->isMinimized();
|
||||
}
|
||||
|
||||
void PluginContainerProxy::requestReset() {
|
||||
// We could signal qApp to sequence this, but it turns out that requestReset is only used from within the main thread anyway.
|
||||
qApp->resetSensors(true);
|
||||
}
|
||||
|
||||
void PluginContainerProxy::showDisplayPluginsTools(bool show) {
|
||||
DependencyManager::get<DialogsManager>()->hmdTools(show);
|
||||
}
|
||||
|
||||
GLWidget* PluginContainerProxy::getPrimaryWidget() {
|
||||
return qApp->_glWidget;
|
||||
}
|
||||
|
||||
MainWindow* PluginContainerProxy::getPrimaryWindow() {
|
||||
return qApp->getWindow();
|
||||
}
|
||||
|
||||
QOpenGLContext* PluginContainerProxy::getPrimaryContext() {
|
||||
return qApp->_glWidget->context()->contextHandle();
|
||||
}
|
||||
|
||||
const DisplayPluginPointer PluginContainerProxy::getActiveDisplayPlugin() const {
|
||||
return qApp->getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
bool PluginContainerProxy::makeRenderingContextCurrent() {
|
||||
return qApp->_offscreenContext->makeCurrent();
|
||||
}
|
||||
|
||||
void PluginContainerProxy::releaseSceneTexture(const gpu::TexturePointer& texture) {
|
||||
Q_ASSERT(QThread::currentThread() == qApp->thread());
|
||||
auto& framebufferMap = qApp->_lockedFramebufferMap;
|
||||
Q_ASSERT(framebufferMap.contains(texture));
|
||||
auto framebufferPointer = framebufferMap[texture];
|
||||
framebufferMap.remove(texture);
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
framebufferCache->releaseFramebuffer(framebufferPointer);
|
||||
}
|
||||
|
||||
void PluginContainerProxy::releaseOverlayTexture(const gpu::TexturePointer& texture) {
|
||||
qApp->_applicationOverlay.releaseOverlay(texture);
|
||||
}
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#pragma once
|
||||
#ifndef hifi_PluginContainerProxy_h
|
||||
#define hifi_PluginContainerProxy_h
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QRect>
|
||||
|
||||
#include <plugins/Forward.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
|
||||
class QActionGroup;
|
||||
|
||||
class PluginContainerProxy : public QObject, PluginContainer {
|
||||
Q_OBJECT
|
||||
PluginContainerProxy();
|
||||
virtual ~PluginContainerProxy();
|
||||
virtual void showDisplayPluginsTools(bool show = true) override;
|
||||
virtual void requestReset() override;
|
||||
virtual bool makeRenderingContextCurrent() override;
|
||||
virtual void releaseSceneTexture(const gpu::TexturePointer& texture) override;
|
||||
virtual void releaseOverlayTexture(const gpu::TexturePointer& texture) override;
|
||||
virtual GLWidget* getPrimaryWidget() override;
|
||||
virtual MainWindow* getPrimaryWindow() override;
|
||||
virtual ui::Menu* getPrimaryMenu() override;
|
||||
virtual QOpenGLContext* getPrimaryContext() override;
|
||||
virtual bool isForeground() override;
|
||||
virtual const DisplayPluginPointer getActiveDisplayPlugin() const override;
|
||||
|
||||
friend class Application;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -722,7 +722,7 @@ void MyAvatar::saveData() {
|
|||
settings.setValue("displayName", _displayName);
|
||||
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||
settings.setValue("useSnapTurn", _useSnapTurn);
|
||||
settings.setValue("clearOverlayWhenDriving", _clearOverlayWhenDriving);
|
||||
settings.setValue("clearOverlayWhenMoving", _clearOverlayWhenMoving);
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
|
@ -842,7 +842,7 @@ void MyAvatar::loadData() {
|
|||
setDisplayName(settings.value("displayName").toString());
|
||||
setCollisionSoundURL(settings.value("collisionSoundURL", DEFAULT_AVATAR_COLLISION_SOUND_URL).toString());
|
||||
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
||||
setClearOverlayWhenDriving(settings.value("clearOverlayWhenDriving", _clearOverlayWhenDriving).toBool());
|
||||
setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool());
|
||||
|
||||
settings.endGroup();
|
||||
|
||||
|
|
|
@ -159,8 +159,8 @@ public:
|
|||
|
||||
Q_INVOKABLE bool getSnapTurn() const { return _useSnapTurn; }
|
||||
Q_INVOKABLE void setSnapTurn(bool on) { _useSnapTurn = on; }
|
||||
Q_INVOKABLE bool getClearOverlayWhenDriving() const { return _clearOverlayWhenDriving; }
|
||||
Q_INVOKABLE void setClearOverlayWhenDriving(bool on) { _clearOverlayWhenDriving = on; }
|
||||
Q_INVOKABLE bool getClearOverlayWhenMoving() const { return _clearOverlayWhenMoving; }
|
||||
Q_INVOKABLE void setClearOverlayWhenMoving(bool on) { _clearOverlayWhenMoving = on; }
|
||||
|
||||
Q_INVOKABLE void setHMDLeanRecenterEnabled(bool value) { _hmdLeanRecenterEnabled = value; }
|
||||
Q_INVOKABLE bool getHMDLeanRecenterEnabled() const { return _hmdLeanRecenterEnabled; }
|
||||
|
@ -405,7 +405,7 @@ private:
|
|||
QString _fullAvatarModelName;
|
||||
QUrl _animGraphUrl {""};
|
||||
bool _useSnapTurn { true };
|
||||
bool _clearOverlayWhenDriving { false };
|
||||
bool _clearOverlayWhenMoving { true };
|
||||
|
||||
// cache of the current HMD sensor position and orientation
|
||||
// in sensor space.
|
||||
|
|
|
@ -15,15 +15,6 @@ class QmlWrapper : public QObject {
|
|||
public:
|
||||
QmlWrapper(QObject* qmlObject, QObject* parent = nullptr)
|
||||
: QObject(parent), _qmlObject(qmlObject) {
|
||||
|
||||
const QMetaObject *metaobject = qmlObject->metaObject();
|
||||
int count = metaobject->propertyCount();
|
||||
qDebug() << "Scanning properties for " << qmlObject;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
QMetaProperty metaproperty = metaobject->property(i);
|
||||
const char *name = metaproperty.name();
|
||||
qDebug() << "Property " << name;
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void writeProperty(QString propertyName, QVariant propertyValue) {
|
||||
|
|
|
@ -20,7 +20,7 @@ class ToolbarProxy;
|
|||
class ToolbarScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE QObject* getToolbar(const QString& toolbarId);
|
||||
Q_INVOKABLE QObject* getToolbar(const QString& toolbarId);
|
||||
};
|
||||
|
||||
#endif // hifi_ToolbarScriptingInterface_h
|
||||
|
|
|
@ -32,7 +32,7 @@ bool OverlayConductor::headOutsideOverlay() const {
|
|||
glm::vec3 uiPos = uiTransform.getTranslation();
|
||||
glm::vec3 uiForward = uiTransform.getRotation() * glm::vec3(0.0f, 0.0f, -1.0f);
|
||||
|
||||
const float MAX_COMPOSITOR_DISTANCE = 0.6f;
|
||||
const float MAX_COMPOSITOR_DISTANCE = 0.99f; // If you're 1m from center of ui sphere, you're at the surface.
|
||||
const float MAX_COMPOSITOR_ANGLE = 180.0f; // rotation check is effectively disabled
|
||||
if (glm::distance(uiPos, hmdPos) > MAX_COMPOSITOR_DISTANCE ||
|
||||
glm::dot(uiForward, hmdForward) < cosf(glm::radians(MAX_COMPOSITOR_ANGLE))) {
|
||||
|
@ -124,7 +124,7 @@ void OverlayConductor::update(float dt) {
|
|||
_flags &= ~SuppressedByDrive;
|
||||
}
|
||||
} else {
|
||||
if (myAvatar->getClearOverlayWhenDriving() && drivingChanged && isDriving) {
|
||||
if (myAvatar->getClearOverlayWhenMoving() && drivingChanged && isDriving) {
|
||||
_flags |= SuppressedByDrive;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,9 +62,9 @@ void setupPreferences() {
|
|||
preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Snap turn when in HMD", getter, setter));
|
||||
}
|
||||
{
|
||||
auto getter = [=]()->bool {return myAvatar->getClearOverlayWhenDriving(); };
|
||||
auto setter = [=](bool value) { myAvatar->setClearOverlayWhenDriving(value); };
|
||||
preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Clear overlays when driving", getter, setter));
|
||||
auto getter = [=]()->bool {return myAvatar->getClearOverlayWhenMoving(); };
|
||||
auto setter = [=](bool value) { myAvatar->setClearOverlayWhenMoving(value); };
|
||||
preferences->addPreference(new CheckPreference(AVATAR_BASICS, "Clear overlays when moving", getter, setter));
|
||||
}
|
||||
{
|
||||
auto getter = []()->QString { return Snapshot::snapshotsLocation.get(); };
|
||||
|
|
|
@ -163,7 +163,6 @@ void Rig::destroyAnimGraph() {
|
|||
}
|
||||
|
||||
void Rig::initJointStates(const FBXGeometry& geometry, const glm::mat4& modelOffset) {
|
||||
|
||||
_geometryOffset = AnimPose(geometry.offset);
|
||||
_invGeometryOffset = _geometryOffset.inverse();
|
||||
setModelOffset(modelOffset);
|
||||
|
@ -1224,8 +1223,7 @@ void Rig::copyJointsIntoJointData(QVector<JointData>& jointDataVec) const {
|
|||
}
|
||||
|
||||
void Rig::copyJointsFromJointData(const QVector<JointData>& jointDataVec) {
|
||||
|
||||
if (_animSkeleton) {
|
||||
if (_animSkeleton && jointDataVec.size() == (int)_internalPoseSet._overrideFlags.size()) {
|
||||
|
||||
// transform all the default poses into rig space.
|
||||
const AnimPose geometryToRigPose(_geometryToRigTransform);
|
||||
|
|
|
@ -269,7 +269,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
_lastSentJointData.resize(_jointData.size());
|
||||
|
||||
for (int i=0; i < _jointData.size(); i++) {
|
||||
const JointData& data = _jointData.at(i);
|
||||
const JointData& data = _jointData[i];
|
||||
if (sendAll || _lastSentJointData[i].rotation != data.rotation) {
|
||||
if (sendAll ||
|
||||
!cullSmallChanges ||
|
||||
|
@ -294,7 +294,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
validityBit = 0;
|
||||
validity = *validityPosition++;
|
||||
for (int i = 0; i < _jointData.size(); i ++) {
|
||||
const JointData& data = _jointData[ i ];
|
||||
const JointData& data = _jointData[i];
|
||||
if (validity & (1 << validityBit)) {
|
||||
destinationBuffer += packOrientationQuatToSixBytes(destinationBuffer, data.rotation);
|
||||
}
|
||||
|
@ -317,7 +317,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
|
||||
float maxTranslationDimension = 0.0;
|
||||
for (int i=0; i < _jointData.size(); i++) {
|
||||
const JointData& data = _jointData.at(i);
|
||||
const JointData& data = _jointData[i];
|
||||
if (sendAll || _lastSentJointData[i].translation != data.translation) {
|
||||
if (sendAll ||
|
||||
!cullSmallChanges ||
|
||||
|
@ -348,7 +348,7 @@ QByteArray AvatarData::toByteArray(bool cullSmallChanges, bool sendAll) {
|
|||
validityBit = 0;
|
||||
validity = *validityPosition++;
|
||||
for (int i = 0; i < _jointData.size(); i ++) {
|
||||
const JointData& data = _jointData[ i ];
|
||||
const JointData& data = _jointData[i];
|
||||
if (validity & (1 << validityBit)) {
|
||||
destinationBuffer +=
|
||||
packFloatVec3ToSignedTwoByteFixed(destinationBuffer, data.translation, TRANSLATION_COMPRESSION_RADIX);
|
||||
|
@ -425,7 +425,6 @@ bool AvatarData::shouldLogError(const quint64& now) {
|
|||
|
||||
// read data in packet starting at byte offset and return number of bytes parsed
|
||||
int AvatarData::parseDataFromBuffer(const QByteArray& buffer) {
|
||||
|
||||
// lazily allocate memory for HeadData in case we're not an Avatar instance
|
||||
if (!_headData) {
|
||||
_headData = new HeadData(this);
|
||||
|
@ -669,7 +668,9 @@ void AvatarData::setJointData(int index, const glm::quat& rotation, const glm::v
|
|||
}
|
||||
JointData& data = _jointData[index];
|
||||
data.rotation = rotation;
|
||||
data.rotationSet = true;
|
||||
data.translation = translation;
|
||||
data.translationSet = true;
|
||||
}
|
||||
|
||||
void AvatarData::clearJointData(int index) {
|
||||
|
@ -774,6 +775,7 @@ void AvatarData::setJointRotation(int index, const glm::quat& rotation) {
|
|||
}
|
||||
JointData& data = _jointData[index];
|
||||
data.rotation = rotation;
|
||||
data.rotationSet = true;
|
||||
}
|
||||
|
||||
void AvatarData::setJointTranslation(int index, const glm::vec3& translation) {
|
||||
|
@ -789,6 +791,7 @@ void AvatarData::setJointTranslation(int index, const glm::vec3& translation) {
|
|||
}
|
||||
JointData& data = _jointData[index];
|
||||
data.translation = translation;
|
||||
data.translationSet = true;
|
||||
}
|
||||
|
||||
void AvatarData::clearJointData(const QString& name) {
|
||||
|
@ -858,7 +861,6 @@ void AvatarData::setJointTranslations(QVector<glm::vec3> jointTranslations) {
|
|||
"setJointTranslations", Qt::BlockingQueuedConnection,
|
||||
Q_ARG(QVector<glm::vec3>, jointTranslations));
|
||||
}
|
||||
|
||||
if (_jointData.size() < jointTranslations.size()) {
|
||||
_jointData.resize(jointTranslations.size());
|
||||
}
|
||||
|
@ -1100,6 +1102,7 @@ void AvatarData::sendIdentityPacket() {
|
|||
void AvatarData::updateJointMappings() {
|
||||
_jointIndices.clear();
|
||||
_jointNames.clear();
|
||||
_jointData.clear();
|
||||
|
||||
if (_skeletonModelURL.fileName().toLower().endsWith(".fst")) {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
@ -1457,7 +1460,6 @@ void AvatarData::fromJson(const QJsonObject& json) {
|
|||
auto joint = jointDataFromJsonValue(jointJson);
|
||||
jointArray.push_back(joint);
|
||||
setJointData(i, joint.rotation, joint.translation);
|
||||
_jointData[i].rotationSet = true; // Have to do that to broadcast the avatar new pose
|
||||
i++;
|
||||
}
|
||||
setRawJointData(jointArray);
|
||||
|
|
|
@ -44,6 +44,20 @@ bool AvatarHashMap::isAvatarInRange(const glm::vec3& position, const float range
|
|||
return false;
|
||||
}
|
||||
|
||||
int AvatarHashMap::numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters) {
|
||||
auto hashCopy = getHashCopy();
|
||||
auto rangeMeters2 = rangeMeters * rangeMeters;
|
||||
int count = 0;
|
||||
for (const AvatarSharedPointer& sharedAvatar : hashCopy) {
|
||||
glm::vec3 avatarPosition = sharedAvatar->getPosition();
|
||||
auto distance2 = glm::distance2(avatarPosition, position);
|
||||
if (distance2 < rangeMeters2) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
AvatarSharedPointer AvatarHashMap::newSharedAvatar() {
|
||||
return std::make_shared<AvatarData>();
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ public:
|
|||
Q_INVOKABLE AvatarData* getAvatar(QUuid avatarID);
|
||||
|
||||
virtual AvatarSharedPointer getAvatarBySessionID(const QUuid& sessionID) { return findAvatar(sessionID); }
|
||||
int numberOfAvatarsInRange(const glm::vec3& position, float rangeMeters);
|
||||
|
||||
signals:
|
||||
void avatarAddedEvent(const QUuid& sessionUUID);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
set(TARGET_NAME display-plugins)
|
||||
setup_hifi_library(OpenGL)
|
||||
link_hifi_libraries(shared plugins gl gpu-gl ui)
|
||||
link_hifi_libraries(shared plugins ui-plugins gl gpu-gl ui)
|
||||
|
||||
target_opengl()
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <SettingHandle.h>
|
||||
|
||||
#include "DisplayPlugin.h"
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
|
||||
static Setting::Handle<float> IPD_SCALE_HANDLE("hmd.ipdScale", 1.0f);
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include <QtGui/QGuiApplication>
|
||||
#include <QtWidgets/QAction>
|
||||
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
|
||||
const QString Basic2DWindowOpenGLDisplayPlugin::NAME("Desktop");
|
||||
|
||||
|
|
|
@ -425,7 +425,7 @@ glm::mat4 CompositorHelper::getReticleTransform(const glm::mat4& eyePose, const
|
|||
d = glm::normalize(overlaySurfacePoint);
|
||||
}
|
||||
reticlePosition = headPosition + (d * getReticleDepth());
|
||||
quat reticleOrientation = quat(vec3(-spherical.y, spherical.x, 0.0f));
|
||||
quat reticleOrientation = glm::quat_cast(_currentDisplayPlugin->getHeadPose());
|
||||
vec3 reticleScale = vec3(Cursor::Manager::instance().getScale() * reticleSize * getReticleDepth());
|
||||
return glm::inverse(eyePose) * createMatFromScaleQuatAndPos(reticleScale, reticleOrientation, reticlePosition);
|
||||
} else {
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
#include "NullDisplayPlugin.h"
|
||||
|
||||
#include <QtGui/QImage>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
|
||||
const QString NullDisplayPlugin::NAME("NullDisplayPlugin");
|
||||
|
||||
|
|
|
@ -22,12 +22,13 @@
|
|||
#include <NumericalConstants.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <gl/Config.h>
|
||||
#include <gl/GLEscrow.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <CursorManager.h>
|
||||
#include "CompositorHelper.h"
|
||||
#include <ui/Menu.h>
|
||||
|
||||
|
||||
#if THREADED_PRESENT
|
||||
|
@ -202,6 +203,7 @@ private:
|
|||
|
||||
#endif
|
||||
|
||||
|
||||
OpenGLDisplayPlugin::OpenGLDisplayPlugin() {
|
||||
_sceneTextureEscrow.setRecycler([this](const gpu::TexturePointer& texture){
|
||||
cleanupForSceneTexture(texture);
|
||||
|
@ -234,10 +236,11 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
cursorData.hotSpot = vec2(0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_container) {
|
||||
return false;
|
||||
}
|
||||
_vsyncSupported = _container->getPrimaryWidget()->isVsyncSupported();
|
||||
|
||||
|
||||
#if THREADED_PRESENT
|
||||
// Start the present thread if necessary
|
||||
QSharedPointer<PresentThread> presentThread;
|
||||
|
@ -282,7 +285,11 @@ bool OpenGLDisplayPlugin::activate() {
|
|||
animation->start();
|
||||
});
|
||||
|
||||
return DisplayPlugin::activate();
|
||||
if (isHmd() && (getHmdScreen() >= 0)) {
|
||||
_container->showDisplayPluginsTools();
|
||||
}
|
||||
|
||||
return Parent::activate();
|
||||
}
|
||||
|
||||
void OpenGLDisplayPlugin::deactivate() {
|
||||
|
@ -301,7 +308,16 @@ void OpenGLDisplayPlugin::deactivate() {
|
|||
_container->makeRenderingContextCurrent();
|
||||
#endif
|
||||
internalDeactivate();
|
||||
DisplayPlugin::deactivate();
|
||||
|
||||
_container->showDisplayPluginsTools(false);
|
||||
if (!_container->currentDisplayActions().isEmpty()) {
|
||||
auto menu = _container->getPrimaryMenu();
|
||||
foreach(auto itemInfo, _container->currentDisplayActions()) {
|
||||
menu->removeMenuItem(itemInfo.first, itemInfo.second);
|
||||
}
|
||||
_container->currentDisplayActions().clear();
|
||||
}
|
||||
Parent::deactivate();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -120,7 +120,7 @@ protected:
|
|||
QMap<gpu::TexturePointer, uint32_t> _sceneTextureToFrameIndexMap;
|
||||
uint32_t _currentPresentFrameIndex { 0 };
|
||||
float _compositeOverlayAlpha{ 1.0f };
|
||||
|
||||
|
||||
gpu::TexturePointer _currentSceneTexture;
|
||||
gpu::TexturePointer _currentOverlayTexture;
|
||||
|
||||
|
@ -165,4 +165,3 @@ private:
|
|||
float _overlayAlpha{ 1.0f };
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <QtWidgets/QWidget>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <CursorManager.h>
|
||||
#include <gl/GLWidget.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
|
@ -420,8 +420,9 @@ bool HmdDisplayPlugin::setHandLaser(uint32_t hands, HandLaserMode mode, const ve
|
|||
}
|
||||
|
||||
void HmdDisplayPlugin::compositeExtra() {
|
||||
std::array<HandLaserInfo, 2> handLasers;
|
||||
std::array<mat4, 2> renderHandPoses;
|
||||
const int NUMBER_OF_HANDS = 2;
|
||||
std::array<HandLaserInfo, NUMBER_OF_HANDS> handLasers;
|
||||
std::array<mat4, NUMBER_OF_HANDS> renderHandPoses;
|
||||
Transform uiModelTransform;
|
||||
withPresentThreadLock([&] {
|
||||
handLasers = _handLasers;
|
||||
|
@ -443,9 +444,9 @@ void HmdDisplayPlugin::compositeExtra() {
|
|||
using namespace oglplus;
|
||||
useProgram(_laserProgram);
|
||||
_laserGeometry->Use();
|
||||
std::array<mat4, 2> handLaserModelMatrices;
|
||||
std::array<mat4, NUMBER_OF_HANDS> handLaserModelMatrices;
|
||||
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int i = 0; i < NUMBER_OF_HANDS; ++i) {
|
||||
if (renderHandPoses[i] == identity) {
|
||||
continue;
|
||||
}
|
||||
|
@ -485,7 +486,7 @@ void HmdDisplayPlugin::compositeExtra() {
|
|||
auto eyePose = _currentPresentFrameInfo.presentPose * getEyeToHeadTransform(eye);
|
||||
auto view = glm::inverse(eyePose);
|
||||
const auto& projection = _eyeProjections[eye];
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
for (int i = 0; i < NUMBER_OF_HANDS; ++i) {
|
||||
if (handLaserModelMatrices[i] == identity) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "SideBySideStereoDisplayPlugin.h"
|
||||
#include <GLMHelpers.h>
|
||||
#include <CursorManager.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <gl/GLWidget.h>
|
||||
#include "../CompositorHelper.h"
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include <ViewFrustum.h>
|
||||
#include <MatrixStack.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <gl/GLWidget.h>
|
||||
#include <CursorManager.h>
|
||||
#include "../CompositorHelper.h"
|
||||
|
|
|
@ -150,8 +150,10 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
|
||||
if (!canRezPermanentEntities && (entity->getLifetime() != properties.getLifetime())) {
|
||||
// we don't allow a Node that can't create permanent entities to adjust lifetimes on existing ones
|
||||
qCDebug(entities) << "Refusing disallowed entity lifetime adjustment.";
|
||||
return false;
|
||||
if (properties.lifetimeChanged()) {
|
||||
qCDebug(entities) << "Refusing disallowed entity lifetime adjustment.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// enforce support for locked entities. If an entity is currently locked, then the only
|
||||
|
@ -322,8 +324,8 @@ bool EntityTree::updateEntityWithElement(EntityItemPointer entity, const EntityI
|
|||
bool EntityTree::permissionsAllowRez(const EntityItemProperties& properties, bool canRez, bool canRezTmp) {
|
||||
float lifeTime = properties.getLifetime();
|
||||
|
||||
if (lifeTime == 0.0f || lifeTime > _maxTmpEntityLifetime) {
|
||||
// this is an attempt to rez a permanent entity.
|
||||
if (lifeTime == ENTITY_ITEM_IMMORTAL_LIFETIME || lifeTime > _maxTmpEntityLifetime) {
|
||||
// this is an attempt to rez a permanent or non-temporary entity.
|
||||
if (!canRez) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <QtGui/QSurfaceFormat>
|
||||
#include <QtOpenGL/QGL>
|
||||
#include <QOpenGLContext>
|
||||
#include <QtCore/QRegularExpression>
|
||||
|
||||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat() {
|
||||
static QSurfaceFormat format;
|
||||
|
@ -39,6 +40,13 @@ const QGLFormat& getDefaultGLFormat() {
|
|||
return glFormat;
|
||||
}
|
||||
|
||||
int glVersionToInteger(QString glVersion) {
|
||||
QStringList versionParts = glVersion.split(QRegularExpression("[\\.\\s]"));
|
||||
int majorNumber = versionParts[0].toInt();
|
||||
int minorNumber = versionParts[1].toInt();
|
||||
return majorNumber * 100 + minorNumber * 10;
|
||||
}
|
||||
|
||||
QJsonObject getGLContextData() {
|
||||
if (!QOpenGLContext::currentContext()) {
|
||||
return QJsonObject();
|
||||
|
|
|
@ -27,5 +27,6 @@ void setGLFormatVersion(F& format, int major = 4, int minor = 5) { format.setVer
|
|||
const QSurfaceFormat& getDefaultOpenGLSurfaceFormat();
|
||||
const QGLFormat& getDefaultGLFormat();
|
||||
QJsonObject getGLContextData();
|
||||
int glVersionToInteger(QString glVersion);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -24,8 +24,15 @@ GLPipeline* GLPipeline::sync(const Pipeline& pipeline) {
|
|||
|
||||
// No object allocated yet, let's see if it's worth it...
|
||||
ShaderPointer shader = pipeline.getProgram();
|
||||
|
||||
// If this pipeline's shader has already failed to compile, don't try again
|
||||
if (shader->compilationHasFailed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
GLShader* programObject = GLShader::sync(*shader);
|
||||
if (programObject == nullptr) {
|
||||
shader->setCompilationHasFailed(true);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,6 +120,9 @@ public:
|
|||
bool isProgram() const { return getType() > NUM_DOMAINS; }
|
||||
bool isDomain() const { return getType() < NUM_DOMAINS; }
|
||||
|
||||
void setCompilationHasFailed(bool compilationHasFailed) { _compilationHasFailed = compilationHasFailed; }
|
||||
bool compilationHasFailed() const { return _compilationHasFailed; }
|
||||
|
||||
const Source& getSource() const { return _source; }
|
||||
|
||||
const Shaders& getShaders() const { return _shaders; }
|
||||
|
@ -180,6 +183,9 @@ protected:
|
|||
|
||||
// The type of the shader, the master key
|
||||
Type _type;
|
||||
|
||||
// Whether or not the shader compilation failed
|
||||
bool _compilationHasFailed { false };
|
||||
};
|
||||
|
||||
typedef Shader::Pointer ShaderPointer;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
set(TARGET_NAME input-plugins)
|
||||
setup_hifi_library()
|
||||
link_hifi_libraries(shared plugins controllers)
|
||||
link_hifi_libraries(shared plugins ui-plugins controllers)
|
||||
|
||||
GroupSources("src/input-plugins")
|
||||
|
|
|
@ -44,6 +44,7 @@ Q_DECLARE_METATYPE(QNetworkAccessManager::Operation)
|
|||
Q_DECLARE_METATYPE(JSONCallbackParameters)
|
||||
|
||||
const QString ACCOUNTS_GROUP = "accounts";
|
||||
static const auto METAVERSE_SESSION_ID_HEADER = QString("HFM-SessionID").toLocal8Bit();
|
||||
|
||||
JSONCallbackParameters::JSONCallbackParameters(QObject* jsonCallbackReceiver, const QString& jsonCallbackMethod,
|
||||
QObject* errorCallbackReceiver, const QString& errorCallbackMethod,
|
||||
|
@ -222,8 +223,7 @@ void AccountManager::sendRequest(const QString& path,
|
|||
// if we're allowed to send usage data, include whatever the current session ID is with this request
|
||||
auto& activityLogger = UserActivityLogger::getInstance();
|
||||
if (activityLogger.isEnabled()) {
|
||||
static const QString METAVERSE_SESSION_ID_HEADER = "HFM-SessionID";
|
||||
networkRequest.setRawHeader(METAVERSE_SESSION_ID_HEADER.toLocal8Bit(),
|
||||
networkRequest.setRawHeader(METAVERSE_SESSION_ID_HEADER,
|
||||
uuidStringWithoutCurlyBraces(_sessionID).toLocal8Bit());
|
||||
}
|
||||
|
||||
|
@ -322,6 +322,9 @@ void AccountManager::processReply() {
|
|||
QNetworkReply* requestReply = reinterpret_cast<QNetworkReply*>(sender());
|
||||
|
||||
if (requestReply->error() == QNetworkReply::NoError) {
|
||||
if (requestReply->hasRawHeader(METAVERSE_SESSION_ID_HEADER)) {
|
||||
_sessionID = requestReply->rawHeader(METAVERSE_SESSION_ID_HEADER);
|
||||
}
|
||||
passSuccessToCallback(requestReply);
|
||||
} else {
|
||||
passErrorToCallback(requestReply);
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
|
||||
class JSONCallbackParameters {
|
||||
public:
|
||||
JSONCallbackParameters(QObject* jsonCallbackReceiver = NULL, const QString& jsonCallbackMethod = QString(),
|
||||
QObject* errorCallbackReceiver = NULL, const QString& errorCallbackMethod = QString(),
|
||||
QObject* updateReceiver = NULL, const QString& updateSlot = QString());
|
||||
JSONCallbackParameters(QObject* jsonCallbackReceiver = nullptr, const QString& jsonCallbackMethod = QString(),
|
||||
QObject* errorCallbackReceiver = nullptr, const QString& errorCallbackMethod = QString(),
|
||||
QObject* updateReceiver = nullptr, const QString& updateSlot = QString());
|
||||
|
||||
bool isEmpty() const { return !jsonCallbackReceiver && !errorCallbackReceiver; }
|
||||
|
||||
|
@ -86,6 +86,7 @@ public:
|
|||
|
||||
static QJsonObject dataObjectFromResponse(QNetworkReply& requestReply);
|
||||
|
||||
QUuid getSessionID() const { return _sessionID; }
|
||||
void setSessionID(const QUuid& sessionID) { _sessionID = sessionID; }
|
||||
|
||||
public slots:
|
||||
|
@ -139,7 +140,7 @@ private:
|
|||
bool _isWaitingForKeypairResponse { false };
|
||||
QByteArray _pendingPrivateKey;
|
||||
|
||||
QUuid _sessionID;
|
||||
QUuid _sessionID { QUuid::createUuid() };
|
||||
};
|
||||
|
||||
#endif // hifi_AccountManager_h
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "AddressManager.h"
|
||||
#include "NodeList.h"
|
||||
#include "NetworkLogging.h"
|
||||
#include "UserActivityLogger.h"
|
||||
|
||||
|
||||
const QString ADDRESS_MANAGER_SETTINGS_GROUP = "AddressManager";
|
||||
|
@ -130,6 +131,10 @@ const JSONCallbackParameters& AddressManager::apiCallbackParameters() {
|
|||
}
|
||||
|
||||
bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
||||
static QString URL_TYPE_USER = "user";
|
||||
static QString URL_TYPE_DOMAIN_ID = "domain_id";
|
||||
static QString URL_TYPE_PLACE = "place";
|
||||
static QString URL_TYPE_NETWORK_ADDRESS = "network_address";
|
||||
if (lookupUrl.scheme() == HIFI_URL_SCHEME) {
|
||||
|
||||
qCDebug(networking) << "Trying to go to URL" << lookupUrl.toString();
|
||||
|
@ -147,6 +152,8 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
if (handleUsername(lookupUrl.authority())) {
|
||||
// handled a username for lookup
|
||||
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_USER, lookupUrl.toString());
|
||||
|
||||
// in case we're failing to connect to where we thought this user was
|
||||
// store their username as previous lookup so we can refresh their location via API
|
||||
_previousLookup = lookupUrl;
|
||||
|
@ -157,6 +164,8 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
if (handleNetworkAddress(lookupUrl.host()
|
||||
+ (lookupUrl.port() == -1 ? "" : ":" + QString::number(lookupUrl.port())), trigger, hostChanged)) {
|
||||
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_NETWORK_ADDRESS, lookupUrl.toString());
|
||||
|
||||
// a network address lookup clears the previous lookup since we don't expect to re-attempt it
|
||||
_previousLookup.clear();
|
||||
|
||||
|
@ -174,6 +183,8 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
// we may have a path that defines a relative viewpoint - if so we should jump to that now
|
||||
handlePath(path, trigger);
|
||||
} else if (handleDomainID(lookupUrl.host())){
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_DOMAIN_ID, lookupUrl.toString());
|
||||
|
||||
// store this domain ID as the previous lookup in case we're failing to connect and want to refresh API info
|
||||
_previousLookup = lookupUrl;
|
||||
|
||||
|
@ -181,6 +192,8 @@ bool AddressManager::handleUrl(const QUrl& lookupUrl, LookupTrigger trigger) {
|
|||
// try to look up the domain ID on the metaverse API
|
||||
attemptDomainIDLookup(lookupUrl.host(), lookupUrl.path(), trigger);
|
||||
} else {
|
||||
UserActivityLogger::getInstance().wentTo(trigger, URL_TYPE_PLACE, lookupUrl.toString());
|
||||
|
||||
// store this place name as the previous lookup in case we fail to connect and want to refresh API info
|
||||
_previousLookup = lookupUrl;
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ using NodePermissionsPointer = std::shared_ptr<NodePermissions>;
|
|||
class NodePermissions {
|
||||
public:
|
||||
NodePermissions() { _id = QUuid::createUuid().toString(); }
|
||||
NodePermissions(const QString& name) { _id = name; }
|
||||
NodePermissions(const QString& name) { _id = name.toLower(); }
|
||||
NodePermissions(QMap<QString, QVariant> perms) {
|
||||
_id = perms["permissions_id"].toString();
|
||||
_id = perms["permissions_id"].toString().toLower();
|
||||
canConnectToDomain = perms["id_can_connect"].toBool();
|
||||
canAdjustLocks = perms["id_can_adjust_locks"].toBool();
|
||||
canRezPermanentEntities = perms["id_can_rez"].toBool();
|
||||
|
@ -38,7 +38,7 @@ public:
|
|||
QString getID() const { return _id; }
|
||||
|
||||
// the _id member isn't authenticated and _username is.
|
||||
void setUserName(QString userName) { _userName = userName; }
|
||||
void setUserName(QString userName) { _userName = userName.toLower(); }
|
||||
QString getUserName() { return _userName; }
|
||||
|
||||
bool isAssignment { false };
|
||||
|
@ -88,6 +88,23 @@ protected:
|
|||
QString _userName;
|
||||
};
|
||||
|
||||
|
||||
// wrap QHash in a class that forces all keys to be lowercase
|
||||
class NodePermissionsMap {
|
||||
public:
|
||||
NodePermissionsMap() { }
|
||||
NodePermissionsPointer& operator[](const QString& key) { return _data[key.toLower()]; }
|
||||
NodePermissionsPointer operator[](const QString& key) const { return _data.value(key.toLower()); }
|
||||
bool contains(const QString& key) const { return _data.contains(key.toLower()); }
|
||||
QList<QString> keys() const { return _data.keys(); }
|
||||
QHash<QString, NodePermissionsPointer> get() { return _data; }
|
||||
void clear() { _data.clear(); }
|
||||
|
||||
private:
|
||||
QHash<QString, NodePermissionsPointer> _data;
|
||||
};
|
||||
|
||||
|
||||
const NodePermissions DEFAULT_AGENT_PERMISSIONS;
|
||||
|
||||
QDebug operator<<(QDebug debug, const NodePermissions& perms);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
#include "UserActivityLogger.h"
|
||||
#include <DependencyManager.h>
|
||||
#include "AddressManager.h"
|
||||
|
||||
static const QString USER_ACTIVITY_URL = "/api/v1/user_activities";
|
||||
|
||||
|
@ -125,6 +126,19 @@ void UserActivityLogger::changedDomain(QString domainURL) {
|
|||
}
|
||||
|
||||
void UserActivityLogger::connectedDevice(QString typeOfDevice, QString deviceName) {
|
||||
static QStringList DEVICE_BLACKLIST = {
|
||||
"Desktop",
|
||||
"NullDisplayPlugin",
|
||||
"3D TV - Side by Side Stereo",
|
||||
"3D TV - Interleaved",
|
||||
|
||||
"Keyboard/Mouse"
|
||||
};
|
||||
|
||||
if (DEVICE_BLACKLIST.contains(deviceName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString ACTION_NAME = "connected_device";
|
||||
QJsonObject actionDetails;
|
||||
const QString TYPE_OF_DEVICE = "type_of_device";
|
||||
|
@ -148,12 +162,34 @@ void UserActivityLogger::loadedScript(QString scriptName) {
|
|||
|
||||
}
|
||||
|
||||
void UserActivityLogger::wentTo(QString destinationType, QString destinationName) {
|
||||
void UserActivityLogger::wentTo(AddressManager::LookupTrigger lookupTrigger, QString destinationType, QString destinationName) {
|
||||
// Only accept these types of triggers. Other triggers are usually used internally in AddressManager.
|
||||
QString trigger;
|
||||
switch (lookupTrigger) {
|
||||
case AddressManager::UserInput:
|
||||
trigger = "UserInput";
|
||||
break;
|
||||
case AddressManager::Back:
|
||||
trigger = "Back";
|
||||
break;
|
||||
case AddressManager::Forward:
|
||||
trigger = "Forward";
|
||||
break;
|
||||
case AddressManager::StartupFromSettings:
|
||||
trigger = "StartupFromSettings";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
const QString ACTION_NAME = "went_to";
|
||||
QJsonObject actionDetails;
|
||||
const QString TRIGGER_TYPE_KEY = "trigger";
|
||||
const QString DESTINATION_TYPE_KEY = "destination_type";
|
||||
const QString DESTINATION_NAME_KEY = "detination_name";
|
||||
|
||||
actionDetails.insert(TRIGGER_TYPE_KEY, trigger);
|
||||
actionDetails.insert(DESTINATION_TYPE_KEY, destinationType);
|
||||
actionDetails.insert(DESTINATION_NAME_KEY, destinationName);
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QNetworkReply>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include "AddressManager.h"
|
||||
|
||||
class UserActivityLogger : public QObject {
|
||||
Q_OBJECT
|
||||
|
@ -42,7 +43,7 @@ public slots:
|
|||
void changedDomain(QString domainURL);
|
||||
void connectedDevice(QString typeOfDevice, QString deviceName);
|
||||
void loadedScript(QString scriptName);
|
||||
void wentTo(QString destinationType, QString destinationName);
|
||||
void wentTo(AddressManager::LookupTrigger trigger, QString destinationType, QString destinationName);
|
||||
|
||||
private slots:
|
||||
void requestError(QNetworkReply& errorReply);
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// UserActivityLoggerScriptingInterface.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Ryan Huffman on 6/06/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "UserActivityLoggerScriptingInterface.h"
|
||||
#include "UserActivityLogger.h"
|
||||
|
||||
void UserActivityLoggerScriptingInterface::enabledEdit() {
|
||||
logAction("enabled_edit");
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::openedMarketplace() {
|
||||
logAction("opened_marketplace");
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::toggledAway(bool isAway) {
|
||||
logAction("toggled_away", { { "is_away", isAway } });
|
||||
}
|
||||
|
||||
void UserActivityLoggerScriptingInterface::logAction(QString action, QJsonObject details) {
|
||||
QMetaObject::invokeMethod(&UserActivityLogger::getInstance(), "logAction",
|
||||
Q_ARG(QString, action),
|
||||
Q_ARG(QJsonObject, details));
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// UserActivityLoggerScriptingInterface.h
|
||||
// libraries/networking/src
|
||||
//
|
||||
// Created by Ryan Huffman on 6/06/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_UserActivityLoggerScriptingInterface_h
|
||||
#define hifi_UserActivityLoggerScriptingInterface_h
|
||||
|
||||
#include <QObject>
|
||||
#include <QJsonObject>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
|
||||
class UserActivityLoggerScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Q_INVOKABLE void enabledEdit();
|
||||
Q_INVOKABLE void openedMarketplace();
|
||||
Q_INVOKABLE void toggledAway(bool isAway);
|
||||
|
||||
private:
|
||||
void logAction(QString action, QJsonObject details = {});
|
||||
};
|
||||
|
||||
#endif // hifi_UserActivityLoggerScriptingInterface_h
|
|
@ -135,7 +135,14 @@ void EntityMotionState::handleEasyChanges(uint32_t& flags) {
|
|||
_nextOwnershipBid = 0;
|
||||
}
|
||||
if ((flags & Simulation::DIRTY_PHYSICS_ACTIVATION) && !_body->isActive()) {
|
||||
_body->activate();
|
||||
if (_body->isKinematicObject()) {
|
||||
// only force activate kinematic bodies (dynamic shouldn't need force and
|
||||
// active static bodies are special (see PhysicsEngine::_activeStaticBodies))
|
||||
_body->activate(true);
|
||||
_lastKinematicStep = ObjectMotionState::getWorldSimulationStep();
|
||||
} else {
|
||||
_body->activate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +1,6 @@
|
|||
#include "DisplayPlugin.h"
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <ui/Menu.h>
|
||||
|
||||
#include "PluginContainer.h"
|
||||
|
||||
bool DisplayPlugin::activate() {
|
||||
if (isHmd() && (getHmdScreen() >= 0)) {
|
||||
_container->showDisplayPluginsTools();
|
||||
}
|
||||
return Parent::activate();
|
||||
}
|
||||
|
||||
void DisplayPlugin::deactivate() {
|
||||
_container->showDisplayPluginsTools(false);
|
||||
if (!_container->currentDisplayActions().isEmpty()) {
|
||||
auto menu = _container->getPrimaryMenu();
|
||||
foreach(auto itemInfo, _container->currentDisplayActions()) {
|
||||
menu->removeMenuItem(itemInfo.first, itemInfo.second);
|
||||
}
|
||||
_container->currentDisplayActions().clear();
|
||||
}
|
||||
Parent::deactivate();
|
||||
}
|
||||
|
||||
int64_t DisplayPlugin::getPaintDelayUsecs() const {
|
||||
std::lock_guard<std::mutex> lock(_paintDelayMutex);
|
||||
|
|
|
@ -132,8 +132,6 @@ public:
|
|||
Present = QEvent::User + 1
|
||||
};
|
||||
|
||||
bool activate() override;
|
||||
void deactivate() override;
|
||||
virtual bool isHmd() const { return false; }
|
||||
virtual int getHmdScreen() const { return -1; }
|
||||
/// By default, all HMDs are stereo
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "Forward.h"
|
||||
|
||||
class Plugin : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
/// \return human-readable name
|
||||
virtual const QString& getName() const = 0;
|
||||
|
@ -63,6 +64,13 @@ public:
|
|||
virtual void saveSettings() const {}
|
||||
virtual void loadSettings() {}
|
||||
|
||||
signals:
|
||||
// These signals should be emitted when a device is first known to be available. In some cases this will
|
||||
// be in `init()`, in other cases, like Neuron, this isn't known until activation.
|
||||
// SDL2 isn't a device itself, but can have 0+ subdevices. subdeviceConnected is used in this case.
|
||||
void deviceConnected(QString pluginName) const;
|
||||
void subdeviceConnected(QString pluginName, QString subdeviceName) const;
|
||||
|
||||
protected:
|
||||
bool _active { false };
|
||||
PluginContainer* _container { nullptr };
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QPluginLoader>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
||||
#include "RuntimePlugin.h"
|
||||
#include "DisplayPlugin.h"
|
||||
#include "InputPlugin.h"
|
||||
#include "PluginContainer.h"
|
||||
|
||||
|
||||
PluginManager* PluginManager::getInstance() {
|
||||
|
@ -120,6 +122,15 @@ static DisplayPluginList displayPlugins;
|
|||
|
||||
const DisplayPluginList& PluginManager::getDisplayPlugins() {
|
||||
static std::once_flag once;
|
||||
static auto deviceAddedCallback = [](QString deviceName) {
|
||||
qDebug() << "Added device: " << deviceName;
|
||||
UserActivityLogger::getInstance().connectedDevice("display", deviceName);
|
||||
};
|
||||
static auto subdeviceAddedCallback = [](QString pluginName, QString deviceName) {
|
||||
qDebug() << "Added subdevice: " << deviceName;
|
||||
UserActivityLogger::getInstance().connectedDevice("display", pluginName + " | " + deviceName);
|
||||
};
|
||||
|
||||
std::call_once(once, [&] {
|
||||
// Grab the built in plugins
|
||||
displayPlugins = ::getDisplayPlugins();
|
||||
|
@ -133,9 +144,10 @@ const DisplayPluginList& PluginManager::getDisplayPlugins() {
|
|||
}
|
||||
}
|
||||
}
|
||||
auto& container = PluginContainer::getInstance();
|
||||
for (auto plugin : displayPlugins) {
|
||||
plugin->setContainer(&container);
|
||||
connect(plugin.get(), &Plugin::deviceConnected, this, deviceAddedCallback, Qt::QueuedConnection);
|
||||
connect(plugin.get(), &Plugin::subdeviceConnected, this, subdeviceAddedCallback, Qt::QueuedConnection);
|
||||
plugin->setContainer(_container);
|
||||
plugin->init();
|
||||
}
|
||||
|
||||
|
@ -156,6 +168,15 @@ void PluginManager::disableDisplayPlugin(const QString& name) {
|
|||
const InputPluginList& PluginManager::getInputPlugins() {
|
||||
static InputPluginList inputPlugins;
|
||||
static std::once_flag once;
|
||||
static auto deviceAddedCallback = [](QString deviceName) {
|
||||
qDebug() << "Added device: " << deviceName;
|
||||
UserActivityLogger::getInstance().connectedDevice("input", deviceName);
|
||||
};
|
||||
static auto subdeviceAddedCallback = [](QString pluginName, QString deviceName) {
|
||||
qDebug() << "Added subdevice: " << deviceName;
|
||||
UserActivityLogger::getInstance().connectedDevice("input", pluginName + " | " + deviceName);
|
||||
};
|
||||
|
||||
std::call_once(once, [&] {
|
||||
inputPlugins = ::getInputPlugins();
|
||||
|
||||
|
@ -171,9 +192,10 @@ const InputPluginList& PluginManager::getInputPlugins() {
|
|||
}
|
||||
}
|
||||
|
||||
auto& container = PluginContainer::getInstance();
|
||||
for (auto plugin : inputPlugins) {
|
||||
plugin->setContainer(&container);
|
||||
connect(plugin.get(), &Plugin::deviceConnected, this, deviceAddedCallback, Qt::QueuedConnection);
|
||||
connect(plugin.get(), &Plugin::subdeviceConnected, this, subdeviceAddedCallback, Qt::QueuedConnection);
|
||||
plugin->setContainer(_container);
|
||||
plugin->init();
|
||||
}
|
||||
});
|
||||
|
|
|
@ -26,4 +26,7 @@ public:
|
|||
void disableDisplays(const QStringList& displays);
|
||||
void disableInputs(const QStringList& inputs);
|
||||
void saveSettings();
|
||||
void setContainer(PluginContainer* container) { _container = container; }
|
||||
private:
|
||||
PluginContainer* _container { nullptr };
|
||||
};
|
||||
|
|
|
@ -122,7 +122,7 @@ GPUIdent* GPUIdent::ensureQuery(const QString& vendor, const QString& renderer)
|
|||
}
|
||||
if (count > bestCount) {
|
||||
bestCount = count;
|
||||
_name = sString;
|
||||
_name = QString(sString).trimmed();
|
||||
|
||||
hr = spInstance->Get(CComBSTR(_T("DriverVersion")), 0, &var, 0, 0);
|
||||
if (hr == S_OK) {
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#ifdef Q_OS_WIN
|
||||
#include "CPUIdent.h"
|
||||
#include <Psapi.h>
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -843,3 +844,29 @@ void printSystemInformation() {
|
|||
(envVariables.contains(env) ? " = " + envVariables.value(env) : " NOT FOUND");
|
||||
}
|
||||
}
|
||||
|
||||
bool getMemoryInfo(MemoryInfo& info) {
|
||||
#ifdef Q_OS_WIN
|
||||
MEMORYSTATUSEX ms;
|
||||
ms.dwLength = sizeof(ms);
|
||||
if (!GlobalMemoryStatusEx(&ms)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
info.totalMemoryBytes = ms.ullTotalPhys;
|
||||
info.availMemoryBytes = ms.ullAvailPhys;
|
||||
info.usedMemoryBytes = ms.ullTotalPhys - ms.ullAvailPhys;
|
||||
|
||||
|
||||
PROCESS_MEMORY_COUNTERS_EX pmc;
|
||||
if (!GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PROCESS_MEMORY_COUNTERS*>(&pmc), sizeof(pmc))) {
|
||||
return false;
|
||||
}
|
||||
info.processUsedMemoryBytes = pmc.PrivateUsage;
|
||||
info.processPeakUsedMemoryBytes = pmc.PeakPagefileUsage;
|
||||
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
|
@ -204,4 +204,14 @@ void disableQtBearerPoll();
|
|||
|
||||
void printSystemInformation();
|
||||
|
||||
struct MemoryInfo {
|
||||
uint64_t totalMemoryBytes;
|
||||
uint64_t availMemoryBytes;
|
||||
uint64_t usedMemoryBytes;
|
||||
uint64_t processUsedMemoryBytes;
|
||||
uint64_t processPeakUsedMemoryBytes;
|
||||
};
|
||||
|
||||
bool getMemoryInfo(MemoryInfo& info);
|
||||
|
||||
#endif // hifi_SharedUtil_h
|
||||
|
|
3
libraries/ui-plugins/CMakeLists.txt
Normal file
3
libraries/ui-plugins/CMakeLists.txt
Normal file
|
@ -0,0 +1,3 @@
|
|||
set(TARGET_NAME ui-plugins)
|
||||
setup_hifi_library(OpenGL)
|
||||
link_hifi_libraries(shared plugins ui)
|
|
@ -16,7 +16,7 @@
|
|||
#include <QtCore/QPair>
|
||||
#include <QtCore/QRect>
|
||||
|
||||
#include "Forward.h"
|
||||
#include <plugins/Forward.h>
|
||||
|
||||
class QAction;
|
||||
class GLWidget;
|
||||
|
@ -63,8 +63,8 @@ public:
|
|||
virtual GLWidget* getPrimaryWidget() = 0;
|
||||
virtual MainWindow* getPrimaryWindow() = 0;
|
||||
virtual QOpenGLContext* getPrimaryContext() = 0;
|
||||
virtual bool isForeground() = 0;
|
||||
virtual const DisplayPluginPointer getActiveDisplayPlugin() const = 0;
|
||||
virtual bool isForeground() const = 0;
|
||||
virtual DisplayPluginPointer getActiveDisplayPlugin() const = 0;
|
||||
|
||||
/// settings interface
|
||||
bool getBoolSetting(const QString& settingName, bool defaultValue);
|
||||
|
@ -84,3 +84,4 @@ protected:
|
|||
std::map<QString, QActionGroup*> _exclusiveGroups;
|
||||
QRect _savedGeometry { 10, 120, 800, 600 };
|
||||
};
|
||||
|
|
@ -387,6 +387,8 @@ bool NeuronPlugin::activate() {
|
|||
} else {
|
||||
qCDebug(inputplugins) << "NeuronPlugin: success connecting to " << _serverAddress.c_str() << ":" << _serverPort;
|
||||
|
||||
emit deviceConnected(getName());
|
||||
|
||||
BRRegisterAutoSyncParmeter(_socketRef, Cmd_CombinationMode);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ void SDL2Manager::init() {
|
|||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->registerDevice(joystick);
|
||||
emit joystickAdded(joystick.get());
|
||||
emit subdeviceConnected(getName(), SDL_GameControllerName(controller));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -157,6 +158,7 @@ void SDL2Manager::pluginUpdate(float deltaTime, const controller::InputCalibrati
|
|||
_openJoysticks[id] = joystick;
|
||||
userInputMapper->registerDevice(joystick);
|
||||
emit joystickAdded(joystick.get());
|
||||
emit subdeviceConnected(getName(), SDL_GameControllerName(controller));
|
||||
}
|
||||
} else if (event.type == SDL_CONTROLLERDEVICEREMOVED) {
|
||||
if (_openJoysticks.contains(event.cdevice.which)) {
|
||||
|
|
|
@ -8,5 +8,5 @@
|
|||
|
||||
set(TARGET_NAME hifiSixense)
|
||||
setup_hifi_plugin(Script Qml Widgets)
|
||||
link_hifi_libraries(shared controllers ui plugins input-plugins)
|
||||
link_hifi_libraries(shared controllers ui plugins ui-plugins input-plugins)
|
||||
target_sixense()
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
#include <NumericalConstants.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <SettingHandle.h>
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
@ -137,6 +137,12 @@ void SixenseManager::setSixenseFilter(bool filter) {
|
|||
void SixenseManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
BAIL_IF_NOT_LOADED
|
||||
|
||||
static bool sixenseHasBeenConnected { false };
|
||||
if (!sixenseHasBeenConnected && sixenseIsBaseConnected(0)) {
|
||||
sixenseHasBeenConnected = true;
|
||||
emit deviceConnected(getName());
|
||||
}
|
||||
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->withLock([&, this]() {
|
||||
_inputDevice->update(deltaTime, inputCalibrationData);
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include <UserActivityLogger.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
|
||||
const QString SpacemouseManager::NAME { "Spacemouse" };
|
||||
|
@ -59,7 +58,6 @@ bool SpacemouseManager::activate() {
|
|||
if (instance->getDeviceID() == controller::Input::INVALID_DEVICE) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->registerDevice(instance);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", NAME);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -330,7 +328,6 @@ bool SpacemouseManager::RawInputEventFilter(void* msg, long* result) {
|
|||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
if (Is3dmouseAttached() && instance->getDeviceID() == controller::Input::INVALID_DEVICE) {
|
||||
userInputMapper->registerDevice(instance);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse");
|
||||
}
|
||||
else if (!Is3dmouseAttached() && instance->getDeviceID() != controller::Input::INVALID_DEVICE) {
|
||||
userInputMapper->removeDevice(instance->getDeviceID());
|
||||
|
@ -857,7 +854,7 @@ void SpacemouseManager::init() {
|
|||
if (Is3dmouseAttached() && instance->getDeviceID() == controller::Input::INVALID_DEVICE) {
|
||||
auto userInputMapper = DependencyManager::get<UserInputMapper>();
|
||||
userInputMapper->registerDevice(instance);
|
||||
UserActivityLogger::getInstance().connectedDevice("controller", "Spacemouse");
|
||||
emit deviceConnected(getName());
|
||||
}
|
||||
//let one axis be dominant
|
||||
//ConnexionClientControl(fConnexionClientID, kConnexionCtlSetSwitches, kConnexionSwitchDominant | kConnexionSwitchEnableAll, NULL);
|
||||
|
|
|
@ -13,7 +13,7 @@ if (WIN32)
|
|||
|
||||
set(TARGET_NAME oculus)
|
||||
setup_hifi_plugin(Multimedia)
|
||||
link_hifi_libraries(shared gl gpu controllers ui plugins display-plugins input-plugins audio-client networking)
|
||||
link_hifi_libraries(shared gl gpu controllers ui plugins ui-plugins display-plugins input-plugins audio-client networking)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
#include <QtCore/QLoggingCategory>
|
||||
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <controllers/UserInputMapper.h>
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
|
|
|
@ -28,6 +28,12 @@ bool OculusDisplayPlugin::internalActivate() {
|
|||
return result;
|
||||
}
|
||||
|
||||
void OculusDisplayPlugin::init() {
|
||||
Plugin::init();
|
||||
|
||||
emit deviceConnected(getName());
|
||||
}
|
||||
|
||||
void OculusDisplayPlugin::cycleDebugOutput() {
|
||||
if (_session) {
|
||||
currentDebugMode = static_cast<ovrPerfHudMode>((currentDebugMode + 1) % ovrPerfHud_Count);
|
||||
|
|
|
@ -17,6 +17,8 @@ class OculusDisplayPlugin : public OculusBaseDisplayPlugin {
|
|||
public:
|
||||
const QString& getName() const override { return NAME; }
|
||||
|
||||
void init() override;
|
||||
|
||||
QString getPreferredAudioInDevice() const override;
|
||||
QString getPreferredAudioOutDevice() const override;
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ if (APPLE)
|
|||
|
||||
set(TARGET_NAME oculusLegacy)
|
||||
setup_hifi_plugin()
|
||||
link_hifi_libraries(shared gl gpu plugins ui display-plugins input-plugins)
|
||||
link_hifi_libraries(shared gl gpu plugins ui ui-plugins display-plugins input-plugins)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <gl/OglplusHelpers.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "plugins/PluginContainer.h"
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include "OculusHelpers.h"
|
||||
|
||||
using namespace oglplus;
|
||||
|
@ -36,6 +36,12 @@ const QString OculusLegacyDisplayPlugin::NAME("Oculus Rift");
|
|||
OculusLegacyDisplayPlugin::OculusLegacyDisplayPlugin() {
|
||||
}
|
||||
|
||||
void OculusLegacyDisplayPlugin::init() {
|
||||
Plugin::init();
|
||||
|
||||
emit deviceConnected(getName());
|
||||
}
|
||||
|
||||
void OculusLegacyDisplayPlugin::resetSensors() {
|
||||
ovrHmd_RecenterPose(_hmd);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,8 @@ public:
|
|||
bool isSupported() const override;
|
||||
const QString& getName() const override { return NAME; }
|
||||
|
||||
void init() override;
|
||||
|
||||
int getHmdScreen() const override;
|
||||
|
||||
// Stereo specific methods
|
||||
|
|
|
@ -12,7 +12,7 @@ if (WIN32)
|
|||
set(TARGET_NAME openvr)
|
||||
setup_hifi_plugin(OpenGL Script Qml Widgets)
|
||||
link_hifi_libraries(shared gl networking controllers ui
|
||||
plugins display-plugins input-plugins script-engine
|
||||
plugins display-plugins ui-plugins input-plugins script-engine
|
||||
render-utils model gpu render model-networking fbx)
|
||||
|
||||
include_hifi_library_headers(octree)
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
#include <controllers/Pose.h>
|
||||
#include <PerfStat.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
#include <shared/NsightHelpers.h>
|
||||
|
@ -46,6 +46,12 @@ bool OpenVrDisplayPlugin::isSupported() const {
|
|||
return openVrSupported();
|
||||
}
|
||||
|
||||
void OpenVrDisplayPlugin::init() {
|
||||
Plugin::init();
|
||||
|
||||
emit deviceConnected(getName());
|
||||
}
|
||||
|
||||
bool OpenVrDisplayPlugin::internalActivate() {
|
||||
_openVrDisplayActive = true;
|
||||
_container->setIsOptionChecked(StandingHMDSensorMode, true);
|
||||
|
@ -267,7 +273,7 @@ void OpenVrDisplayPlugin::unsuppressKeyboard() {
|
|||
return;
|
||||
}
|
||||
if (1 == _keyboardSupressionCount.fetch_sub(1)) {
|
||||
enableOpenVrKeyboard();
|
||||
enableOpenVrKeyboard(_container);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,8 @@ public:
|
|||
bool isSupported() const override;
|
||||
const QString& getName() const override { return NAME; }
|
||||
|
||||
void init() override;
|
||||
|
||||
float getTargetFrameRate() const override { return TARGET_RATE_OpenVr; }
|
||||
|
||||
void customizeContext() override;
|
||||
|
|
|
@ -21,6 +21,9 @@
|
|||
#include <OffscreenUi.h>
|
||||
#include <controllers/Pose.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <ui/Menu.h>
|
||||
#include "../../interface/src/Menu.h"
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(displayplugins)
|
||||
Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display")
|
||||
|
@ -91,7 +94,7 @@ void releaseOpenVrSystem() {
|
|||
|
||||
static char textArray[8192];
|
||||
|
||||
static QMetaObject::Connection _focusConnection, _focusTextConnection;
|
||||
static QMetaObject::Connection _focusConnection, _focusTextConnection, _overlayMenuConnection;
|
||||
extern bool _openVrDisplayActive;
|
||||
static vr::IVROverlay* _overlay { nullptr };
|
||||
static QObject* _keyboardFocusObject { nullptr };
|
||||
|
@ -99,7 +102,8 @@ static QString _existingText;
|
|||
static Qt::InputMethodHints _currentHints;
|
||||
extern vr::TrackedDevicePose_t _trackedDevicePose[vr::k_unMaxTrackedDeviceCount];
|
||||
static bool _keyboardShown { false };
|
||||
static const uint32_t SHOW_KEYBOARD_DELAY_MS = 100;
|
||||
static bool _overlayRevealed { false };
|
||||
static const uint32_t SHOW_KEYBOARD_DELAY_MS = 400;
|
||||
|
||||
void showOpenVrKeyboard(bool show = true) {
|
||||
if (!_overlay) {
|
||||
|
@ -175,13 +179,26 @@ void finishOpenVrKeyboardInput() {
|
|||
static const QString DEBUG_FLAG("HIFI_DISABLE_STEAM_VR_KEYBOARD");
|
||||
bool disableSteamVrKeyboard = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
|
||||
void enableOpenVrKeyboard() {
|
||||
void enableOpenVrKeyboard(PluginContainer* container) {
|
||||
if (disableSteamVrKeyboard) {
|
||||
return;
|
||||
}
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
_overlay = vr::VROverlay();
|
||||
|
||||
|
||||
auto menu = container->getPrimaryMenu();
|
||||
auto action = menu->getActionForOption(MenuOption::Overlays);
|
||||
|
||||
// When the overlays are revealed, suppress the keyboard from appearing on text focus for a tenth of a second.
|
||||
_overlayMenuConnection = QObject::connect(action, &QAction::triggered, [action] {
|
||||
if (action->isChecked()) {
|
||||
_overlayRevealed = true;
|
||||
const int KEYBOARD_DELAY_MS = 100;
|
||||
QTimer::singleShot(KEYBOARD_DELAY_MS, [&] { _overlayRevealed = false; });
|
||||
}
|
||||
});
|
||||
|
||||
_focusConnection = QObject::connect(offscreenUi->getWindow(), &QQuickWindow::focusObjectChanged, [](QObject* object) {
|
||||
if (object != _keyboardFocusObject) {
|
||||
showOpenVrKeyboard(false);
|
||||
|
@ -190,6 +207,11 @@ void enableOpenVrKeyboard() {
|
|||
|
||||
_focusTextConnection = QObject::connect(offscreenUi.data(), &OffscreenUi::focusTextChanged, [](bool focusText) {
|
||||
if (_openVrDisplayActive) {
|
||||
if (_overlayRevealed) {
|
||||
// suppress at most one text focus event
|
||||
_overlayRevealed = false;
|
||||
return;
|
||||
}
|
||||
showOpenVrKeyboard(focusText);
|
||||
}
|
||||
});
|
||||
|
@ -200,6 +222,7 @@ void disableOpenVrKeyboard() {
|
|||
if (disableSteamVrKeyboard) {
|
||||
return;
|
||||
}
|
||||
QObject::disconnect(_overlayMenuConnection);
|
||||
QObject::disconnect(_focusTextConnection);
|
||||
QObject::disconnect(_focusConnection);
|
||||
}
|
||||
|
@ -325,4 +348,4 @@ controller::Pose openVrControllerPoseToHandPose(bool isLeftHand, const mat4& mat
|
|||
result.velocity = linearVelocity + glm::cross(angularVelocity, position - extractTranslation(mat));
|
||||
result.angularVelocity = angularVelocity;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <controllers/Forward.h>
|
||||
#include <plugins/Forward.h>
|
||||
|
||||
bool openVrSupported();
|
||||
|
||||
|
@ -20,7 +21,7 @@ vr::IVRSystem* acquireOpenVrSystem();
|
|||
void releaseOpenVrSystem();
|
||||
void handleOpenVrEvents();
|
||||
bool openVrQuitRequested();
|
||||
void enableOpenVrKeyboard();
|
||||
void enableOpenVrKeyboard(PluginContainer* container);
|
||||
void disableOpenVrKeyboard();
|
||||
bool isOpenVrKeyboardShown();
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <gpu/Context.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <NumericalConstants.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
|
@ -63,7 +63,7 @@ bool ViveControllerManager::activate() {
|
|||
}
|
||||
Q_ASSERT(_system);
|
||||
|
||||
enableOpenVrKeyboard();
|
||||
enableOpenVrKeyboard(_container);
|
||||
|
||||
// OpenVR provides 3d mesh representations of the controllers
|
||||
// Disabled controller rendering code
|
||||
|
@ -228,7 +228,6 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
|
|||
if (!_registeredWithInputMapper && _inputDevice->_trackedControllers > 0) {
|
||||
userInputMapper->registerDevice(_inputDevice);
|
||||
_registeredWithInputMapper = true;
|
||||
UserActivityLogger::getInstance().connectedDevice("spatial_controller", "steamVR");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ var toolBar = (function() {
|
|||
newZoneButton,
|
||||
newParticleButton
|
||||
|
||||
var toolIconUrl = Script.resolvePath("assets/images/tools/");
|
||||
var toolIconUrl = Script.resolvePath("../../system/assets/images/tools/");
|
||||
|
||||
function initialize() {
|
||||
print("Toolbars: " + Toolbars);
|
||||
|
|
|
@ -158,6 +158,8 @@ function goAway() {
|
|||
return;
|
||||
}
|
||||
|
||||
UserActivityLogger.toggledAway(true);
|
||||
|
||||
isAway = true;
|
||||
print('going "away"');
|
||||
wasMuted = AudioDevice.getMuted();
|
||||
|
@ -191,6 +193,9 @@ function goActive() {
|
|||
if (!isAway) {
|
||||
return;
|
||||
}
|
||||
|
||||
UserActivityLogger.toggledAway(false);
|
||||
|
||||
isAway = false;
|
||||
print('going "active"');
|
||||
if (!wasMuted) {
|
||||
|
|
|
@ -868,6 +868,7 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.createHotspots = function () {
|
||||
var props, overlay;
|
||||
|
||||
var HAND_SPHERE_COLOR = { red: 90, green: 255, blue: 90 };
|
||||
var HAND_SPHERE_ALPHA = 0.7;
|
||||
|
@ -884,7 +885,7 @@ function MyController(hand) {
|
|||
if (DRAW_HAND_SPHERES) {
|
||||
// add tiny spheres around the palm.
|
||||
var handPosition = this.getHandPosition();
|
||||
var overlay = Overlays.addOverlay("sphere", {
|
||||
overlay = Overlays.addOverlay("sphere", {
|
||||
position: handPosition,
|
||||
size: HAND_SPHERE_RADIUS * 2,
|
||||
color: HAND_SPHERE_COLOR,
|
||||
|
@ -909,7 +910,7 @@ function MyController(hand) {
|
|||
var _this = this;
|
||||
this.entityPropertyCache.getEntities().forEach(function (entityID) {
|
||||
if (_this.entityIsEquippableWithoutDistanceCheck(entityID)) {
|
||||
var props = _this.entityPropertyCache.getProps(entityID);
|
||||
props = _this.entityPropertyCache.getProps(entityID);
|
||||
|
||||
overlay = Overlays.addOverlay("sphere", {
|
||||
rotation: props.rotation,
|
||||
|
@ -931,7 +932,7 @@ function MyController(hand) {
|
|||
}
|
||||
|
||||
if (DRAW_GRAB_SPHERES && _this.entityIsGrabbable(entityID)) {
|
||||
var props = _this.entityPropertyCache.getProps(entityID);
|
||||
props = _this.entityPropertyCache.getProps(entityID);
|
||||
|
||||
overlay = Overlays.addOverlay("sphere", {
|
||||
rotation: props.rotation,
|
||||
|
@ -956,16 +957,17 @@ function MyController(hand) {
|
|||
|
||||
this.updateHotspots = function() {
|
||||
var _this = this;
|
||||
var props;
|
||||
this.hotspotOverlays.forEach(function (overlayInfo) {
|
||||
if (overlayInfo.type === "hand") {
|
||||
Overlays.editOverlay(overlayInfo.overlay, { position: _this.getHandPosition() });
|
||||
} else if (overlayInfo.type === "equip") {
|
||||
_this.entityPropertyCache.updateEntity(overlayInfo.entityID);
|
||||
var props = _this.entityPropertyCache.getProps(overlayInfo.entityID);
|
||||
props = _this.entityPropertyCache.getProps(overlayInfo.entityID);
|
||||
Overlays.editOverlay(overlayInfo.overlay, { position: props.position, rotation: props.rotation });
|
||||
} else if (overlayInfo.type === "near") {
|
||||
_this.entityPropertyCache.updateEntity(overlayInfo.entityID);
|
||||
var props = _this.entityPropertyCache.getProps(overlayInfo.entityID);
|
||||
props = _this.entityPropertyCache.getProps(overlayInfo.entityID);
|
||||
Overlays.editOverlay(overlayInfo.overlay, { position: props.position, rotation: props.rotation });
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
"use strict";
|
||||
/*jslint vars: true, plusplus: true*/
|
||||
/*globals Script, Overlays, Controller, Reticle, HMD, Camera, Entities, MyAvatar, Settings, Menu, ScriptDiscoveryService, Window, Vec3, Quat, print */
|
||||
/*globals Script, Overlays, Controller, Reticle, HMD, Camera, Entities, MyAvatar, Settings, Menu, ScriptDiscoveryService, Window, Vec3, Quat, print*/
|
||||
|
||||
//
|
||||
// handControllerPointer.js
|
||||
|
@ -14,15 +14,11 @@
|
|||
//
|
||||
|
||||
// Control the "mouse" using hand controller. (HMD and desktop.)
|
||||
// For now:
|
||||
// Hydra thumb button 3 is left-mouse, button 4 is right-mouse.
|
||||
// A click in the center of the vive thumb pad is left mouse. Vive menu button is context menu (right mouse).
|
||||
// First-person only.
|
||||
// Starts right handed, but switches to whichever is free: Whichever hand was NOT most recently squeezed.
|
||||
// (For now, the thumb buttons on both controllers are always on.)
|
||||
// When over a HUD element, the reticle is shown where the active hand controller beam intersects the HUD.
|
||||
// Otherwise, the active hand controller shows a red ball where a click will act.
|
||||
|
||||
// When partially squeezing over a HUD element, a laser or the reticle is shown where the active hand
|
||||
// controller beam intersects the HUD.
|
||||
|
||||
|
||||
// UTILITIES -------------
|
||||
|
@ -89,20 +85,15 @@ function Trigger(label) {
|
|||
state = 'full';
|
||||
} else if (that.triggerSmoothedReleased()) {
|
||||
state = null;
|
||||
// These depend on previous state:
|
||||
// null -> squeezed ==> partial
|
||||
// full -> !squeezed ==> partial
|
||||
// Otherwise no change.
|
||||
} else if (that.triggerSmoothedSqueezed()) {
|
||||
if (!state) {
|
||||
state = 'partial';
|
||||
}
|
||||
} else if (state === 'full') {
|
||||
// Another way to do this would be to have hysteresis in this branch, but that seems to make things harder to use.
|
||||
// In particular, the vive has a nice detent as you release off of full, and we want that to be a transition from
|
||||
// full to partial.
|
||||
state = 'partial';
|
||||
}
|
||||
that.state = state;
|
||||
};
|
||||
// Answer a controller source function (answering either 0.0 or 1.0), with hysteresis.
|
||||
// Answer a controller source function (answering either 0.0 or 1.0).
|
||||
that.partial = function () {
|
||||
return that.state ? 1.0 : 0.0; // either 'partial' or 'full'
|
||||
};
|
||||
|
@ -369,24 +360,9 @@ clickMapping.enable();
|
|||
|
||||
// VISUAL AID -----------
|
||||
// Same properties as handControllerGrab search sphere
|
||||
var BALL_SIZE = 0.011;
|
||||
var BALL_ALPHA = 0.5;
|
||||
var LASER_SEARCH_COLOR_XYZW = {x: 10 / 255, y: 10 / 255, z: 255 / 255, w: BALL_ALPHA};
|
||||
var LASER_TRIGGER_COLOR_XYZW = {x: 250 / 255, y: 10 / 255, z: 10 / 255, w: BALL_ALPHA};
|
||||
var fakeProjectionBall = Overlays.addOverlay("sphere", {
|
||||
size: 5 * BALL_SIZE,
|
||||
color: {red: 255, green: 10, blue: 10},
|
||||
ignoreRayIntersection: true,
|
||||
alpha: BALL_ALPHA,
|
||||
visible: false,
|
||||
solid: true,
|
||||
drawInFront: true // Even when burried inside of something, show it.
|
||||
});
|
||||
var overlays = [fakeProjectionBall]; // If we want to try showing multiple balls and lasers.
|
||||
Script.scriptEnding.connect(function () {
|
||||
overlays.forEach(Overlays.deleteOverlay);
|
||||
});
|
||||
var visualizationIsShowing = false; // Not whether it desired, but simply whether it is. Just an optimziation.
|
||||
var LASER_ALPHA = 0.5;
|
||||
var LASER_SEARCH_COLOR_XYZW = {x: 10 / 255, y: 10 / 255, z: 255 / 255, w: LASER_ALPHA};
|
||||
var LASER_TRIGGER_COLOR_XYZW = {x: 250 / 255, y: 10 / 255, z: 10 / 255, w: LASER_ALPHA};
|
||||
var SYSTEM_LASER_DIRECTION = {x: 0, y: 0, z: -1};
|
||||
var systemLaserOn = false;
|
||||
function clearSystemLaser() {
|
||||
|
@ -401,81 +377,30 @@ function setColoredLaser() { // answer trigger state if lasers supported, else f
|
|||
return HMD.setHandLasers(activeHudLaser, true, color, SYSTEM_LASER_DIRECTION) && activeTrigger.state;
|
||||
|
||||
}
|
||||
function turnOffVisualization(optionalEnableClicks) { // because we're showing cursor on HUD
|
||||
if (!optionalEnableClicks) {
|
||||
expireMouseCursor();
|
||||
clearSystemLaser();
|
||||
} else if (activeTrigger.state && (!systemLaserOn || (systemLaserOn !== activeTrigger.state))) { // last=>wrong color
|
||||
// If the active plugin doesn't implement hand lasers, show the mouse reticle instead.
|
||||
systemLaserOn = setColoredLaser();
|
||||
Reticle.visible = !systemLaserOn;
|
||||
} else if ((systemLaserOn || Reticle.visible) && !activeTrigger.state) {
|
||||
clearSystemLaser();
|
||||
Reticle.visible = false;
|
||||
}
|
||||
|
||||
if (!visualizationIsShowing) {
|
||||
return;
|
||||
}
|
||||
visualizationIsShowing = false;
|
||||
overlays.forEach(function (overlay) {
|
||||
Overlays.editOverlay(overlay, {visible: false});
|
||||
});
|
||||
}
|
||||
var MAX_RAY_SCALE = 32000; // Anything large. It's a scale, not a distance.
|
||||
function updateVisualization(controllerPosition, controllerDirection, hudPosition3d, hudPosition2d) {
|
||||
ignore(controllerPosition, controllerDirection, hudPosition2d);
|
||||
clearSystemLaser();
|
||||
// Show an indication of where the cursor will appear when crossing a HUD element,
|
||||
// and where in-world clicking will occur.
|
||||
//
|
||||
// There are a number of ways we could do this, but for now, it's a blue sphere that rolls along
|
||||
// the HUD surface, and a red sphere that rolls along the 3d objects that will receive the click.
|
||||
// We'll leave it to other scripts (like handControllerGrab) to show a search beam when desired.
|
||||
|
||||
function intersection3d(position, direction) {
|
||||
// Answer in-world intersection (entity or 3d overlay), or way-out point
|
||||
var pickRay = {origin: position, direction: direction};
|
||||
var result = findRayIntersection(pickRay);
|
||||
return result.intersects ? result.intersection : Vec3.sum(position, Vec3.multiply(MAX_RAY_SCALE, direction));
|
||||
}
|
||||
|
||||
visualizationIsShowing = true;
|
||||
// We'd rather in-world interactions be done at the termination of the hand beam
|
||||
// -- intersection3d(controllerPosition, controllerDirection). Maybe have handControllerGrab
|
||||
// direclty manipulate both entity and 3d overlay objects.
|
||||
// For now, though, we present a false projection of the cursor onto whatever is below it. This is
|
||||
// different from the hand beam termination because the false projection is from the camera, while
|
||||
// the hand beam termination is from the hand.
|
||||
/* // FIXME: We can tighten this up later, once we know what will and won't be included.
|
||||
var eye = Camera.getPosition();
|
||||
var falseProjection = intersection3d(eye, Vec3.subtract(hudPosition3d, eye));
|
||||
Overlays.editOverlay(fakeProjectionBall, {visible: true, position: falseProjection});
|
||||
*/
|
||||
Reticle.visible = false;
|
||||
|
||||
return visualizationIsShowing; // In case we change caller to act conditionally.
|
||||
}
|
||||
|
||||
// MAIN OPERATIONS -----------
|
||||
//
|
||||
function update() {
|
||||
var now = Date.now();
|
||||
function off() {
|
||||
expireMouseCursor();
|
||||
clearSystemLaser();
|
||||
}
|
||||
if (!handControllerLockOut.expired(now)) {
|
||||
return turnOffVisualization(); // Let them use mouse it in peace.
|
||||
return off(); // Let them use mouse it in peace.
|
||||
}
|
||||
if (!Menu.isOptionChecked("First Person")) {
|
||||
return turnOffVisualization(); // What to do? menus can be behind hand!
|
||||
return off(); // What to do? menus can be behind hand!
|
||||
}
|
||||
if (!Window.hasFocus() || !Reticle.allowMouseCapture) {
|
||||
return turnOffVisualization(); // Don't mess with other apps or paused mouse activity
|
||||
return off(); // Don't mess with other apps or paused mouse activity
|
||||
}
|
||||
leftTrigger.update();
|
||||
rightTrigger.update();
|
||||
var controllerPose = Controller.getPoseValue(activeHand);
|
||||
// Valid if any plugged-in hand controller is "on". (uncradled Hydra, green-lighted Vive...)
|
||||
if (!controllerPose.valid) {
|
||||
return turnOffVisualization(); // Controller is cradled.
|
||||
return off(); // Controller is cradled.
|
||||
}
|
||||
var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation),
|
||||
MyAvatar.position);
|
||||
|
@ -487,7 +412,7 @@ function update() {
|
|||
if (Menu.isOptionChecked("Overlays")) { // With our hud resetting strategy, hudPoint3d should be valid here
|
||||
print('Controller is parallel to HUD'); // so let us know that our assumptions are wrong.
|
||||
}
|
||||
return turnOffVisualization();
|
||||
return off();
|
||||
}
|
||||
var hudPoint2d = overlayFromWorldPoint(hudPoint3d);
|
||||
|
||||
|
@ -499,13 +424,22 @@ function update() {
|
|||
if (HMD.active) {
|
||||
Reticle.depth = hudReticleDistance();
|
||||
}
|
||||
return turnOffVisualization(true);
|
||||
if (activeTrigger.state && (!systemLaserOn || (systemLaserOn !== activeTrigger.state))) { // last=>wrong color
|
||||
// If the active plugin doesn't implement hand lasers, show the mouse reticle instead.
|
||||
systemLaserOn = setColoredLaser();
|
||||
Reticle.visible = !systemLaserOn;
|
||||
} else if ((systemLaserOn || Reticle.visible) && !activeTrigger.state) {
|
||||
clearSystemLaser();
|
||||
Reticle.visible = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
// We are not pointing at a HUD element (but it could be a 3d overlay).
|
||||
if (!activeTrigger.state) {
|
||||
return turnOffVisualization(); // No trigger (with hysteresis).
|
||||
return off(); // No trigger
|
||||
}
|
||||
updateVisualization(controllerPosition, controllerDirection, hudPoint3d, hudPoint2d);
|
||||
clearSystemLaser();
|
||||
Reticle.visible = false;
|
||||
}
|
||||
|
||||
var UPDATE_INTERVAL = 50; // milliseconds. Script.update is too frequent.
|
||||
|
|
|
@ -150,6 +150,8 @@ function showMarketplace(marketplaceID) {
|
|||
marketplaceWindow.setURL(url);
|
||||
marketplaceWindow.setVisible(true);
|
||||
marketplaceWindow.raise();
|
||||
|
||||
UserActivityLogger.logAction("opened_marketplace");
|
||||
}
|
||||
|
||||
function hideMarketplace() {
|
||||
|
@ -347,6 +349,7 @@ var toolBar = (function() {
|
|||
selectionManager.clearSelections();
|
||||
cameraManager.disable();
|
||||
} else {
|
||||
UserActivityLogger.enabledEdit();
|
||||
hasShownPropertiesTool = false;
|
||||
entityListTool.setVisible(true);
|
||||
gridTool.setVisible(true);
|
||||
|
|
|
@ -33,6 +33,8 @@ function showExamples(marketplaceID) {
|
|||
print("setting examples URL to " + url);
|
||||
examplesWindow.setURL(url);
|
||||
examplesWindow.setVisible(true);
|
||||
|
||||
UserActivityLogger.openedMarketplace();
|
||||
}
|
||||
|
||||
function hideExamples() {
|
||||
|
|
|
@ -452,6 +452,7 @@
|
|||
var elTextText = document.getElementById("property-text-text");
|
||||
var elTextLineHeight = document.getElementById("property-text-line-height");
|
||||
var elTextTextColor = document.getElementById("property-text-text-color");
|
||||
var elTextFaceCamera = document.getElementById("property-text-face-camera");
|
||||
var elTextTextColorRed = document.getElementById("property-text-text-color-red");
|
||||
var elTextTextColorGreen = document.getElementById("property-text-text-color-green");
|
||||
var elTextTextColorBlue = document.getElementById("property-text-text-color-blue");
|
||||
|
@ -726,6 +727,7 @@
|
|||
|
||||
elTextText.value = properties.text;
|
||||
elTextLineHeight.value = properties.lineHeight.toFixed(4);
|
||||
elTextFaceCamera = properties.faceCamera;
|
||||
elTextTextColor.style.backgroundColor = "rgb(" + properties.textColor.red + "," + properties.textColor.green + "," + properties.textColor.blue + ")";
|
||||
elTextTextColorRed.value = properties.textColor.red;
|
||||
elTextTextColorGreen.value = properties.textColor.green;
|
||||
|
@ -988,8 +990,8 @@
|
|||
elModelTextures.addEventListener('change', createEmitTextPropertyUpdateFunction('textures'));
|
||||
|
||||
elTextText.addEventListener('change', createEmitTextPropertyUpdateFunction('text'));
|
||||
elTextFaceCamera.addEventListener('change', createEmitCheckedPropertyUpdateFunction('faceCamera'));
|
||||
elTextLineHeight.addEventListener('change', createEmitNumberPropertyUpdateFunction('lineHeight'));
|
||||
|
||||
var textTextColorChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'textColor', elTextTextColorRed, elTextTextColorGreen, elTextTextColorBlue);
|
||||
elTextTextColorRed.addEventListener('change', textTextColorChangeFunction);
|
||||
|
@ -1707,6 +1709,10 @@
|
|||
<label for="property-text-text">Text content</label>
|
||||
<input type="text" id="property-text-text">
|
||||
</div>
|
||||
<div class="text-group text-section property checkbox">
|
||||
<input type="checkbox" id="property-text-face-camera">
|
||||
<label for="property-text-face-camera"> Face Camera</label>
|
||||
</div>
|
||||
<div class="text-group text-section property number">
|
||||
<label>Line height <span class="unit">m</span></label>
|
||||
<input type="number" id="property-text-line-height" min="0" step="0.005">
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var PopUpMenu = function (properties) {
|
||||
var PopUpMenu = function(properties) {
|
||||
var value = properties.value,
|
||||
promptOverlay,
|
||||
valueOverlay,
|
||||
|
@ -217,7 +217,7 @@ var PopUpMenu = function (properties) {
|
|||
};
|
||||
};
|
||||
|
||||
var usersWindow = (function () {
|
||||
var usersWindow = (function() {
|
||||
|
||||
var baseURL = Script.resolvePath("assets/images/tools/"),
|
||||
WINDOW_WIDTH = 260,
|
||||
|
@ -253,7 +253,11 @@ var usersWindow = (function () {
|
|||
WINDOW_BORDER_BOTTOM_MARGIN = WINDOW_BASE_MARGIN,
|
||||
WINDOW_BORDER_LEFT_MARGIN = WINDOW_BASE_MARGIN,
|
||||
WINDOW_BORDER_RADIUS = 4,
|
||||
WINDOW_BORDER_COLOR = { red: 255, green: 255, blue: 255 },
|
||||
WINDOW_BORDER_COLOR = {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
WINDOW_BORDER_ALPHA = 0.5,
|
||||
windowBorder,
|
||||
|
||||
|
@ -377,9 +381,12 @@ var usersWindow = (function () {
|
|||
isMirrorDisplay = false,
|
||||
isFullscreenMirror = false,
|
||||
|
||||
windowPosition = { }, // Bottom left corner of window pane.
|
||||
windowPosition = {}, // Bottom left corner of window pane.
|
||||
isMovingWindow = false,
|
||||
movingClickOffset = { x: 0, y: 0 },
|
||||
movingClickOffset = {
|
||||
x: 0,
|
||||
y: 0
|
||||
},
|
||||
|
||||
isUsingScrollbars = false,
|
||||
isMovingScrollbar = false,
|
||||
|
@ -401,9 +408,7 @@ var usersWindow = (function () {
|
|||
}
|
||||
|
||||
// Reserve space for title, friends button, and option controls
|
||||
nonUsersHeight = WINDOW_MARGIN + windowLineHeight + FRIENDS_BUTTON_SPACER + FRIENDS_BUTTON_HEIGHT + DISPLAY_SPACER
|
||||
+ windowLineHeight + VISIBILITY_SPACER
|
||||
+ windowLineHeight + WINDOW_BASE_MARGIN;
|
||||
nonUsersHeight = WINDOW_MARGIN + windowLineHeight + FRIENDS_BUTTON_SPACER + FRIENDS_BUTTON_HEIGHT + DISPLAY_SPACER + windowLineHeight + VISIBILITY_SPACER + windowLineHeight + WINDOW_BASE_MARGIN;
|
||||
|
||||
// Limit window to height of viewport above window position minus VU meter and mirror if displayed
|
||||
windowHeight = linesOfUsers.length * windowLineHeight - windowLineSpacing + nonUsersHeight;
|
||||
|
@ -456,17 +461,14 @@ var usersWindow = (function () {
|
|||
x: scrollbarBackgroundPosition.x,
|
||||
y: scrollbarBackgroundPosition.y
|
||||
});
|
||||
scrollbarBarPosition.y = scrollbarBackgroundPosition.y + 1
|
||||
+ scrollbarValue * (scrollbarBackgroundHeight - scrollbarBarHeight - 2);
|
||||
scrollbarBarPosition.y = scrollbarBackgroundPosition.y + 1 + scrollbarValue * (scrollbarBackgroundHeight - scrollbarBarHeight - 2);
|
||||
Overlays.editOverlay(scrollbarBar, {
|
||||
x: scrollbarBackgroundPosition.x + 1,
|
||||
y: scrollbarBarPosition.y
|
||||
});
|
||||
|
||||
x = windowLeft + WINDOW_MARGIN;
|
||||
y = windowPosition.y - FRIENDS_BUTTON_HEIGHT - DISPLAY_SPACER
|
||||
- windowLineHeight - VISIBILITY_SPACER
|
||||
- windowLineHeight - WINDOW_BASE_MARGIN;
|
||||
y = windowPosition.y - FRIENDS_BUTTON_HEIGHT - DISPLAY_SPACER - windowLineHeight - VISIBILITY_SPACER - windowLineHeight - WINDOW_BASE_MARGIN;
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
x: x,
|
||||
y: y
|
||||
|
@ -554,9 +556,36 @@ var usersWindow = (function () {
|
|||
usersRequest.ontimeout = pollUsersTimedOut;
|
||||
usersRequest.onreadystatechange = processUsers;
|
||||
usersRequest.send();
|
||||
checkLoggedIn();
|
||||
}
|
||||
|
||||
processUsers = function () {
|
||||
var loggedIn = false;
|
||||
|
||||
function checkLoggedIn() {
|
||||
loggedIn = Account.isLoggedIn();
|
||||
if (loggedIn === false) {
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
visible: false
|
||||
});
|
||||
visibilityControl.setVisible(false);
|
||||
displayControl.setVisible(false);
|
||||
} else {
|
||||
if (isMinimized === true) {
|
||||
loggedIn = true;
|
||||
return
|
||||
}
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
visible: true
|
||||
});
|
||||
visibilityControl.setVisible(true);
|
||||
displayControl.setVisible(true);
|
||||
loggedIn = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
processUsers = function() {
|
||||
var response,
|
||||
myUsername,
|
||||
user,
|
||||
|
@ -609,7 +638,7 @@ var usersWindow = (function () {
|
|||
}
|
||||
};
|
||||
|
||||
pollUsersTimedOut = function () {
|
||||
pollUsersTimedOut = function() {
|
||||
print("Error: Request for users status timed out");
|
||||
usersTimer = Script.setTimeout(pollUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay.
|
||||
};
|
||||
|
@ -633,11 +662,15 @@ var usersWindow = (function () {
|
|||
Overlays.editOverlay(scrollbarBar, {
|
||||
visible: isVisible && isUsingScrollbars && !isMinimized
|
||||
});
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
visible: isVisible && !isMinimized
|
||||
});
|
||||
displayControl.setVisible(isVisible && !isMinimized);
|
||||
visibilityControl.setVisible(isVisible && !isMinimized);
|
||||
|
||||
if (loggedIn === true) {
|
||||
Overlays.editOverlay(friendsButton, {
|
||||
visible: isVisible && !isMinimized
|
||||
});
|
||||
displayControl.setVisible(isVisible && !isMinimized);
|
||||
visibilityControl.setVisible(isVisible && !isMinimized);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function setVisible(visible) {
|
||||
|
@ -730,9 +763,7 @@ var usersWindow = (function () {
|
|||
|
||||
userClicked = firstUserToDisplay + lineClicked;
|
||||
|
||||
if (0 <= userClicked && userClicked < linesOfUsers.length && 0 <= overlayX
|
||||
&& overlayX <= usersOnline[linesOfUsers[userClicked]].textWidth) {
|
||||
//print("Go to " + usersOnline[linesOfUsers[userClicked]].username);
|
||||
if (0 <= userClicked && userClicked < linesOfUsers.length && 0 <= overlayX && overlayX <= usersOnline[linesOfUsers[userClicked]].textWidth) {
|
||||
location.goToUser(usersOnline[linesOfUsers[userClicked]].username);
|
||||
}
|
||||
|
||||
|
@ -800,12 +831,8 @@ var usersWindow = (function () {
|
|||
var isVisible;
|
||||
|
||||
if (isMovingScrollbar) {
|
||||
if (scrollbarBackgroundPosition.x - WINDOW_MARGIN <= event.x
|
||||
&& event.x <= scrollbarBackgroundPosition.x + SCROLLBAR_BACKGROUND_WIDTH + WINDOW_MARGIN
|
||||
&& scrollbarBackgroundPosition.y - WINDOW_MARGIN <= event.y
|
||||
&& event.y <= scrollbarBackgroundPosition.y + scrollbarBackgroundHeight + WINDOW_MARGIN) {
|
||||
scrollbarValue = (event.y - scrollbarBarClickedAt * scrollbarBarHeight - scrollbarBackgroundPosition.y)
|
||||
/ (scrollbarBackgroundHeight - scrollbarBarHeight - 2);
|
||||
if (scrollbarBackgroundPosition.x - WINDOW_MARGIN <= event.x && event.x <= scrollbarBackgroundPosition.x + SCROLLBAR_BACKGROUND_WIDTH + WINDOW_MARGIN && scrollbarBackgroundPosition.y - WINDOW_MARGIN <= event.y && event.y <= scrollbarBackgroundPosition.y + scrollbarBackgroundHeight + WINDOW_MARGIN) {
|
||||
scrollbarValue = (event.y - scrollbarBarClickedAt * scrollbarBarHeight - scrollbarBackgroundPosition.y) / (scrollbarBackgroundHeight - scrollbarBarHeight - 2);
|
||||
scrollbarValue = Math.min(Math.max(scrollbarValue, 0.0), 1.0);
|
||||
firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay));
|
||||
updateOverlayPositions();
|
||||
|
@ -831,13 +858,9 @@ var usersWindow = (function () {
|
|||
|
||||
isVisible = isBorderVisible;
|
||||
if (isVisible) {
|
||||
isVisible = windowPosition.x - WINDOW_BORDER_LEFT_MARGIN <= event.x
|
||||
&& event.x <= windowPosition.x - WINDOW_BORDER_LEFT_MARGIN + WINDOW_BORDER_WIDTH
|
||||
&& windowPosition.y - windowHeight - WINDOW_BORDER_TOP_MARGIN <= event.y
|
||||
&& event.y <= windowPosition.y + WINDOW_BORDER_BOTTOM_MARGIN;
|
||||
isVisible = windowPosition.x - WINDOW_BORDER_LEFT_MARGIN <= event.x && event.x <= windowPosition.x - WINDOW_BORDER_LEFT_MARGIN + WINDOW_BORDER_WIDTH && windowPosition.y - windowHeight - WINDOW_BORDER_TOP_MARGIN <= event.y && event.y <= windowPosition.y + WINDOW_BORDER_BOTTOM_MARGIN;
|
||||
} else {
|
||||
isVisible = windowPosition.x <= event.x && event.x <= windowPosition.x + WINDOW_WIDTH
|
||||
&& windowPosition.y - windowHeight <= event.y && event.y <= windowPosition.y;
|
||||
isVisible = windowPosition.x <= event.x && event.x <= windowPosition.x + WINDOW_WIDTH && windowPosition.y - windowHeight <= event.y && event.y <= windowPosition.y;
|
||||
}
|
||||
if (isVisible !== isBorderVisible) {
|
||||
isBorderVisible = isVisible;
|
||||
|
@ -878,8 +901,7 @@ var usersWindow = (function () {
|
|||
isMirrorDisplay = Menu.isOptionChecked(MIRROR_MENU_ITEM);
|
||||
isFullscreenMirror = Menu.isOptionChecked(FULLSCREEN_MIRROR_MENU_ITEM);
|
||||
|
||||
if (viewport.y !== oldViewport.y || isMirrorDisplay !== oldIsMirrorDisplay
|
||||
|| isFullscreenMirror !== oldIsFullscreenMirror) {
|
||||
if (viewport.y !== oldViewport.y || isMirrorDisplay !== oldIsMirrorDisplay || isFullscreenMirror !== oldIsFullscreenMirror) {
|
||||
calculateWindowHeight();
|
||||
updateUsersDisplay();
|
||||
}
|
||||
|
@ -929,8 +951,8 @@ var usersWindow = (function () {
|
|||
} else {
|
||||
hmdViewport = Controller.getRecommendedOverlayRect();
|
||||
windowPosition = {
|
||||
x: (viewport.x - hmdViewport.width) / 2, // HMD viewport is narrower than screen.
|
||||
y: hmdViewport.height // HMD viewport starts at top of screen but only extends down so far.
|
||||
x: (viewport.x - hmdViewport.width) / 2, // HMD viewport is narrower than screen.
|
||||
y: hmdViewport.height // HMD viewport starts at top of screen but only extends down so far.
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -938,7 +960,7 @@ var usersWindow = (function () {
|
|||
|
||||
windowBorder = Overlays.addOverlay("rectangle", {
|
||||
x: 0,
|
||||
y: viewport.y, // Start up off-screen
|
||||
y: viewport.y, // Start up off-screen
|
||||
width: WINDOW_BORDER_WIDTH,
|
||||
height: windowBorderHeight,
|
||||
radius: WINDOW_BORDER_RADIUS,
|
||||
|
@ -1101,6 +1123,11 @@ var usersWindow = (function () {
|
|||
visible: isVisible && !isMinimized
|
||||
});
|
||||
|
||||
|
||||
Script.setTimeout(function() {
|
||||
checkLoggedIn()
|
||||
}, 0);
|
||||
|
||||
Controller.mousePressEvent.connect(onMousePressEvent);
|
||||
Controller.mouseMoveEvent.connect(onMouseMoveEvent);
|
||||
Controller.mouseReleaseEvent.connect(onMouseReleaseEvent);
|
||||
|
@ -1143,4 +1170,4 @@ var usersWindow = (function () {
|
|||
|
||||
setUp();
|
||||
Script.scriptEnding.connect(tearDown);
|
||||
}());
|
||||
}());
|
129
scripts/tutorials/getDomainMetadata.js
Normal file
129
scripts/tutorials/getDomainMetadata.js
Normal file
|
@ -0,0 +1,129 @@
|
|||
//
|
||||
// Created by Zach Pomerantz on June 16, 2016.
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
var SERVER = 'https://metaverse.highfidelity.com/api/v1';
|
||||
|
||||
var OVERLAY = null;
|
||||
|
||||
// Every time you enter a domain, display the domain's metadata
|
||||
location.hostChanged.connect(function(host) {
|
||||
print('Detected host change:', host);
|
||||
|
||||
// Fetch the domain ID from the metaverse
|
||||
var placeData = request(SERVER + '/places/' + host);
|
||||
if (!placeData) {
|
||||
print('Cannot find place name - abandoning metadata request for', host);
|
||||
return;
|
||||
|
||||
}
|
||||
var domainID = placeData.data.place.domain.id;
|
||||
print('Domain ID:', domainID);
|
||||
|
||||
// Fetch the domain metadata from the metaverse
|
||||
var domainData = request(SERVER + '/domains/' + domainID);
|
||||
print(SERVER + '/domains/' + domainID);
|
||||
if (!domainData) {
|
||||
print('Cannot find domain data - abandoning metadata request for', domainID);
|
||||
return;
|
||||
}
|
||||
var metadata = domainData.domain;
|
||||
print('Domain metadata:', JSON.stringify(metadata));
|
||||
|
||||
// Display the fetched metadata in an overlay
|
||||
displayMetadata(host, metadata);
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(clearMetadata);
|
||||
|
||||
function displayMetadata(place, metadata) {
|
||||
clearMetadata();
|
||||
|
||||
var COLOR_TEXT = { red: 255, green: 255, blue: 255 };
|
||||
var COLOR_BACKGROUND = { red: 0, green: 0, blue: 0 };
|
||||
var MARGIN = 200;
|
||||
var STARTING_OPACITY = 0.8;
|
||||
var FADE_AFTER_SEC = 2;
|
||||
var FADE_FOR_SEC = 4;
|
||||
|
||||
var fade_per_sec = STARTING_OPACITY / FADE_FOR_SEC;
|
||||
var properties = {
|
||||
color: COLOR_TEXT,
|
||||
alpha: STARTING_OPACITY,
|
||||
backgroundColor: COLOR_BACKGROUND,
|
||||
backgroundAlpha: STARTING_OPACITY,
|
||||
font: { size: 24 },
|
||||
x: MARGIN,
|
||||
y: MARGIN
|
||||
};
|
||||
|
||||
// Center the overlay on the screen
|
||||
properties.width = Window.innerWidth - MARGIN*2;
|
||||
properties.height = Window.innerHeight - MARGIN*2;
|
||||
|
||||
// Parse the metadata into text
|
||||
parsed = [ 'Welcome to ' + place + '!',, ];
|
||||
if (metadata.description) {
|
||||
parsed.push(description);
|
||||
}
|
||||
if (metadata.tags && metadata.tags.length) {
|
||||
parsed.push('Tags: ' + metadata.tags.join(','));
|
||||
}
|
||||
if (metadata.capacity) {
|
||||
parsed.push('Capacity (max users): ' + metadata.capacity);
|
||||
}
|
||||
if (metadata.maturity) {
|
||||
parsed.push('Maturity: ' + metadata.maturity);
|
||||
}
|
||||
if (metadata.hosts && metadata.hosts.length) {
|
||||
parsed.push('Hosts: ' + metadata.tags.join(','));
|
||||
}
|
||||
if (metadata.online_users) {
|
||||
parsed.push('Users online: ' + metadata.online_users);
|
||||
}
|
||||
|
||||
properties.text = parsed.join('\n\n');
|
||||
|
||||
// Display the overlay
|
||||
OVERLAY = Overlays.addOverlay('text', properties);
|
||||
|
||||
// Fade out the overlay over 10 seconds
|
||||
!function() {
|
||||
var overlay = OVERLAY;
|
||||
var alpha = STARTING_OPACITY;
|
||||
|
||||
var fade = function() {
|
||||
// Only fade so long as the same overlay is up
|
||||
if (overlay == OVERLAY) {
|
||||
alpha -= fade_per_sec / 10;
|
||||
if (alpha <= 0) {
|
||||
clearMetadata();
|
||||
} else {
|
||||
Overlays.editOverlay(overlay, { alpha: alpha, backgroundAlpha: alpha });
|
||||
Script.setTimeout(fade, 100);
|
||||
}
|
||||
}
|
||||
};
|
||||
Script.setTimeout(fade, FADE_AFTER_SEC * 1000);
|
||||
}();
|
||||
}
|
||||
|
||||
function clearMetadata() {
|
||||
if (OVERLAY) {
|
||||
Overlays.deleteOverlay(OVERLAY);
|
||||
}
|
||||
}
|
||||
|
||||
// Request JSON from a url, synchronously
|
||||
function request(url) {
|
||||
var req = new XMLHttpRequest();
|
||||
req.responseType = 'json';
|
||||
req.open('GET', url, false);
|
||||
req.send();
|
||||
return req.status == 200 ? req.response : null;
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ setup_hifi_project(Script Qml)
|
|||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "Tests/manual-tests/")
|
||||
|
||||
# link in the shared libraries
|
||||
link_hifi_libraries(shared gl script-engine plugins render-utils input-plugins display-plugins controllers)
|
||||
link_hifi_libraries(shared gl script-engine plugins render-utils ui-plugins input-plugins display-plugins controllers)
|
||||
|
||||
|
||||
if (WIN32)
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include <QtQml/QQmlContext>
|
||||
|
||||
#include <plugins/Plugin.h>
|
||||
#include <plugins/PluginContainer.h>
|
||||
#include <ui-plugins/PluginContainer.h>
|
||||
#include <plugins/PluginManager.h>
|
||||
#include <input-plugins/InputPlugin.h>
|
||||
#include <input-plugins/KeyboardMouseDevice.h>
|
||||
|
@ -90,8 +90,8 @@ public:
|
|||
virtual MainWindow* getPrimaryWindow() override { return nullptr; }
|
||||
virtual QOpenGLContext* getPrimaryContext() override { return nullptr; }
|
||||
virtual ui::Menu* getPrimaryMenu() override { return nullptr; }
|
||||
virtual bool isForeground() override { return true; }
|
||||
virtual const DisplayPluginPointer getActiveDisplayPlugin() const override { return DisplayPluginPointer(); }
|
||||
virtual bool isForeground() const override { return true; }
|
||||
virtual DisplayPluginPointer getActiveDisplayPlugin() const override { return DisplayPluginPointer(); }
|
||||
};
|
||||
|
||||
class MyControllerScriptingInterface : public controller::ScriptingInterface {
|
||||
|
|
|
@ -57,7 +57,7 @@ ApplicationWindow {
|
|||
"particle-01.svg",
|
||||
]
|
||||
property int iconIndex: 0
|
||||
readonly property string toolIconUrl: "file:///C:/Users/bdavi/git/hifi/scripts/system/assets/images/tools/"
|
||||
readonly property string toolIconUrl: "../../../../../scripts/system/assets/images/tools/"
|
||||
text: "Create Button"
|
||||
onClicked: {
|
||||
var name = icons[iconIndex];
|
||||
|
|
Loading…
Reference in a new issue