Merge pull request #475 from kasenvr/v2020.2.2-rc
Merge v2020.2.2-rc into master
|
@ -176,7 +176,7 @@ std::pair<AssetUtils::BakingStatus, QString> AssetServer::getAssetStatus(const A
|
|||
} else if (loaded && meta.failedLastBake) {
|
||||
return { AssetUtils::Error, meta.lastBakeErrors };
|
||||
}
|
||||
|
||||
|
||||
return { AssetUtils::Pending, "" };
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ void AssetServer::maybeBake(const AssetUtils::AssetPath& path, const AssetUtils:
|
|||
void AssetServer::createEmptyMetaFile(const AssetUtils::AssetHash& hash) {
|
||||
QString metaFilePath = "atp:/" + hash + "/meta.json";
|
||||
QFile metaFile { metaFilePath };
|
||||
|
||||
|
||||
if (!metaFile.exists()) {
|
||||
qDebug() << "Creating metafile for " << hash;
|
||||
if (metaFile.open(QFile::WriteOnly)) {
|
||||
|
@ -285,7 +285,7 @@ void updateConsumedCores() {
|
|||
auto coreCount = std::thread::hardware_concurrency();
|
||||
if (isInterfaceRunning) {
|
||||
coreCount = coreCount > MIN_CORES_FOR_MULTICORE ? CPU_AFFINITY_COUNT_HIGH : CPU_AFFINITY_COUNT_LOW;
|
||||
}
|
||||
}
|
||||
qCDebug(asset_server) << "Setting max consumed cores to " << coreCount;
|
||||
setMaxCores(coreCount);
|
||||
}
|
||||
|
@ -931,6 +931,9 @@ void AssetServer::sendStatsPacket() {
|
|||
connectionStats["5. Period (us)"] = stats.packetSendPeriod;
|
||||
connectionStats["6. Up (Mb/s)"] = stats.sentBytes * megabitsPerSecPerByte;
|
||||
connectionStats["7. Down (Mb/s)"] = stats.receivedBytes * megabitsPerSecPerByte;
|
||||
connectionStats["last_heard_time_msecs"] = date.toUTC().toMSecsSinceEpoch();
|
||||
connectionStats["last_heard_ago_msecs"] = date.msecsTo(QDateTime::currentDateTime());
|
||||
|
||||
nodeStats["Connection Stats"] = connectionStats;
|
||||
|
||||
using Events = udt::ConnectionStats::Stats::Event;
|
||||
|
@ -1147,7 +1150,7 @@ bool AssetServer::deleteMappings(const AssetUtils::AssetPathList& paths) {
|
|||
hashesToCheckForDeletion << it->second;
|
||||
|
||||
qCDebug(asset_server) << "Deleted a mapping:" << path << "=>" << it->second;
|
||||
|
||||
|
||||
_fileMappings.erase(it);
|
||||
} else {
|
||||
qCDebug(asset_server) << "Unable to delete a mapping that was not found:" << path;
|
||||
|
|
|
@ -668,6 +668,12 @@ QJsonObject AudioMixerClientData::getAudioStreamStats() {
|
|||
downstreamStats["min_gap_30s"] = formatUsecTime(streamStats._timeGapWindowMin);
|
||||
downstreamStats["max_gap_30s"] = formatUsecTime(streamStats._timeGapWindowMax);
|
||||
downstreamStats["avg_gap_30s"] = formatUsecTime(streamStats._timeGapWindowAverage);
|
||||
downstreamStats["min_gap_usecs"] = static_cast<double>(streamStats._timeGapMin);
|
||||
downstreamStats["max_gap_usecs"] = static_cast<double>(streamStats._timeGapMax);
|
||||
downstreamStats["avg_gap_usecs"] = static_cast<double>(streamStats._timeGapAverage);
|
||||
downstreamStats["min_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowMin);
|
||||
downstreamStats["max_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowMax);
|
||||
downstreamStats["avg_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowAverage);
|
||||
|
||||
result["downstream"] = downstreamStats;
|
||||
|
||||
|
@ -695,6 +701,13 @@ QJsonObject AudioMixerClientData::getAudioStreamStats() {
|
|||
upstreamStats["max_gap_30s"] = formatUsecTime(streamStats._timeGapWindowMax);
|
||||
upstreamStats["avg_gap_30s"] = formatUsecTime(streamStats._timeGapWindowAverage);
|
||||
|
||||
upstreamStats["min_gap_usecs"] = static_cast<double>(streamStats._timeGapMin);
|
||||
upstreamStats["max_gap_usecs"] = static_cast<double>(streamStats._timeGapMax);
|
||||
upstreamStats["avg_gap_usecs"] = static_cast<double>(streamStats._timeGapAverage);
|
||||
upstreamStats["min_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowMin);
|
||||
upstreamStats["max_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowMax);
|
||||
upstreamStats["avg_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowAverage);
|
||||
|
||||
result["upstream"] = upstreamStats;
|
||||
} else {
|
||||
result["upstream"] = "mic unknown";
|
||||
|
@ -725,6 +738,12 @@ QJsonObject AudioMixerClientData::getAudioStreamStats() {
|
|||
upstreamStats["max_gap_30s"] = formatUsecTime(streamStats._timeGapWindowMax);
|
||||
upstreamStats["avg_gap_30s"] = formatUsecTime(streamStats._timeGapWindowAverage);
|
||||
|
||||
upstreamStats["min_gap_usecs"] = static_cast<double>(streamStats._timeGapMin);
|
||||
upstreamStats["max_gap_usecs"] = static_cast<double>(streamStats._timeGapMax);
|
||||
upstreamStats["avg_gap_usecs"] = static_cast<double>(streamStats._timeGapAverage);
|
||||
upstreamStats["min_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowMin);
|
||||
upstreamStats["max_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowMax);
|
||||
upstreamStats["avg_gap_30s_usecs"] = static_cast<double>(streamStats._timeGapWindowAverage);
|
||||
injectorArray.push_back(upstreamStats);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -89,6 +89,7 @@ int OctreeServer::_shortProcessWait = 0;
|
|||
int OctreeServer::_noProcessWait = 0;
|
||||
|
||||
static const QString PERSIST_FILE_DOWNLOAD_PATH = "/models.json.gz";
|
||||
static const double NANOSECONDS_PER_SECOND = 1000000.0;;
|
||||
|
||||
|
||||
void OctreeServer::resetSendingStats() {
|
||||
|
@ -1197,7 +1198,7 @@ void OctreeServer::domainSettingsRequestComplete() {
|
|||
} else {
|
||||
beginRunning();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OctreeServer::beginRunning() {
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
|
@ -1344,6 +1345,10 @@ QString OctreeServer::getUptime() {
|
|||
return formattedUptime;
|
||||
}
|
||||
|
||||
double OctreeServer::getUptimeSeconds() {
|
||||
return (usecTimestampNow() - _startedUSecs) / NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
|
||||
QString OctreeServer::getFileLoadTime() {
|
||||
QString result;
|
||||
if (isInitialLoadComplete()) {
|
||||
|
@ -1386,6 +1391,10 @@ QString OctreeServer::getFileLoadTime() {
|
|||
return result;
|
||||
}
|
||||
|
||||
double OctreeServer::getFileLoadTimeSeconds() {
|
||||
return getLoadElapsedTime() / NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
|
||||
QString OctreeServer::getConfiguration() {
|
||||
QString result;
|
||||
for (int i = 1; i < _argc; i++) {
|
||||
|
@ -1421,6 +1430,8 @@ void OctreeServer::sendStatsPacket() {
|
|||
statsArray1["4. persistFileLoadTime"] = getFileLoadTime();
|
||||
statsArray1["5. clients"] = getCurrentClientCount();
|
||||
statsArray1["6. threads"] = threadsStats;
|
||||
statsArray1["uptime_seconds"] = getUptimeSeconds();
|
||||
statsArray1["persistFileLoadTime_seconds"] = getFileLoadTimeSeconds();
|
||||
|
||||
// Octree Stats
|
||||
QJsonObject octreeStats;
|
||||
|
|
|
@ -158,7 +158,9 @@ protected:
|
|||
void initHTTPManager(int port);
|
||||
void resetSendingStats();
|
||||
QString getUptime();
|
||||
double getUptimeSeconds();
|
||||
QString getFileLoadTime();
|
||||
double getFileLoadTimeSeconds();
|
||||
QString getConfiguration();
|
||||
QString getStatusLink();
|
||||
|
||||
|
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 264 KiB |
|
@ -2,10 +2,12 @@ include(vcpkg_common_functions)
|
|||
set(ARISTO_VERSION 0.8.1)
|
||||
set(MASTER_COPY_SOURCE_PATH ${CURRENT_BUILDTREES_DIR}/src)
|
||||
|
||||
file(READ "${VCPKG_ROOT_DIR}/_env/EXTERNAL_BUILD_ASSETS.txt" EXTERNAL_BUILD_ASSETS)
|
||||
|
||||
if (WIN32)
|
||||
vcpkg_download_distfile(
|
||||
ARISTO_SOURCE_ARCHIVE
|
||||
URLS https://athena-public.s3.amazonaws.com/seth/aristo-0.8.1-windows.zip
|
||||
URLS "${EXTERNAL_BUILD_ASSETS}/seth/aristo-0.8.1-windows.zip"
|
||||
SHA512 05179c63b72a1c9f5be8a7a2b7389025da683400dbf819e5a6199dd6473c56774d2885182dc5a11cb6324058d228a4ead832222e8b3e1bebaa4c61982e85f0a8
|
||||
FILENAME aristo-0.8.1-windows.zip
|
||||
)
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
Source: sranipal
|
||||
Version: 1.1.0.1
|
||||
Description: SRanipal
|
||||
Description: super reality animation pal!
|
||||
|
|
|
@ -2,10 +2,12 @@ include(vcpkg_common_functions)
|
|||
set(SRANIPAL_VERSION 1.1.0.1)
|
||||
set(MASTER_COPY_SOURCE_PATH ${CURRENT_BUILDTREES_DIR}/src)
|
||||
|
||||
file(READ "${VCPKG_ROOT_DIR}/_env/EXTERNAL_BUILD_ASSETS.txt" EXTERNAL_BUILD_ASSETS)
|
||||
|
||||
if (WIN32)
|
||||
vcpkg_download_distfile(
|
||||
SRANIPAL_SOURCE_ARCHIVE
|
||||
URLS https://athena-public.s3.amazonaws.com/seth/sranipal-1.1.0.1-windows.zip
|
||||
URLS "${EXTERNAL_BUILD_ASSETS}/seth/sranipal-1.1.0.1-windows.zip"
|
||||
SHA512 b09ce012abe4e3c71e8e69626bdd7823ff6576601a821ab365275f2764406a3e5f7b65fcf2eb1d0962eff31eb5958a148b00901f67c229dc6ace56eb5e6c9e1b
|
||||
FILENAME sranipal-1.1.0.1-windows.zip
|
||||
)
|
||||
|
|
|
@ -57,6 +57,29 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Monitoring",
|
||||
"name": "monitoring",
|
||||
"restart": false,
|
||||
"settings": [
|
||||
{
|
||||
"name": "enable_prometheus_exporter",
|
||||
"label": "Enable Prometheus Exporter",
|
||||
"help": "Enable a Prometheus exporter to make it possible to gather the stats that are available at <a href='/'>Nodes</a> tab with a <a href='https://prometheus.io/'>Prometheus</a> server. This makes it possible to keep track of long-term domain statistics for graphing, troubleshooting, and performance monitoring.",
|
||||
"default": false,
|
||||
"type": "checkbox",
|
||||
"advanced": true
|
||||
},
|
||||
{
|
||||
"name": "prometheus_exporter_port",
|
||||
"label": "Prometheus TCP Port",
|
||||
"help": "This is the port where the Prometheus exporter accepts connections. It listens both on IPv4 and IPv6 and can be accessed remotely, so you should make sure to restrict access with a firewall as needed.",
|
||||
"default": "9703",
|
||||
"type": "int",
|
||||
"advanced": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "Paths",
|
||||
"html_id": "paths",
|
||||
|
|
14
domain-server/resources/prometheus_exporter/index.html
Normal file
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Vircadia Prometheus exporter</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Vircadia Prometheus exporter</h1>
|
||||
|
||||
<p>This is the <a href="https://prometheus.io/">Prometheus</a> exporter, used to export stats about the domain server for graphing and analysis.</p>
|
||||
<p>
|
||||
<a href="/metrics">Metrics</a>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 5.3 KiB After Width: | Height: | Size: 4.2 KiB |
|
@ -52,6 +52,7 @@ var URLs = {
|
|||
// STABLE METAVERSE_URL: https://metaverse.highfidelity.com
|
||||
// STAGING METAVERSE_URL: https://staging.highfidelity.com
|
||||
METAVERSE_URL: 'https://metaverse.highfidelity.com',
|
||||
CDN_URL: 'https://cdn.highfidelity.com',
|
||||
PLACE_URL: 'https://hifi.place',
|
||||
};
|
||||
|
||||
|
|
|
@ -67,16 +67,13 @@ Q_LOGGING_CATEGORY(domain_server_ice, "hifi.domain_server.ice")
|
|||
|
||||
const QString ACCESS_TOKEN_KEY_PATH = "metaverse.access_token";
|
||||
const QString DomainServer::REPLACEMENT_FILE_EXTENSION = ".replace";
|
||||
const int MIN_PORT = 1;
|
||||
const int MAX_PORT = 65535;
|
||||
|
||||
|
||||
int const DomainServer::EXIT_CODE_REBOOT = 234923;
|
||||
|
||||
#if USE_STABLE_GLOBAL_SERVICES
|
||||
const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.com";
|
||||
#else
|
||||
const QString ICE_SERVER_DEFAULT_HOSTNAME = "dev-ice.highfidelity.com";
|
||||
#endif
|
||||
|
||||
QString DomainServer::_iceServerAddr { ICE_SERVER_DEFAULT_HOSTNAME };
|
||||
QString DomainServer::_iceServerAddr { NetworkingConstants::ICE_SERVER_DEFAULT_HOSTNAME };
|
||||
int DomainServer::_iceServerPort { ICE_SERVER_DEFAULT_PORT };
|
||||
bool DomainServer::_overrideDomainID { false };
|
||||
QUuid DomainServer::_overridingDomainID;
|
||||
|
@ -229,7 +226,6 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
this, &DomainServer::updateDownstreamNodes);
|
||||
connect(&_settingsManager, &DomainServerSettingsManager::settingsUpdated,
|
||||
this, &DomainServer::updateUpstreamNodes);
|
||||
|
||||
setupGroupCacheRefresh();
|
||||
|
||||
optionallySetupOAuth();
|
||||
|
@ -330,6 +326,8 @@ DomainServer::DomainServer(int argc, char* argv[]) :
|
|||
_nodePingMonitorTimer = new QTimer{ this };
|
||||
connect(_nodePingMonitorTimer, &QTimer::timeout, this, &DomainServer::nodePingMonitor);
|
||||
_nodePingMonitorTimer->start(NODE_PING_MONITOR_INTERVAL_MSECS);
|
||||
|
||||
initializeExporter();
|
||||
}
|
||||
|
||||
void DomainServer::parseCommandLine(int argc, char* argv[]) {
|
||||
|
@ -424,6 +422,11 @@ DomainServer::~DomainServer() {
|
|||
_contentManager->terminate();
|
||||
}
|
||||
|
||||
if (_httpExporterManager) {
|
||||
_httpExporterManager->close();
|
||||
delete _httpExporterManager;
|
||||
}
|
||||
|
||||
DependencyManager::destroy<AccountManager>();
|
||||
|
||||
// cleanup the AssetClient thread
|
||||
|
@ -1977,7 +1980,6 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
const QString URI_API_BACKUPS_ID = "/api/backups/";
|
||||
const QString URI_API_BACKUPS_DOWNLOAD_ID = "/api/backups/download/";
|
||||
const QString URI_API_BACKUPS_RECOVER = "/api/backups/recover/";
|
||||
|
||||
const QString UUID_REGEX_STRING = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
|
||||
|
||||
QPointer<HTTPConnection> connectionPtr { connection };
|
||||
|
@ -3037,6 +3039,27 @@ void DomainServer::updateUpstreamNodes() {
|
|||
updateReplicationNodes(Upstream);
|
||||
}
|
||||
|
||||
void DomainServer::initializeExporter()
|
||||
{
|
||||
static const QString ENABLE_EXPORTER = "monitoring.enable_prometheus_exporter";
|
||||
static const QString EXPORTER_PORT = "monitoring.prometheus_exporter_port";
|
||||
|
||||
bool isExporterEnabled = _settingsManager.valueOrDefaultValueForKeyPath(ENABLE_EXPORTER).toBool();
|
||||
int exporterPort = _settingsManager.valueOrDefaultValueForKeyPath(EXPORTER_PORT).toInt();
|
||||
|
||||
if (exporterPort < MIN_PORT || exporterPort > MAX_PORT) {
|
||||
qCWarning(domain_server) << "Prometheus exporter port " << exporterPort << " is out of range.";
|
||||
isExporterEnabled = false;
|
||||
}
|
||||
|
||||
qCDebug(domain_server) << "Setting up Prometheus exporter";
|
||||
|
||||
if (isExporterEnabled && !_httpExporterManager) {
|
||||
qCInfo(domain_server) << "Starting Prometheus exporter on port " << exporterPort;
|
||||
_httpExporterManager = new HTTPManager(QHostAddress::Any, (quint16)exporterPort, QString("%1/resources/prometheus_exporter/").arg(QCoreApplication::applicationDirPath()), &_exporter);
|
||||
}
|
||||
}
|
||||
|
||||
void DomainServer::updateReplicatedNodes() {
|
||||
// Make sure we have downstream nodes in our list
|
||||
static const QString REPLICATED_USERS_KEY = "users";
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "DomainContentBackupManager.h"
|
||||
|
||||
#include "PendingAssignedNodeData.h"
|
||||
#include "DomainServerExporter.h"
|
||||
|
||||
#include <QLoggingCategory>
|
||||
|
||||
|
@ -115,7 +116,7 @@ private slots:
|
|||
void sendHeartbeatToIceServer();
|
||||
void nodePingMonitor();
|
||||
|
||||
void handleConnectedNode(SharedNodePointer newNode, quint64 requestReceiveTime);
|
||||
void handleConnectedNode(SharedNodePointer newNode, quint64 requestReceiveTime);
|
||||
void handleTempDomainSuccess(QNetworkReply* requestReply);
|
||||
void handleTempDomainError(QNetworkReply* requestReply);
|
||||
|
||||
|
@ -138,6 +139,7 @@ private slots:
|
|||
void updateReplicatedNodes();
|
||||
void updateDownstreamNodes();
|
||||
void updateUpstreamNodes();
|
||||
void initializeExporter();
|
||||
|
||||
void tokenGrantFinished();
|
||||
void profileRequestFinished();
|
||||
|
@ -234,8 +236,10 @@ private:
|
|||
std::vector<QString> _replicatedUsernames;
|
||||
|
||||
DomainGatekeeper _gatekeeper;
|
||||
DomainServerExporter _exporter;
|
||||
|
||||
HTTPManager _httpManager;
|
||||
HTTPManager* _httpExporterManager { nullptr };
|
||||
std::unique_ptr<HTTPSManager> _httpsManager;
|
||||
|
||||
QHash<QUuid, SharedAssignmentPointer> _allAssignments;
|
||||
|
|
471
domain-server/src/DomainServerExporter.cpp
Normal file
|
@ -0,0 +1,471 @@
|
|||
//
|
||||
// DomainServerExporter.cpp
|
||||
// domain-server/src
|
||||
//
|
||||
// Created by Dale Glass on 3 Apr 2020.
|
||||
// Copyright 2020 Dale Glass
|
||||
//
|
||||
// Prometheus exporter
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
// TODO:
|
||||
//
|
||||
// Look into the data provided by OctreeServer::handleHTTPRequest in assignment-client/src/octree/OctreeServer.cpp
|
||||
// Turns out the octree server (entity server) can optionally deliver additional statistics via another HTTP server
|
||||
// that is disabled by default. This functionality can be enabled by setting statusPort to a port number.
|
||||
//
|
||||
// Look into what appears in Audio Mixer -> z_listeners -> jitter -> injectors, so far it's been an empty list.
|
||||
|
||||
#include <QLoggingCategory>
|
||||
#include <QUrl>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonDocument>
|
||||
#include <QRegularExpression>
|
||||
#include <QSet>
|
||||
|
||||
#include "DomainServerExporter.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "LimitedNodeList.h"
|
||||
#include "HTTPConnection.h"
|
||||
#include "DomainServerNodeData.h"
|
||||
|
||||
Q_LOGGING_CATEGORY(domain_server_exporter, "hifi.domain_server.prometheus_exporter")
|
||||
|
||||
static const QMap<QString, DomainServerExporter::MetricType> TYPE_MAP {
|
||||
{ "asset_server_assignment_stats_num_queued_check_ins" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_connection_stats_cw_p" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_connection_stats_down_mb_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_connection_stats_est_max_p_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_connection_stats_last_heard_ago_msecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_connection_stats_last_heard_time_msecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_connection_stats_period_us" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_connection_stats_rtt_ms" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_connection_stats_up_mb_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_downstream_stats_duplicates" , DomainServerExporter::MetricType::Counter },
|
||||
{ "asset_server_downstream_stats_recvd_p_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_downstream_stats_recvd_packets" , DomainServerExporter::MetricType::Counter },
|
||||
{ "asset_server_downstream_stats_sent_ack" , DomainServerExporter::MetricType::Counter },
|
||||
{ "asset_server_io_stats_inbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_io_stats_inbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_io_stats_outbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_io_stats_outbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_upstream_stats_procd_ack" , DomainServerExporter::MetricType::Counter },
|
||||
{ "asset_server_upstream_stats_recvd_ack" , DomainServerExporter::MetricType::Counter },
|
||||
{ "asset_server_upstream_stats_retransmitted" , DomainServerExporter::MetricType::Counter },
|
||||
{ "asset_server_upstream_stats_sent_p_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "asset_server_upstream_stats_sent_packets" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_assignment_stats_num_queued_check_ins" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_listeners_per_frame" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_listeners_silent_per_frame" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_streams_per_frame" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_check_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_check_time_trailing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_events" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_events_trailing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_frame" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_frame_trailing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_mix" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_mix_trailing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_packets" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_packets_trailing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_sleep" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_sleep_trailing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_tic" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_avg_timing_stats_us_per_tic_trailing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_io_stats_inbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_io_stats_inbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_io_stats_outbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_io_stats_outbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_available" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_available_avg_10s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_avg_gap_30s_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_avg_gap_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_desired" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_lost_percent" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_lost_percent_30s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_max_gap_30s_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_max_gap_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_min_gap_30s_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_min_gap_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_downstream_not_mixed" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_downstream_overflows" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_downstream_starves" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_downstream_unplayed" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_injectors" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_upstream_available" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_available_avg_10s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_avg_gap_30s_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_avg_gap_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_desired_calc" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_lost_percent" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_lost_percent_30s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_max_gap_30s_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_max_gap_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_mic_desired" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_min_gap_30s_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_min_gap_usecs" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_listeners_jitter_upstream_not_mixed" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_upstream_overflows" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_upstream_silents_dropped" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_upstream_starves" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_jitter_upstream_unplayed" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_listeners_outbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_mix_stats_active_streams" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_mix_stats_active_to_inactive" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_active_to_skippped" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_avg_mixes_per_block" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_mix_stats_hrtf_renders" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_hrtf_resets" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_hrtf_updates" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_inactive_streams" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_mix_stats_inactive_to_active" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_inactive_to_skippped" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_percent_hrtf_mixes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_mix_stats_percent_manual_echo_mixes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_mix_stats_percent_manual_stereo_mixes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_mix_stats_skipped_streams" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_skippped_to_active" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_skippped_to_inactive" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_mix_stats_total_mixes" , DomainServerExporter::MetricType::Counter },
|
||||
{ "audio_mixer_silent_packets_per_frame" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_threads" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_throttling_ratio" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_trailing_mix_ratio" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "audio_mixer_use_dynamic_jitter_buffers" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_assignment_stats_num_queued_check_ins" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_av_data_receive_rate" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_avg_other_av_skips_per_second" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_avg_other_av_starves_per_second" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_delta_full_vs_avatar_data_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_inbound_av_data_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_inbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_num_avs_sent_last_frame" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_outbound_av_data_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_outbound_av_traits_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_outbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_recent_other_av_in_view" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_recent_other_av_out_of_view" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_avatars_total_num_out_of_order_sends" , DomainServerExporter::MetricType::Counter },
|
||||
{ "avatar_mixer_average_listeners_last_second" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_broadcast_loop_rate" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_io_stats_inbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_io_stats_inbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_io_stats_outbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_io_stats_outbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_parallel_tasks_broadcast_avatar_data_functor" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_parallel_tasks_broadcast_avatar_data_innner" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_parallel_tasks_broadcast_avatar_data_lock_wait" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_parallel_tasks_broadcast_avatar_data_node_transform" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_parallel_tasks_broadcast_avatar_data_total" , DomainServerExporter::MetricType::Counter },
|
||||
{ "avatar_mixer_parallel_tasks_display_name_management_total" , DomainServerExporter::MetricType::Counter },
|
||||
{ "avatar_mixer_parallel_tasks_process_queued_avatar_data_packets_lock_wait" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_parallel_tasks_process_queued_avatar_data_packets_total" , DomainServerExporter::MetricType::Counter },
|
||||
{ "avatar_mixer_single_core_tasks_incoming_packets_handle_avatar_identity_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_single_core_tasks_incoming_packets_handle_avatar_query_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_single_core_tasks_incoming_packets_handle_kill_avatar_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_single_core_tasks_incoming_packets_handle_node_ignore_request_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_single_core_tasks_incoming_packets_handle_radius_ignore_request_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_single_core_tasks_incoming_packets_handle_requests_domain_list_data_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_single_core_tasks_process_events" , DomainServerExporter::MetricType::Counter },
|
||||
{ "avatar_mixer_single_core_tasks_queue_incoming_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_single_core_tasks_send_stats" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_received_1_nodes_processed" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_1_nodes_broadcasted_to" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_2_average_others_included" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_3_average_over_budget_avatars" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_4_average_data_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_5_average_traits_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_6_average_identity_bytes" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_sent_7_average_hero_avatars" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_1_process_incoming_packets" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_2_ignore_calculation" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_3_to_byte_array" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_4_avatar_data_packing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_5_packet_sending" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_slaves_aggregate_per_frame_timing_6_job_elapsed_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_threads" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_throttling_ratio" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "avatar_mixer_trailing_mix_ratio" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_assignment_stats_num_queued_check_ins" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_io_stats_inbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_io_stats_inbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_io_stats_outbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_io_stats_outbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_nodes_inbound_kbit_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_nodes_outbound_kbit_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_nodes_reliable_packet_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_nodes_unreliable_packet_s" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_octree_stats_element_count" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_octree_stats_internal_element_count" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_octree_stats_leaf_element_count" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_script_server_script_engine_stats_number_running_scripts" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_assignment_stats_num_queued_check_ins" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_inbound_data_packet_queue" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_inbound_data_total_elements" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_inbound_data_total_packets" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_inbound_timing_avg_lock_wait_time_per_element" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_inbound_timing_avg_lock_wait_time_per_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_inbound_timing_avg_process_time_per_element" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_inbound_timing_avg_process_time_per_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_inbound_timing_avg_transit_time_per_packet" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_misc_clients" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_misc_persist_file_load_time_seconds" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_misc_threads_handle_pacekt_send" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_misc_threads_packet_distributor" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_misc_threads_processing" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_misc_threads_write_datagram" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_misc_uptime_seconds" , DomainServerExporter::MetricType::Counter },
|
||||
{ "entity_server_entity_server_octree_element_count" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_octree_internal_element_count" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_octree_leaf_element_count" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_outbound_data_total_bytes" , DomainServerExporter::MetricType::Counter },
|
||||
{ "entity_server_entity_server_outbound_data_total_bytes_bit_masks" , DomainServerExporter::MetricType::Counter },
|
||||
{ "entity_server_entity_server_outbound_data_total_bytes_octal_codes" , DomainServerExporter::MetricType::Counter },
|
||||
{ "entity_server_entity_server_outbound_data_total_bytes_wasted" , DomainServerExporter::MetricType::Counter },
|
||||
{ "entity_server_entity_server_outbound_data_total_packets" , DomainServerExporter::MetricType::Counter },
|
||||
{ "entity_server_entity_server_outbound_timing_avg_compress_and_write_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_outbound_timing_avg_encode_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_outbound_timing_avg_inside_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_outbound_timing_avg_loop_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_outbound_timing_avg_send_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_outbound_timing_avg_tree_traverse_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_entity_server_outbound_timing_node_wait_time" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_io_stats_inbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_io_stats_inbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_io_stats_outbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "entity_server_io_stats_outbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "messages_mixer_assignment_stats_num_queued_check_ins" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "messages_mixer_io_stats_inbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "messages_mixer_io_stats_inbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "messages_mixer_io_stats_outbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "messages_mixer_io_stats_outbound_pps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "messages_mixer_messages_inbound_kbps" , DomainServerExporter::MetricType::Gauge },
|
||||
{ "messages_mixer_messages_outbound_kbps" , DomainServerExporter::MetricType::Gauge }
|
||||
};
|
||||
|
||||
|
||||
// Things we're not going to convert for various reasons, such as containing text,
|
||||
// or having a value followed by an unit ("5.2 seconds").
|
||||
//
|
||||
// Things like text like usernames have no place in the Prometheus model, so they can be skipped.
|
||||
//
|
||||
// For numeric values with an unit, instead of trying to parse it, the stats will just need to
|
||||
// have a second copy of the metric added, with the value expressed as a number, with the original
|
||||
// being blacklisted here.
|
||||
|
||||
static const QSet<QString> BLACKLIST = {
|
||||
"asset_server_connection_stats_last_heard", // Timestamp as a string
|
||||
"asset_server_username", // Username
|
||||
"audio_mixer_listeners_jitter_downstream_avg_gap", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_downstream_avg_gap_30s", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_downstream_max_gap", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_downstream_max_gap_30s", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_downstream_min_gap", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_downstream_min_gap_30s", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_injectors", // Array, empty. TODO: check if this ever contains anything.
|
||||
"audio_mixer_listeners_jitter_upstream", // Only exists in the absence of a connection
|
||||
"audio_mixer_listeners_jitter_upstream_avg_gap", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_upstream_avg_gap_30s", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_upstream_max_gap", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_upstream_max_gap_30s", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_upstream_min_gap", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_jitter_upstream_min_gap_30s", // Number as string with unit name, alternative added
|
||||
"audio_mixer_listeners_username", // Username
|
||||
"avatar_mixer_avatars_display_name", // Username
|
||||
"avatar_mixer_avatars_username", // Username
|
||||
"entity_script_server_nodes_node_type", // Username
|
||||
"entity_script_server_nodes_username", // Username
|
||||
"entity_server_entity_server_misc_configuration", // Text
|
||||
"entity_server_entity_server_misc_detailed_stats_url", // URL
|
||||
"entity_server_entity_server_misc_persist_file_load_time", // Number as string with unit name, alternative added
|
||||
"entity_server_entity_server_misc_uptime", // Number as string with unit name, alternative added
|
||||
"messages_mixer_messages_username" // Username
|
||||
};
|
||||
|
||||
DomainServerExporter::DomainServerExporter() {
|
||||
}
|
||||
|
||||
bool DomainServerExporter::handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler) {
|
||||
const QString URI_METRICS = "/metrics";
|
||||
const QString EXPORTER_MIME_TYPE = "text/plain";
|
||||
|
||||
qCDebug(domain_server_exporter) << "Request on URL " << url;
|
||||
|
||||
if (url.path() == URI_METRICS) {
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
QString output = "";
|
||||
QTextStream outStream(&output);
|
||||
|
||||
nodeList->eachNode([this, &outStream](const SharedNodePointer& node) { generateMetricsForNode(outStream, node); });
|
||||
|
||||
connection->respond(HTTPConnection::StatusCode200, output.toUtf8(), qPrintable(EXPORTER_MIME_TYPE));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QString DomainServerExporter::escapeName(const QString& name) {
|
||||
QRegularExpression invalidCharacters("[^A-Za-z0-9_]");
|
||||
|
||||
QString result = name;
|
||||
|
||||
// If a key is named something like: "6. threads", turn it into just "threads"
|
||||
result.replace(QRegularExpression("^\\d+\\. "), "");
|
||||
result.replace(QRegularExpression("^\\d+_"), "");
|
||||
|
||||
// If a key is named something like "z_listeners", turn it into just "listeners"
|
||||
result.replace(QRegularExpression("^z_"), "");
|
||||
|
||||
// If a key is named something like "lost%", change it to "lost_percent_".
|
||||
// redundant underscores will be removed below.
|
||||
result.replace(QRegularExpression("%"), "_percent_");
|
||||
|
||||
// change mixedCaseNames to mixed_case_names
|
||||
result.replace(QRegularExpression("([a-z])([A-Z])"), "\\1_\\2");
|
||||
|
||||
// Replace all invalid characters with a _
|
||||
result.replace(invalidCharacters, "_");
|
||||
|
||||
// Remove any "_" characters at the beginning or end
|
||||
result.replace(QRegularExpression("^_+"), "");
|
||||
result.replace(QRegularExpression("_+$"), "");
|
||||
|
||||
// Replace any duplicated _ characters with a single one
|
||||
result.replace(QRegularExpression("_+"), "_");
|
||||
|
||||
result = result.toLower();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void DomainServerExporter::generateMetricsForNode(QTextStream& stream, const SharedNodePointer& node) {
|
||||
QJsonObject statsObject = static_cast<DomainServerNodeData*>(node->getLinkedData())->getStatsJSONObject();
|
||||
QString nodeType = NodeType::getNodeTypeName(static_cast<NodeType_t>(node->getType()));
|
||||
|
||||
stream << "\n\n\n";
|
||||
stream << "###############################################################\n";
|
||||
stream << "# " << nodeType << "\n";
|
||||
stream << "###############################################################\n";
|
||||
|
||||
generateMetricsFromJson(stream, nodeType, escapeName(nodeType), QHash<QString, QString>(), statsObject);
|
||||
}
|
||||
|
||||
void DomainServerExporter::generateMetricsFromJson(QTextStream& stream,
|
||||
QString originalPath,
|
||||
QString path,
|
||||
QHash<QString, QString> labels,
|
||||
const QJsonObject& root) {
|
||||
for (auto iter = root.constBegin(); iter != root.constEnd(); ++iter) {
|
||||
auto escapedKey = escapeName(iter.key());
|
||||
auto metricValue = iter.value();
|
||||
auto metricName = path + "_" + escapedKey;
|
||||
auto origMetricName = originalPath + " -> " + iter.key();
|
||||
|
||||
if (metricValue.isObject()) {
|
||||
QUuid possible_uuid = QUuid::fromString(iter.key());
|
||||
|
||||
if (possible_uuid.isNull()) {
|
||||
generateMetricsFromJson(stream, originalPath + " -> " + iter.key(), path + "_" + escapedKey, labels,
|
||||
iter.value().toObject());
|
||||
} else {
|
||||
labels.insert("uuid", possible_uuid.toString(QUuid::WithoutBraces));
|
||||
generateMetricsFromJson(stream, originalPath, path, labels, iter.value().toObject());
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (BLACKLIST.contains(metricName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool conversionOk = false;
|
||||
double converted = 0;
|
||||
|
||||
if (metricValue.isString()) {
|
||||
// Prometheus only deals with numeric values. See if this string contains a valid one
|
||||
|
||||
QString tmp = metricValue.toString();
|
||||
converted = tmp.toDouble(&conversionOk);
|
||||
|
||||
if (!conversionOk) {
|
||||
qCWarning(domain_server_exporter) << "Failed to convert value of " << origMetricName << " (" << metricName
|
||||
<< ") to double: " << tmp << "'";
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
stream << QString("\n# HELP %1 %2 -> %3\n").arg(metricName).arg(originalPath).arg(iter.key());
|
||||
|
||||
if (TYPE_MAP.contains(metricName)) {
|
||||
stream << "# TYPE " << metricName << " ";
|
||||
switch (TYPE_MAP[metricName]) {
|
||||
case DomainServerExporter::MetricType::Untyped:
|
||||
stream << "untyped";
|
||||
break;
|
||||
case DomainServerExporter::MetricType::Counter:
|
||||
stream << "counter";
|
||||
break;
|
||||
case DomainServerExporter::MetricType::Gauge:
|
||||
stream << "gauge";
|
||||
break;
|
||||
case DomainServerExporter::MetricType::Histogram:
|
||||
stream << "histogram";
|
||||
break;
|
||||
case DomainServerExporter::MetricType::Summary:
|
||||
stream << "summary";
|
||||
break;
|
||||
}
|
||||
stream << "\n";
|
||||
} else {
|
||||
qCWarning(domain_server_exporter)
|
||||
<< "Type for metric " << origMetricName << " (" << metricName << ") not known.";
|
||||
}
|
||||
|
||||
stream << path << "_" << escapedKey;
|
||||
if (!labels.isEmpty()) {
|
||||
stream << "{";
|
||||
|
||||
bool isFirst = true;
|
||||
QHashIterator<QString, QString> iter(labels);
|
||||
|
||||
while (iter.hasNext()) {
|
||||
iter.next();
|
||||
|
||||
if (!isFirst) {
|
||||
stream << ",";
|
||||
}
|
||||
|
||||
QString escapedValue = iter.value();
|
||||
escapedValue.replace("\\", "\\\\");
|
||||
escapedValue.replace("\"", "\\\"");
|
||||
escapedValue.replace("\n", "\\\n");
|
||||
|
||||
stream << iter.key() << "=\"" << escapedValue << "\"";
|
||||
|
||||
isFirst = false;
|
||||
}
|
||||
stream << "}";
|
||||
}
|
||||
|
||||
stream << " ";
|
||||
|
||||
if (metricValue.isBool()) {
|
||||
stream << (iter.value().toBool() ? "1" : "0");
|
||||
} else if (metricValue.isDouble()) {
|
||||
stream << metricValue.toDouble();
|
||||
} else if (metricValue.isString()) {
|
||||
// Converted above
|
||||
stream << converted;
|
||||
} else {
|
||||
qCWarning(domain_server_exporter)
|
||||
<< "Can't convert metric " << origMetricName << "(" << metricName << ") with value " << metricValue;
|
||||
}
|
||||
|
||||
stream << "\n";
|
||||
}
|
||||
}
|
55
domain-server/src/DomainServerExporter.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// DomainServerExporter.h
|
||||
// domain-server/src
|
||||
//
|
||||
// Created by Dale Glass on 3 Apr 2020.
|
||||
// Copyright 2020 Dale Glass
|
||||
//
|
||||
// Prometheus exporter
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef DOMAINSERVEREXPORTER_H
|
||||
#define DOMAINSERVEREXPORTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include "HTTPManager.h"
|
||||
#include "Node.h"
|
||||
#include <QTextStream>
|
||||
#include <QJsonObject>
|
||||
#include <QRegularExpression>
|
||||
#include <QHash>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Prometheus exporter for domain stats
|
||||
*
|
||||
* This class exportors the statistics that can be seen on the domain's page in
|
||||
* a format that can be parsed by Prometheus. This is useful for troubleshooting,
|
||||
* monitoring performance, and making pretty graphs.
|
||||
*/
|
||||
class DomainServerExporter : public HTTPRequestHandler
|
||||
{
|
||||
public:
|
||||
typedef enum {
|
||||
Untyped, /* Works the same as Gauge, with the difference of signalling that the actual type is unknown */
|
||||
Counter, /* Value only goes up. Eg, number of packets received */
|
||||
Gauge, /* Current numerical value that can go up or down. Current temperature, memory usage, etc */
|
||||
Histogram, /* Samples sorted in buckets gathered over time */
|
||||
Summary
|
||||
} MetricType;
|
||||
|
||||
DomainServerExporter();
|
||||
~DomainServerExporter() = default;
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
|
||||
private:
|
||||
QString escapeName(const QString &name);
|
||||
void generateMetricsForNode(QTextStream& stream, const SharedNodePointer& node);
|
||||
void generateMetricsFromJson(QTextStream& stream, QString originalPath, QString path, QHash<QString, QString> labels, const QJsonObject& obj);
|
||||
};
|
||||
|
||||
#endif // DOMAINSERVEREXPORTER_H
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 4 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 6.8 KiB |
|
@ -1,123 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 150 150"
|
||||
enable-background="new 0 0 512 512"
|
||||
xml:space="preserve"
|
||||
id="svg2"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="hifi-logo-blackish.svg"
|
||||
width="150"
|
||||
height="150"><metadata
|
||||
id="metadata57"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs55" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1835"
|
||||
inkscape:window-height="1057"
|
||||
id="namedview53"
|
||||
showgrid="false"
|
||||
inkscape:zoom="2.6074563"
|
||||
inkscape:cx="256"
|
||||
inkscape:cy="67.100056"
|
||||
inkscape:window-x="77"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" /><g
|
||||
id="Layer_1"
|
||||
transform="translate(-30.500027,-42.2)"><g
|
||||
id="g5"><g
|
||||
id="g7"><path
|
||||
d="M 155.3,67.4 C 141.9,54.3 124.5,47 105.8,47 86.8,47 69.4,54.3 56,67.4 42.9,80.8 35.5,98.2 35.5,117.2 c 0,18.7 7.3,36.4 20.5,49.5 13.2,13.1 30.8,20.5 49.5,20.5 18.7,0 36.4,-7.3 49.5,-20.5 13.1,-13.1 20.5,-30.8 20.5,-49.5 0.3,-18.9 -7,-36.4 -20.2,-49.8 z m -5,94.3 c -11.9,11.9 -27.8,18.4 -44.7,18.4 C 88.7,180.1 73,173.5 60.9,161.7 49,149.8 42.5,133.9 42.5,117 c 0,-16.9 6.6,-32.6 18.4,-44.7 11.9,-11.9 27.8,-18.4 44.7,-18.4 16.9,0 32.6,6.6 44.7,18.4 11.9,11.9 18.4,27.8 18.4,44.7 0,16.9 -6.6,32.8 -18.4,44.7 z"
|
||||
id="path9"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /><g
|
||||
id="g11"><path
|
||||
d="m 86.8,142 c -1.5,0 -3,-1.3 -3,-3 l 0,-54.1 c 0,-1.5 1.3,-3 3,-3 1.5,0 3,1.3 3,3 l 0,54.3 c 0.1,1.5 -1.2,2.8 -3,2.8 z"
|
||||
id="path13"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /><path
|
||||
d="m 90.4,83.4 c -2,2 -5.1,2 -6.8,0 -2,-2 -2,-5.1 0,-6.8 2,-2 5.1,-2 6.8,0 2,2 2,5 0,6.8"
|
||||
id="path15"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /><g
|
||||
id="g17"><path
|
||||
d="m 86.8,87.9 c -2,0 -4,-0.8 -5.6,-2.3 -3,-3 -3,-8.1 0,-11.1 1.5,-1.5 3.5,-2.3 5.6,-2.3 2.1,0 4,0.8 5.6,2.3 1.5,1.5 2.3,3.5 2.3,5.6 0,2.1 -0.8,4 -2.3,5.6 -1.5,1.2 -3.3,2.2 -5.6,2.2 z m 0,-9.8 c -0.5,0 -1,0.3 -1.5,0.5 -0.8,0.8 -0.8,2 0,2.8 0.8,0.8 2,0.8 2.8,0 0.3,-0.3 0.5,-0.8 0.5,-1.5 0,-0.5 -0.3,-1 -0.5,-1.5 -0.2,-0.1 -0.7,-0.3 -1.3,-0.3 z"
|
||||
id="path19"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /></g><path
|
||||
d="m 83.6,140.5 c 2,-2 5.1,-2 6.8,0 2,2 2,5.1 0,6.8 -2,2 -5.1,2 -6.8,0 -2.1,-1.8 -2.1,-4.8 0,-6.8"
|
||||
id="path21"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /><g
|
||||
id="g23"><path
|
||||
d="m 86.8,151.8 c -2,0 -4,-0.8 -5.6,-2.3 C 79.6,148 79,146 79,144 c 0,-2 0.8,-4 2.3,-5.6 1.5,-1.6 3.5,-2.3 5.6,-2.3 2.1,0 4,0.8 5.6,2.3 1.6,1.5 2.3,3.5 2.3,5.6 0,2.1 -0.8,4 -2.3,5.6 -1.6,1.5 -3.4,2.2 -5.7,2.2 z m 0,-9.8 c -0.5,0 -1,0.3 -1.5,0.5 -0.3,0.3 -0.5,0.8 -0.5,1.5 0,0.5 0.3,1 0.5,1.5 0.8,0.8 2,0.8 2.8,0 0.3,-0.3 0.5,-0.8 0.5,-1.5 0,-0.5 -0.3,-1 -0.5,-1.5 -0.2,-0.3 -0.7,-0.5 -1.3,-0.5 z"
|
||||
id="path25"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /></g><g
|
||||
id="g27"><path
|
||||
d="m 124.5,152.3 c -1.5,0 -3,-1.3 -3,-3 l 0,-54.3 c 0,-1.5 1.3,-3 3,-3 1.5,0 3,1.3 3,3 l 0,54.3 c 0,1.8 -1.5,3 -3,3 z"
|
||||
id="path29"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /></g><path
|
||||
d="m 128,93.7 c -2,2 -5.1,2 -6.8,0 -2,-2 -2,-5.1 0,-6.8 2,-2 5.1,-2 6.8,0 1.8,1.8 1.8,4.8 0,6.8"
|
||||
id="path31"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /><g
|
||||
id="g33"><path
|
||||
d="m 124.5,98 c -2,0 -4,-0.8 -5.6,-2.3 -3,-3 -3,-8.1 0,-11.1 1.5,-1.5 3.5,-2.3 5.6,-2.3 2,0 4,0.8 5.6,2.3 1.5,1.5 2.3,3.5 2.3,5.6 0,2 -0.8,4 -2.3,5.6 -1.6,1.5 -3.6,2.2 -5.6,2.2 z m 0,-9.8 c -0.5,0 -1,0.3 -1.5,0.5 -0.8,0.8 -0.8,2 0,2.8 0.8,0.8 2,0.8 2.8,0 0.3,-0.3 0.5,-0.8 0.5,-1.5 0,-0.5 -0.3,-1 -0.5,-1.5 -0.3,-0.1 -0.8,-0.3 -1.3,-0.3 z"
|
||||
id="path35"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /></g><g
|
||||
id="g37"><path
|
||||
d="m 124.5,162.2 c -2,0 -4,-0.8 -5.6,-2.3 -3,-3 -3,-8.1 0,-11.1 1.5,-1.5 3.5,-2.3 5.6,-2.3 2,0 4,0.8 5.6,2.3 1.5,1.5 2.3,3.5 2.3,5.6 0,2.1 -0.8,4 -2.3,5.6 -1.6,1.2 -3.6,2.2 -5.6,2.2 z m 0,-9.9 c -0.5,0 -1,0.3 -1.5,0.5 -0.8,0.8 -0.8,2 0,2.8 0.8,0.8 2,0.8 2.8,0 0.3,-0.3 0.5,-0.8 0.5,-1.5 0,-0.7 -0.3,-1 -0.5,-1.5 -0.3,0 -0.8,-0.3 -1.3,-0.3 z"
|
||||
id="path39"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /></g><path
|
||||
d="m 121,150.8 c 2,-2 5.1,-2 6.8,0 2,2 2,5.1 0,6.8 -2,2 -5.1,2 -6.8,0 -1.8,-1.7 -1.8,-5 0,-6.8"
|
||||
id="path41"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#333333" /><g
|
||||
id="g43"><rect
|
||||
x="85.099998"
|
||||
y="113.2"
|
||||
transform="matrix(-0.9064,-0.4224,0.4224,-0.9064,152.6722,266.0858)"
|
||||
width="41.400002"
|
||||
height="5.8000002"
|
||||
id="rect45"
|
||||
style="fill:#333333" /></g></g></g></g></g><g
|
||||
id="Layer_2_copy"
|
||||
display="none"
|
||||
style="display:none"
|
||||
transform="translate(0,-362)"><path
|
||||
display="inline"
|
||||
d="m 500,511.5 -488,0 c -6.6,0 -12,-5.4 -12,-12 l 0,-168 c 0,-6.6 5.4,-12 12,-12 l 488,0 c 6.6,0 12,5.4 12,12 l 0,168 c 0,6.6 -5.4,12 -12,12 z"
|
||||
id="path48"
|
||||
inkscape:connector-curvature="0"
|
||||
style="display:inline;fill:#ffffff" /><g
|
||||
id="Layer_2"
|
||||
display="inline"
|
||||
style="display:inline"><path
|
||||
d="M 500,384 12,384 C 5.4,384 0,378.6 0,372 L 0,12 C 0,5.4 5.4,0 12,0 l 488,0 c 6.6,0 12,5.4 12,12 l 0,360 c 0,6.6 -5.4,12 -12,12 z"
|
||||
id="path51"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#368db0" /></g></g></svg>
|
Before Width: | Height: | Size: 6.7 KiB |
|
@ -1,58 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 55.5 55.5" enable-background="new 0 0 55.5 55.5" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#0E7077" d="M47.4,8.1C42.1,2.9,35.2,0,27.8,0C20.3,0,13.4,2.9,8.1,8.1C2.9,13.4,0,20.3,0,27.8
|
||||
c0,7.4,2.9,14.4,8.1,19.6c5.2,5.2,12.2,8.1,19.6,8.1c7.4,0,14.4-2.9,19.6-8.1c5.2-5.2,8.1-12.2,8.1-19.6
|
||||
C55.5,20.3,52.6,13.4,47.4,8.1z M45.4,45.4c-4.7,4.7-11,7.3-17.7,7.3c-6.7,0-12.9-2.6-17.7-7.3c-4.7-4.7-7.3-11-7.3-17.7
|
||||
c0-6.7,2.6-12.9,7.3-17.7c4.7-4.7,11-7.3,17.7-7.3c6.7,0,12.9,2.6,17.7,7.3c4.7,4.7,7.3,11,7.3,17.7
|
||||
C52.7,34.4,50.1,40.7,45.4,45.4z"/>
|
||||
<g>
|
||||
<path fill="#0E7077" d="M20.3,37.6c-0.6,0-1.2-0.5-1.2-1.2V15c0-0.6,0.5-1.2,1.2-1.2c0.6,0,1.2,0.5,1.2,1.2v21.5
|
||||
C21.5,37.1,21,37.6,20.3,37.6z"/>
|
||||
<path fill="#0E7077" d="M21.7,14.4c-0.8,0.8-2,0.8-2.7,0c-0.8-0.8-0.8-2,0-2.7c0.8-0.8,2-0.8,2.7,0
|
||||
C22.5,12.5,22.5,13.7,21.7,14.4"/>
|
||||
<g>
|
||||
<path fill="#0E7077" d="M20.3,16.2c-0.8,0-1.6-0.3-2.2-0.9c-1.2-1.2-1.2-3.2,0-4.4c0.6-0.6,1.4-0.9,2.2-0.9
|
||||
c0.8,0,1.6,0.3,2.2,0.9c0.6,0.6,0.9,1.4,0.9,2.2c0,0.8-0.3,1.6-0.9,2.2C21.9,15.8,21.2,16.2,20.3,16.2z M20.3,12.3
|
||||
c-0.2,0-0.4,0.1-0.6,0.2c-0.3,0.3-0.3,0.8,0,1.1c0.3,0.3,0.8,0.3,1.1,0c0.1-0.1,0.2-0.3,0.2-0.6c0-0.2-0.1-0.4-0.2-0.6
|
||||
C20.7,12.4,20.5,12.3,20.3,12.3z"/>
|
||||
</g>
|
||||
<path fill="#0E7077" d="M19,37c0.8-0.8,2-0.8,2.7,0c0.8,0.8,0.8,2,0,2.7c-0.8,0.8-2,0.8-2.7,0C18.2,39,18.2,37.8,19,37"/>
|
||||
<g>
|
||||
<path fill="#0E7077" d="M20.3,41.5c-0.8,0-1.6-0.3-2.2-0.9c-0.6-0.6-0.9-1.4-0.9-2.2c0-0.8,0.3-1.6,0.9-2.2
|
||||
c0.6-0.6,1.4-0.9,2.2-0.9c0.8,0,1.6,0.3,2.2,0.9c0.6,0.6,0.9,1.4,0.9,2.2c0,0.8-0.3,1.6-0.9,2.2C21.9,41.2,21.2,41.5,20.3,41.5z
|
||||
M20.3,37.6c-0.2,0-0.4,0.1-0.6,0.2c-0.1,0.1-0.2,0.3-0.2,0.6c0,0.2,0.1,0.4,0.2,0.6c0.3,0.3,0.8,0.3,1.1,0
|
||||
c0.1-0.1,0.2-0.3,0.2-0.6c0-0.2-0.1-0.4-0.2-0.6C20.7,37.7,20.5,37.6,20.3,37.6z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#0E7077" d="M35.2,41.7c-0.6,0-1.2-0.5-1.2-1.2V19c0-0.6,0.5-1.2,1.2-1.2c0.6,0,1.2,0.5,1.2,1.2v21.5
|
||||
C36.4,41.2,35.8,41.7,35.2,41.7z"/>
|
||||
</g>
|
||||
<path fill="#0E7077" d="M36.6,18.5c-0.8,0.8-2,0.8-2.7,0c-0.8-0.8-0.8-2,0-2.7c0.8-0.8,2-0.8,2.7,0
|
||||
C37.3,16.5,37.3,17.7,36.6,18.5"/>
|
||||
<g>
|
||||
<path fill="#0E7077" d="M35.2,20.2c-0.8,0-1.6-0.3-2.2-0.9c-1.2-1.2-1.2-3.2,0-4.4c0.6-0.6,1.4-0.9,2.2-0.9
|
||||
c0.8,0,1.6,0.3,2.2,0.9c0.6,0.6,0.9,1.4,0.9,2.2c0,0.8-0.3,1.6-0.9,2.2C36.8,19.9,36,20.2,35.2,20.2z M35.2,16.3
|
||||
c-0.2,0-0.4,0.1-0.6,0.2c-0.3,0.3-0.3,0.8,0,1.1c0.3,0.3,0.8,0.3,1.1,0c0.1-0.1,0.2-0.3,0.2-0.6c0-0.2-0.1-0.4-0.2-0.6
|
||||
C35.6,16.4,35.4,16.3,35.2,16.3z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path fill="#0E7077" d="M35.2,45.6c-0.8,0-1.6-0.3-2.2-0.9c-1.2-1.2-1.2-3.2,0-4.4c0.6-0.6,1.4-0.9,2.2-0.9
|
||||
c0.8,0,1.6,0.3,2.2,0.9c0.6,0.6,0.9,1.4,0.9,2.2c0,0.8-0.3,1.6-0.9,2.2C36.8,45.2,36,45.6,35.2,45.6z M35.2,41.7
|
||||
c-0.2,0-0.4,0.1-0.6,0.2c-0.3,0.3-0.3,0.8,0,1.1c0.3,0.3,0.8,0.3,1.1,0c0.1-0.1,0.2-0.3,0.2-0.6s-0.1-0.4-0.2-0.6
|
||||
C35.6,41.8,35.4,41.7,35.2,41.7z"/>
|
||||
</g>
|
||||
<path fill="#0E7077" d="M33.8,41.1c0.8-0.8,2-0.8,2.7,0c0.8,0.8,0.8,2,0,2.7c-0.8,0.8-2,0.8-2.7,0C33.1,43.1,33.1,41.8,33.8,41.1
|
||||
"/>
|
||||
<g>
|
||||
|
||||
<rect x="19.6" y="26.2" transform="matrix(0.9064 0.4224 -0.4224 0.9064 14.1626 -9.1647)" fill="#0E7077" width="16.4" height="2.3"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 3.6 KiB |
|
@ -1,157 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
viewBox="0 0 360 120.9"
|
||||
data-name="Layer 1"
|
||||
id="Layer_1">
|
||||
<metadata
|
||||
id="metadata5178">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Artboard 1</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs5143">
|
||||
<style
|
||||
id="style5141">.cls-1{fill:#fff;}</style>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="201.98439"
|
||||
x2="188.125"
|
||||
y1="74.484383"
|
||||
x1="52.476562"
|
||||
id="linearGradient7736"
|
||||
xlink:href="#linearGradient7734"
|
||||
gradientTransform="matrix(0.36497785,0,0,0.36497785,267.61793,-6.286912)" />
|
||||
<linearGradient
|
||||
id="linearGradient7734">
|
||||
<stop
|
||||
id="stop7730"
|
||||
offset="0"
|
||||
style="stop-color:#ff0000;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#ffff00;stop-opacity:1"
|
||||
offset="0.39864159"
|
||||
id="stop7738" />
|
||||
<stop
|
||||
id="stop7740"
|
||||
offset="0.54261029"
|
||||
style="stop-color:#ccff00;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#00ffff;stop-opacity:1"
|
||||
offset="0.71236038"
|
||||
id="stop7742" />
|
||||
<stop
|
||||
id="stop7744"
|
||||
offset="0.99037486"
|
||||
style="stop-color:#ff00ff;stop-opacity:1" />
|
||||
<stop
|
||||
id="stop7732"
|
||||
offset="1"
|
||||
style="stop-color:#0000ff;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<filter
|
||||
height="1.2171938"
|
||||
y="-0.10859691"
|
||||
width="1.1880955"
|
||||
x="-0.09404768"
|
||||
id="filter7597"
|
||||
style="color-interpolation-filters:sRGB">
|
||||
<feGaussianBlur
|
||||
id="feGaussianBlur7599"
|
||||
stdDeviation="4.2634807" />
|
||||
</filter>
|
||||
</defs>
|
||||
<title
|
||||
id="title5145">Artboard 1</title>
|
||||
<g
|
||||
id="text4562"
|
||||
style="font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;display:inline;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
aria-label="Project Athena">
|
||||
<path
|
||||
id="path5741"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="M 0.3661321,106.82553 V 72.265531 H 17.406132 q 4.944,0 8.208,2.592 3.264,2.592 4.224,7.296 0.336,1.632 0.336,3.312 0,5.136 -3.12,8.304 -3.072,3.12 -7.92,3.12 h -6 v 9.935999 z M 15.198132,88.057531 q 2.592,0 3.024,-2.112 0.144,-0.72 0.144,-1.296 0,-1.872 -1.488,-2.496 -0.24,-0.096 -0.624,-0.144 -0.384,-0.048 -1.296,-0.048 h -1.824 v 6.096 z" />
|
||||
<path
|
||||
id="path5743"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="M 32.428632,106.82553 V 88.009531 l 11.04,-6.624 v 3.792 l 0.576,-0.528 q 2.832,-2.592 6.768,-2.592 0.528,0 0.912,0 0.384,0 1.008,0.144 0.624,0.144 1.056,0.24 0.48,0.096 1.296,0.432 l -3.696,11.136 q -0.288,-0.288 -0.816,-0.624 -0.528,-0.336 -1.104,-0.528 -0.528,-0.24 -1.344,-0.24 -1.488,0 -2.544,0.912 -1.008,0.864 -1.2,2.064 -0.192,1.152 -0.192,2.496 v 8.735999 z" />
|
||||
<path
|
||||
id="path5745"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 54.405132,94.825531 q 0,-5.424 3.888,-9.264 3.936,-3.888 9.504,-3.888 2.736,0 5.184,1.056 3.84,1.584 6,4.944 2.16,3.36 2.16,7.248 0,2.496 -0.96,4.848 -0.912,2.351999 -2.832,4.271999 -3.936,3.936 -9.552,3.936 -5.616,0 -9.504,-3.84 -3.888,-3.84 -3.888,-9.311999 z m 11.712,2.544 q 0.672,0.72 1.68,0.72 1.008,0 1.728,-0.816 0.768,-0.864 0.768,-2.448 0,-1.536 -0.768,-2.4 -0.72,-0.864 -1.728,-0.864 -1.008,0 -1.68,0.768 -0.864,0.96 -0.864,2.496 0,1.584 0.864,2.544 z" />
|
||||
<path
|
||||
id="path5747"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="M 84.272382,115.46553 V 87.913531 l 11.76,-6.48 v 34.031999 z m 0.096,-39.167999 q 0,-2.592 1.68,-4.512 1.68,-1.92 4.224,-1.92 1.392,0 2.544,0.432 1.152,0.384 2.064,1.296 1.824,1.776 1.824,4.368 0,2.544 -1.776,4.368 -1.728,1.776 -4.176,1.776 -2.592,0 -4.512,-1.632 -1.872,-1.68 -1.872,-4.176 z" />
|
||||
<path
|
||||
id="path5749"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 124.75588,91.465531 -13.44,6.816 0.24,0.336 q 0.768,0.768 1.584,0.768 0.336,0 0.816,-0.192 0.48,-0.192 0.912,-0.672 l 0.096,-0.192 0.144,-0.192 7.488,4.511999 q -1.44,1.92 -3.552,3.216 -2.112,1.248 -4.656,1.728 -1.344,0.24 -2.496,0.24 -3.504,0 -6.48,-1.776 -6.335998,-3.6 -6.335998,-10.799999 0,-1.104 0.24,-2.544 0.624,-4.08 3.455998,-6.96 2.832,-2.88 6.912,-3.648 1.248,-0.192 1.728,-0.192 0.528,-0.048 0.816,-0.048 1.296,0 2.544,0.288 6.864,1.488 9.552,7.968 z m -11.52,-1.728 q -0.96,0 -1.392,0.144 -1.44,0.432 -2.112,1.488 -0.672,1.056 -0.672,2.112 0,0.384 0.192,1.056 l 6.624,-3.36 q -0.48,-0.624 -1.152,-1.008 -0.672,-0.432 -1.488,-0.432 z" />
|
||||
<path
|
||||
id="path5751"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 148.01638,83.785531 -2.592,8.64 -0.432,-0.288 q -1.344,-0.816 -2.208,-0.96 -0.864,-0.192 -1.536,-0.192 -1.68,0 -2.688,1.488 -0.576,1.008 -0.576,2.064 0,0.288 0.096,0.768 0.624,2.736 3.456,2.736 1.392,0 3.024,-0.672 l 0.576,-0.192 0.288,-0.144 2.4,7.919999 q -0.912,0.672 -2.16,1.2 -3.6,1.632 -7.008,1.632 -6.72,0 -10.56,-5.856 -2.16,-3.215999 -2.16,-7.199999 0,-1.248 0.288,-2.64 0.96,-4.704 4.56,-7.536 3.648,-2.88 8.688,-2.88 3.264,0 6.528,1.248 0.576,0.192 0.96,0.384 0.432,0.192 1.056,0.48 z" />
|
||||
<path
|
||||
id="path5753"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 147.34438,91.609531 16.128,-20.208 v 11.232 h 5.616 l -3.12,8.976 h -2.496 v 15.215999 h -11.76 V 91.609531 Z" />
|
||||
<path
|
||||
id="path5755"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 179.49613,106.82553 12.288,-34.559999 h 13.296 l 12.288,34.559999 h -13.824 l -0.96,-4.416 h -8.304 l -1.008,4.416 z m 21.6,-13.151999 -1.872,-8.256 -0.432,-1.968 -0.288,-2.304 q 0,0.912 -0.144,1.392 -0.096,0.48 -0.192,0.96 l -0.48,1.92 -1.872,8.256 z" />
|
||||
<path
|
||||
id="path5757"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 214.75063,91.609531 16.128,-20.208 v 11.232 h 5.616 l -3.12,8.976 h -2.496 v 15.215999 h -11.76 V 91.609531 Z" />
|
||||
<path
|
||||
id="path5759"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="M 236.14738,106.82553 V 77.689531 l 11.76,-6.528 v 13.488 l 0.288,-0.336 0.384,-0.336 q 1.152,-1.008 2.592,-1.536 2.016,-0.72 3.888,-0.72 3.6,0 5.904,2.4 2.304,2.4 2.304,6.144 v 16.559999 h -11.76 V 94.393531 q 0,-2.688 -2.112,-2.4 -1.488,0.288 -1.488,2.448 v 12.383999 z" />
|
||||
<path
|
||||
id="path5761"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 292.00588,91.465531 -13.44,6.816 0.24,0.336 q 0.768,0.768 1.584,0.768 0.336,0 0.816,-0.192 0.48,-0.192 0.912,-0.672 l 0.096,-0.192 0.144,-0.192 7.488,4.511999 q -1.44,1.92 -3.552,3.216 -2.112,1.248 -4.656,1.728 -1.344,0.24 -2.496,0.24 -3.504,0 -6.48,-1.776 -6.336,-3.6 -6.336,-10.799999 0,-1.104 0.24,-2.544 0.624,-4.08 3.456,-6.96 2.832,-2.88 6.912,-3.648 1.248,-0.192 1.728,-0.192 0.528,-0.048 0.816,-0.048 1.296,0 2.544,0.288 6.864,1.488 9.552,7.968 z m -11.52,-1.728 q -0.96,0 -1.392,0.144 -1.44,0.432 -2.112,1.488 -0.672,1.056 -0.672,2.112 0,0.384 0.192,1.056 l 6.624,-3.36 q -0.48,-0.624 -1.152,-1.008 -0.672,-0.432 -1.488,-0.432 z" />
|
||||
<path
|
||||
id="path5763"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 293.52238,87.913531 11.04,-6.576 v 3.552 q 1.152,-1.44 3.024,-2.208 1.872,-0.816 4.464,-0.816 4.128,0 6.336,2.352 2.256,2.304 2.256,6.528 v 16.079999 h -11.76 V 94.153531 q 0,-2.304 -1.776,-2.304 -1.776,0 -1.776,2.88 l 0.048,12.095999 h -11.76 z" />
|
||||
<path
|
||||
id="path5765"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48px;font-family:OpineHeavy;-inkscape-font-specification:OpineHeavy;fill:#ffffff;fill-opacity:1;stroke:none;stroke-opacity:1"
|
||||
d="m 341.70088,84.889531 v -2.256 h 11.088 v 24.191999 h -11.088 v -2.496 q -1.2,1.488 -3.072,2.304 -1.872,0.816 -4.32,0.816 -4.56,0 -7.44,-3.12 -3.12,-3.36 -3.12,-9.215999 0,-5.856 3.072,-9.504 3.072,-3.648 7.584,-3.648 1.008,0 2.256,0.24 1.248,0.24 2.64,0.96 1.392,0.72 2.4,1.728 z m -3.84,12.864 q 0.192,0.048 0.336,0.048 0.144,0 0.192,0 1.104,0 1.824,-0.912 0.768,-0.96 0.768,-2.64 0,-1.344 -0.576,-2.112 -0.528,-0.816 -1.536,-1.056 -0.192,-0.048 -0.528,-0.048 -2.256,0 -2.64,2.88 v 0.624 q 0,1.392 0.528,2.256 0.576,0.816 1.632,0.96 z" />
|
||||
</g>
|
||||
<path
|
||||
transform="matrix(0.69899025,0,0,0.69899025,269.31594,32.684837)"
|
||||
id="path3799-2"
|
||||
d="m 91.832079,57.500977 -54.399819,-3e-6 -27.199907,-47.111626 27.199912,-47.111623 54.399818,3e-6 27.199907,47.111626 z"
|
||||
style="display:inline;opacity:0.93500001;fill:#3a3937;fill-opacity:1;stroke:#0092d4;stroke-width:9.56400013;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;filter:url(#filter7597)" />
|
||||
<path
|
||||
id="path4704"
|
||||
d="m 333.58541,10.641061 c -1.33042,-0.003 -2.6614,0.02719 -3.99105,0.08885 -10.63729,0.492794 -21.18542,3.054485 -30.61336,7.960541 -12.58659,6.549722 -22.9644,17.350793 -27.86872,30.474604 -0.74714,1.999314 -1.43163,4.195201 -1.50307,6.589093 -0.0565,1.888571 0.29775,3.884417 1.27773,5.657351 l 3.81151,-1.936715 c -0.56198,-1.016544 -0.833,-2.297505 -0.79411,-3.599793 0.0501,-1.679736 0.56345,-3.455978 1.24801,-5.287791 4.49756,-12.035358 14.14243,-22.123913 25.85832,-28.220559 8.79888,-4.578713 18.73478,-7.001788 28.79335,-7.470115 3.35287,-0.156099 6.7192,-0.09515 10.06201,0.175426 2.93218,0.237351 5.73367,0.646171 8.1239,1.68684 1.19179,0.518899 2.27932,1.195515 3.16519,2.017423 0.42257,0.392059 0.80015,0.822607 1.12389,1.278292 l 3.82437,-1.942984 c -0.5612,-0.867683 -1.23086,-1.656127 -1.97867,-2.349944 -1.30077,-1.206889 -2.80875,-2.124025 -4.37706,-2.806858 -3.12999,-1.362756 -6.42744,-1.788546 -9.52453,-2.039252 -2.20449,-0.178433 -4.42036,-0.270573 -6.63771,-0.274441 z"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4.23338938;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||
<path
|
||||
id="rect4616"
|
||||
d="M 332.27108,6.4873186 302.92243,35.836669 V 7.463203 h -8.85213 v 64.708723 h 8.85213 v -23.81623 l 5.76336,-5.764087 25.34887,25.348857 6.25951,-6.259517 -25.34886,-25.348857 23.58527,-23.585265 z"
|
||||
style="display:inline;opacity:1;fill:url(#linearGradient7736);fill-opacity:1;stroke:none;stroke-width:7.73268747;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:none;fill-opacity:1;stroke:#0092d4;stroke-width:6.68530035;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 333.50566,72.877373 -38.02494,-2e-6 -19.01247,-32.930565 19.01248,-32.9305635 38.02494,1.8e-6 19.01247,32.9305657 z"
|
||||
id="path3799" />
|
||||
<path
|
||||
id="path4704-6"
|
||||
d="m 356.08812,18.088179 -3.82438,1.945692 c 0.35892,0.501671 0.65258,1.033693 0.86041,1.582768 0.50474,1.333501 0.56989,2.917749 0.29001,4.495637 -0.28192,1.589386 -0.90095,3.203676 -1.66094,4.844551 -5.48664,11.845931 -16.20091,21.205609 -28.57285,26.516947 -12.39358,5.320605 -26.41056,6.815809 -40.05475,5.569639 -1.68347,-0.153759 -3.24995,-0.35005 -4.62129,-0.787094 -1.35534,-0.431958 -2.54518,-1.130952 -3.29455,-2.02716 -0.18643,-0.22298 -0.36768,-0.495132 -0.51492,-0.758591 l -3.81239,1.922314 c 0.2748,0.493806 0.61298,1.012955 0.9906,1.464582 1.42784,1.70764 3.3631,2.74692 5.29048,3.361179 1.9114,0.609193 3.80307,0.816132 5.5596,0.976564 14.23496,1.300129 28.98,-0.233493 42.19527,-5.906858 13.23694,-5.68266 24.75883,-15.678884 30.75317,-28.620923 0.8299,-1.791855 1.60226,-3.728332 1.97824,-5.847981 0.37802,-2.131162 0.34038,-4.441307 -0.49205,-6.640562 -0.28066,-0.741451 -0.64526,-1.437996 -1.06966,-2.090704 z"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:4.23338938;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||
</svg>
|
Before Width: | Height: | Size: 16 KiB |
23
interface/resources/images/vircadia-banner.svg
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" width="1880" height="320" viewBox="0 0 1880.00 320.00" enable-background="new 0 0 1880.00 320.00" xml:space="preserve">
|
||||
<radialGradient id="SVGID_Fill1_" cx="-571.529" cy="-604.157" r="3176.39" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.451163" stop-color="#01BDFF" stop-opacity="1"/>
|
||||
<stop offset="0.827907" stop-color="#8C1AFF" stop-opacity="1"/>
|
||||
</radialGradient>
|
||||
<path fill="url(#SVGID_Fill1_)" stroke-width="0.2" stroke-linejoin="round" d="M 28.723,5.00146L 1706.72,5.00146C 1726.61,5.00146 1750.24,21.1192 1759.51,41.0015L 1870.49,278.999C 1879.76,298.881 1871.16,314.999 1851.28,314.999L 173.277,314.999C 153.395,314.999 129.761,298.881 120.49,278.999L 9.51012,41.0015C 0.238872,21.1192 8.84079,5.00146 28.723,5.00146 Z "/>
|
||||
<path fill="#36393F" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 678.939,23.013L 1697.3,23.0124C 1723.4,22.9324 1739.32,35.2514 1749.85,58.4911L 1844.51,261.508C 1860.58,289.515 1859.52,298.385 1825.06,296.987L 677.061,296.987"/>
|
||||
<g>
|
||||
<path fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 699.7,159.966C 699.7,145.281 702.032,131.093 706.698,117.404C 711.363,103.714 718.063,91.58 726.796,81.0016C 735.529,70.4231 745.996,61.9604 758.199,55.6133C 770.401,49.2663 784.039,46.0927 799.112,46.0927L 906.779,46.0927L 906.779,93.8823L 800.189,93.8823C 794.686,93.8823 789.003,95.7491 783.142,99.4827C 777.28,103.216 771.896,108.132 766.992,114.23C 762.087,120.328 758.019,127.36 754.789,135.325C 751.559,143.29 749.944,151.379 749.944,159.593C 749.944,167.807 751.499,175.896 754.61,183.861C 757.72,191.826 761.788,198.92 766.812,205.142C 771.837,211.365 777.459,216.343 783.68,220.077C 789.901,223.81 796.122,225.677 802.342,225.677L 906.779,225.677L 906.779,273.467L 798.036,273.467C 782.244,273.467 768.248,270.044 756.045,263.199C 743.843,256.354 733.555,247.456 725.181,236.504C 716.807,225.553 710.466,213.356 706.16,199.915C 701.853,186.475 699.7,173.158 699.7,159.966 Z "/>
|
||||
<rect x="1464.81" y="46.0927" fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" width="55.9871" height="227.374"/>
|
||||
</g>
|
||||
<path fill="#FFFFFF" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 493.02,97.6159L 493.02,139.602L 493,139.602L 493,199.602L 493.02,199.602L 493.02,273.467L 439.123,273.467L 439.123,46.0928L 566.737,46.0928C 578.327,46.0928 588.237,48.2707 596.467,52.6265C 604.696,56.9823 611.419,62.7071 616.635,69.8009C 621.851,76.8946 625.618,84.9218 627.936,93.8824C 630.254,102.843 631.413,111.928 631.413,121.137C 631.413,128.604 630.428,136.009 628.457,143.352C 626.487,150.695 623.763,157.54 620.286,163.887C 616.809,170.234 612.578,175.896 607.594,180.874C 602.61,185.852 597.104,189.71 591.077,192.448L 654.363,273.467L 588.295,273.467L 521,188.288L 521,149.512L 566.737,149.512C 568.359,149.512 569.982,148.517 571.605,146.526C 573.227,144.534 574.618,142.17 575.777,139.432C 576.937,136.694 577.922,133.894 578.733,131.031C 579.544,128.169 579.95,125.991 579.95,124.498C 579.95,122.257 579.718,119.644 579.255,116.657C 578.791,113.67 578.038,110.746 576.995,107.883C 575.951,105.021 574.56,102.594 572.822,100.603C 571.083,98.6115 569.055,97.6159 566.737,97.6159L 493.02,97.6159 Z "/>
|
||||
<g>
|
||||
<rect x="340.465" y="46.0927" fill="#FFFFFF" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" width="54.9846" height="227.374"/>
|
||||
</g>
|
||||
<path fill="#FFFFFF" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 55.5166,46.093L 161.961,273.467L 214.479,273.467L 216.626,269.689L 115.436,46.093L 55.5166,46.093 Z "/>
|
||||
<path fill="#FFFFFF" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 231.92,235.709L 319.513,46.0926L 259.594,46.0926L 202.957,171.669L 231.92,235.709 Z "/>
|
||||
<path fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 987.874,273.467L 926.863,273.467L 1034.17,46.0927L 1088,46.0927L 1195.67,273.467L 1134.66,273.467L 1106.67,212.983L 1047.45,212.983L 1044.83,212.918L 1065.94,164.447L 1087.65,164.447L 1060.73,106.576"/>
|
||||
<path fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 1605.13,273.467L 1544.12,273.467L 1651.43,46.0927L 1705.26,46.0927L 1812.93,273.467L 1751.91,273.467L 1723.92,212.983L 1664.7,212.983L 1662,212.918L 1683.24,164.447L 1704.9,164.447L 1677.98,106.576"/>
|
||||
<path fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 1438.98,159.966C 1438.98,173.158 1436.83,186.475 1432.52,199.915C 1428.22,213.356 1421.88,225.553 1413.5,236.504C 1405.13,247.456 1394.84,256.354 1382.64,263.199C 1370.43,270.044 1356.44,273.467 1340.65,273.467L 1217.91,273.467L 1217.91,121.9L 1272.1,121.9L 1272.1,225.677L 1335.98,225.677C 1342.2,225.677 1348.42,223.81 1354.64,220.077C 1360.86,216.343 1366.49,211.365 1371.51,205.142C 1376.54,198.92 1380.6,191.826 1383.71,183.861C 1386.82,175.896 1388.38,167.807 1388.38,159.593C 1388.38,150.632 1386.58,142.17 1383,134.205C 1379.41,126.24 1375.04,119.271 1369.9,113.297C 1364.75,107.323 1359.31,102.594 1353.57,99.1094C 1347.82,95.6247 1342.8,93.8824 1338.49,93.8824L 1272.1,93.8824L 1272.1,93.9001L 1217.91,93.9001L 1217.91,46.0927L 1332.03,46.0927C 1350.46,46.0927 1366.43,49.0796 1379.95,55.0533C 1393.46,61.0269 1404.59,69.1163 1413.32,79.3215C 1422.06,89.5265 1428.52,101.536 1432.7,115.35C 1436.89,129.165 1438.98,144.037 1438.98,159.966 Z "/>
|
||||
</svg>
|
|
@ -1,23 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" baseProfile="full" width="1880" height="320" viewBox="0 0 1880.00 320.00" enable-background="new 0 0 1880.00 320.00" xml:space="preserve">
|
||||
<radialGradient id="SVGID_Fill1_" cx="-571.529" cy="-604.157" r="3176.39" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.451163" stop-color="#01BDFF" stop-opacity="1"/>
|
||||
<stop offset="0.827907" stop-color="#8C1AFF" stop-opacity="1"/>
|
||||
</radialGradient>
|
||||
<path fill="url(#SVGID_Fill1_)" stroke-width="0.2" stroke-linejoin="round" d="M 28.723,5.00146L 1706.72,5.00146C 1726.61,5.00146 1750.24,21.1192 1759.51,41.0015L 1870.49,278.999C 1879.76,298.881 1871.16,314.999 1851.28,314.999L 173.277,314.999C 153.395,314.999 129.761,298.881 120.49,278.999L 9.51012,41.0015C 0.238872,21.1192 8.84079,5.00146 28.723,5.00146 Z "/>
|
||||
<path fill="#36393F" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 678.939,23.013L 1697.3,23.0124C 1723.4,22.9324 1739.32,35.2514 1749.85,58.4911L 1844.51,261.508C 1860.58,289.515 1859.52,298.385 1825.06,296.987L 677.061,296.987"/>
|
||||
<g>
|
||||
<path fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 699.7,159.966C 699.7,145.281 702.032,131.093 706.698,117.404C 711.363,103.714 718.063,91.58 726.796,81.0016C 735.529,70.4231 745.996,61.9604 758.199,55.6133C 770.401,49.2663 784.039,46.0927 799.112,46.0927L 906.779,46.0927L 906.779,93.8823L 800.189,93.8823C 794.686,93.8823 789.003,95.7491 783.142,99.4827C 777.28,103.216 771.896,108.132 766.992,114.23C 762.087,120.328 758.019,127.36 754.789,135.325C 751.559,143.29 749.944,151.379 749.944,159.593C 749.944,167.807 751.499,175.896 754.61,183.861C 757.72,191.826 761.788,198.92 766.812,205.142C 771.837,211.365 777.459,216.343 783.68,220.077C 789.901,223.81 796.122,225.677 802.342,225.677L 906.779,225.677L 906.779,273.467L 798.036,273.467C 782.244,273.467 768.248,270.044 756.045,263.199C 743.843,256.354 733.555,247.456 725.181,236.504C 716.807,225.553 710.466,213.356 706.16,199.915C 701.853,186.475 699.7,173.158 699.7,159.966 Z "/>
|
||||
<rect x="1464.81" y="46.0927" fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" width="55.9871" height="227.374"/>
|
||||
</g>
|
||||
<path fill="#FFFFFF" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 493.02,97.6159L 493.02,139.602L 493,139.602L 493,199.602L 493.02,199.602L 493.02,273.467L 439.123,273.467L 439.123,46.0928L 566.737,46.0928C 578.327,46.0928 588.237,48.2707 596.467,52.6265C 604.696,56.9823 611.419,62.7071 616.635,69.8009C 621.851,76.8946 625.618,84.9218 627.936,93.8824C 630.254,102.843 631.413,111.928 631.413,121.137C 631.413,128.604 630.428,136.009 628.457,143.352C 626.487,150.695 623.763,157.54 620.286,163.887C 616.809,170.234 612.578,175.896 607.594,180.874C 602.61,185.852 597.104,189.71 591.077,192.448L 654.363,273.467L 588.295,273.467L 521,188.288L 521,149.512L 566.737,149.512C 568.359,149.512 569.982,148.517 571.605,146.526C 573.227,144.534 574.618,142.17 575.777,139.432C 576.937,136.694 577.922,133.894 578.733,131.031C 579.544,128.169 579.95,125.991 579.95,124.498C 579.95,122.257 579.718,119.644 579.255,116.657C 578.791,113.67 578.038,110.746 576.995,107.883C 575.951,105.021 574.56,102.594 572.822,100.603C 571.083,98.6115 569.055,97.6159 566.737,97.6159L 493.02,97.6159 Z "/>
|
||||
<g>
|
||||
<rect x="340.465" y="46.0927" fill="#FFFFFF" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" width="54.9846" height="227.374"/>
|
||||
</g>
|
||||
<path fill="#FFFFFF" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 55.5166,46.093L 161.961,273.467L 214.479,273.467L 216.626,269.689L 115.436,46.093L 55.5166,46.093 Z "/>
|
||||
<path fill="#FFFFFF" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 231.92,235.709L 319.513,46.0926L 259.594,46.0926L 202.957,171.669L 231.92,235.709 Z "/>
|
||||
<path fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 987.874,273.467L 926.863,273.467L 1034.17,46.0927L 1088,46.0927L 1195.67,273.467L 1134.66,273.467L 1106.67,212.983L 1047.45,212.983L 1044.83,212.918L 1065.94,164.447L 1087.65,164.447L 1060.73,106.576"/>
|
||||
<path fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 1605.13,273.467L 1544.12,273.467L 1651.43,46.0927L 1705.26,46.0927L 1812.93,273.467L 1751.91,273.467L 1723.92,212.983L 1664.7,212.983L 1662,212.918L 1683.24,164.447L 1704.9,164.447L 1677.98,106.576"/>
|
||||
<path fill="#FAFAFA" fill-opacity="1" stroke-width="0.2" stroke-linejoin="round" d="M 1438.98,159.966C 1438.98,173.158 1436.83,186.475 1432.52,199.915C 1428.22,213.356 1421.88,225.553 1413.5,236.504C 1405.13,247.456 1394.84,256.354 1382.64,263.199C 1370.43,270.044 1356.44,273.467 1340.65,273.467L 1217.91,273.467L 1217.91,121.9L 1272.1,121.9L 1272.1,225.677L 1335.98,225.677C 1342.2,225.677 1348.42,223.81 1354.64,220.077C 1360.86,216.343 1366.49,211.365 1371.51,205.142C 1376.54,198.92 1380.6,191.826 1383.71,183.861C 1386.82,175.896 1388.38,167.807 1388.38,159.593C 1388.38,150.632 1386.58,142.17 1383,134.205C 1379.41,126.24 1375.04,119.271 1369.9,113.297C 1364.75,107.323 1359.31,102.594 1353.57,99.1094C 1347.82,95.6247 1342.8,93.8824 1338.49,93.8824L 1272.1,93.8824L 1272.1,93.9001L 1217.91,93.9001L 1217.91,46.0927L 1332.03,46.0927C 1350.46,46.0927 1366.43,49.0796 1379.95,55.0533C 1393.46,61.0269 1404.59,69.1163 1413.32,79.3215C 1422.06,89.5265 1428.52,101.536 1432.7,115.35C 1436.89,129.165 1438.98,144.037 1438.98,159.966 Z "/>
|
||||
</svg>
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
id="svg17"
|
||||
xml:space="preserve"
|
||||
enable-background="new 0 0 256.00 256.00"
|
||||
viewBox="0 0 257.6 257.6"
|
||||
height="56"
|
||||
width="56"
|
||||
version="1.1"><metadata
|
||||
id="metadata23"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs21" />
|
||||
<radialGradient
|
||||
gradientTransform="translate(1.15,1.25)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
r="410"
|
||||
cy="-40.865398"
|
||||
cx="-40.865398"
|
||||
id="SVGID_Fill1_">
|
||||
<stop
|
||||
id="stop2"
|
||||
stop-opacity="1"
|
||||
stop-color="#01BDFF"
|
||||
offset="0.35814" />
|
||||
<stop
|
||||
id="stop4"
|
||||
stop-opacity="1"
|
||||
stop-color="#466BFF"
|
||||
offset="0.618605" />
|
||||
<stop
|
||||
id="stop6"
|
||||
stop-opacity="1"
|
||||
stop-color="#8C1AFF"
|
||||
offset="0.855814" />
|
||||
</radialGradient>
|
||||
<circle
|
||||
style="fill:url(#SVGID_Fill1_);stroke-width:0.2;stroke-linejoin:round"
|
||||
r="125"
|
||||
id="ellipse9"
|
||||
cy="129.25"
|
||||
cx="129.14999" />
|
||||
<g
|
||||
transform="translate(1.15,1.25)"
|
||||
id="g15">
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.2;stroke-linejoin:round"
|
||||
id="path11"
|
||||
d="m 48,65.0981 64.513,137.8039 h 31.829 l 1.301,-2.289 L 84.3151,65.0981 Z" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke-width:0.2;stroke-linejoin:round"
|
||||
id="path13"
|
||||
d="M 154.913,180.019 208,65.0978 h -36.315 l -34.326,76.1082 z" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -3,10 +3,10 @@
|
|||
//
|
||||
// Created by David Rowe on 3 Jun 2015
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
//
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
import Hifi 1.0
|
||||
import QtQuick 2.4
|
||||
|
@ -87,7 +87,7 @@ FocusScope {
|
|||
anchors.centerIn: parent
|
||||
sourceSize.width: 500
|
||||
sourceSize.height: 91
|
||||
source: "../images/vircadia-logo.svg"
|
||||
source: "../images/vircadia-banner.svg"
|
||||
horizontalAlignment: Image.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
// Created by Clement on 7/18/16
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -486,6 +487,7 @@ Item {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: signUpContainer
|
||||
width: loginContainer.width
|
||||
|
@ -494,7 +496,7 @@ Item {
|
|||
anchors {
|
||||
left: loginContainer.left
|
||||
top: loginContainer.bottom
|
||||
topMargin: 0.15 * parent.height
|
||||
topMargin: 0.05 * parent.height
|
||||
}
|
||||
TextMetrics {
|
||||
id: signUpTextMetrics
|
||||
|
@ -542,37 +544,54 @@ Item {
|
|||
"errorString": "" });
|
||||
}
|
||||
}
|
||||
}
|
||||
TextMetrics {
|
||||
id: dismissButtonTextMetrics
|
||||
font: loginErrorMessage.font
|
||||
text: dismissButton.text
|
||||
}
|
||||
HifiControlsUit.Button {
|
||||
id: dismissButton
|
||||
width: dismissButtonTextMetrics.width
|
||||
height: d.minHeightButton
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
right: parent.right
|
||||
margins: 3 * hifi.dimensions.contentSpacing.y
|
||||
}
|
||||
color: hifi.buttons.noneBorderlessWhite
|
||||
text: qsTr("No thanks, take me in-world! >")
|
||||
fontCapitalization: Font.MixedCase
|
||||
fontFamily: linkAccountBody.fontFamily
|
||||
fontSize: linkAccountBody.fontSize
|
||||
fontBold: linkAccountBody.fontBold
|
||||
visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam && !linkAccountBody.linkOculus;
|
||||
onClicked: {
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user dismissed login screen"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
loginDialog.dismissLoginDialog();
|
||||
|
||||
Text {
|
||||
id: signUpTextSecond
|
||||
text: qsTr("or")
|
||||
anchors {
|
||||
left: signUpShortcutText.right
|
||||
leftMargin: hifi.dimensions.contentSpacing.x
|
||||
}
|
||||
lineHeight: 1
|
||||
color: "white"
|
||||
font.family: linkAccountBody.fontFamily
|
||||
font.pixelSize: linkAccountBody.textFieldFontSize
|
||||
font.bold: linkAccountBody.fontBold
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam && !linkAccountBody.linkOculus;
|
||||
}
|
||||
|
||||
TextMetrics {
|
||||
id: dismissButtonTextMetrics
|
||||
font: loginErrorMessage.font
|
||||
text: dismissButton.text
|
||||
}
|
||||
HifiControlsUit.Button {
|
||||
id: dismissButton
|
||||
width: loginButton.width
|
||||
height: d.minHeightButton
|
||||
anchors {
|
||||
top: signUpText.bottom
|
||||
topMargin: hifi.dimensions.contentSpacing.y
|
||||
left: loginButton.left
|
||||
}
|
||||
text: qsTr("Use without account, log in anonymously")
|
||||
fontCapitalization: Font.MixedCase
|
||||
fontFamily: linkAccountBody.fontFamily
|
||||
fontSize: linkAccountBody.fontSize
|
||||
fontBold: linkAccountBody.fontBold
|
||||
visible: loginDialog.getLoginDialogPoppedUp() && !linkAccountBody.linkSteam && !linkAccountBody.linkOculus;
|
||||
onClicked: {
|
||||
if (linkAccountBody.loginDialogPoppedUp) {
|
||||
var data = {
|
||||
"action": "user dismissed login screen"
|
||||
};
|
||||
UserActivityLogger.logAction("encourageLoginDialog", data);
|
||||
loginDialog.dismissLoginDialog();
|
||||
}
|
||||
root.tryDestroy();
|
||||
}
|
||||
root.tryDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ FocusScope {
|
|||
anchors.centerIn: parent
|
||||
sourceSize.width: 500
|
||||
sourceSize.height: 91
|
||||
source: "../images/vircadia-logo.svg"
|
||||
source: "../images/vircadia-banner.svg"
|
||||
horizontalAlignment: Image.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ ScrollingWindow {
|
|||
|
||||
Image {
|
||||
id: logo
|
||||
source: "../images/hifi-logo.svg"
|
||||
source: "../images/vircadia-logo.svg"
|
||||
width: updateDialog.logoSize
|
||||
height: updateDialog.logoSize
|
||||
anchors {
|
||||
|
|
|
@ -131,7 +131,7 @@ FocusScope {
|
|||
anchors.centerIn: parent
|
||||
sourceSize.width: 400
|
||||
sourceSize.height: 73
|
||||
source: "../../images/vircadia-logo.svg"
|
||||
source: "../../images/vircadia-banner.svg"
|
||||
horizontalAlignment: Image.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,7 +128,7 @@ ShadowRectangle {
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: Link to a Project Athena version of the video.
|
||||
// FIXME: Link to a Vircadias version of the video.
|
||||
/*
|
||||
RalewayButton {
|
||||
id: video
|
||||
|
|
|
@ -25,7 +25,7 @@ Rectangle {
|
|||
Image {
|
||||
width: 400; height: 73
|
||||
fillMode: Image.PreserveAspectFit
|
||||
source: "../../../images/vircadia-logo.svg"
|
||||
source: "../../../images/vircadia-banner.svg"
|
||||
}
|
||||
Item { height: 30; width: 1 }
|
||||
Column {
|
||||
|
@ -53,7 +53,7 @@ Rectangle {
|
|||
textFormat: Text.StyledText
|
||||
linkColor: "#00B4EF"
|
||||
color: "white"
|
||||
text: "<a href=\"https:/github.com/kasenvr/project-athena\">Vircadia Github</a>."
|
||||
text: "<a href=\"https://github.com/kasenvr/project-athena\">Vircadia Github</a>."
|
||||
size: 20
|
||||
onLinkActivated: {
|
||||
HiFiAbout.openUrl("https:/github.com/kasenvr/project-athena");
|
||||
|
|
|
@ -347,7 +347,6 @@ static const QString STANDARD_TO_ACTION_MAPPING_NAME = "Standard to Action";
|
|||
static const QString NO_MOVEMENT_MAPPING_NAME = "Standard to Action (No Movement)";
|
||||
static const QString NO_MOVEMENT_MAPPING_JSON = PathUtils::resourcesPath() + "/controllers/standard_nomovement.json";
|
||||
|
||||
static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";
|
||||
static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds
|
||||
static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop";
|
||||
static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin";
|
||||
|
@ -7620,7 +7619,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) {
|
|||
|
||||
QUrl scriptURL { scriptFilenameOrURL };
|
||||
|
||||
if (scriptURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) {
|
||||
if (scriptURL.host().endsWith(NetworkingConstants::MARKETPLACE_CDN_HOSTNAME)) {
|
||||
int startIndex = shortName.lastIndexOf('/') + 1;
|
||||
int endIndex = shortName.lastIndexOf('?');
|
||||
shortName = shortName.mid(startIndex, endIndex - startIndex);
|
||||
|
@ -7743,7 +7742,7 @@ bool Application::askToReplaceDomainContent(const QString& url) {
|
|||
const int MAX_CHARACTERS_PER_LINE = 90;
|
||||
if (DependencyManager::get<NodeList>()->getThisNodeCanReplaceContent()) {
|
||||
QUrl originURL { url };
|
||||
if (originURL.host().endsWith(MARKETPLACE_CDN_HOSTNAME)) {
|
||||
if (originURL.host().endsWith(NetworkingConstants::MARKETPLACE_CDN_HOSTNAME)) {
|
||||
// Create a confirmation dialog when this call is made
|
||||
static const QString infoText = simpleWordWrap("Your domain's content will be replaced with a new content set. "
|
||||
"If you want to save what you have now, create a backup before proceeding. For more information about backing up "
|
||||
|
|
|
@ -223,9 +223,7 @@ public:
|
|||
bool getPreferStylusOverLaser() { return _preferStylusOverLaserSetting.get(); }
|
||||
void setPreferStylusOverLaser(bool value);
|
||||
|
||||
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||
//bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
||||
bool getPreferAvatarFingerOverStylus() { return false; }
|
||||
bool getPreferAvatarFingerOverStylus() { return _preferAvatarFingerOverStylusSetting.get(); }
|
||||
void setPreferAvatarFingerOverStylus(bool value);
|
||||
|
||||
bool getMiniTabletEnabled() { return _miniTabletEnabledSetting.get(); }
|
||||
|
|
|
@ -799,19 +799,19 @@ Menu::Menu() {
|
|||
// Help > Vircadia Docs
|
||||
action = addActionToQMenuAndActionHash(helpMenu, "Online Documentation");
|
||||
connect(action, &QAction::triggered, qApp, [] {
|
||||
QDesktopServices::openUrl(QUrl("https://docs.vircadia.dev/"));
|
||||
QDesktopServices::openUrl(NetworkingConstants::HELP_DOCS_URL);
|
||||
});
|
||||
|
||||
// Help > Vircadia Forum
|
||||
/* action = addActionToQMenuAndActionHash(helpMenu, "Online Forums");
|
||||
connect(action, &QAction::triggered, qApp, [] {
|
||||
QDesktopServices::openUrl(QUrl("https://forums.highfidelity.com/"));
|
||||
QDesktopServices::openUrl(NetworkingConstants::HELP_FORUM_URL));
|
||||
}); */
|
||||
|
||||
// Help > Scripting Reference
|
||||
action = addActionToQMenuAndActionHash(helpMenu, "Online Script Reference");
|
||||
connect(action, &QAction::triggered, qApp, [] {
|
||||
QDesktopServices::openUrl(QUrl("https://apidocs.vircadia.dev/"));
|
||||
QDesktopServices::openUrl(NetworkingConstants::HELP_SCRIPTING_REFERENCE_URL);
|
||||
});
|
||||
|
||||
addActionToQMenuAndActionHash(helpMenu, "Controls Reference", 0, qApp, SLOT(showHelp()));
|
||||
|
@ -821,13 +821,13 @@ Menu::Menu() {
|
|||
// Help > Release Notes
|
||||
action = addActionToQMenuAndActionHash(helpMenu, "Release Notes");
|
||||
connect(action, &QAction::triggered, qApp, [] {
|
||||
QDesktopServices::openUrl(QUrl("https://docs.vircadia.dev/release-notes.html"));
|
||||
QDesktopServices::openUrl(NetworkingConstants::HELP_RELEASE_NOTES_URL);
|
||||
});
|
||||
|
||||
// Help > Report a Bug!
|
||||
action = addActionToQMenuAndActionHash(helpMenu, "Report a Bug!");
|
||||
connect(action, &QAction::triggered, qApp, [] {
|
||||
QDesktopServices::openUrl(QUrl("https://github.com/kasenvr/project-athena/issues"));
|
||||
QDesktopServices::openUrl(NetworkingConstants::HELP_BUG_REPORT_URL);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,7 @@ public:
|
|||
static bool isValidNewProjectName(const QString& projectPath, const QString& projectName);
|
||||
|
||||
static QString getDefaultProjectsPath() {
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Project Athena Projects";
|
||||
return QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/Vircadia Projects";
|
||||
}
|
||||
|
||||
signals:
|
||||
|
|
|
@ -379,7 +379,7 @@ int main(int argc, const char* argv[]) {
|
|||
PROFILE_SYNC_END(startup, "app full ctor", "");
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
app.setWindowIcon(QIcon(PathUtils::resourcesPath() + "images/hifi-logo.svg"));
|
||||
app.setWindowIcon(QIcon(PathUtils::resourcesPath() + "images/vircadia-logo.svg"));
|
||||
#endif
|
||||
|
||||
QTimer exitTimer;
|
||||
|
|
|
@ -223,13 +223,11 @@ void setupPreferences() {
|
|||
preferences->addPreference(preference);
|
||||
}
|
||||
|
||||
/*
|
||||
// FIXME: Remove setting completely or make available through JavaScript API?
|
||||
{
|
||||
auto getter = []()->bool { return qApp->getPreferAvatarFingerOverStylus(); };
|
||||
auto setter = [](bool value) { qApp->setPreferAvatarFingerOverStylus(value); };
|
||||
preferences->addPreference(new CheckPreference(UI_CATEGORY, "Prefer Avatar Finger Over Stylus", getter, setter));
|
||||
}*/
|
||||
}
|
||||
|
||||
// Snapshots
|
||||
static const QString SNAPSHOTS { "Snapshots" };
|
||||
|
|
|
@ -610,6 +610,14 @@ QString defaultAudioDeviceName(QAudio::Mode mode) {
|
|||
<< " [" << deviceName << "] [" << "]";
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
if ( mode == QAudio::AudioInput ) {
|
||||
deviceName = QAudioDeviceInfo::defaultInputDevice().deviceName();
|
||||
} else {
|
||||
deviceName = QAudioDeviceInfo::defaultOutputDevice().deviceName();
|
||||
}
|
||||
#endif
|
||||
return deviceName;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <ApplicationVersion.h>
|
||||
#include <BuildInfo.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <NetworkingConstants.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
AutoUpdater::AutoUpdater() :
|
||||
|
@ -36,18 +37,15 @@ void AutoUpdater::checkForUpdate() {
|
|||
this->getLatestVersionData();
|
||||
}
|
||||
|
||||
const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
|
||||
const QUrl MASTER_BUILDS_XML_URL("https://highfidelity.com/dev-builds.xml");
|
||||
|
||||
void AutoUpdater::getLatestVersionData() {
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
|
||||
QUrl buildsURL;
|
||||
|
||||
if (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable) {
|
||||
buildsURL = BUILDS_XML_URL;
|
||||
buildsURL = NetworkingConstants::BUILDS_XML_URL;
|
||||
} else if (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Master) {
|
||||
buildsURL = MASTER_BUILDS_XML_URL;
|
||||
buildsURL = NetworkingConstants::MASTER_BUILDS_XML_URL;
|
||||
}
|
||||
|
||||
QNetworkRequest latestVersionRequest(buildsURL);
|
||||
|
|
|
@ -312,7 +312,10 @@ void UserInputMapper::update(float deltaTime) {
|
|||
Input::NamedVector UserInputMapper::getAvailableInputs(uint16 deviceID) const {
|
||||
Locker locker(_lock);
|
||||
auto iterator = _registeredDevices.find(deviceID);
|
||||
return iterator->second->getAvailableInputs();
|
||||
if (iterator != _registeredDevices.end()) {
|
||||
return iterator->second->getAvailableInputs();
|
||||
}
|
||||
return Input::NamedVector();
|
||||
}
|
||||
|
||||
QVector<Action> UserInputMapper::getAllActions() const {
|
||||
|
@ -366,7 +369,7 @@ bool UserInputMapper::triggerHapticPulse(float strength, float duration, control
|
|||
Locker locker(_lock);
|
||||
bool toReturn = false;
|
||||
for (const auto& device : _registeredDevices) {
|
||||
toReturn = toReturn || device.second->triggerHapticPulse(strength, duration, hand);
|
||||
toReturn = device.second->triggerHapticPulse(strength, duration, hand) || toReturn;
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
@ -1237,16 +1240,42 @@ void UserInputMapper::disableMapping(const Mapping::Pointer& mapping) {
|
|||
}
|
||||
|
||||
void UserInputMapper::setActionState(Action action, float value, bool valid) {
|
||||
Locker locker(_lock);
|
||||
_actionStates[toInt(action)] = value;
|
||||
_actionStatesValid[toInt(action)] = valid;
|
||||
}
|
||||
|
||||
void UserInputMapper::deltaActionState(Action action, float delta, bool valid) {
|
||||
Locker locker(_lock);
|
||||
_actionStates[toInt(action)] += delta;
|
||||
bool wasValid = _actionStatesValid[toInt(action)];
|
||||
_actionStatesValid[toInt(action)] = wasValid & valid;
|
||||
}
|
||||
|
||||
float UserInputMapper::getActionState(Action action) const {
|
||||
Locker locker(_lock);
|
||||
|
||||
int index = toInt(action);
|
||||
if (index >= 0 && index < _actionStates.size()) {
|
||||
return _actionStates[index];
|
||||
}
|
||||
|
||||
qCDebug(controllers) << "UserInputMapper::getActionState invalid action:" << index;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
bool UserInputMapper::getActionStateValid(Action action) const {
|
||||
Locker locker(_lock);
|
||||
|
||||
int index = toInt(action);
|
||||
if (index >= 0 && index < _actionStatesValid.size()) {
|
||||
return _actionStatesValid[index];
|
||||
}
|
||||
|
||||
qCDebug(controllers) << "UserInputMapper::getActionStateValid invalid action:" << index;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -81,8 +81,8 @@ namespace controller {
|
|||
QVector<Action> getAllActions() const;
|
||||
QString getActionName(Action action) const;
|
||||
QString getStandardPoseName(uint16_t pose);
|
||||
float getActionState(Action action) const { return _actionStates[toInt(action)]; }
|
||||
bool getActionStateValid(Action action) const { return _actionStatesValid[toInt(action)]; }
|
||||
float getActionState(Action action) const;
|
||||
bool getActionStateValid(Action action) const;
|
||||
Pose getPoseState(Action action) const;
|
||||
int findAction(const QString& actionName) const;
|
||||
QVector<QString> getActionNames() const;
|
||||
|
|
|
@ -34,7 +34,7 @@ class HTTPManager : public QTcpServer, public HTTPRequestHandler {
|
|||
public:
|
||||
/// Initializes the manager.
|
||||
HTTPManager(const QHostAddress& listenAddress, quint16 port, const QString& documentRoot, HTTPRequestHandler* requestHandler = nullptr);
|
||||
|
||||
|
||||
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler = false) override;
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -1446,14 +1446,17 @@ void EntityTree::addCertifiedEntityOnServer(EntityItemPointer entity) {
|
|||
entityList << entityItemID; // adds to list within hash because entityList is a reference.
|
||||
qCDebug(entities) << "Certificate ID" << certID << "belongs to" << entityItemID << "total" << entityList.size() << "entities.";
|
||||
}
|
||||
// Delete an already-existing entity from the tree if it has the same
|
||||
// Handle an already-existing entity from the tree if it has the same
|
||||
// CertificateID as the entity we're trying to add.
|
||||
if (!existingEntityItemID.isNull()) {
|
||||
qCDebug(entities) << "Certificate ID" << certID << "already exists on entity with ID"
|
||||
<< existingEntityItemID << ". Deleting existing entity.";
|
||||
withWriteLock([&] {
|
||||
deleteEntity(existingEntityItemID, true);
|
||||
});
|
||||
<< existingEntityItemID << ". No action will be taken to remove it.";
|
||||
// FIXME: All certificate checking needs to be moved to its own files,
|
||||
// then the deletion settings need to have a toggle for domain owners
|
||||
// and a setting to change the verification service provider.
|
||||
// withWriteLock([&] {
|
||||
// deleteEntity(existingEntityItemID, true);
|
||||
// });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1527,10 +1530,13 @@ void EntityTree::startDynamicDomainVerificationOnServer(float minimumAgeToRemove
|
|||
continue;
|
||||
}
|
||||
qCDebug(entities) << "Entity's cert's domain ID" << jsonObject["domain_id"].toString()
|
||||
<< "doesn't match the current Domain ID" << thisDomainID << "; deleting entity" << entityID;
|
||||
withWriteLock([&] {
|
||||
deleteEntity(entityID, true);
|
||||
});
|
||||
<< "doesn't match the current Domain ID" << thisDomainID << ". No action will be taken to remove it: " << entityID;
|
||||
// FIXME: All certificate checking needs to be moved to its own files,
|
||||
// then the deletion settings need to have a toggle for domain owners
|
||||
// and a setting to change the verification service provider.
|
||||
// withWriteLock([&] {
|
||||
// deleteEntity(entityID, true);
|
||||
// });
|
||||
}
|
||||
{
|
||||
QWriteLocker entityCertificateIDMapLocker(&_entityCertificateIDMapLock);
|
||||
|
@ -1555,10 +1561,13 @@ void EntityTree::startChallengeOwnershipTimer(const EntityItemID& entityItemID)
|
|||
}
|
||||
});
|
||||
connect(_challengeOwnershipTimeoutTimer, &QTimer::timeout, this, [=]() {
|
||||
qCDebug(entities) << "Ownership challenge timed out, deleting entity" << entityItemID;
|
||||
withWriteLock([&] {
|
||||
deleteEntity(entityItemID, true);
|
||||
});
|
||||
qCDebug(entities) << "Ownership challenge timed out for entity " << entityItemID << ". No action will be taken to remove it.";
|
||||
// FIXME: All certificate checking needs to be moved to its own files,
|
||||
// then the deletion settings need to have a toggle for domain owners
|
||||
// and a setting to change the verification service provider.
|
||||
// withWriteLock([&] {
|
||||
// deleteEntity(entityItemID, true);
|
||||
// });
|
||||
if (_challengeOwnershipTimeoutTimer) {
|
||||
_challengeOwnershipTimeoutTimer->stop();
|
||||
_challengeOwnershipTimeoutTimer->deleteLater();
|
||||
|
@ -1650,10 +1659,13 @@ void EntityTree::sendChallengeOwnershipPacket(const QString& certID, const QStri
|
|||
QByteArray text = computeNonce(entityItemID, ownerKey);
|
||||
|
||||
if (text == "") {
|
||||
qCDebug(entities) << "CRITICAL ERROR: Couldn't compute nonce. Deleting entity...";
|
||||
withWriteLock([&] {
|
||||
deleteEntity(entityItemID, true);
|
||||
});
|
||||
qCDebug(entities) << "CRITICAL ERROR: Couldn't compute nonce. No action will be taken to remove this entity.";
|
||||
// FIXME: All certificate checking needs to be moved to its own files,
|
||||
// then the deletion settings need to have a toggle for domain owners
|
||||
// and a setting to change the verification service provider.
|
||||
// withWriteLock([&] {
|
||||
// deleteEntity(entityItemID, true);
|
||||
// });
|
||||
} else {
|
||||
qCDebug(entities) << "Challenging ownership of Cert ID" << certID;
|
||||
// 2. Send the nonce to the rezzing avatar's node
|
||||
|
@ -1724,15 +1736,21 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
|
|||
|
||||
if (networkReply->error() == QNetworkReply::NoError) {
|
||||
if (!jsonObject["invalid_reason"].toString().isEmpty()) {
|
||||
qCDebug(entities) << "invalid_reason not empty, deleting entity" << entityItemID;
|
||||
withWriteLock([&] {
|
||||
deleteEntity(entityItemID, true);
|
||||
});
|
||||
qCDebug(entities) << "invalid_reason not empty, no action will be taken to delete entity" << entityItemID;
|
||||
// FIXME: All certificate checking needs to be moved to its own files,
|
||||
// then the deletion settings need to have a toggle for domain owners
|
||||
// and a setting to change the verification service provider.
|
||||
// withWriteLock([&] {
|
||||
// deleteEntity(entityItemID, true);
|
||||
// });
|
||||
} else if (jsonObject["transfer_status"].toArray().first().toString() == "failed") {
|
||||
qCDebug(entities) << "'transfer_status' is 'failed', deleting entity" << entityItemID;
|
||||
withWriteLock([&] {
|
||||
deleteEntity(entityItemID, true);
|
||||
});
|
||||
qCDebug(entities) << "'transfer_status' is 'failed', no action will be taken to delete entity" << entityItemID;
|
||||
// FIXME: All certificate checking needs to be moved to its own files,
|
||||
// then the deletion settings need to have a toggle for domain owners
|
||||
// and a setting to change the verification service provider.
|
||||
// withWriteLock([&] {
|
||||
// deleteEntity(entityItemID, true);
|
||||
// });
|
||||
} else {
|
||||
// Second, challenge ownership of the PoP cert
|
||||
// (ignore pending status; a failure will be cleaned up during DDV)
|
||||
|
@ -1742,11 +1760,14 @@ void EntityTree::validatePop(const QString& certID, const EntityItemID& entityIt
|
|||
senderNode);
|
||||
}
|
||||
} else {
|
||||
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; deleting entity" << entityItemID
|
||||
qCDebug(entities) << "Call to" << networkReply->url() << "failed with error" << networkReply->error() << "; no action will be taken to delete entity" << entityItemID
|
||||
<< "More info:" << jsonObject;
|
||||
withWriteLock([&] {
|
||||
deleteEntity(entityItemID, true);
|
||||
});
|
||||
// FIXME: All certificate checking needs to be moved to its own files,
|
||||
// then the deletion settings need to have a toggle for domain owners
|
||||
// and a setting to change the verification service provider.
|
||||
// withWriteLock([&] {
|
||||
// deleteEntity(entityItemID, true);
|
||||
// });
|
||||
}
|
||||
|
||||
networkReply->deleteLater();
|
||||
|
|
|
@ -211,6 +211,7 @@ void DomainHandler::setURLAndID(QUrl domainURL, QUuid domainID) {
|
|||
// if it's in the error state, reset and try again.
|
||||
if (_domainURL != domainURL
|
||||
|| (_sockAddr.getPort() != domainPort && domainURL.scheme() == URL_SCHEME_HIFI)
|
||||
|| isServerless() // For reloading content in serverless domain.
|
||||
|| _isInErrorState) {
|
||||
// re-set the domain info so that auth information is reloaded
|
||||
hardReset("Changing domain URL");
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
#include "NetworkingConstants.h"
|
||||
#include "MetaverseAPI.h"
|
||||
|
||||
const unsigned short DEFAULT_DOMAIN_SERVER_PORT =
|
||||
const unsigned short DEFAULT_DOMAIN_SERVER_PORT =
|
||||
QProcessEnvironment::systemEnvironment()
|
||||
.contains("HIFI_DOMAIN_SERVER_PORT")
|
||||
? QProcessEnvironment::systemEnvironment()
|
||||
|
@ -41,7 +41,7 @@ const unsigned short DEFAULT_DOMAIN_SERVER_PORT =
|
|||
.toUShort()
|
||||
: 40102;
|
||||
|
||||
const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT =
|
||||
const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT =
|
||||
QProcessEnvironment::systemEnvironment()
|
||||
.contains("HIFI_DOMAIN_SERVER_DTLS_PORT")
|
||||
? QProcessEnvironment::systemEnvironment()
|
||||
|
@ -49,7 +49,7 @@ const unsigned short DEFAULT_DOMAIN_SERVER_DTLS_PORT =
|
|||
.toUShort()
|
||||
: 40103;
|
||||
|
||||
const quint16 DOMAIN_SERVER_HTTP_PORT =
|
||||
const quint16 DOMAIN_SERVER_HTTP_PORT =
|
||||
QProcessEnvironment::systemEnvironment()
|
||||
.contains("HIFI_DOMAIN_SERVER_HTTP_PORT")
|
||||
? QProcessEnvironment::systemEnvironment()
|
||||
|
@ -57,7 +57,7 @@ const quint16 DOMAIN_SERVER_HTTP_PORT =
|
|||
.toUInt()
|
||||
: 40100;
|
||||
|
||||
const quint16 DOMAIN_SERVER_HTTPS_PORT =
|
||||
const quint16 DOMAIN_SERVER_HTTPS_PORT =
|
||||
QProcessEnvironment::systemEnvironment()
|
||||
.contains("HIFI_DOMAIN_SERVER_HTTPS_PORT")
|
||||
? QProcessEnvironment::systemEnvironment()
|
||||
|
@ -65,6 +65,15 @@ const quint16 DOMAIN_SERVER_HTTPS_PORT =
|
|||
.toUInt()
|
||||
: 40101;
|
||||
|
||||
const quint16 DOMAIN_SERVER_EXPORTER_PORT =
|
||||
QProcessEnvironment::systemEnvironment()
|
||||
.contains("VIRCADIA_DOMAIN_SERVER_EXPORTER_PORT")
|
||||
? QProcessEnvironment::systemEnvironment()
|
||||
.value("VIRCADIA_DOMAIN_SERVER_EXPORTER_PORT")
|
||||
.toUInt()
|
||||
: 9703;
|
||||
|
||||
|
||||
const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
|
||||
|
||||
class DomainHandler : public QObject {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// libraries/networking/src
|
||||
//
|
||||
// Created by Kalila (kasenvr) on 2019-12-16.
|
||||
// Copyright 2019 Project Athena
|
||||
// Copyright 2019 Vircadia
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// libraries/networking/src
|
||||
//
|
||||
// Created by Kalila (kasenvr) on 2019-12-16.
|
||||
// Copyright 2019 Project Athena
|
||||
// Copyright 2019 Vircadia
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
|
|
@ -27,6 +27,28 @@ namespace NetworkingConstants {
|
|||
|
||||
const QUrl METAVERSE_SERVER_URL_STABLE { "https://metaverse.highfidelity.com" };
|
||||
const QUrl METAVERSE_SERVER_URL_STAGING { "https://staging-metaverse.vircadia.com" };
|
||||
|
||||
// Web Engine requests to this parent domain have an account authorization header added
|
||||
const QString AUTH_HOSTNAME_BASE = "highfidelity.com";
|
||||
|
||||
const QUrl BUILDS_XML_URL("https://highfidelity.com/builds.xml");
|
||||
const QUrl MASTER_BUILDS_XML_URL("https://highfidelity.com/dev-builds.xml");
|
||||
|
||||
|
||||
#if USE_STABLE_GLOBAL_SERVICES
|
||||
const QString ICE_SERVER_DEFAULT_HOSTNAME = "ice.highfidelity.com";
|
||||
#else
|
||||
const QString ICE_SERVER_DEFAULT_HOSTNAME = "dev-ice.highfidelity.com";
|
||||
#endif
|
||||
|
||||
const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";
|
||||
|
||||
const QUrl HELP_DOCS_URL { "https://docs.vircadia.dev" };
|
||||
const QUrl HELP_FORUM_URL { "https://forums.vircadia.dev" };
|
||||
const QUrl HELP_SCRIPTING_REFERENCE_URL{ "https://apidocs.vircadia.dev/" };
|
||||
const QUrl HELP_RELEASE_NOTES_URL{ "https://docs.vircadia.dev/release-notes.html" };
|
||||
const QUrl HELP_BUG_REPORT_URL{ "https://github.com/kasenvr/project-athena/issues" };
|
||||
|
||||
}
|
||||
|
||||
const QString HIFI_URL_SCHEME_ABOUT = "about";
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace {
|
|||
auto metaverseServerURL = MetaverseAPI::getCurrentMetaverseServerURL();
|
||||
static const QStringList HF_HOSTS = {
|
||||
"highfidelity.com", "highfidelity.io",
|
||||
metaverseServerURL.toString(), "metaverse.highfidelity.io"
|
||||
metaverseServerURL.toString(),
|
||||
};
|
||||
const auto& scheme = url.scheme();
|
||||
const auto& host = url.host();
|
||||
|
|
|
@ -281,6 +281,7 @@ void LeapMotionPlugin::InputDevice::update(float deltaTime, const controller::In
|
|||
|
||||
glm::vec3 pos;
|
||||
glm::quat rot;
|
||||
glm::quat prevRot;
|
||||
if (_isLeapOnHMD) {
|
||||
auto jointPosition = joints[i].position;
|
||||
const glm::vec3 HMD_EYE_TO_LEAP_OFFSET = glm::vec3(0.0f, 0.0f, -0.09f); // Eyes to surface of Leap Motion.
|
||||
|
@ -291,17 +292,24 @@ void LeapMotionPlugin::InputDevice::update(float deltaTime, const controller::In
|
|||
glm::quat jointOrientation = joints[i].orientation;
|
||||
jointOrientation = glm::quat(jointOrientation.w, -jointOrientation.x, -jointOrientation.z, -jointOrientation.y);
|
||||
rot = controllerToAvatarRotation * hmdSensorOrientation * jointOrientation;
|
||||
|
||||
glm::quat prevJointOrientation = prevJoints[i].orientation;
|
||||
prevJointOrientation =
|
||||
glm::quat(prevJointOrientation.w, -prevJointOrientation.x, -prevJointOrientation.z, -prevJointOrientation.y);
|
||||
prevRot = controllerToAvatarRotation * hmdSensorOrientation * prevJointOrientation;
|
||||
|
||||
} else {
|
||||
pos = controllerToAvatarRotation * (joints[i].position - leapMotionOffset);
|
||||
const glm::quat ZERO_HAND_ORIENTATION = glm::quat(glm::vec3(PI_OVER_TWO, PI, 0.0f));
|
||||
rot = controllerToAvatarRotation * joints[i].orientation * ZERO_HAND_ORIENTATION;
|
||||
prevRot = controllerToAvatarRotation * prevJoints[i].orientation * ZERO_HAND_ORIENTATION;
|
||||
}
|
||||
|
||||
glm::vec3 linearVelocity, angularVelocity;
|
||||
if (i < prevJoints.size()) {
|
||||
linearVelocity = (pos - (prevJoints[i].position * METERS_PER_CENTIMETER)) / deltaTime; // m/s
|
||||
// quat log imaginary part points along the axis of rotation, with length of one half the angle of rotation.
|
||||
glm::quat d = glm::log(rot * glm::inverse(prevJoints[i].orientation));
|
||||
glm::quat d = glm::log(rot * glm::inverse(prevRot));
|
||||
angularVelocity = glm::vec3(d.x, d.y, d.z) / (0.5f * deltaTime); // radians/s
|
||||
}
|
||||
|
||||
|
|
|
@ -15,5 +15,7 @@ if (WIN32 AND (NOT USE_GLES))
|
|||
include_hifi_library_headers(octree)
|
||||
|
||||
target_openvr()
|
||||
target_sranipal()
|
||||
target_aristo()
|
||||
target_link_libraries(${TARGET_NAME} Winmm.lib)
|
||||
endif()
|
||||
|
|
|
@ -13,6 +13,21 @@
|
|||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4091 )
|
||||
#pragma warning( disable : 4334 )
|
||||
#endif
|
||||
|
||||
#include <SRanipal.h>
|
||||
#include <SRanipal_Eye.h>
|
||||
#include <SRanipal_Enums.h>
|
||||
#include <interface_gesture.hpp>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <PathUtils.h>
|
||||
#include <GeometryCache.h>
|
||||
|
@ -37,6 +52,8 @@
|
|||
#include <Plugins/InputConfiguration.h>
|
||||
#include <controllers/StandardControls.h>
|
||||
|
||||
#include "OpenVrDisplayPlugin.h"
|
||||
|
||||
extern PoseData _nextSimPoseData;
|
||||
|
||||
vr::IVRSystem* acquireOpenVrSystem();
|
||||
|
@ -62,6 +79,32 @@ static const int SECOND_FOOT = 1;
|
|||
static const int HIP = 2;
|
||||
static const int CHEST = 3;
|
||||
|
||||
enum ViveHandJointIndex {
|
||||
HAND = 0,
|
||||
THUMB_1,
|
||||
THUMB_2,
|
||||
THUMB_3,
|
||||
THUMB_4,
|
||||
INDEX_1,
|
||||
INDEX_2,
|
||||
INDEX_3,
|
||||
INDEX_4,
|
||||
MIDDLE_1,
|
||||
MIDDLE_2,
|
||||
MIDDLE_3,
|
||||
MIDDLE_4,
|
||||
RING_1,
|
||||
RING_2,
|
||||
RING_3,
|
||||
RING_4,
|
||||
PINKY_1,
|
||||
PINKY_2,
|
||||
PINKY_3,
|
||||
PINKY_4,
|
||||
|
||||
Size
|
||||
};
|
||||
|
||||
const char* ViveControllerManager::NAME { "OpenVR" };
|
||||
|
||||
const std::map<vr::ETrackingResult, QString> TRACKING_RESULT_TO_STRING = {
|
||||
|
@ -130,6 +173,51 @@ static glm::mat4 calculateResetMat() {
|
|||
return glm::mat4();
|
||||
}
|
||||
|
||||
class ViveProEyeReadThread : public QThread {
|
||||
public:
|
||||
ViveProEyeReadThread() {
|
||||
setObjectName("OpenVR ViveProEye Read Thread");
|
||||
}
|
||||
void run() override {
|
||||
while (!quit) {
|
||||
ViveSR::anipal::Eye::EyeData eyeData;
|
||||
int result = ViveSR::anipal::Eye::GetEyeData(&eyeData);
|
||||
{
|
||||
QMutexLocker locker(&eyeDataMutex);
|
||||
eyeDataBuffer.getEyeDataResult = result;
|
||||
if (result == ViveSR::Error::WORK) {
|
||||
uint64_t leftValids = eyeData.verbose_data.left.eye_data_validata_bit_mask;
|
||||
uint64_t rightValids = eyeData.verbose_data.right.eye_data_validata_bit_mask;
|
||||
|
||||
eyeDataBuffer.leftDirectionValid =
|
||||
(leftValids & (uint64_t)ViveSR::anipal::Eye::SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY) > (uint64_t)0;
|
||||
eyeDataBuffer.rightDirectionValid =
|
||||
(rightValids & (uint64_t)ViveSR::anipal::Eye::SINGLE_EYE_DATA_GAZE_DIRECTION_VALIDITY) > (uint64_t)0;
|
||||
eyeDataBuffer.leftOpennessValid =
|
||||
(leftValids & (uint64_t)ViveSR::anipal::Eye::SINGLE_EYE_DATA_EYE_OPENNESS_VALIDITY) > (uint64_t)0;
|
||||
eyeDataBuffer.rightOpennessValid =
|
||||
(rightValids & (uint64_t)ViveSR::anipal::Eye::SINGLE_EYE_DATA_EYE_OPENNESS_VALIDITY) > (uint64_t)0;
|
||||
|
||||
float *leftGaze = eyeData.verbose_data.left.gaze_direction_normalized.elem_;
|
||||
float *rightGaze = eyeData.verbose_data.right.gaze_direction_normalized.elem_;
|
||||
eyeDataBuffer.leftEyeGaze = glm::vec3(leftGaze[0], leftGaze[1], leftGaze[2]);
|
||||
eyeDataBuffer.rightEyeGaze = glm::vec3(rightGaze[0], rightGaze[1], rightGaze[2]);
|
||||
|
||||
eyeDataBuffer.leftEyeOpenness = eyeData.verbose_data.left.eye_openness;
|
||||
eyeDataBuffer.rightEyeOpenness = eyeData.verbose_data.right.eye_openness;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool quit { false };
|
||||
|
||||
// mutex and buffer for moving data from this thread to the other one
|
||||
QMutex eyeDataMutex;
|
||||
EyeDataBuffer eyeDataBuffer;
|
||||
};
|
||||
|
||||
|
||||
static QString outOfRangeDataStrategyToString(ViveControllerManager::OutOfRangeDataStrategy strategy) {
|
||||
switch (strategy) {
|
||||
default:
|
||||
|
@ -211,6 +299,81 @@ QString ViveControllerManager::configurationLayout() {
|
|||
return OPENVR_LAYOUT;
|
||||
}
|
||||
|
||||
bool isDeviceIndexActive(vr::IVRSystem*& system, uint32_t deviceIndex) {
|
||||
if (!system) {
|
||||
return false;
|
||||
}
|
||||
if (deviceIndex != vr::k_unTrackedDeviceIndexInvalid &&
|
||||
system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller &&
|
||||
system->IsTrackedDeviceConnected(deviceIndex)) {
|
||||
vr::EDeviceActivityLevel activityLevel = system->GetTrackedDeviceActivityLevel(deviceIndex);
|
||||
if (activityLevel == vr::k_EDeviceActivityLevel_UserInteraction) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isHandControllerActive(vr::IVRSystem*& system, vr::ETrackedControllerRole deviceRole) {
|
||||
if (!system) {
|
||||
return false;
|
||||
}
|
||||
auto deviceIndex = system->GetTrackedDeviceIndexForControllerRole(deviceRole);
|
||||
return isDeviceIndexActive(system, deviceIndex);
|
||||
}
|
||||
|
||||
bool areBothHandControllersActive(vr::IVRSystem*& system) {
|
||||
return
|
||||
isHandControllerActive(system, vr::TrackedControllerRole_LeftHand) &&
|
||||
isHandControllerActive(system, vr::TrackedControllerRole_RightHand);
|
||||
}
|
||||
|
||||
|
||||
void ViveControllerManager::enableGestureDetection() {
|
||||
if (_viveCameraHandTracker) {
|
||||
return;
|
||||
}
|
||||
if (!ViveSR::anipal::Eye::IsViveProEye()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// #define HAND_TRACKER_USE_EXTERNAL_TRANSFORM 1
|
||||
|
||||
#ifdef HAND_TRACKER_USE_EXTERNAL_TRANSFORM
|
||||
UseExternalTransform(true); // camera hand tracker results are in HMD frame
|
||||
#else
|
||||
UseExternalTransform(false); // camera hand tracker results are in sensor frame
|
||||
#endif
|
||||
GestureOption options; // defaults are GestureBackendAuto and GestureModeSkeleton
|
||||
GestureFailure gestureFailure = StartGestureDetection(&options);
|
||||
switch (gestureFailure) {
|
||||
case GestureFailureNone:
|
||||
qDebug() << "StartGestureDetection success";
|
||||
_viveCameraHandTracker = true;
|
||||
break;
|
||||
case GestureFailureOpenCL:
|
||||
qDebug() << "StartGestureDetection (Only on Windows) OpenCL is not supported on the machine";
|
||||
break;
|
||||
case GestureFailureCamera:
|
||||
qDebug() << "StartGestureDetection Start camera failed";
|
||||
break;
|
||||
case GestureFailureInternal:
|
||||
qDebug() << "StartGestureDetection Internal errors";
|
||||
break;
|
||||
case GestureFailureCPUOnPC:
|
||||
qDebug() << "StartGestureDetection CPU backend is not supported on Windows";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ViveControllerManager::disableGestureDetection() {
|
||||
if (!_viveCameraHandTracker) {
|
||||
return;
|
||||
}
|
||||
StopGestureDetection();
|
||||
_viveCameraHandTracker = false;
|
||||
}
|
||||
|
||||
bool ViveControllerManager::activate() {
|
||||
InputPlugin::activate();
|
||||
|
||||
|
@ -230,6 +393,28 @@ bool ViveControllerManager::activate() {
|
|||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->registerDevice(_inputDevice);
|
||||
_registeredWithInputMapper = true;
|
||||
|
||||
if (ViveSR::anipal::Eye::IsViveProEye()) {
|
||||
qDebug() << "Vive Pro eye-tracking detected";
|
||||
|
||||
int error = ViveSR::anipal::Initial(ViveSR::anipal::Eye::ANIPAL_TYPE_EYE, NULL);
|
||||
if (error == ViveSR::Error::WORK) {
|
||||
_viveProEye = true;
|
||||
qDebug() << "Successfully initialize Eye engine.";
|
||||
} else if (error == ViveSR::Error::RUNTIME_NOT_FOUND) {
|
||||
_viveProEye = false;
|
||||
qDebug() << "please follows SRanipal SDK guide to install SR_Runtime first";
|
||||
} else {
|
||||
_viveProEye = false;
|
||||
qDebug() << "Failed to initialize Eye engine. please refer to ViveSR error code:" << error;
|
||||
}
|
||||
|
||||
if (_viveProEye) {
|
||||
_viveProEyeReadThread = std::make_shared<ViveProEyeReadThread>();
|
||||
_viveProEyeReadThread->start(QThread::HighPriority);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -251,6 +436,13 @@ void ViveControllerManager::deactivate() {
|
|||
userInputMapper->removeDevice(_inputDevice->_deviceID);
|
||||
_registeredWithInputMapper = false;
|
||||
|
||||
if (_viveProEyeReadThread) {
|
||||
_viveProEyeReadThread->quit = true;
|
||||
_viveProEyeReadThread->wait();
|
||||
_viveProEyeReadThread = nullptr;
|
||||
ViveSR::anipal::Release(ViveSR::anipal::Eye::ANIPAL_TYPE_EYE);
|
||||
}
|
||||
|
||||
saveSettings();
|
||||
}
|
||||
|
||||
|
@ -262,6 +454,317 @@ bool ViveControllerManager::isHeadControllerMounted() const {
|
|||
return activityLevel == vr::k_EDeviceActivityLevel_UserInteraction;
|
||||
}
|
||||
|
||||
void ViveControllerManager::invalidateEyeInputs() {
|
||||
_inputDevice->_poseStateMap[controller::LEFT_EYE].valid = false;
|
||||
_inputDevice->_poseStateMap[controller::RIGHT_EYE].valid = false;
|
||||
_inputDevice->_axisStateMap[controller::EYEBLINK_L].valid = false;
|
||||
_inputDevice->_axisStateMap[controller::EYEBLINK_R].valid = false;
|
||||
}
|
||||
|
||||
|
||||
void ViveControllerManager::updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
if (!isHeadControllerMounted()) {
|
||||
invalidateEyeInputs();
|
||||
return;
|
||||
}
|
||||
|
||||
EyeDataBuffer eyeDataBuffer;
|
||||
{
|
||||
// GetEyeData takes around 4ms to finish, so we run it on a thread.
|
||||
QMutexLocker locker(&_viveProEyeReadThread->eyeDataMutex);
|
||||
memcpy(&eyeDataBuffer, &_viveProEyeReadThread->eyeDataBuffer, sizeof(eyeDataBuffer));
|
||||
}
|
||||
|
||||
if (eyeDataBuffer.getEyeDataResult != ViveSR::Error::WORK) {
|
||||
invalidateEyeInputs();
|
||||
return;
|
||||
}
|
||||
|
||||
// only update from buffer values if the new data is "valid"
|
||||
if (!eyeDataBuffer.leftDirectionValid) {
|
||||
eyeDataBuffer.leftEyeGaze = _prevEyeData.leftEyeGaze;
|
||||
eyeDataBuffer.leftDirectionValid = _prevEyeData.leftDirectionValid;
|
||||
}
|
||||
if (!eyeDataBuffer.rightDirectionValid) {
|
||||
eyeDataBuffer.rightEyeGaze = _prevEyeData.rightEyeGaze;
|
||||
eyeDataBuffer.rightDirectionValid = _prevEyeData.rightDirectionValid;
|
||||
}
|
||||
if (!eyeDataBuffer.leftOpennessValid) {
|
||||
eyeDataBuffer.leftEyeOpenness = _prevEyeData.leftEyeOpenness;
|
||||
eyeDataBuffer.leftOpennessValid = _prevEyeData.leftOpennessValid;
|
||||
}
|
||||
if (!eyeDataBuffer.rightOpennessValid) {
|
||||
eyeDataBuffer.rightEyeOpenness = _prevEyeData.rightEyeOpenness;
|
||||
eyeDataBuffer.rightOpennessValid = _prevEyeData.rightOpennessValid;
|
||||
}
|
||||
_prevEyeData = eyeDataBuffer;
|
||||
|
||||
// transform data into what the controller system expects.
|
||||
|
||||
// in the data from sranipal, left=+x, up=+y, forward=+z
|
||||
mat4 localLeftEyeMat = glm::lookAt(vec3(0.0f, 0.0f, 0.0f),
|
||||
glm::vec3(eyeDataBuffer.leftEyeGaze[0],
|
||||
eyeDataBuffer.leftEyeGaze[1],
|
||||
-eyeDataBuffer.leftEyeGaze[2]),
|
||||
vec3(0.0f, 1.0f, 0.0f));
|
||||
quat localLeftEyeRot = glm::quat_cast(localLeftEyeMat);
|
||||
quat avatarLeftEyeRot = _inputDevice->_poseStateMap[controller::HEAD].rotation * localLeftEyeRot;
|
||||
|
||||
mat4 localRightEyeMat = glm::lookAt(vec3(0.0f, 0.0f, 0.0f),
|
||||
glm::vec3(eyeDataBuffer.rightEyeGaze[0],
|
||||
eyeDataBuffer.rightEyeGaze[1],
|
||||
-eyeDataBuffer.rightEyeGaze[2]),
|
||||
vec3(0.0f, 1.0f, 0.0f));
|
||||
quat localRightEyeRot = glm::quat_cast(localRightEyeMat);
|
||||
quat avatarRightEyeRot = _inputDevice->_poseStateMap[controller::HEAD].rotation * localRightEyeRot;
|
||||
|
||||
// TODO -- figure out translations for eyes
|
||||
if (eyeDataBuffer.leftDirectionValid) {
|
||||
_inputDevice->_poseStateMap[controller::LEFT_EYE] = controller::Pose(glm::vec3(), avatarLeftEyeRot);
|
||||
_inputDevice->_poseStateMap[controller::LEFT_EYE].valid = true;
|
||||
} else {
|
||||
_inputDevice->_poseStateMap[controller::LEFT_EYE].valid = false;
|
||||
}
|
||||
if (eyeDataBuffer.rightDirectionValid) {
|
||||
_inputDevice->_poseStateMap[controller::RIGHT_EYE] = controller::Pose(glm::vec3(), avatarRightEyeRot);
|
||||
_inputDevice->_poseStateMap[controller::RIGHT_EYE].valid = true;
|
||||
} else {
|
||||
_inputDevice->_poseStateMap[controller::RIGHT_EYE].valid = false;
|
||||
}
|
||||
|
||||
quint64 now = usecTimestampNow();
|
||||
|
||||
// in hifi, 0 is open 1 is closed. in SRanipal 1 is open, 0 is closed.
|
||||
if (eyeDataBuffer.leftOpennessValid) {
|
||||
_inputDevice->_axisStateMap[controller::EYEBLINK_L] =
|
||||
controller::AxisValue(1.0f - eyeDataBuffer.leftEyeOpenness, now);
|
||||
} else {
|
||||
_inputDevice->_poseStateMap[controller::EYEBLINK_L].valid = false;
|
||||
}
|
||||
if (eyeDataBuffer.rightOpennessValid) {
|
||||
_inputDevice->_axisStateMap[controller::EYEBLINK_R] =
|
||||
controller::AxisValue(1.0f - eyeDataBuffer.rightEyeOpenness, now);
|
||||
} else {
|
||||
_inputDevice->_poseStateMap[controller::EYEBLINK_R].valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 ViveControllerManager::getRollingAverageHandPoint(int handIndex, int pointIndex) const {
|
||||
#if 0
|
||||
return _handPoints[0][handIndex][pointIndex];
|
||||
#else
|
||||
glm::vec3 result;
|
||||
for (int s = 0; s < NUMBER_OF_HAND_TRACKER_SMOOTHING_FRAMES; s++) {
|
||||
result += _handPoints[s][handIndex][pointIndex];
|
||||
}
|
||||
return result / NUMBER_OF_HAND_TRACKER_SMOOTHING_FRAMES;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
controller::Pose ViveControllerManager::trackedHandDataToPose(int hand, const glm::vec3& palmFacing,
|
||||
int nearHandPositionIndex, int farHandPositionIndex) {
|
||||
glm::vec3 nearPoint = getRollingAverageHandPoint(hand, nearHandPositionIndex);
|
||||
|
||||
glm::quat poseRot;
|
||||
if (nearHandPositionIndex != farHandPositionIndex) {
|
||||
glm::vec3 farPoint = getRollingAverageHandPoint(hand, farHandPositionIndex);
|
||||
|
||||
glm::vec3 pointingDir = farPoint - nearPoint; // y axis
|
||||
glm::vec3 otherAxis = glm::cross(pointingDir, palmFacing);
|
||||
|
||||
glm::mat4 rotMat;
|
||||
rotMat = glm::mat4(glm::vec4(otherAxis, 0.0f),
|
||||
glm::vec4(pointingDir, 0.0f),
|
||||
glm::vec4(palmFacing * (hand == 0 ? 1.0f : -1.0f), 0.0f),
|
||||
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
poseRot = glm::normalize(glmExtractRotation(rotMat));
|
||||
}
|
||||
|
||||
if (!isNaN(poseRot)) {
|
||||
controller::Pose pose(nearPoint, poseRot);
|
||||
return pose;
|
||||
} else {
|
||||
controller::Pose pose;
|
||||
pose.valid = false;
|
||||
return pose;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ViveControllerManager::trackFinger(int hand, int jointIndex1, int jointIndex2, int jointIndex3, int jointIndex4,
|
||||
controller::StandardPoseChannel joint1, controller::StandardPoseChannel joint2,
|
||||
controller::StandardPoseChannel joint3, controller::StandardPoseChannel joint4) {
|
||||
|
||||
glm::vec3 point1 = getRollingAverageHandPoint(hand, jointIndex1);
|
||||
glm::vec3 point2 = getRollingAverageHandPoint(hand, jointIndex2);
|
||||
glm::vec3 point3 = getRollingAverageHandPoint(hand, jointIndex3);
|
||||
glm::vec3 point4 = getRollingAverageHandPoint(hand, jointIndex4);
|
||||
|
||||
glm::vec3 wristPos = getRollingAverageHandPoint(hand, ViveHandJointIndex::HAND);
|
||||
glm::vec3 thumb2 = getRollingAverageHandPoint(hand, ViveHandJointIndex::THUMB_2);
|
||||
glm::vec3 pinkie1 = getRollingAverageHandPoint(hand, ViveHandJointIndex::PINKY_1);
|
||||
|
||||
// 1st
|
||||
glm::vec3 palmFacing = glm::normalize(glm::cross(pinkie1 - wristPos, thumb2 - wristPos));
|
||||
glm::vec3 handForward = glm::normalize(point1 - wristPos);
|
||||
glm::vec3 x = glm::normalize(glm::cross(palmFacing, handForward));
|
||||
glm::vec3 y = glm::normalize(point2 - point1);
|
||||
glm::vec3 z = (hand == 0) ? glm::cross(y, x) : glm::cross(x, y);
|
||||
glm::mat4 rotMat1 = glm::mat4(glm::vec4(x, 0.0f),
|
||||
glm::vec4(y, 0.0f),
|
||||
glm::vec4(z, 0.0f),
|
||||
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
glm::quat rot1 = glm::normalize(glmExtractRotation(rotMat1));
|
||||
if (!isNaN(rot1)) {
|
||||
_inputDevice->_poseStateMap[joint1] = controller::Pose(point1, rot1);
|
||||
}
|
||||
|
||||
|
||||
// 2nd
|
||||
glm::vec3 x2 = x; // glm::normalize(glm::cross(point3 - point2, point2 - point1));
|
||||
glm::vec3 y2 = glm::normalize(point3 - point2);
|
||||
glm::vec3 z2 = (hand == 0) ? glm::cross(y2, x2) : glm::cross(x2, y2);
|
||||
|
||||
glm::mat4 rotMat2 = glm::mat4(glm::vec4(x2, 0.0f),
|
||||
glm::vec4(y2, 0.0f),
|
||||
glm::vec4(z2, 0.0f),
|
||||
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
glm::quat rot2 = glm::normalize(glmExtractRotation(rotMat2));
|
||||
if (!isNaN(rot2)) {
|
||||
_inputDevice->_poseStateMap[joint2] = controller::Pose(point2, rot2);
|
||||
}
|
||||
|
||||
|
||||
// 3rd
|
||||
glm::vec3 x3 = x; // glm::normalize(glm::cross(point4 - point3, point3 - point1));
|
||||
glm::vec3 y3 = glm::normalize(point4 - point3);
|
||||
glm::vec3 z3 = (hand == 0) ? glm::cross(y3, x3) : glm::cross(x3, y3);
|
||||
|
||||
glm::mat4 rotMat3 = glm::mat4(glm::vec4(x3, 0.0f),
|
||||
glm::vec4(y3, 0.0f),
|
||||
glm::vec4(z3, 0.0f),
|
||||
glm::vec4(0.0f, 0.0f, 0.0f, 1.0f));
|
||||
glm::quat rot3 = glm::normalize(glmExtractRotation(rotMat3));
|
||||
if (!isNaN(rot3)) {
|
||||
_inputDevice->_poseStateMap[joint3] = controller::Pose(point3, rot3);
|
||||
}
|
||||
|
||||
|
||||
// 4th
|
||||
glm::quat rot4 = rot3;
|
||||
if (!isNaN(rot4)) {
|
||||
_inputDevice->_poseStateMap[joint4] = controller::Pose(point4, rot4);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ViveControllerManager::updateCameraHandTracker(float deltaTime,
|
||||
const controller::InputCalibrationData& inputCalibrationData) {
|
||||
|
||||
if (areBothHandControllersActive(_system)) {
|
||||
// if both hand-controllers are in use, don't do camera hand tracking
|
||||
disableGestureDetection();
|
||||
} else {
|
||||
enableGestureDetection();
|
||||
}
|
||||
|
||||
if (!_viveCameraHandTracker) {
|
||||
return;
|
||||
}
|
||||
|
||||
const GestureResult* results = NULL;
|
||||
int handTrackerFrameIndex { -1 };
|
||||
int resultsHandCount = GetGestureResult(&results, &handTrackerFrameIndex);
|
||||
|
||||
// FIXME: Why the commented-out condition?
|
||||
if (handTrackerFrameIndex >= 0 /* && handTrackerFrameIndex != _lastHandTrackerFrameIndex */) {
|
||||
#ifdef HAND_TRACKER_USE_EXTERNAL_TRANSFORM
|
||||
glm::mat4 trackedHandToAvatar =
|
||||
glm::inverse(inputCalibrationData.avatarMat) *
|
||||
inputCalibrationData.sensorToWorldMat *
|
||||
inputCalibrationData.hmdSensorMat;
|
||||
// glm::mat4 trackedHandToAvatar = _inputDevice->_poseStateMap[controller::HEAD].getMatrix() * Matrices::Y_180;
|
||||
#else
|
||||
DisplayPluginPointer displayPlugin = _container->getActiveDisplayPlugin();
|
||||
std::shared_ptr<OpenVrDisplayPlugin> openVRDisplayPlugin =
|
||||
std::dynamic_pointer_cast<OpenVrDisplayPlugin>(displayPlugin);
|
||||
glm::mat4 sensorResetMatrix;
|
||||
if (openVRDisplayPlugin) {
|
||||
sensorResetMatrix = openVRDisplayPlugin->getSensorResetMatrix();
|
||||
}
|
||||
|
||||
glm::mat4 trackedHandToAvatar =
|
||||
glm::inverse(inputCalibrationData.avatarMat) *
|
||||
inputCalibrationData.sensorToWorldMat *
|
||||
sensorResetMatrix;
|
||||
#endif
|
||||
|
||||
// roll all the old points in the rolling average
|
||||
memmove(&(_handPoints[1]),
|
||||
&(_handPoints[0]),
|
||||
sizeof(_handPoints[0]) * (NUMBER_OF_HAND_TRACKER_SMOOTHING_FRAMES - 1));
|
||||
|
||||
for (int handIndex = 0; handIndex < resultsHandCount; handIndex++) {
|
||||
bool isLeftHand = results[handIndex].isLeft;
|
||||
|
||||
vr::ETrackedControllerRole controllerRole =
|
||||
isLeftHand ? vr::TrackedControllerRole_LeftHand : vr::TrackedControllerRole_RightHand;
|
||||
if (isHandControllerActive(_system, controllerRole)) {
|
||||
continue; // if the controller for this hand is tracked, ignore camera hand tracking
|
||||
}
|
||||
|
||||
int hand = isLeftHand ? 0 : 1;
|
||||
for (int pointIndex = 0; pointIndex < NUMBER_OF_HAND_POINTS; pointIndex++) {
|
||||
glm::vec3 pos(results[handIndex].points[3 * pointIndex],
|
||||
results[handIndex].points[3 * pointIndex + 1],
|
||||
-results[handIndex].points[3 * pointIndex + 2]);
|
||||
_handPoints[0][hand][pointIndex] = transformPoint(trackedHandToAvatar, pos);
|
||||
}
|
||||
|
||||
glm::vec3 wristPos = getRollingAverageHandPoint(hand, ViveHandJointIndex::HAND);
|
||||
glm::vec3 thumb2 = getRollingAverageHandPoint(hand, ViveHandJointIndex::THUMB_2);
|
||||
glm::vec3 pinkie1 = getRollingAverageHandPoint(hand, ViveHandJointIndex::PINKY_1);
|
||||
glm::vec3 palmFacing = glm::cross(pinkie1 - wristPos, thumb2 - wristPos); // z axis
|
||||
|
||||
_inputDevice->_poseStateMap[isLeftHand ? controller::LEFT_HAND : controller::RIGHT_HAND] =
|
||||
trackedHandDataToPose(hand, palmFacing, ViveHandJointIndex::HAND, ViveHandJointIndex::MIDDLE_1);
|
||||
trackFinger(hand, ViveHandJointIndex::THUMB_1, ViveHandJointIndex::THUMB_2, ViveHandJointIndex::THUMB_3,
|
||||
ViveHandJointIndex::THUMB_4,
|
||||
isLeftHand ? controller::LEFT_HAND_THUMB1 : controller::RIGHT_HAND_THUMB1,
|
||||
isLeftHand ? controller::LEFT_HAND_THUMB2 : controller::RIGHT_HAND_THUMB2,
|
||||
isLeftHand ? controller::LEFT_HAND_THUMB3 : controller::RIGHT_HAND_THUMB3,
|
||||
isLeftHand ? controller::LEFT_HAND_THUMB4 : controller::RIGHT_HAND_THUMB4);
|
||||
trackFinger(hand, ViveHandJointIndex::INDEX_1, ViveHandJointIndex::INDEX_2, ViveHandJointIndex::INDEX_3,
|
||||
ViveHandJointIndex::INDEX_4,
|
||||
isLeftHand ? controller::LEFT_HAND_INDEX1 : controller::RIGHT_HAND_INDEX1,
|
||||
isLeftHand ? controller::LEFT_HAND_INDEX2 : controller::RIGHT_HAND_INDEX2,
|
||||
isLeftHand ? controller::LEFT_HAND_INDEX3 : controller::RIGHT_HAND_INDEX3,
|
||||
isLeftHand ? controller::LEFT_HAND_INDEX4 : controller::RIGHT_HAND_INDEX4);
|
||||
trackFinger(hand, ViveHandJointIndex::MIDDLE_1, ViveHandJointIndex::MIDDLE_2, ViveHandJointIndex::MIDDLE_3,
|
||||
ViveHandJointIndex::MIDDLE_4,
|
||||
isLeftHand ? controller::LEFT_HAND_MIDDLE1 : controller::RIGHT_HAND_MIDDLE1,
|
||||
isLeftHand ? controller::LEFT_HAND_MIDDLE2 : controller::RIGHT_HAND_MIDDLE2,
|
||||
isLeftHand ? controller::LEFT_HAND_MIDDLE3 : controller::RIGHT_HAND_MIDDLE3,
|
||||
isLeftHand ? controller::LEFT_HAND_MIDDLE4 : controller::RIGHT_HAND_MIDDLE4);
|
||||
trackFinger(hand, ViveHandJointIndex::RING_1, ViveHandJointIndex::RING_2, ViveHandJointIndex::RING_3,
|
||||
ViveHandJointIndex::RING_4,
|
||||
isLeftHand ? controller::LEFT_HAND_RING1 : controller::RIGHT_HAND_RING1,
|
||||
isLeftHand ? controller::LEFT_HAND_RING2 : controller::RIGHT_HAND_RING2,
|
||||
isLeftHand ? controller::LEFT_HAND_RING3 : controller::RIGHT_HAND_RING3,
|
||||
isLeftHand ? controller::LEFT_HAND_RING4 : controller::RIGHT_HAND_RING4);
|
||||
trackFinger(hand, ViveHandJointIndex::PINKY_1, ViveHandJointIndex::PINKY_2, ViveHandJointIndex::PINKY_3,
|
||||
ViveHandJointIndex::PINKY_4,
|
||||
isLeftHand ? controller::LEFT_HAND_PINKY1 : controller::RIGHT_HAND_PINKY1,
|
||||
isLeftHand ? controller::LEFT_HAND_PINKY2 : controller::RIGHT_HAND_PINKY2,
|
||||
isLeftHand ? controller::LEFT_HAND_PINKY3 : controller::RIGHT_HAND_PINKY3,
|
||||
isLeftHand ? controller::LEFT_HAND_PINKY4 : controller::RIGHT_HAND_PINKY4);
|
||||
}
|
||||
}
|
||||
_lastHandTrackerFrameIndex = handTrackerFrameIndex;
|
||||
}
|
||||
|
||||
|
||||
void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) {
|
||||
|
||||
if (!_system) {
|
||||
|
@ -297,6 +800,12 @@ void ViveControllerManager::pluginUpdate(float deltaTime, const controller::Inpu
|
|||
userInputMapper->registerDevice(_inputDevice);
|
||||
_registeredWithInputMapper = true;
|
||||
}
|
||||
|
||||
if (_viveProEye) {
|
||||
updateEyeTracker(deltaTime, inputCalibrationData);
|
||||
}
|
||||
|
||||
updateCameraHandTracker(deltaTime, inputCalibrationData);
|
||||
}
|
||||
|
||||
void ViveControllerManager::loadSettings() {
|
||||
|
@ -830,9 +1339,7 @@ void ViveControllerManager::InputDevice::handleHmd(uint32_t deviceIndex, const c
|
|||
|
||||
void ViveControllerManager::InputDevice::handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand) {
|
||||
|
||||
if (_system->IsTrackedDeviceConnected(deviceIndex) &&
|
||||
_system->GetTrackedDeviceClass(deviceIndex) == vr::TrackedDeviceClass_Controller &&
|
||||
_nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid) {
|
||||
if (isDeviceIndexActive(_system, deviceIndex) && _nextSimPoseData.vrPoses[deviceIndex].bPoseIsValid) {
|
||||
|
||||
// process pose
|
||||
const mat4& mat = _nextSimPoseData.poses[deviceIndex];
|
||||
|
@ -1401,9 +1908,52 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI
|
|||
makePair(LEFT_GRIP, "LeftGrip"),
|
||||
makePair(RIGHT_GRIP, "RightGrip"),
|
||||
|
||||
// 3d location of controller
|
||||
// 3d location of left controller and fingers
|
||||
makePair(LEFT_HAND, "LeftHand"),
|
||||
makePair(LEFT_HAND_THUMB1, "LeftHandThumb1"),
|
||||
makePair(LEFT_HAND_THUMB2, "LeftHandThumb2"),
|
||||
makePair(LEFT_HAND_THUMB3, "LeftHandThumb3"),
|
||||
makePair(LEFT_HAND_THUMB4, "LeftHandThumb4"),
|
||||
makePair(LEFT_HAND_INDEX1, "LeftHandIndex1"),
|
||||
makePair(LEFT_HAND_INDEX2, "LeftHandIndex2"),
|
||||
makePair(LEFT_HAND_INDEX3, "LeftHandIndex3"),
|
||||
makePair(LEFT_HAND_INDEX4, "LeftHandIndex4"),
|
||||
makePair(LEFT_HAND_MIDDLE1, "LeftHandMiddle1"),
|
||||
makePair(LEFT_HAND_MIDDLE2, "LeftHandMiddle2"),
|
||||
makePair(LEFT_HAND_MIDDLE3, "LeftHandMiddle3"),
|
||||
makePair(LEFT_HAND_MIDDLE4, "LeftHandMiddle4"),
|
||||
makePair(LEFT_HAND_RING1, "LeftHandRing1"),
|
||||
makePair(LEFT_HAND_RING2, "LeftHandRing2"),
|
||||
makePair(LEFT_HAND_RING3, "LeftHandRing3"),
|
||||
makePair(LEFT_HAND_RING4, "LeftHandRing4"),
|
||||
makePair(LEFT_HAND_PINKY1, "LeftHandPinky1"),
|
||||
makePair(LEFT_HAND_PINKY2, "LeftHandPinky2"),
|
||||
makePair(LEFT_HAND_PINKY3, "LeftHandPinky3"),
|
||||
makePair(LEFT_HAND_PINKY4, "LeftHandPinky4"),
|
||||
|
||||
// 3d location of right controller and fingers
|
||||
makePair(RIGHT_HAND, "RightHand"),
|
||||
makePair(RIGHT_HAND_THUMB1, "RightHandThumb1"),
|
||||
makePair(RIGHT_HAND_THUMB2, "RightHandThumb2"),
|
||||
makePair(RIGHT_HAND_THUMB3, "RightHandThumb3"),
|
||||
makePair(RIGHT_HAND_THUMB4, "RightHandThumb4"),
|
||||
makePair(RIGHT_HAND_INDEX1, "RightHandIndex1"),
|
||||
makePair(RIGHT_HAND_INDEX2, "RightHandIndex2"),
|
||||
makePair(RIGHT_HAND_INDEX3, "RightHandIndex3"),
|
||||
makePair(RIGHT_HAND_INDEX4, "RightHandIndex4"),
|
||||
makePair(RIGHT_HAND_MIDDLE1, "RightHandMiddle1"),
|
||||
makePair(RIGHT_HAND_MIDDLE2, "RightHandMiddle2"),
|
||||
makePair(RIGHT_HAND_MIDDLE3, "RightHandMiddle3"),
|
||||
makePair(RIGHT_HAND_MIDDLE4, "RightHandMiddle4"),
|
||||
makePair(RIGHT_HAND_RING1, "RightHandRing1"),
|
||||
makePair(RIGHT_HAND_RING2, "RightHandRing2"),
|
||||
makePair(RIGHT_HAND_RING3, "RightHandRing3"),
|
||||
makePair(RIGHT_HAND_RING4, "RightHandRing4"),
|
||||
makePair(RIGHT_HAND_PINKY1, "RightHandPinky1"),
|
||||
makePair(RIGHT_HAND_PINKY2, "RightHandPinky2"),
|
||||
makePair(RIGHT_HAND_PINKY3, "RightHandPinky3"),
|
||||
makePair(RIGHT_HAND_PINKY4, "RightHandPinky4"),
|
||||
|
||||
makePair(LEFT_FOOT, "LeftFoot"),
|
||||
makePair(RIGHT_FOOT, "RightFoot"),
|
||||
makePair(HIPS, "Hips"),
|
||||
|
@ -1411,6 +1961,10 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI
|
|||
makePair(HEAD, "Head"),
|
||||
makePair(LEFT_ARM, "LeftArm"),
|
||||
makePair(RIGHT_ARM, "RightArm"),
|
||||
makePair(LEFT_EYE, "LeftEye"),
|
||||
makePair(RIGHT_EYE, "RightEye"),
|
||||
makePair(EYEBLINK_L, "EyeBlink_L"),
|
||||
makePair(EYEBLINK_R, "EyeBlink_R"),
|
||||
|
||||
// 16 tracked poses
|
||||
makePair(TRACKED_OBJECT_00, "TrackedObject00"),
|
||||
|
|
|
@ -31,6 +31,23 @@ namespace vr {
|
|||
class IVRSystem;
|
||||
}
|
||||
|
||||
class ViveProEyeReadThread;
|
||||
|
||||
class EyeDataBuffer {
|
||||
public:
|
||||
int getEyeDataResult { 0 };
|
||||
bool leftDirectionValid { false };
|
||||
bool rightDirectionValid { false };
|
||||
bool leftOpennessValid { false };
|
||||
bool rightOpennessValid { false };
|
||||
glm::vec3 leftEyeGaze;
|
||||
glm::vec3 rightEyeGaze;
|
||||
float leftEyeOpenness { 0.0f };
|
||||
float rightEyeOpenness { 0.0f };
|
||||
};
|
||||
|
||||
|
||||
|
||||
class ViveControllerManager : public InputPlugin {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
@ -49,12 +66,18 @@ public:
|
|||
bool isHeadController() const override { return true; }
|
||||
bool isHeadControllerMounted() const;
|
||||
|
||||
void enableGestureDetection();
|
||||
void disableGestureDetection();
|
||||
|
||||
bool activate() override;
|
||||
void deactivate() override;
|
||||
|
||||
QString getDeviceName() { return QString::fromStdString(_inputDevice->_headsetName); }
|
||||
|
||||
void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
|
||||
void invalidateEyeInputs();
|
||||
void updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData);
|
||||
void updateCameraHandTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData);
|
||||
void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
|
||||
|
||||
virtual void saveSettings() const override;
|
||||
|
@ -229,6 +252,23 @@ private:
|
|||
vr::IVRSystem* _system { nullptr };
|
||||
std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_system) };
|
||||
|
||||
bool _viveProEye { false };
|
||||
std::shared_ptr<ViveProEyeReadThread> _viveProEyeReadThread;
|
||||
EyeDataBuffer _prevEyeData;
|
||||
|
||||
bool _viveCameraHandTracker { false };
|
||||
int _lastHandTrackerFrameIndex { -1 };
|
||||
|
||||
const static int NUMBER_OF_HAND_TRACKER_SMOOTHING_FRAMES { 6 };
|
||||
const static int NUMBER_OF_HAND_POINTS { 21 };
|
||||
glm::vec3 _handPoints[NUMBER_OF_HAND_TRACKER_SMOOTHING_FRAMES][2][NUMBER_OF_HAND_POINTS]; // 2 for number of hands
|
||||
glm::vec3 getRollingAverageHandPoint(int handIndex, int pointIndex) const;
|
||||
controller::Pose trackedHandDataToPose(int hand, const glm::vec3& palmFacing,
|
||||
int nearHandPositionIndex, int farHandPositionIndex);
|
||||
void trackFinger(int hand, int jointIndex1, int jointIndex2, int jointIndex3, int jointIndex4,
|
||||
controller::StandardPoseChannel joint1, controller::StandardPoseChannel joint2,
|
||||
controller::StandardPoseChannel joint3, controller::StandardPoseChannel joint4);
|
||||
|
||||
static const char* NAME;
|
||||
};
|
||||
|
||||
|
|
|
@ -34,7 +34,8 @@ var DEFAULT_SCRIPTS_COMBINED = [
|
|||
"system/miniTablet.js",
|
||||
"system/audioMuteOverlay.js",
|
||||
"system/inspect.js",
|
||||
"system/keyboardShortcuts/keyboardShortcuts.js"
|
||||
"system/keyboardShortcuts/keyboardShortcuts.js",
|
||||
"system/hand-track-walk.js"
|
||||
];
|
||||
var DEFAULT_SCRIPTS_SEPARATE = [
|
||||
"system/controllers/controllerScripts.js",
|
||||
|
|
|
@ -35,7 +35,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
var DEBUG = false;
|
||||
var SHOW_GRAB_SPHERE = false;
|
||||
|
||||
|
||||
if (typeof Test !== "undefined") {
|
||||
PROFILE = true;
|
||||
}
|
||||
|
@ -54,6 +53,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
this.pointerManager = new PointerManager();
|
||||
this.grabSphereOverlays = [null, null];
|
||||
this.targetIDs = {};
|
||||
this.debugPanelID = null;
|
||||
this.debugLines = [];
|
||||
|
||||
// a module can occupy one or more "activity" slots while it's running. If all the required slots for a module are
|
||||
// not set to false (not in use), a module cannot start. When a module is using a slot, that module's name
|
||||
|
@ -97,11 +98,15 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
};
|
||||
|
||||
this.runningPluginNames = {};
|
||||
|
||||
this.leftTriggerValue = 0;
|
||||
this.leftTriggerClicked = 0;
|
||||
this.leftTrackerClicked = false; // is leftTriggerClicked == 1 because a hand tracker set it?
|
||||
this.leftSecondaryValue = 0;
|
||||
|
||||
this.rightTriggerValue = 0;
|
||||
this.rightTriggerClicked = 0;
|
||||
this.leftSecondaryValue = 0;
|
||||
this.rightTrackerClicked = false; // is rightTriggerClicked == 1 because a hand tracker set it?
|
||||
this.rightSecondaryValue = 0;
|
||||
|
||||
this.leftTriggerPress = function (value) {
|
||||
|
@ -162,6 +167,38 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
}
|
||||
};
|
||||
|
||||
this.checkForHandTrackingClick = function() {
|
||||
|
||||
var pinchOnBelowDistance = 0.016;
|
||||
var pinchOffAboveDistance = 0.035;
|
||||
|
||||
var leftIndexPose = Controller.getPoseValue(Controller.Standard.LeftHandIndex4);
|
||||
var leftThumbPose = Controller.getPoseValue(Controller.Standard.LeftHandThumb4);
|
||||
var leftThumbToIndexDistance = Vec3.distance(leftIndexPose.translation, leftThumbPose.translation);
|
||||
if (leftIndexPose.valid && leftThumbPose.valid && leftThumbToIndexDistance < pinchOnBelowDistance) {
|
||||
_this.leftTriggerClicked = 1;
|
||||
_this.leftTriggerValue = 1;
|
||||
_this.leftTrackerClicked = true;
|
||||
} else if (_this.leftTrackerClicked && leftThumbToIndexDistance > pinchOffAboveDistance) {
|
||||
_this.leftTriggerClicked = 0;
|
||||
_this.leftTriggerValue = 0;
|
||||
_this.leftTrackerClicked = false;
|
||||
}
|
||||
|
||||
var rightIndexPose = Controller.getPoseValue(Controller.Standard.RightHandIndex4);
|
||||
var rightThumbPose = Controller.getPoseValue(Controller.Standard.RightHandThumb4);
|
||||
var rightThumbToIndexDistance = Vec3.distance(rightIndexPose.translation, rightThumbPose.translation);
|
||||
if (rightIndexPose.valid && rightThumbPose.valid && rightThumbToIndexDistance < pinchOnBelowDistance) {
|
||||
_this.rightTriggerClicked = 1;
|
||||
_this.rightTriggerValue = 1;
|
||||
_this.rightTrackerClicked = true;
|
||||
} else if (_this.rightTrackerClicked && rightThumbToIndexDistance > pinchOffAboveDistance) {
|
||||
_this.rightTriggerClicked = 0;
|
||||
_this.rightTriggerValue = 0;
|
||||
_this.rightTrackerClicked = false;
|
||||
}
|
||||
};
|
||||
|
||||
this.update = function () {
|
||||
try {
|
||||
_this.updateInternal();
|
||||
|
@ -171,6 +208,18 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
Script.setTimeout(_this.update, BASIC_TIMER_INTERVAL_MS);
|
||||
};
|
||||
|
||||
this.addDebugLine = function(line) {
|
||||
if (this.debugLines.length > 8) {
|
||||
this.debugLines.shift();
|
||||
}
|
||||
this.debugLines.push(line);
|
||||
var debugPanelText = "";
|
||||
this.debugLines.forEach(function(debugLine) {
|
||||
debugPanelText += debugLine + "\n";
|
||||
});
|
||||
Entities.editEntity(this.debugPanelID, { text: debugPanelText });
|
||||
};
|
||||
|
||||
this.updateInternal = function () {
|
||||
if (PROFILE) {
|
||||
Script.beginProfileRange("dispatch.pre");
|
||||
|
@ -274,6 +323,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
}
|
||||
|
||||
var nearbyEntityIDs = Entities.findEntities(controllerPosition, findRadius);
|
||||
|
||||
for (var j = 0; j < nearbyEntityIDs.length; j++) {
|
||||
var entityID = nearbyEntityIDs[j];
|
||||
var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
|
||||
|
@ -369,6 +419,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
}
|
||||
}
|
||||
|
||||
// check for hand-tracking "click"
|
||||
_this.checkForHandTrackingClick();
|
||||
|
||||
// bundle up all the data about the current situation
|
||||
var controllerData = {
|
||||
triggerValues: [_this.leftTriggerValue, _this.rightTriggerValue],
|
||||
|
@ -406,7 +459,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
_this.markSlots(candidatePlugin, orderedPluginName);
|
||||
_this.pointerManager.makePointerVisible(candidatePlugin.parameters.handLaser);
|
||||
if (DEBUG) {
|
||||
print("controllerDispatcher running " + orderedPluginName);
|
||||
_this.addDebugLine("running " + orderedPluginName);
|
||||
}
|
||||
}
|
||||
if (PROFILE) {
|
||||
|
@ -438,8 +491,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
|
||||
if (DEBUG) {
|
||||
if (JSON.stringify(_this.targetIDs[runningPluginName]) != JSON.stringify(runningness.targets)) {
|
||||
print("controllerDispatcher targetIDs[" + runningPluginName + "] = " +
|
||||
JSON.stringify(runningness.targets));
|
||||
_this.addDebugLine("targetIDs[" + runningPluginName + "] = " +
|
||||
JSON.stringify(runningness.targets));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -450,12 +503,12 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
delete _this.runningPluginNames[runningPluginName];
|
||||
delete _this.targetIDs[runningPluginName];
|
||||
if (DEBUG) {
|
||||
print("controllerDispatcher deleted targetIDs[" + runningPluginName + "]");
|
||||
_this.addDebugLine("deleted targetIDs[" + runningPluginName + "]");
|
||||
}
|
||||
_this.markSlots(plugin, false);
|
||||
_this.pointerManager.makePointerInvisible(plugin.parameters.handLaser);
|
||||
if (DEBUG) {
|
||||
print("controllerDispatcher stopping " + runningPluginName);
|
||||
_this.addDebugLine("stopping " + runningPluginName);
|
||||
}
|
||||
}
|
||||
_this.pointerManager.lockPointerEnd(plugin.parameters.handLaser, runningness.laserLockInfo);
|
||||
|
@ -599,7 +652,33 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
Overlays.mousePressOnOverlay.disconnect(mousePress);
|
||||
Entities.mousePressOnEntity.disconnect(mousePress);
|
||||
Messages.messageReceived.disconnect(controllerDispatcher.handleMessage);
|
||||
if (_this.debugPanelID) {
|
||||
Entities.deleteEntity(_this.debugPanelID);
|
||||
_this.debugPanelID = null;
|
||||
}
|
||||
};
|
||||
|
||||
if (DEBUG) {
|
||||
this.debugPanelID = Entities.addEntity({
|
||||
name: "controllerDispatcher debug panel",
|
||||
type: "Text",
|
||||
dimensions: { x: 1.0, y: 0.3, z: 0.01 },
|
||||
parentID: MyAvatar.sessionUUID,
|
||||
// parentJointIndex: MyAvatar.getJointIndex("_CAMERA_MATRIX"),
|
||||
parentJointIndex: -1,
|
||||
localPosition: { x: -0.25, y: 0.8, z: -1.2 },
|
||||
textColor: { red: 255, green: 255, blue: 255},
|
||||
backgroundColor: { red: 0, green: 0, blue: 0},
|
||||
text: "",
|
||||
lineHeight: 0.03,
|
||||
leftMargin: 0.015,
|
||||
topMargin: 0.01,
|
||||
backgroundAlpha: 0.7,
|
||||
textAlpha: 1.0,
|
||||
unlit: true,
|
||||
ignorePickIntersection: true
|
||||
}, "local");
|
||||
}
|
||||
}
|
||||
|
||||
function mouseReleaseOnOverlay(overlayID, event) {
|
||||
|
@ -629,6 +708,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
Messages.subscribe('Hifi-Hand-RayPick-Blacklist');
|
||||
Messages.messageReceived.connect(controllerDispatcher.handleMessage);
|
||||
|
||||
Script.scriptEnding.connect(controllerDispatcher.cleanup);
|
||||
Script.scriptEnding.connect(function () {
|
||||
controllerDispatcher.cleanup();
|
||||
});
|
||||
Script.setTimeout(controllerDispatcher.update, BASIC_TIMER_INTERVAL_MS);
|
||||
}());
|
||||
|
|
|
@ -17,7 +17,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
this.hand = hand;
|
||||
this.disableModules = false;
|
||||
this.parameters = makeDispatcherModuleParameters(
|
||||
90,
|
||||
95,
|
||||
this.hand === RIGHT_HAND ?
|
||||
["rightHand", "rightHandEquip", "rightHandTrigger"] :
|
||||
["leftHand", "leftHandEquip", "leftHandTrigger"],
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
|
||||
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD,
|
||||
Picks, makeLaserLockInfo, makeLaserParams, AddressManager, getEntityParents, Selection, DISPATCHER_HOVERING_LIST,
|
||||
worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, Uuid, Picks
|
||||
worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, Uuid, Picks, handsAreTracked, Messages
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -374,6 +374,9 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
|
||||
this.isReady = function (controllerData) {
|
||||
if (HMD.active) {
|
||||
if (handsAreTracked()) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
if (this.notPointingAtEntity(controllerData)) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC,
|
||||
projectOntoEntityXYPlane, ContextOverlay, HMD, Picks, makeLaserLockInfo, makeLaserParams, AddressManager,
|
||||
getEntityParents, Selection, DISPATCHER_HOVERING_LIST, unhighlightTargetEntity, Messages, findGrabbableGroupParent,
|
||||
worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES
|
||||
worldPositionToRegistrationFrameMatrix, DISPATCHER_PROPERTIES, handsAreTracked
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -63,7 +63,6 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.endedGrab = 0;
|
||||
this.MIN_HAPTIC_PULSE_INTERVAL = 500; // ms
|
||||
this.disabled = false;
|
||||
var _this = this;
|
||||
this.initialControllerRotation = Quat.IDENTITY;
|
||||
this.currentControllerRotation = Quat.IDENTITY;
|
||||
this.manipulating = false;
|
||||
|
@ -99,7 +98,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
|
||||
this.getOffhand = function () {
|
||||
return (this.hand === RIGHT_HAND ? LEFT_HAND : RIGHT_HAND);
|
||||
}
|
||||
};
|
||||
|
||||
// Activation criteria for rotating a fargrabbed entity. If we're changing the mapping, this is where to do it.
|
||||
this.shouldManipulateTarget = function (controllerData) {
|
||||
|
@ -406,6 +405,9 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
|
||||
this.isReady = function (controllerData) {
|
||||
if (HMD.active) {
|
||||
if (handsAreTracked()) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
if (this.notPointingAtEntity(controllerData)) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
/* global Script, RIGHT_HAND, LEFT_HAND, MyAvatar,
|
||||
makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters,
|
||||
getGrabbableData, makeLaserParams, DISPATCHER_PROPERTIES
|
||||
getGrabbableData, makeLaserParams, DISPATCHER_PROPERTIES, RayPick, handsAreTracked
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -63,6 +63,9 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
|
||||
this.isReady = function (controllerData) {
|
||||
this.targetEntityID = null;
|
||||
if (handsAreTracked()) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
if (controllerData.triggerClicks[this.hand] === 0) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.run = function (controllerData, deltaTime) {
|
||||
|
||||
if (this.grabbing) {
|
||||
if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE &&
|
||||
if (!controllerData.triggerClicks[this.hand] &&
|
||||
controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
this.endNearGrabEntity();
|
||||
return makeRunningValues(false, [], []);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
/* global Script, MyAvatar, Controller, Uuid, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
|
||||
makeRunningValues, Vec3, makeDispatcherModuleParameters, Overlays, HMD, Settings, getEnabledModuleByName, Pointers,
|
||||
Picks, PickType
|
||||
Picks, PickType, Keyboard
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -52,22 +52,21 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.disable = false;
|
||||
|
||||
this.otherModuleNeedsToRun = function(controllerData) {
|
||||
var grabOverlayModuleName = this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay";
|
||||
var grabOverlayModule = getEnabledModuleByName(grabOverlayModuleName);
|
||||
var grabEntityModuleName = this.hand === RIGHT_HAND ? "RightNearParentingGrabEntity" : "LeftNearParentingGrabEntity";
|
||||
var grabEntityModuleName = this.hand === RIGHT_HAND ? "RightNearGrabEntity" : "LeftNearGrabEntity";
|
||||
var grabEntityModule = getEnabledModuleByName(grabEntityModuleName);
|
||||
var grabOverlayModuleReady = grabOverlayModule ? grabOverlayModule.isReady(controllerData) : makeRunningValues(false, [], []);
|
||||
var grabEntityModuleReady = grabEntityModule ? grabEntityModule.isReady(controllerData) : makeRunningValues(false, [], []);
|
||||
var farGrabModuleName = this.hand === RIGHT_HAND ? "RightFarActionGrabEntity" : "LeftFarActionGrabEntity";
|
||||
|
||||
var farGrabModuleName = this.hand === RIGHT_HAND ? "RightFarGrabEntity" : "LeftFarGrabEntity";
|
||||
var farGrabModule = getEnabledModuleByName(farGrabModuleName);
|
||||
var farGrabModuleReady = farGrabModule ? farGrabModule.isReady(controllerData) : makeRunningValues(false, [], []);
|
||||
|
||||
var nearTabletHighlightModuleName =
|
||||
this.hand === RIGHT_HAND ? "RightNearTabletHighlight" : "LeftNearTabletHighlight";
|
||||
var nearTabletHighlightModule = getEnabledModuleByName(nearTabletHighlightModuleName);
|
||||
var nearTabletHighlightModuleReady = nearTabletHighlightModule
|
||||
? nearTabletHighlightModule.isReady(controllerData) : makeRunningValues(false, [], []);
|
||||
return grabOverlayModuleReady.active || farGrabModuleReady.active || grabEntityModuleReady.active
|
||||
|| nearTabletHighlightModuleReady.active;
|
||||
var nearTabletHighlightModuleReady = nearTabletHighlightModule ?
|
||||
nearTabletHighlightModule.isReady(controllerData) : makeRunningValues(false, [], []);
|
||||
|
||||
return farGrabModuleReady.active || grabEntityModuleReady.active;
|
||||
};
|
||||
|
||||
this.overlayLaserActive = function(controllerData) {
|
||||
|
@ -121,14 +120,15 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
}
|
||||
|
||||
// Add the mini tablet.
|
||||
if (HMD.miniTabletScreenID && Overlays.getProperty(HMD.miniTabletScreenID, "visible")) {
|
||||
if (HMD.miniTabletScreenID && Overlays.getProperty(HMD.miniTabletScreenID, "visible") &&
|
||||
this.hand != HMD.miniTabletHand) {
|
||||
stylusTarget = getOverlayDistance(controllerPosition, HMD.miniTabletScreenID);
|
||||
if (stylusTarget) {
|
||||
stylusTargets.push(stylusTarget);
|
||||
}
|
||||
}
|
||||
|
||||
const WEB_DISPLAY_STYLUS_DISTANCE = (Keyboard.raised && Keyboard.preferMalletsOverLasers) ? 0.2 : 0.5;
|
||||
var WEB_DISPLAY_STYLUS_DISTANCE = (Keyboard.raised && Keyboard.preferMalletsOverLasers) ? 0.2 : 0.5;
|
||||
var nearStylusTarget = isNearStylusTarget(stylusTargets, WEB_DISPLAY_STYLUS_DISTANCE * sensorScaleFactor);
|
||||
|
||||
if (nearStylusTarget.length !== 0) {
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
"use strict";
|
||||
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
/* global Script, makeRunningValues, enableDispatcherModule, disableDispatcherModule,
|
||||
makeDispatcherModuleParameters, handsAreTracked, Controller, Vec3, Tablet, HMD, MyAvatar
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
Script.include("/~/system/libraries/controllers.js");
|
||||
|
||||
(function() {
|
||||
|
||||
function TrackedHandTablet() {
|
||||
this.mappingName = 'hand-track-tablet-' + Math.random();
|
||||
this.inputMapping = Controller.newMapping(this.mappingName);
|
||||
this.leftIndexPos = null;
|
||||
this.leftThumbPos = null;
|
||||
this.rightIndexPos = null;
|
||||
this.rightThumbPos = null;
|
||||
this.touchOnBelowDistance = 0.016;
|
||||
this.touchOffAboveDistance = 0.045;
|
||||
|
||||
this.gestureCompleted = false;
|
||||
this.previousGestureCompleted = false;
|
||||
|
||||
this.parameters = makeDispatcherModuleParameters(
|
||||
70,
|
||||
["rightHand", "leftHand"],
|
||||
[],
|
||||
100);
|
||||
|
||||
this.checkForGesture = function () {
|
||||
if (this.leftThumbPos && this.leftIndexPos && this.rightThumbPos && this.rightIndexPos) {
|
||||
var leftTipDistance = Vec3.distance(this.leftThumbPos, this.leftIndexPos);
|
||||
var rightTipDistance = Vec3.distance(this.rightThumbPos, this.rightIndexPos);
|
||||
if (leftTipDistance < this.touchOnBelowDistance && rightTipDistance < this.touchOnBelowDistance) {
|
||||
this.gestureCompleted = true;
|
||||
} else if (leftTipDistance > this.touchOffAboveDistance || rightTipDistance > this.touchOffAboveDistance) {
|
||||
this.gestureCompleted = false;
|
||||
} // else don't change gestureCompleted
|
||||
} else {
|
||||
this.gestureCompleted = false;
|
||||
}
|
||||
|
||||
if (this.gestureCompleted && !this.previousGestureCompleted) {
|
||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||
if (HMD.showTablet) {
|
||||
HMD.closeTablet(false);
|
||||
} else if (!HMD.showTablet && !tablet.toolbarMode && !MyAvatar.isAway) {
|
||||
tablet.gotoHomeScreen();
|
||||
HMD.openTablet(false);
|
||||
}
|
||||
}
|
||||
|
||||
this.previousGestureCompleted = this.gestureCompleted;
|
||||
};
|
||||
|
||||
this.leftIndexChanged = function (pose) {
|
||||
if (pose.valid) {
|
||||
this.leftIndexPos = pose.translation;
|
||||
} else {
|
||||
this.leftIndexPos = null;
|
||||
}
|
||||
this.checkForGesture();
|
||||
};
|
||||
|
||||
this.leftThumbChanged = function (pose) {
|
||||
if (pose.valid) {
|
||||
this.leftThumbPos = pose.translation;
|
||||
} else {
|
||||
this.leftThumbPos = null;
|
||||
}
|
||||
this.checkForGesture();
|
||||
};
|
||||
|
||||
this.rightIndexChanged = function (pose) {
|
||||
if (pose.valid) {
|
||||
this.rightIndexPos = pose.translation;
|
||||
} else {
|
||||
this.rightIndexPos = null;
|
||||
}
|
||||
this.checkForGesture();
|
||||
};
|
||||
|
||||
this.rightThumbChanged = function (pose) {
|
||||
if (pose.valid) {
|
||||
this.rightThumbPos = pose.translation;
|
||||
} else {
|
||||
this.rightThumbPos = null;
|
||||
}
|
||||
this.checkForGesture();
|
||||
};
|
||||
|
||||
this.isReady = function (controllerData) {
|
||||
return makeRunningValues(handsAreTracked() && this.gestureCompleted, [], []);
|
||||
};
|
||||
|
||||
this.run = function (controllerData) {
|
||||
return this.isReady(controllerData);
|
||||
};
|
||||
|
||||
this.setup = function () {
|
||||
var _this = this;
|
||||
this.inputMapping.from(Controller.Standard.LeftHandIndex4).peek().to(function (pose) {
|
||||
_this.leftIndexChanged(pose);
|
||||
});
|
||||
this.inputMapping.from(Controller.Standard.LeftHandThumb4).peek().to(function (pose) {
|
||||
_this.leftThumbChanged(pose);
|
||||
});
|
||||
this.inputMapping.from(Controller.Standard.RightHandIndex4).peek().to(function (pose) {
|
||||
_this.rightIndexChanged(pose);
|
||||
});
|
||||
this.inputMapping.from(Controller.Standard.RightHandThumb4).peek().to(function (pose) {
|
||||
_this.rightThumbChanged(pose);
|
||||
});
|
||||
|
||||
Controller.enableMapping(this.mappingName);
|
||||
};
|
||||
|
||||
this.cleanUp = function () {
|
||||
this.inputMapping.disable();
|
||||
};
|
||||
}
|
||||
|
||||
var trackedHandWalk = new TrackedHandTablet();
|
||||
trackedHandWalk.setup();
|
||||
enableDispatcherModule("TrackedHandTablet", trackedHandWalk);
|
||||
|
||||
function cleanup() {
|
||||
trackedHandWalk.cleanUp();
|
||||
disableDispatcherModule("TrackedHandTablet");
|
||||
}
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
}());
|
172
scripts/system/controllers/controllerModules/trackedHandWalk.js
Normal file
|
@ -0,0 +1,172 @@
|
|||
"use strict";
|
||||
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
/* global Script, makeRunningValues, enableDispatcherModule, disableDispatcherModule,
|
||||
makeDispatcherModuleParameters, handsAreTracked, Controller, Vec3
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
Script.include("/~/system/libraries/controllers.js");
|
||||
|
||||
(function() {
|
||||
|
||||
function TrackedHandWalk() {
|
||||
this.gestureMappingName = 'hand-track-walk-gesture-' + Math.random();
|
||||
this.inputGestureMapping = Controller.newMapping(this.gestureMappingName);
|
||||
this.mappingName = 'hand-track-walk-' + Math.random();
|
||||
this.inputMapping = Controller.newMapping(this.mappingName);
|
||||
this.leftIndexPos = null;
|
||||
this.leftThumbPos = null;
|
||||
this.rightIndexPos = null;
|
||||
this.rightThumbPos = null;
|
||||
this.touchOnBelowDistance = 0.016;
|
||||
this.touchOffAboveDistance = 0.045;
|
||||
this.walkingForward = false;
|
||||
this.walkingBackward = false;
|
||||
|
||||
this.mappingEnabled = false;
|
||||
|
||||
this.parameters = makeDispatcherModuleParameters(
|
||||
80,
|
||||
["rightHand", "leftHand"],
|
||||
[],
|
||||
100);
|
||||
|
||||
this.getControlPoint = function () {
|
||||
return Vec3.multiply(Vec3.sum(this.leftIndexPos, this.rightIndexPos), 0.5);
|
||||
};
|
||||
|
||||
this.updateWalking = function () {
|
||||
if (this.leftIndexPos && this.rightIndexPos) {
|
||||
var indexTipDistance = Vec3.distance(this.leftIndexPos, this.rightIndexPos);
|
||||
if (indexTipDistance < this.touchOnBelowDistance) {
|
||||
this.walkingForward = true;
|
||||
this.controlPoint = this.getControlPoint();
|
||||
} else if (this.walkingForward && indexTipDistance > this.touchOffAboveDistance) {
|
||||
this.walkingForward = false;
|
||||
} // else don't change walkingForward
|
||||
}
|
||||
|
||||
if (this.leftThumbPos && this.rightThumbPos) {
|
||||
var thumbTipDistance = Vec3.distance(this.leftThumbPos, this.rightThumbPos);
|
||||
if (thumbTipDistance < this.touchOnBelowDistance) {
|
||||
this.walkingBackward = true;
|
||||
this.controlPoint = this.getControlPoint();
|
||||
} else if (this.walkingBackward && thumbTipDistance > this.touchOffAboveDistance) {
|
||||
this.walkingBackward = false;
|
||||
} // else don't change this.walkingBackward
|
||||
}
|
||||
|
||||
if ((this.walkingForward || this.walkingBackward) && !this.mappingEnabled) {
|
||||
Controller.enableMapping(this.mappingName);
|
||||
this.mappingEnabled = true;
|
||||
} else if (!(this.walkingForward || this.walkingBackward) && this.mappingEnabled) {
|
||||
this.inputMapping.disable();
|
||||
this.mappingEnabled = false;
|
||||
} // else don't change mappingEnabled
|
||||
};
|
||||
|
||||
this.leftIndexChanged = function (pose) {
|
||||
if (pose.valid) {
|
||||
this.leftIndexPos = pose.translation;
|
||||
} else {
|
||||
this.leftIndexPos = null;
|
||||
}
|
||||
this.updateWalking();
|
||||
};
|
||||
|
||||
this.leftThumbChanged = function (pose) {
|
||||
if (pose.valid) {
|
||||
this.leftThumbPos = pose.translation;
|
||||
} else {
|
||||
this.leftThumbPos = null;
|
||||
}
|
||||
this.updateWalking();
|
||||
};
|
||||
|
||||
this.rightIndexChanged = function (pose) {
|
||||
if (pose.valid) {
|
||||
this.rightIndexPos = pose.translation;
|
||||
} else {
|
||||
this.rightIndexPos = null;
|
||||
}
|
||||
this.updateWalking();
|
||||
};
|
||||
|
||||
this.rightThumbChanged = function (pose) {
|
||||
if (pose.valid) {
|
||||
this.rightThumbPos = pose.translation;
|
||||
} else {
|
||||
this.rightThumbPos = null;
|
||||
}
|
||||
this.updateWalking();
|
||||
};
|
||||
|
||||
this.isReady = function (controllerData) {
|
||||
return makeRunningValues(handsAreTracked() && (this.walkingForward || this.walkingBackward), [], []);
|
||||
};
|
||||
|
||||
this.run = function (controllerData) {
|
||||
return this.isReady(controllerData);
|
||||
};
|
||||
|
||||
this.setup = function () {
|
||||
var _this = this;
|
||||
this.inputGestureMapping.from(Controller.Standard.LeftHandIndex4).peek().to(function (pose) {
|
||||
_this.leftIndexChanged(pose);
|
||||
});
|
||||
this.inputGestureMapping.from(Controller.Standard.LeftHandThumb4).peek().to(function (pose) {
|
||||
_this.leftThumbChanged(pose);
|
||||
});
|
||||
this.inputGestureMapping.from(Controller.Standard.RightHandIndex4).peek().to(function (pose) {
|
||||
_this.rightIndexChanged(pose);
|
||||
});
|
||||
this.inputGestureMapping.from(Controller.Standard.RightHandThumb4).peek().to(function (pose) {
|
||||
_this.rightThumbChanged(pose);
|
||||
});
|
||||
|
||||
this.inputMapping.from(function() {
|
||||
if (_this.walkingForward) {
|
||||
// var currentPoint = _this.getControlPoint();
|
||||
// return currentPoint.z - _this.controlPoint.z;
|
||||
return -0.5;
|
||||
} else if (_this.walkingBackward) {
|
||||
// var currentPoint = _this.getControlPoint();
|
||||
// return currentPoint.z - _this.controlPoint.z;
|
||||
return 0.5;
|
||||
} else {
|
||||
// return Controller.getActionValue(Controller.Standard.TranslateZ);
|
||||
return 0.0;
|
||||
}
|
||||
}).to(Controller.Actions.TranslateZ);
|
||||
|
||||
// this.inputMapping.from(function() {
|
||||
// if (_this.walkingForward) {
|
||||
// var currentPoint = _this.getControlPoint();
|
||||
// return currentPoint.x - _this.controlPoint.x;
|
||||
// } else {
|
||||
// return Controller.getActionValue(Controller.Standard.Yaw);
|
||||
// }
|
||||
// }).to(Controller.Actions.Yaw);
|
||||
|
||||
Controller.enableMapping(this.gestureMappingName);
|
||||
};
|
||||
|
||||
this.cleanUp = function () {
|
||||
this.inputGestureMapping.disable();
|
||||
this.inputMapping.disable();
|
||||
};
|
||||
}
|
||||
|
||||
var trackedHandWalk = new TrackedHandWalk();
|
||||
trackedHandWalk.setup();
|
||||
enableDispatcherModule("TrackedHandWalk", trackedHandWalk);
|
||||
|
||||
function cleanup() {
|
||||
trackedHandWalk.cleanUp();
|
||||
disableDispatcherModule("TrackedHandWalk");
|
||||
}
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
}());
|
|
@ -34,7 +34,9 @@ var CONTOLLER_SCRIPTS = [
|
|||
"controllerModules/nearTabletHighlight.js",
|
||||
"controllerModules/nearGrabEntity.js",
|
||||
"controllerModules/farGrabEntity.js",
|
||||
"controllerModules/pushToTalk.js"
|
||||
"controllerModules/pushToTalk.js",
|
||||
"controllerModules/trackedHandWalk.js",
|
||||
"controllerModules/trackedHandTablet.js"
|
||||
];
|
||||
|
||||
var DEBUG_MENU_ITEM = "Debug defaultScripts.js";
|
||||
|
|
|
@ -603,20 +603,28 @@ var toolBar = (function () {
|
|||
Script.setTimeout(dimensionsCheckFunction, DIMENSIONS_CHECK_INTERVAL);
|
||||
}
|
||||
// Make sure the model entity is loaded before we try to figure out
|
||||
// its dimensions.
|
||||
var MAX_LOADED_CHECKS = 10;
|
||||
// its dimensions. We need to give ample time to load the entity.
|
||||
var MAX_LOADED_CHECKS = 100; // 100 * 100ms = 10 seconds.
|
||||
var LOADED_CHECK_INTERVAL = 100;
|
||||
var isLoadedCheckCount = 0;
|
||||
var entityIsLoadedCheck = function() {
|
||||
isLoadedCheckCount++;
|
||||
if (isLoadedCheckCount === MAX_LOADED_CHECKS || Entities.isLoaded(entityID)) {
|
||||
var naturalDimensions = Entities.getEntityProperties(entityID, "naturalDimensions").naturalDimensions;
|
||||
|
||||
|
||||
if (isLoadedCheckCount === MAX_LOADED_CHECKS) {
|
||||
console.log("Model entity failed to load in time: " + (MAX_LOADED_CHECKS * LOADED_CHECK_INTERVAL) + " ... setting dimensions to: " + JSON.stringify(naturalDimensions))
|
||||
}
|
||||
|
||||
Entities.editEntity(entityID, {
|
||||
visible: true,
|
||||
dimensions: naturalDimensions
|
||||
})
|
||||
dimensionsCheckCallback();
|
||||
// We want to update the selection manager again since the script has moved on without us.
|
||||
selectionManager.clearSelections(this);
|
||||
entityListTool.sendUpdate();
|
||||
selectionManager.setSelections([entityID], this);
|
||||
return;
|
||||
}
|
||||
Script.setTimeout(entityIsLoadedCheck, LOADED_CHECK_INTERVAL);
|
||||
|
|
56
scripts/system/html/css/miniHandTablet.css
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
miniTablet.css
|
||||
|
||||
Copyright 2019 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
|
||||
*/
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
html {
|
||||
background-color: #404040;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
section {
|
||||
background-color: #404040;
|
||||
position: relative;
|
||||
padding: 32px 0px;
|
||||
}
|
||||
|
||||
.button {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 149px;
|
||||
height: 149px;
|
||||
}
|
||||
|
||||
#expand {
|
||||
width: 149px;
|
||||
height: 149px;
|
||||
background-size: 100% 100%;
|
||||
background-image: url("./img/mt-expand-normal.svg");
|
||||
}
|
||||
|
||||
#expand:hover {
|
||||
background-image: url("./img/mt-expand-hover.svg");
|
||||
}
|
||||
|
||||
#expand:hover.unhover {
|
||||
background-image: url("./img/mt-expand-normal.svg");
|
||||
}
|
||||
|
||||
#expand img {
|
||||
}
|
|
@ -35,7 +35,9 @@
|
|||
|
||||
function setUnhover() {
|
||||
if (!isUnhover) {
|
||||
gotoButton.classList.add("unhover");
|
||||
if (gotoButton) {
|
||||
gotoButton.classList.add("unhover");
|
||||
}
|
||||
expandButton.classList.add("unhover");
|
||||
isUnhover = true;
|
||||
}
|
||||
|
@ -43,7 +45,9 @@
|
|||
|
||||
function clearUnhover() {
|
||||
if (isUnhover) {
|
||||
gotoButton.classList.remove("unhover");
|
||||
if (gotoButton) {
|
||||
gotoButton.classList.remove("unhover");
|
||||
}
|
||||
expandButton.classList.remove("unhover");
|
||||
isUnhover = false;
|
||||
}
|
||||
|
@ -62,10 +66,14 @@
|
|||
|
||||
switch (message.type) {
|
||||
case MUTE_MESSAGE:
|
||||
muteImage.src = message.icon;
|
||||
if (muteImage) {
|
||||
muteImage.src = message.icon;
|
||||
}
|
||||
break;
|
||||
case GOTO_MESSAGE:
|
||||
gotoImage.src = message.icon;
|
||||
if (gotoImage) {
|
||||
gotoImage.src = message.icon;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -130,9 +138,7 @@
|
|||
|
||||
function onLoad() {
|
||||
muteButton = document.getElementById("mute");
|
||||
muteImage = document.getElementById("mute-img");
|
||||
gotoButton = document.getElementById("goto");
|
||||
gotoImage = document.getElementById("goto-img");
|
||||
expandButton = document.getElementById("expand");
|
||||
|
||||
connectEventBridge();
|
||||
|
@ -140,11 +146,19 @@
|
|||
document.body.addEventListener("mouseenter", onBodyHover, false);
|
||||
document.body.addEventListener("mouseleave", onBodyUnhover, false);
|
||||
|
||||
muteButton.addEventListener("mouseenter", onButtonHover, false);
|
||||
gotoButton.addEventListener("mouseenter", onButtonHover, false);
|
||||
if (muteButton) {
|
||||
muteImage = document.getElementById("mute-img");
|
||||
muteButton.addEventListener("mouseenter", onButtonHover, false);
|
||||
muteButton.addEventListener("click", onMuteButtonClick, true);
|
||||
}
|
||||
|
||||
if (gotoButton) {
|
||||
gotoImage = document.getElementById("goto-img");
|
||||
gotoButton.addEventListener("mouseenter", onButtonHover, false);
|
||||
gotoButton.addEventListener("click", onGotoButtonClick, true);
|
||||
}
|
||||
|
||||
expandButton.addEventListener("mouseenter", onButtonHover, false);
|
||||
muteButton.addEventListener("click", onMuteButtonClick, true);
|
||||
gotoButton.addEventListener("click", onGotoButtonClick, true);
|
||||
expandButton.addEventListener("click", onExpandButtonClick, true);
|
||||
|
||||
document.body.onunload = function () {
|
||||
|
|
26
scripts/system/html/miniHandsTablet.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
<!--
|
||||
miniTablet.html
|
||||
|
||||
Created by David Rowe on 20 Aug 2018.
|
||||
Copyright 2018 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
|
||||
-->
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="stylesheet" type="text/css" href="css/miniHandTablet.css" />
|
||||
</head>
|
||||
<body>
|
||||
<section>
|
||||
<div id="expand" class="button">
|
||||
<img src="./img/expand.svg" />
|
||||
</div>
|
||||
</section>
|
||||
<script src="js/miniTablet.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -164,6 +164,7 @@ WebTablet = function (url, width, dpi, hand, location, visible) {
|
|||
parentID: this.tabletEntityID,
|
||||
parentJointIndex: -1,
|
||||
showKeyboardFocusHighlight: false,
|
||||
grabbable: false,
|
||||
visible: visible
|
||||
});
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
/* global module, HMD, MyAvatar, controllerDispatcherPlugins:true, Quat, Vec3, Overlays, Xform, Mat4,
|
||||
Selection, Uuid,
|
||||
Selection, Uuid, Controller,
|
||||
MSECS_PER_SEC:true , LEFT_HAND:true, RIGHT_HAND:true, FORBIDDEN_GRAB_TYPES:true,
|
||||
HAPTIC_PULSE_STRENGTH:true, HAPTIC_PULSE_DURATION:true, ZERO_VEC:true, ONE_VEC:true,
|
||||
DEFAULT_REGISTRATION_POINT:true, INCHES_TO_METERS:true,
|
||||
|
@ -56,6 +56,7 @@
|
|||
TEAR_AWAY_DISTANCE:true,
|
||||
TEAR_AWAY_COUNT:true,
|
||||
TEAR_AWAY_CHECK_TIME:true,
|
||||
TELEPORT_DEADZONE: true,
|
||||
NEAR_GRAB_DISTANCE: true,
|
||||
distanceBetweenPointAndEntityBoundingBox:true,
|
||||
entityIsEquipped:true,
|
||||
|
@ -63,7 +64,8 @@
|
|||
clearHighlightedEntities:true,
|
||||
unhighlightTargetEntity:true,
|
||||
distanceBetweenEntityLocalPositionAndBoundingBox: true,
|
||||
worldPositionToRegistrationFrameMatrix: true
|
||||
worldPositionToRegistrationFrameMatrix: true,
|
||||
handsAreTracked: true
|
||||
*/
|
||||
|
||||
MSECS_PER_SEC = 1000.0;
|
||||
|
@ -600,6 +602,10 @@ worldPositionToRegistrationFrameMatrix = function(wptrProps, pos) {
|
|||
return offsetMat;
|
||||
};
|
||||
|
||||
handsAreTracked = function () {
|
||||
return Controller.getPoseValue(Controller.Standard.LeftHandIndex3).valid ||
|
||||
Controller.getPoseValue(Controller.Standard.RightHandIndex3).valid;
|
||||
};
|
||||
|
||||
if (typeof module !== 'undefined') {
|
||||
module.exports = {
|
||||
|
@ -624,6 +630,7 @@ if (typeof module !== 'undefined') {
|
|||
TRIGGER_OFF_VALUE: TRIGGER_OFF_VALUE,
|
||||
TRIGGER_ON_VALUE: TRIGGER_ON_VALUE,
|
||||
DISPATCHER_HOVERING_LIST: DISPATCHER_HOVERING_LIST,
|
||||
worldPositionToRegistrationFrameMatrix: worldPositionToRegistrationFrameMatrix
|
||||
worldPositionToRegistrationFrameMatrix: worldPositionToRegistrationFrameMatrix,
|
||||
handsAreTracked: handsAreTracked
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
/* global getTabletWidthFromSettings, TRIGGER_OFF_VALUE */
|
||||
/* global getTabletWidthFromSettings, handsAreTracked, TRIGGER_OFF_VALUE, Controller, Script, Camera, Tablet, MyAvatar,
|
||||
Quat, SoundCache, HMD, Overlays, Vec3, Uuid, Messages */
|
||||
|
||||
(function () {
|
||||
|
||||
|
@ -80,7 +81,6 @@
|
|||
return hand === LEFT_HAND ? RIGHT_HAND : LEFT_HAND;
|
||||
}
|
||||
|
||||
|
||||
UI = function () {
|
||||
|
||||
if (!(this instanceof UI)) {
|
||||
|
@ -114,6 +114,7 @@
|
|||
uiHand = LEFT_HAND,
|
||||
miniUIOverlay = null,
|
||||
MINI_UI_HTML = Script.resolvePath("./html/miniTablet.html"),
|
||||
MINI_HAND_UI_HTML = Script.resolvePath("./html/miniHandsTablet.html"),
|
||||
MINI_UI_DIMENSIONS = { x: 0.059, y: 0.0865, z: 0.001 },
|
||||
MINI_UI_WIDTH_PIXELS = 150,
|
||||
METERS_TO_INCHES = 39.3701,
|
||||
|
@ -291,6 +292,7 @@
|
|||
visible: true
|
||||
});
|
||||
Overlays.editOverlay(miniUIOverlay, {
|
||||
url: handsAreTracked() ? MINI_HAND_UI_HTML : MINI_UI_HTML,
|
||||
localPosition: Vec3.multiply(MyAvatar.sensorToWorldScale, MINI_UI_LOCAL_POSITION),
|
||||
localRotation: MINI_UI_LOCAL_ROTATION,
|
||||
dimensions: Vec3.multiply(initialScale, MINI_UI_DIMENSIONS),
|
||||
|
@ -353,8 +355,8 @@
|
|||
localRotation,
|
||||
localPosition;
|
||||
|
||||
tabletScaleFactor = MyAvatar.sensorToWorldScale
|
||||
* (1 + scaleFactor * (miniTargetWidth - miniInitialWidth) / miniInitialWidth);
|
||||
tabletScaleFactor = MyAvatar.sensorToWorldScale *
|
||||
(1 + scaleFactor * (miniTargetWidth - miniInitialWidth) / miniInitialWidth);
|
||||
dimensions = Vec3.multiply(tabletScaleFactor, MINI_DIMENSIONS);
|
||||
localRotation = Quat.mix(miniExpandLocalRotation, miniTargetLocalRotation, scaleFactor);
|
||||
localPosition =
|
||||
|
@ -469,11 +471,11 @@
|
|||
solid: true,
|
||||
grabbable: true,
|
||||
showKeyboardFocusHighlight: false,
|
||||
drawInFront: true,
|
||||
drawInFront: false,
|
||||
visible: false
|
||||
});
|
||||
miniUIOverlay = Overlays.addOverlay("web3d", {
|
||||
url: MINI_UI_HTML,
|
||||
url: handsAreTracked() ? MINI_HAND_UI_HTML : MINI_UI_HTML,
|
||||
parentID: miniOverlay,
|
||||
localPosition: Vec3.multiply(MyAvatar.sensorToWorldScale, MINI_UI_LOCAL_POSITION),
|
||||
localRotation: MINI_UI_LOCAL_ROTATION,
|
||||
|
@ -482,7 +484,7 @@
|
|||
alpha: 0, // Hide overlay while its content is being created.
|
||||
grabbable: false,
|
||||
showKeyboardFocusHighlight: false,
|
||||
drawInFront: true,
|
||||
drawInFront: false,
|
||||
visible: false
|
||||
});
|
||||
|
||||
|
@ -642,8 +644,8 @@
|
|||
// is grabbing something) or the other hand's trigger is pressed unless it is pointing at the mini tablet. Allow
|
||||
// the triggers to be pressed briefly to allow for the grabbing process.
|
||||
if (show) {
|
||||
isLeftTriggerOff = Controller.getValue(Controller.Standard.LT) < TRIGGER_OFF_VALUE
|
||||
&& Controller.getValue(Controller.Standard.LeftGrip) < TRIGGER_OFF_VALUE;
|
||||
isLeftTriggerOff = Controller.getValue(Controller.Standard.LT) < TRIGGER_OFF_VALUE &&
|
||||
Controller.getValue(Controller.Standard.LeftGrip) < TRIGGER_OFF_VALUE;
|
||||
if (!isLeftTriggerOff) {
|
||||
if (leftTriggerOn === 0) {
|
||||
leftTriggerOn = Date.now();
|
||||
|
@ -653,8 +655,8 @@
|
|||
} else {
|
||||
leftTriggerOn = 0;
|
||||
}
|
||||
isRightTriggerOff = Controller.getValue(Controller.Standard.RT) < TRIGGER_OFF_VALUE
|
||||
&& Controller.getValue(Controller.Standard.RightGrip) < TRIGGER_OFF_VALUE;
|
||||
isRightTriggerOff = Controller.getValue(Controller.Standard.RT) < TRIGGER_OFF_VALUE &&
|
||||
Controller.getValue(Controller.Standard.RightGrip) < TRIGGER_OFF_VALUE;
|
||||
if (!isRightTriggerOff) {
|
||||
if (rightTriggerOn === 0) {
|
||||
rightTriggerOn = Date.now();
|
||||
|
@ -665,8 +667,8 @@
|
|||
rightTriggerOn = 0;
|
||||
}
|
||||
|
||||
show = (hand === LEFT_HAND ? wasLeftTriggerOff : wasRightTriggerOff)
|
||||
&& ((hand === LEFT_HAND ? wasRightTriggerOff : wasLeftTriggerOff) || ui.isLaserPointingAt());
|
||||
show = (hand === LEFT_HAND ? wasLeftTriggerOff : wasRightTriggerOff) &&
|
||||
((hand === LEFT_HAND ? wasRightTriggerOff : wasLeftTriggerOff) || ui.isLaserPointingAt());
|
||||
}
|
||||
|
||||
// Should show mini tablet if it would be oriented toward the camera.
|
||||
|
@ -691,10 +693,10 @@
|
|||
normalDot = Vec3.dot(normalHandVector, miniToCameraDirection);
|
||||
medialAngle = Math.atan2(medialDot, normalDot);
|
||||
lateralAngle = Math.atan2(lateralDot, normalDot);
|
||||
show = -MAX_MEDIAL_WRIST_CAMERA_ANGLE_RAD <= medialAngle
|
||||
&& medialAngle <= MAX_MEDIAL_FINGER_CAMERA_ANGLE_RAD
|
||||
&& -MAX_LATERAL_THUMB_CAMERA_ANGLE_RAD <= lateralAngle
|
||||
&& lateralAngle <= MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD;
|
||||
show = -MAX_MEDIAL_WRIST_CAMERA_ANGLE_RAD <= medialAngle &&
|
||||
medialAngle <= MAX_MEDIAL_FINGER_CAMERA_ANGLE_RAD &&
|
||||
-MAX_LATERAL_THUMB_CAMERA_ANGLE_RAD <= lateralAngle &&
|
||||
lateralAngle <= MAX_LATERAL_PINKY_CAMERA_ANGLE_RAD;
|
||||
|
||||
// Camera looking at mini tablet?
|
||||
cameraToMini = -Vec3.dot(miniToCameraDirection, Quat.getForward(Camera.orientation));
|
||||
|
@ -972,8 +974,8 @@
|
|||
|
||||
function setState(state, data) {
|
||||
if (state !== miniState) {
|
||||
debug("State transition from " + STATE_STRINGS[miniState] + " to " + STATE_STRINGS[state]
|
||||
+ ( data ? " " + JSON.stringify(data) : ""));
|
||||
debug("State transition from " + STATE_STRINGS[miniState] + " to " + STATE_STRINGS[state] +
|
||||
( data ? " " + JSON.stringify(data) : ""));
|
||||
if (STATE_MACHINE[STATE_STRINGS[miniState]].exit) {
|
||||
STATE_MACHINE[STATE_STRINGS[miniState]].exit(data);
|
||||
}
|
||||
|
@ -1061,8 +1063,8 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if (miniState.getState() === miniState.MINI_DISABLED
|
||||
|| (message.grabbedEntity !== HMD.tabletID && message.grabbedEntity !== ui.getMiniTabletID())) {
|
||||
if (miniState.getState() === miniState.MINI_DISABLED ||
|
||||
(message.grabbedEntity !== HMD.tabletID && message.grabbedEntity !== ui.getMiniTabletID())) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Created by Keb Helion, February 2020.
|
||||
// Copyright 2020 Vircadia contributors.
|
||||
//
|
||||
// This script adds a "More Apps" selector to "Project Athena" to allow the user to add optional functionalities to the tablet.
|
||||
// This script adds a "More Apps" selector to "Vircadia" to allow the user to add optional functionalities to the tablet.
|
||||
// This application has been designed to work directly from the Github repository.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
|
|