History

Merge branch master

Mohammed Nafees committed 12 years ago

Commit 29d64372 parents dd74ea6 d441e6a645 files · +22419 −7869Browse files

Showing the changes to interface/src/Application.cpp (1 of 645 files). Show all

Unified · Split

interface/src/Application.cpp+347−587
@@ -1,13 +1,13 @@
1//1//
2// Application.cpp2// Application.cpp
3// interface3// interface/src
4//4//
5// Created by Andrzej Kapolka on 5/10/13.5// Created by Andrzej Kapolka on 5/10/13.
6// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.6// Copyright 2013 High Fidelity, Inc.
7 7//
8#ifdef WIN328// Distributed under the Apache License, Version 2.0.
9#include <Systime.h>9// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10#endif10//
11 11
12#include <sstream>12#include <sstream>
13 13
@@ -62,7 +62,7 @@ · 48 unmodified lines
62#include <UUID.h>62#include <UUID.h>
63#include <OctreeSceneStats.h>63#include <OctreeSceneStats.h>
64#include <LocalVoxelsList.h>64#include <LocalVoxelsList.h>
65#include <FstReader.h>65#include <ModelUploader.h>
66 66
67#include "Application.h"67#include "Application.h"
68#include "InterfaceVersion.h"68#include "InterfaceVersion.h"
@@ -80,6 +80,7 @@ · 11 unmodified lines
80#include "ui/InfoView.h"80#include "ui/InfoView.h"
81#include "ui/Snapshot.h"81#include "ui/Snapshot.h"
82#include "ui/TextRenderer.h"82#include "ui/TextRenderer.h"
83#include "ui/Stats.h"
83 84
84using namespace std;85using namespace std;
85 86
@@ -106,13 +107,9 @@ const float MIRROR_REARVIEW_DISTANCE = 0.65f; · 20 unmodified lines
106const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;107const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
107const float MIRROR_FIELD_OF_VIEW = 30.0f;108const float MIRROR_FIELD_OF_VIEW = 30.0f;
108 109
109const QString CHECK_VERSION_URL = "http://highfidelity.io/latestVersion.xml";110const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml";
110const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";111const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
111 112
112const int STATS_PELS_PER_LINE = 20;
113
114const QString CUSTOM_URL_SCHEME = "hifi:";
115
116void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {113void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
117 if (message.size() > 0) {114 if (message.size() > 0) {
118 QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate);115 QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate);
@@ -132,11 +129,10 @@ QString& Application::resourcesPath() { · 13 unmodified lines
132 return staticResourcePath;129 return staticResourcePath;
133}130}
134 131
135Application::Application(int& argc, char** argv, timeval &startup_time) :132Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
136 QApplication(argc, argv),133 QApplication(argc, argv),
137 _window(new MainWindow(desktop())),134 _window(new MainWindow(desktop())),
138 _glWidget(new GLCanvas()),135 _glWidget(new GLCanvas()),
139 _statsExpanded(false),
140 _nodeThread(new QThread(this)),136 _nodeThread(new QThread(this)),
141 _datagramProcessor(),137 _datagramProcessor(),
142 _frameCount(0),138 _frameCount(0),
@@ -149,9 +145,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 6 unmodified lines
149 _viewFrustum(),145 _viewFrustum(),
150 _lastQueriedViewFrustum(),146 _lastQueriedViewFrustum(),
151 _lastQueriedTime(usecTimestampNow()),147 _lastQueriedTime(usecTimestampNow()),
152 _audioScope(256, 200, true),
153 _trailingAudioLoudness(0.f),
154 _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),148 _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
149 _cameraPushback(0.0f),
155 _mouseX(0),150 _mouseX(0),
156 _mouseY(0),151 _mouseY(0),
157 _lastMouseMove(usecTimestampNow()),152 _lastMouseMove(usecTimestampNow()),
@@ -161,19 +156,20 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 3 unmodified lines
161 _touchAvgY(0.0f),156 _touchAvgY(0.0f),
162 _isTouchPressed(false),157 _isTouchPressed(false),
163 _mousePressed(false),158 _mousePressed(false),
164 _audio(&_audioScope, STARTUP_JITTER_SAMPLES),159 _audio(STARTUP_JITTER_SAMPLES),
165 _enableProcessVoxelsThread(true),160 _enableProcessVoxelsThread(true),
166 _voxelProcessor(),161 _voxelProcessor(),
167 _voxelHideShowThread(&_voxels),162 _voxelHideShowThread(&_voxels),
168 _packetsPerSecond(0),163 _packetsPerSecond(0),
169 _bytesPerSecond(0),164 _bytesPerSecond(0),
170 _recentMaxPackets(0),
171 _resetRecentMaxPacketsSoon(true),
172 _previousScriptLocation(),165 _previousScriptLocation(),
173 _logger(new FileLogger(this)),166 _logger(new FileLogger(this)),
174 _runningScriptsWidget(new RunningScriptsWidget),167 _runningScriptsWidget(new RunningScriptsWidget),
175 _runningScriptsWidgetWasVisible(false)168 _runningScriptsWidgetWasVisible(false)
176{169{
170 // init GnuTLS for DTLS with domain-servers
171 DTLSClientSession::globalInit();
172
177 // read the ApplicationInfo.ini file for Name/Version/Domain information173 // read the ApplicationInfo.ini file for Name/Version/Domain information
178 QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);174 QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
179 175
@@ -231,8 +227,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 51 unmodified lines
231 227
232 audioThread->start();228 audioThread->start();
233 229
234 connect(&nodeList->getDomainInfo(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));230 connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
235 connect(&nodeList->getDomainInfo(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));231 connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));
236 232
237 connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);233 connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
238 connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);234 connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
@@ -240,6 +236,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 1 unmodified line
240 connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer)));236 connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer)));
241 connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer)));237 connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer)));
242 connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle);238 connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle);
239 connect(nodeList, SIGNAL(uuidChanged(const QUuid&)), _myAvatar, SLOT(setSessionUUID(const QUuid&)));
243 connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset);240 connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset);
244 241
245 // connect to appropriate slots on AccountManager242 // connect to appropriate slots on AccountManager
@@ -254,6 +251,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 8 unmodified lines
254 QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);251 QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
255 252
256 _settings = new QSettings(this);253 _settings = new QSettings(this);
254 _numChangedSettings = 0;
257 255
258 // Check to see if the user passed in a command line option for loading a local256 // Check to see if the user passed in a command line option for loading a local
259 // Voxel File.257 // Voxel File.
@@ -277,7 +275,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 17 unmodified lines
277 QTimer* silentNodeTimer = new QTimer();275 QTimer* silentNodeTimer = new QTimer();
278 connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));276 connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
279 silentNodeTimer->moveToThread(_nodeThread);277 silentNodeTimer->moveToThread(_nodeThread);
280 silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);278 silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
281 279
282 // send the identity packet for our avatar each second to our avatar mixer280 // send the identity packet for our avatar each second to our avatar mixer
283 QTimer* identityPacketTimer = new QTimer();281 QTimer* identityPacketTimer = new QTimer();
@@ -346,15 +344,22 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 62 unmodified lines
346 clearScriptsBeforeRunning();344 clearScriptsBeforeRunning();
347 loadScript("http://public.highfidelity.io/scripts/defaultScripts.js");345 loadScript("http://public.highfidelity.io/scripts/defaultScripts.js");
348 346
347 QMutexLocker locker(&_settingsMutex);
349 _settings->setValue("firstRun",QVariant(false));348 _settings->setValue("firstRun",QVariant(false));
350 } else {349 } else {
351 // do this as late as possible so that all required subsystems are inialized350 // do this as late as possible so that all required subsystems are inialized
352 loadScripts();351 loadScripts();
352
353 QMutexLocker locker(&_settingsMutex);
354 _previousScriptLocation = _settings->value("LastScriptLocation", QVariant("")).toString();
353 }355 }
354 356
355 connect(_window, &MainWindow::windowGeometryChanged,357 connect(_window, &MainWindow::windowGeometryChanged,
356 _runningScriptsWidget, &RunningScriptsWidget::setBoundary);358 _runningScriptsWidget, &RunningScriptsWidget::setBoundary);
357 connect(_window, &MainWindow::windowShown, this, &Application::manageRunningScriptsWidgetVisibility);359 connect(_window, &MainWindow::windowShown, this, &Application::manageRunningScriptsWidgetVisibility);
360
361 //When -url in command line, teleport to location
362 urlGoTo(argc, constArgv);
358}363}
359 364
360Application::~Application() {365Application::~Application() {
@@ -404,37 +409,50 @@ Application::~Application() { · 43 unmodified lines
404 delete _glWidget;409 delete _glWidget;
405 410
406 AccountManager::getInstance().destroy();411 AccountManager::getInstance().destroy();
412
413 DTLSClientSession::globalDeinit();
407}414}
408 415
416void Application::saveSettings() {
417 Menu::getInstance()->saveSettings();
418 _rearMirrorTools->saveSettings(_settings);
419
420 if (_voxelImporter) {
421 _voxelImporter->saveSettings(_settings);
422 }
423 _settings->sync();
424 _numChangedSettings = 0;
425}
426
427
409void Application::restoreSizeAndPosition() {428void Application::restoreSizeAndPosition() {
410 QSettings* settings = new QSettings(this);
411 QRect available = desktop()->availableGeometry();429 QRect available = desktop()->availableGeometry();
412 430
413 settings->beginGroup("Window");431 QMutexLocker locker(&_settingsMutex);
432 _settings->beginGroup("Window");
414 433
415 int x = (int)loadSetting(settings, "x", 0);434 int x = (int)loadSetting(_settings, "x", 0);
416 int y = (int)loadSetting(settings, "y", 0);435 int y = (int)loadSetting(_settings, "y", 0);
417 _window->move(x, y);436 _window->move(x, y);
418 437
419 int width = (int)loadSetting(settings, "width", available.width());438 int width = (int)loadSetting(_settings, "width", available.width());
420 int height = (int)loadSetting(settings, "height", available.height());439 int height = (int)loadSetting(_settings, "height", available.height());
421 _window->resize(width, height);440 _window->resize(width, height);
422 441
423 settings->endGroup();442 _settings->endGroup();
424}443}
425 444
426void Application::storeSizeAndPosition() {445void Application::storeSizeAndPosition() {
427 QSettings* settings = new QSettings(this);446 QMutexLocker locker(&_settingsMutex);
428 447 _settings->beginGroup("Window");
429 settings->beginGroup("Window");
430 448
431 settings->setValue("width", _window->rect().width());449 _settings->setValue("width", _window->rect().width());
432 settings->setValue("height", _window->rect().height());450 _settings->setValue("height", _window->rect().height());
433 451
434 settings->setValue("x", _window->pos().x());452 _settings->setValue("x", _window->pos().x());
435 settings->setValue("y", _window->pos().y());453 _settings->setValue("y", _window->pos().y());
436 454
437 settings->endGroup();455 _settings->endGroup();
438}456}
439 457
440void Application::initializeGL() {458void Application::initializeGL() {
@@ -495,7 +513,7 @@ void Application::initializeGL() { · 54 unmodified lines
495 _idleLoopStdev.reset();513 _idleLoopStdev.reset();
496 514
497 if (_justStarted) {515 if (_justStarted) {
498 float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime)) / 1000000.0;516 float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0;
499 _justStarted = false;517 _justStarted = false;
500 qDebug("Startup time: %4.2f seconds.", startupTime);518 qDebug("Startup time: %4.2f seconds.", startupTime);
501 const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";519 const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
@@ -517,18 +535,55 @@ void Application::paintGL() { · 15 unmodified lines
517 535
518 glEnable(GL_LINE_SMOOTH);536 glEnable(GL_LINE_SMOOTH);
519 537
538 float pushback = 0.0f;
539 float pushbackFocalLength = 0.0f;
520 if (OculusManager::isConnected()) {540 if (OculusManager::isConnected()) {
521 _myCamera.setUpShift(0.0f);541 _myCamera.setUpShift(0.0f);
522 _myCamera.setDistance(0.0f);542 _myCamera.setDistance(0.0f);
523 _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing543 _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
524 _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());544 _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
525 _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation());545 _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
526 546
527 } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {547 } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
528 _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay548 _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
529 _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());549 _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
530 _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());550 _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
531 551
552 glm::vec3 planeNormal = _myCamera.getTargetRotation() * IDENTITY_FRONT;
553 const float BASE_PUSHBACK_RADIUS = 0.25f;
554 float pushbackRadius = _myCamera.getNearClip() + _myAvatar->getScale() * BASE_PUSHBACK_RADIUS;
555 glm::vec4 plane(planeNormal, -glm::dot(planeNormal, _myCamera.getTargetPosition()) - pushbackRadius);
556
557 // push camera out of any intersecting avatars
558 foreach (const AvatarSharedPointer& avatarData, _avatarManager.getAvatarHash()) {
559 Avatar* avatar = static_cast<Avatar*>(avatarData.data());
560 if (avatar->isMyAvatar()) {
561 continue;
562 }
563 if (glm::distance(avatar->getPosition(), _myCamera.getTargetPosition()) >
564 avatar->getBoundingRadius() + pushbackRadius) {
565 continue;
566 }
567 float angle = angleBetween(avatar->getPosition() - _myCamera.getTargetPosition(), planeNormal);
568 if (angle > PI_OVER_TWO) {
569 continue;
570 }
571 float scale = 1.0f - angle / PI_OVER_TWO;
572 scale = qMin(1.0f, scale * 2.5f);
573 static CollisionList collisions(64);
574 collisions.clear();
575 if (!avatar->findPlaneCollisions(plane, collisions)) {
576 continue;
577 }
578 for (int i = 0; i < collisions.size(); i++) {
579 pushback = qMax(pushback, glm::length(collisions.getCollision(i)->_penetration) * scale);
580 }
581 }
582 const float MAX_PUSHBACK = 0.35f;
583 pushback = qMin(pushback, MAX_PUSHBACK * _myAvatar->getScale());
584 const float BASE_PUSHBACK_FOCAL_LENGTH = 0.5f;
585 pushbackFocalLength = BASE_PUSHBACK_FOCAL_LENGTH * _myAvatar->getScale();
586
532 } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {587 } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
533 _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing588 _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
534 _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition());589 _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition());
@@ -536,10 +591,35 @@ void Application::paintGL() { · 1 unmodified line
536 591
537 } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {592 } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
538 _myCamera.setTightness(0.0f);593 _myCamera.setTightness(0.0f);
539 float headHeight = _myAvatar->getHead()->calculateAverageEyePosition().y - _myAvatar->getPosition().y;594 glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition();
595 float headHeight = eyePosition.y - _myAvatar->getPosition().y;
540 _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale());596 _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale());
541 _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0));597 _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0));
542 _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));598 _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f)));
599
600 // if the head would intersect the near clip plane, we must push the camera out
601 glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) *
602 (eyePosition - _myCamera.getTargetPosition());
603 const float BASE_PUSHBACK_RADIUS = 0.2f;
604 float pushbackRadius = _myCamera.getNearClip() + _myAvatar->getScale() * BASE_PUSHBACK_RADIUS;
605 pushback = relativePosition.z + pushbackRadius - _myCamera.getDistance();
606 pushbackFocalLength = _myCamera.getDistance();
607 }
608
609 // handle pushback, if any
610 if (pushbackFocalLength > 0.0f) {
611 const float PUSHBACK_DECAY = 0.5f;
612 _cameraPushback = qMax(pushback, _cameraPushback * PUSHBACK_DECAY);
613 if (_cameraPushback > EPSILON) {
614 _myCamera.setTargetPosition(_myCamera.getTargetPosition() +
615 _myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, _cameraPushback));
616 float enlargement = pushbackFocalLength / (pushbackFocalLength + _cameraPushback);
617 _myCamera.setFieldOfView(glm::degrees(2.0f * atanf(enlargement * tanf(
618 glm::radians(Menu::getInstance()->getFieldOfView() * 0.5f)))));
619 } else {
620 _myCamera.setFieldOfView(Menu::getInstance()->getFieldOfView());
621 }
622 updateProjectionMatrix(_myCamera, true);
543 }623 }
544 624
545 // Update camera position625 // Update camera position
@@ -630,6 +710,13 @@ void Application::resizeGL(int width, int height) { · 84 unmodified lines
630 _window->geometry().topLeft().y(),710 _window->geometry().topLeft().y(),
631 _runningScriptsWidget->width(), _window->height());711 _runningScriptsWidget->width(), _window->height());
632 }712 }
713 // update Stats width
714 int horizontalOffset = 0;
715 if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
716 // mirror is enabled, let's set horizontal offset to give stats some margin
717 horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
718 }
719 Stats::getInstance()->resetWidth(width, horizontalOffset);
633}720}
634 721
635void Application::updateProjectionMatrix() {722void Application::updateProjectionMatrix() {
@@ -699,26 +786,9 @@ bool Application::event(QEvent* event) { · 63 unmodified lines
699 // handle custom URL786 // handle custom URL
700 if (event->type() == QEvent::FileOpen) {787 if (event->type() == QEvent::FileOpen) {
701 QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);788 QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
702 if (!fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME)) {789 bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME);
703 QString destination = fileEvent->url().toLocalFile().remove(CUSTOM_URL_SCHEME);790 if (isHifiSchemeURL) {
704 QStringList urlParts = destination.split('/', QString::SkipEmptyParts);791 Menu::getInstance()->goTo(fileEvent->url().toString());
705
706 if (urlParts.count() > 1) {
707 // if url has 2 or more parts, the first one is domain name
708 Menu::getInstance()->goToDomain(urlParts[0]);
709
710 // location coordinates
711 Menu::getInstance()->goToDestination(urlParts[1]);
712 if (urlParts.count() > 2) {
713
714 // location orientation
715 Menu::getInstance()->goToOrientation(urlParts[2]);
716 }
717 } else if (urlParts.count() == 1) {
718
719 // location coordinates
720 Menu::getInstance()->goToDestination(urlParts[0]);
721 }
722 }792 }
723 793
724 return false;794 return false;
@@ -740,6 +810,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 15 unmodified lines
740 if (activeWindow() == _window) {810 if (activeWindow() == _window) {
741 bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);811 bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);
742 bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);812 bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);
813 bool isOption = event->modifiers().testFlag(Qt::AltModifier);
743 switch (event->key()) {814 switch (event->key()) {
744 break;815 break;
745 case Qt::Key_BracketLeft:816 case Qt::Key_BracketLeft:
@@ -754,9 +825,6 @@ void Application::keyPressEvent(QKeyEvent* event) { · 8 unmodified lines
754 case Qt::Key_Period:825 case Qt::Key_Period:
755 Menu::getInstance()->handleViewFrustumOffsetKeyModifier(event->key());826 Menu::getInstance()->handleViewFrustumOffsetKeyModifier(event->key());
756 break;827 break;
757 case Qt::Key_Apostrophe:
758 _audioScope.inputPaused = !_audioScope.inputPaused;
759 break;
760 case Qt::Key_L:828 case Qt::Key_L:
761 if (isShifted) {829 if (isShifted) {
762 Menu::getInstance()->triggerOption(MenuOption::LodTools);830 Menu::getInstance()->triggerOption(MenuOption::LodTools);
@@ -766,6 +834,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 3 unmodified lines
766 break;834 break;
767 835
768 case Qt::Key_E:836 case Qt::Key_E:
837 case Qt::Key_PageUp:
769 if (!_myAvatar->getDriveKeys(UP)) {838 if (!_myAvatar->getDriveKeys(UP)) {
770 _myAvatar->jump();839 _myAvatar->jump();
771 }840 }
@@ -777,6 +846,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 5 unmodified lines
777 break;846 break;
778 847
779 case Qt::Key_C:848 case Qt::Key_C:
849 case Qt::Key_PageDown:
780 _myAvatar->setDriveKeys(DOWN, 1.f);850 _myAvatar->setDriveKeys(DOWN, 1.f);
781 break;851 break;
782 852
@@ -785,9 +855,11 @@ void Application::keyPressEvent(QKeyEvent* event) { · 2 unmodified lines
785 break;855 break;
786 856
787 case Qt::Key_S:857 case Qt::Key_S:
788 if (isShifted && isMeta) {858 if (isShifted && isMeta && !isOption) {
789 Menu::getInstance()->triggerOption(MenuOption::SuppressShortTimings);859 Menu::getInstance()->triggerOption(MenuOption::SuppressShortTimings);
790 } else if (!isShifted && isMeta) {860 } else if (isOption && !isShifted && !isMeta) {
861 Menu::getInstance()->triggerOption(MenuOption::ScriptEditor);
862 } else if (!isOption && !isShifted && isMeta) {
791 takeSnapshot();863 takeSnapshot();
792 } else {864 } else {
793 _myAvatar->setDriveKeys(BACK, 1.f);865 _myAvatar->setDriveKeys(BACK, 1.f);
@@ -963,10 +1035,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) { · 169 unmodified lines
963 1035
964 switch (event->key()) {1036 switch (event->key()) {
965 case Qt::Key_E:1037 case Qt::Key_E:
1038 case Qt::Key_PageUp:
966 _myAvatar->setDriveKeys(UP, 0.f);1039 _myAvatar->setDriveKeys(UP, 0.f);
967 break;1040 break;
968 1041
969 case Qt::Key_C:1042 case Qt::Key_C:
1043 case Qt::Key_PageDown:
970 _myAvatar->setDriveKeys(DOWN, 0.f);1044 _myAvatar->setDriveKeys(DOWN, 0.f);
971 break;1045 break;
972 1046
@@ -1089,7 +1163,11 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { · 116 unmodified lines
1089 _mousePressed = false;1163 _mousePressed = false;
1090 checkBandwidthMeterClick();1164 checkBandwidthMeterClick();
1091 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {1165 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
1092 checkStatsClick();1166 int horizontalOffset = 0;
1167 if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
1168 horizontalOffset = MIRROR_VIEW_WIDTH;
1169 }
1170 Stats::getInstance()->checkClick(_mouseX, _mouseY, _mouseDragStartedX, _mouseDragStartedY, horizontalOffset);
1093 }1171 }
1094 }1172 }
1095 }1173 }
@@ -1155,7 +1233,6 @@ void Application::touchEndEvent(QTouchEvent* event) { · 59 unmodified lines
1155 if (_controllerScriptingInterface.isTouchCaptured()) {1233 if (_controllerScriptingInterface.isTouchCaptured()) {
1156 return;1234 return;
1157 }1235 }
1158
1159 // put any application specific touch behavior below here..1236 // put any application specific touch behavior below here..
1160 _touchDragStartedAvgX = _touchAvgX;1237 _touchDragStartedAvgX = _touchAvgX;
1161 _touchDragStartedAvgY = _touchAvgY;1238 _touchDragStartedAvgY = _touchAvgY;
@@ -1209,26 +1286,24 @@ void Application::sendPingPackets() { · 47 unmodified lines
1209 1286
1210// Every second, check the frame rates and other stuff1287// Every second, check the frame rates and other stuff
1211void Application::timer() {1288void Application::timer() {
1212 gettimeofday(&_timerEnd, NULL);
1213
1214 if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {1289 if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
1215 sendPingPackets();1290 sendPingPackets();
1216 }1291 }
1217 1292
1218 _fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);1293 float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f;
1294
1295 _fps = (float)_frameCount / diffTime;
1219 1296
1220 _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);1297 _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / diffTime;
1221 _bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);1298 _bytesPerSecond = (float) _datagramProcessor.getByteCount() / diffTime;
1222 _frameCount = 0;1299 _frameCount = 0;
1223 1300
1224 _datagramProcessor.resetCounters();1301 _datagramProcessor.resetCounters();
1225 1302
1226 gettimeofday(&_timerStart, NULL);1303 _timerStart.start();
1227 1304
1228 // ask the node list to check in with the domain server1305 // ask the node list to check in with the domain server
1229 NodeList::getInstance()->sendDomainServerCheckIn();1306 NodeList::getInstance()->sendDomainServerCheckIn();
1230
1231
1232}1307}
1233 1308
1234void Application::idle() {1309void Application::idle() {
@@ -1238,13 +1313,11 @@ void Application::idle() { · 3 unmodified lines
1238 bool showWarnings = getLogger()->extraDebugging();1313 bool showWarnings = getLogger()->extraDebugging();
1239 PerformanceWarning warn(showWarnings, "Application::idle()");1314 PerformanceWarning warn(showWarnings, "Application::idle()");
1240 1315
1241 timeval check;
1242 gettimeofday(&check, NULL);
1243
1244 // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran1316 // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran
1245 1317
1246 double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check);1318 double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0;
1247 if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {1319 if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {
1320 _lastTimeUpdated.start();
1248 {1321 {
1249 PerformanceWarning warn(showWarnings, "Application::idle()... update()");1322 PerformanceWarning warn(showWarnings, "Application::idle()... update()");
1250 const float BIGGEST_DELTA_TIME_SECS = 0.25f;1323 const float BIGGEST_DELTA_TIME_SECS = 0.25f;
@@ -1256,7 +1329,6 @@ void Application::idle() { · 5 unmodified lines
1256 }1329 }
1257 {1330 {
1258 PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");1331 PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");
1259 _lastTimeUpdated = check;
1260 _idleLoopStdev.addValue(timeSinceLastUpdate);1332 _idleLoopStdev.addValue(timeSinceLastUpdate);
1261 1333
1262 // Record standard deviation and reset counter if needed1334 // Record standard deviation and reset counter if needed
@@ -1273,6 +1345,9 @@ void Application::idle() { · 10 unmodified lines
1273 // After finishing all of the above work, restart the idle timer, allowing 2ms to process events.1345 // After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
1274 idleTimer->start(2);1346 idleTimer->start(2);
1275 }1347 }
1348 if (_numChangedSettings > 0) {
1349 saveSettings();
1350 }
1276 }1351 }
1277}1352}
1278 1353
@@ -1353,6 +1428,12 @@ glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail& mouseVox · 74 unmodified lines
1353 (mouseVoxel.z + mouseVoxel.s / 2.f) * TREE_SCALE);1428 (mouseVoxel.z + mouseVoxel.s / 2.f) * TREE_SCALE);
1354}1429}
1355 1430
1431FaceTracker* Application::getActiveFaceTracker() {
1432 return _faceshift.isActive() ? static_cast<FaceTracker*>(&_faceshift) :
1433 (_faceplus.isActive() ? static_cast<FaceTracker*>(&_faceplus) :
1434 (_visage.isActive() ? static_cast<FaceTracker*>(&_visage) : NULL));
1435}
1436
1356struct SendVoxelsOperationArgs {1437struct SendVoxelsOperationArgs {
1357 const unsigned char* newBaseOctCode;1438 const unsigned char* newBaseOctCode;
1358};1439};
@@ -1563,8 +1644,8 @@ void Application::init() { · 204 unmodified lines
1563 Qt::QueuedConnection);1644 Qt::QueuedConnection);
1564 }1645 }
1565 1646
1566 gettimeofday(&_timerStart, NULL);1647 _timerStart.start();
1567 gettimeofday(&_lastTimeUpdated, NULL);1648 _lastTimeUpdated.start();
1568 1649
1569 Menu::getInstance()->loadSettings();1650 Menu::getInstance()->loadSettings();
1570 if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {1651 if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {
@@ -1572,8 +1653,9 @@ void Application::init() { · 1 unmodified line
1572 }1653 }
1573 qDebug("Loaded settings");1654 qDebug("Loaded settings");
1574 1655
1575 // initialize Visage and Faceshift after loading the menu settings1656 // initialize our face trackers after loading the menu settings
1576 _faceshift.init();1657 _faceshift.init();
1658 _faceplus.init();
1577 _visage.init();1659 _visage.init();
1578 1660
1579 // fire off an immediate domain-server check in now that settings are loaded1661 // fire off an immediate domain-server check in now that settings are loaded
@@ -1593,16 +1675,12 @@ void Application::init() { · 13 unmodified lines
1593 1675
1594 _particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager);1676 _particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager);
1595 1677
1596 // connect the _particleCollisionSystem to our script engine's ParticleScriptingInterface1678 // connect the _particleCollisionSystem to our script engine's ParticlesScriptingInterface
1597 connect(&_particleCollisionSystem,1679 connect(&_particleCollisionSystem, &ParticleCollisionSystem::particleCollisionWithVoxel,
1598 SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)),1680 ScriptEngine::getParticlesScriptingInterface(), &ParticlesScriptingInterface::particleCollisionWithVoxel);
1599 ScriptEngine::getParticlesScriptingInterface(),
1600 SLOT(forwardParticleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)));
1601 1681
1602 connect(&_particleCollisionSystem,1682 connect(&_particleCollisionSystem, &ParticleCollisionSystem::particleCollisionWithParticle,
1603 SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)),1683 ScriptEngine::getParticlesScriptingInterface(), &ParticlesScriptingInterface::particleCollisionWithParticle);
1604 ScriptEngine::getParticlesScriptingInterface(),
1605 SLOT(forwardParticleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)));
1606 1684
1607 _audio.init(_glWidget);1685 _audio.init(_glWidget);
1608 1686
@@ -1612,6 +1690,20 @@ void Application::init() { · 3 unmodified lines
1612 connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));1690 connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
1613 connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));1691 connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
1614 connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));1692 connect(_rearMirrorTools, SIGNAL(resetView()), SLOT(resetSensors()));
1693
1694 // set up our audio reflector
1695 _audioReflector.setMyAvatar(getAvatar());
1696 _audioReflector.setVoxels(_voxels.getTree());
1697 _audioReflector.setAudio(getAudio());
1698 _audioReflector.setAvatarManager(&_avatarManager);
1699
1700 connect(getAudio(), &Audio::processInboundAudio, &_audioReflector, &AudioReflector::processInboundAudio,Qt::DirectConnection);
1701 connect(getAudio(), &Audio::processLocalAudio, &_audioReflector, &AudioReflector::processLocalAudio,Qt::DirectConnection);
1702 connect(getAudio(), &Audio::preProcessOriginalInboundAudio, &_audioReflector,
1703 &AudioReflector::preProcessOriginalInboundAudio,Qt::DirectConnection);
1704
1705 // save settings when avatar changes
1706 connect(_myAvatar, &MyAvatar::transformChanged, this, &Application::bumpSettings);
1615}1707}
1616 1708
1617void Application::closeMirrorView() {1709void Application::closeMirrorView() {
@@ -1737,19 +1829,11 @@ void Application::updateMyAvatarLookAtPosition() { · 119 unmodified lines
1737 glm::distance(_mouseRayOrigin, _myAvatar->getHead()->calculateAverageEyePosition()));1829 glm::distance(_mouseRayOrigin, _myAvatar->getHead()->calculateAverageEyePosition()));
1738 lookAtSpot = _mouseRayOrigin + _mouseRayDirection * qMax(minEyeDistance, distance);1830 lookAtSpot = _mouseRayOrigin + _mouseRayDirection * qMax(minEyeDistance, distance);
1739 }1831 }
1740 bool trackerActive = false;1832 FaceTracker* tracker = getActiveFaceTracker();
1741 float eyePitch, eyeYaw;1833 if (tracker) {
1742 if (_faceshift.isActive()) {1834 float eyePitch = tracker->getEstimatedEyePitch();
1743 eyePitch = _faceshift.getEstimatedEyePitch();1835 float eyeYaw = tracker->getEstimatedEyeYaw();
1744 eyeYaw = _faceshift.getEstimatedEyeYaw();
1745 trackerActive = true;
1746 1836
1747 } else if (_visage.isActive()) {
1748 eyePitch = _visage.getEstimatedEyePitch();
1749 eyeYaw = _visage.getEstimatedEyeYaw();
1750 trackerActive = true;
1751 }
1752 if (trackerActive) {
1753 // deflect using Faceshift gaze data1837 // deflect using Faceshift gaze data
1754 glm::vec3 origin = _myAvatar->getHead()->calculateAverageEyePosition();1838 glm::vec3 origin = _myAvatar->getHead()->calculateAverageEyePosition();
1755 float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f;1839 float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f;
@@ -1835,15 +1919,15 @@ void Application::updateCamera(float deltaTime) { · 79 unmodified lines
1835 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);1919 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
1836 PerformanceWarning warn(showWarnings, "Application::updateCamera()");1920 PerformanceWarning warn(showWarnings, "Application::updateCamera()");
1837 1921
1838 if (!OculusManager::isConnected() && !TV3DManager::isConnected()) {1922 if (!OculusManager::isConnected() && !TV3DManager::isConnected() &&
1839 if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) {1923 Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) {
1840 float xSign = _myCamera.getMode() == CAMERA_MODE_MIRROR ? 1.0f : -1.0f;1924 FaceTracker* tracker = getActiveFaceTracker();
1841 if (_faceshift.isActive()) {1925 if (tracker) {
1842 const float EYE_OFFSET_SCALE = 0.025f;1926 const float EYE_OFFSET_SCALE = 0.025f;
1843 glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE;1927 glm::vec3 position = tracker->getHeadTranslation() * EYE_OFFSET_SCALE;
1844 _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z));1928 float xSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? 1.0f : -1.0f;
1845 updateProjectionMatrix();1929 _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z));
1846 }1930 updateProjectionMatrix();
1847 }1931 }
1848 }1932 }
1849}1933}
@@ -2137,7 +2221,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node · 287 unmodified lines
2137 int packetLength = endOfQueryPacket - queryPacket;2221 int packetLength = endOfQueryPacket - queryPacket;
2138 2222
2139 // make sure we still have an active socket2223 // make sure we still have an active socket
2140 nodeList->writeDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);2224 nodeList->writeUnverifiedDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
2141 2225
2142 // Feed number of bytes to corresponding channel of the bandwidth meter2226 // Feed number of bytes to corresponding channel of the bandwidth meter
2143 _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength);2227 _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength);
@@ -2252,8 +2336,7 @@ void Application::updateShadowMap() { · 108 unmodified lines
2252 glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z);2336 glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z);
2253 2337
2254 // store view matrix without translation, which we'll use for precision-sensitive objects2338 // store view matrix without translation, which we'll use for precision-sensitive objects
2255 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);2339 updateUntranslatedViewMatrix();
2256 _viewMatrixTranslation = glm::vec3();
2257 2340
2258 _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);2341 _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
2259 _particles.render();2342 _particles.render();
@@ -2338,8 +2421,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 78 unmodified lines
2338 glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);2421 glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
2339 2422
2340 // store view matrix without translation, which we'll use for precision-sensitive objects2423 // store view matrix without translation, which we'll use for precision-sensitive objects
2341 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);2424 updateUntranslatedViewMatrix(-whichCamera.getPosition());
2342 _viewMatrixTranslation = -whichCamera.getPosition();
2343 2425
2344 glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z);2426 glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z);
2345 2427
@@ -2394,6 +2476,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 48 unmodified lines
2394 // disable specular lighting for ground and voxels2476 // disable specular lighting for ground and voxels
2395 glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);2477 glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);
2396 2478
2479 // draw the audio reflector overlay
2480 _audioReflector.render();
2481
2397 // Draw voxels2482 // Draw voxels
2398 if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {2483 if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
2399 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),2484 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
@@ -2470,6 +2555,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 70 unmodified lines
2470 }2555 }
2471}2556}
2472 2557
2558void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation) {
2559 glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);
2560 _viewMatrixTranslation = viewMatrixTranslation;
2561}
2562
2473void Application::loadTranslatedViewMatrix(const glm::vec3& translation) {2563void Application::loadTranslatedViewMatrix(const glm::vec3& translation) {
2474 glLoadMatrixf((const GLfloat*)&_untranslatedViewMatrix);2564 glLoadMatrixf((const GLfloat*)&_untranslatedViewMatrix);
2475 glTranslatef(translation.x + _viewMatrixTranslation.x, translation.y + _viewMatrixTranslation.y,2565 glTranslatef(translation.x + _viewMatrixTranslation.x, translation.y + _viewMatrixTranslation.y,
@@ -2514,32 +2604,22 @@ void Application::displayOverlay() { · 38 unmodified lines
2514 }2604 }
2515 }2605 }
2516 2606
2517 // Audio Scope
2518 const int AUDIO_SCOPE_Y_OFFSET = 135;
2519 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
2520 if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) {
2521 int oscilloscopeTop = _glWidget->height() - AUDIO_SCOPE_Y_OFFSET;
2522 _audioScope.render(MIRROR_VIEW_LEFT_PADDING, oscilloscopeTop);
2523 }
2524 }
2525
2526 // Audio VU Meter and Mute Icon2607 // Audio VU Meter and Mute Icon
2527 const int MUTE_ICON_SIZE = 24;2608 const int MUTE_ICON_SIZE = 24;
2528 const int AUDIO_METER_INSET = 2;2609 const int AUDIO_METER_INSET = 2;
2529 const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET;2610 const int MUTE_ICON_PADDING = 10;
2611 const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET - MUTE_ICON_PADDING;
2530 const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;2612 const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
2531 const int AUDIO_METER_HEIGHT = 8;2613 const int AUDIO_METER_HEIGHT = 8;
2532 const int AUDIO_METER_Y_GAP = 8;2614 const int AUDIO_METER_GAP = 5;
2533 const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET;2615 const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
2534 2616
2535 int audioMeterY;2617 int audioMeterY;
2536 if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {2618 if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
2537 audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_Y_GAP;2619 audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING;
2538 } else {2620 } else {
2539 audioMeterY = AUDIO_METER_Y_GAP;2621 audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
2540 }2622 }
2541 _audio.renderMuteIcon(MIRROR_VIEW_LEFT_PADDING, audioMeterY);
2542
2543 2623
2544 const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0};2624 const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0};
2545 const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0};2625 const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0};
@@ -2549,29 +2629,53 @@ void Application::displayOverlay() { · 3 unmodified lines
2549 const float CLIPPING_INDICATOR_TIME = 1.0f;2629 const float CLIPPING_INDICATOR_TIME = 1.0f;
2550 const float AUDIO_METER_AVERAGING = 0.5;2630 const float AUDIO_METER_AVERAGING = 0.5;
2551 const float LOG2 = log(2.f);2631 const float LOG2 = log(2.f);
2552 const float MAX_LOG2_SAMPLE = 15.f;2632 const float METER_LOUDNESS_SCALE = 2.8f / 5.f;
2633 const float LOG2_LOUDNESS_FLOOR = 11.f;
2553 float audioLevel = 0.f;2634 float audioLevel = 0.f;
2554 float loudness = _audio.getLastInputLoudness() + 1.f;2635 float loudness = _audio.getLastInputLoudness() + 1.f;
2555 _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
2556 2636
2637 _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
2557 float log2loudness = log(_trailingAudioLoudness) / LOG2;2638 float log2loudness = log(_trailingAudioLoudness) / LOG2;
2558 2639
2559 audioLevel = log2loudness / MAX_LOG2_SAMPLE * AUDIO_METER_SCALE_WIDTH;2640 if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
2560 2641 audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
2642 } else {
2643 audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.f)) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH;
2644 }
2645 if (audioLevel > AUDIO_METER_SCALE_WIDTH) {
2646 audioLevel = AUDIO_METER_SCALE_WIDTH;
2647 }
2561 bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));2648 bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
2562 2649
2650 if ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) {
2651 const float MAX_MAGNITUDE = 0.7f;
2652 float magnitude = MAX_MAGNITUDE * (1 - _audio.getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME);
2653 renderCollisionOverlay(_glWidget->width(), _glWidget->height(), magnitude, 1.0f);
2654 }
2655
2656 _audio.renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP,
2657 audioMeterY,
2658 Menu::getInstance()->isOptionChecked(MenuOption::Mirror));
2659
2660 _audio.renderScope(_glWidget->width(), _glWidget->height());
2661
2563 glBegin(GL_QUADS);2662 glBegin(GL_QUADS);
2564 if (isClipping) {2663 if (isClipping) {
2565 glColor3f(1, 0, 0);2664 glColor3f(1, 0, 0);
2566 } else {2665 } else {
2567 glColor3f(0, 0, 0);2666 glColor3f(0.475f, 0.475f, 0.475f);
2568 }2667 }
2668
2669 audioMeterY += AUDIO_METER_HEIGHT;
2670
2671 glColor3f(0, 0, 0);
2569 // Draw audio meter background Quad2672 // Draw audio meter background Quad
2570 glVertex2i(AUDIO_METER_X, audioMeterY);2673 glVertex2i(AUDIO_METER_X, audioMeterY);
2571 glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);2674 glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);
2572 glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);2675 glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);
2573 glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);2676 glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);
2574 2677
2678
2575 if (audioLevel > AUDIO_RED_START) {2679 if (audioLevel > AUDIO_RED_START) {
2576 if (!isClipping) {2680 if (!isClipping) {
2577 glColor3fv(AUDIO_METER_RED);2681 glColor3fv(AUDIO_METER_RED);
@@ -2611,6 +2715,7 @@ void Application::displayOverlay() { · 33 unmodified lines
2611 glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);2715 glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
2612 glEnd();2716 glEnd();
2613 2717
2718
2614 if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {2719 if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
2615 _myAvatar->renderHeadMouse();2720 _myAvatar->renderHeadMouse();
2616 }2721 }
@@ -2620,11 +2725,17 @@ void Application::displayOverlay() { · 3 unmodified lines
2620 glPointSize(1.0f);2725 glPointSize(1.0f);
2621 2726
2622 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {2727 if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
2728 int horizontalOffset = 0;
2729 if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
2730 // mirror is enabled, let's set horizontal offset to give stats some margin
2731 horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
2732 }
2733 int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount();
2623 // Onscreen text about position, servers, etc2734 // Onscreen text about position, servers, etc
2624 displayStats();2735 Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess);
2625 // Bandwidth meter2736 // Bandwidth meter
2626 if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {2737 if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
2627 displayStatsBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68);2738 Stats::drawBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68);
2628 _bandwidthMeter.render(_glWidget->width(), _glWidget->height());2739 _bandwidthMeter.render(_glWidget->width(), _glWidget->height());
2629 }2740 }
2630 }2741 }
@@ -2638,7 +2749,7 @@ void Application::displayOverlay() { · 7 unmodified lines
2638 (Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&2749 (Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
2639 Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))2750 Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
2640 ? 80 : 20;2751 ? 80 : 20;
2641 drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 1.0f, 0.f, frameTimer, WHITE_TEXT);2752 drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT);
2642 }2753 }
2643 2754
2644 _overlays.render2D();2755 _overlays.render2D();
@@ -2646,415 +2757,6 @@ void Application::displayOverlay() { · 1 unmodified line
2646 glPopMatrix();2757 glPopMatrix();
2647}2758}
2648 2759
2649// translucent background box that makes stats more readable
2650void Application::displayStatsBackground(unsigned int rgba, int x, int y, int width, int height) {
2651 glBegin(GL_QUADS);
2652 glColor4f(((rgba >> 24) & 0xff) / 255.0f,
2653 ((rgba >> 16) & 0xff) / 255.0f,
2654 ((rgba >> 8) & 0xff) / 255.0f,
2655 (rgba & 0xff) / 255.0f);
2656 glVertex3f(x, y, 0);
2657 glVertex3f(x + width, y, 0);
2658 glVertex3f(x + width, y + height, 0);
2659 glVertex3f(x , y + height, 0);
2660 glEnd();
2661 glColor4f(1, 1, 1, 1);
2662}
2663
2664// display expanded or contracted stats
2665
2666void Application::displayStats() {
2667 unsigned int backgroundColor = 0x33333399;
2668 int verticalOffset = 0, horizontalOffset = 0, lines = 0;
2669 bool mirrorEnabled = Menu::getInstance()->isOptionChecked(MenuOption::Mirror);
2670
2671 QLocale locale(QLocale::English);
2672 std::stringstream voxelStats;
2673
2674 glPointSize(1.0f);
2675
2676 // we need to take one avatar out so we don't include ourselves
2677 int totalAvatars = _avatarManager.size() - 1;
2678 int totalServers = NodeList::getInstance()->size();
2679
2680 if (mirrorEnabled) {
2681 horizontalOffset += MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
2682 }
2683
2684 lines = _statsExpanded ? 5 : 3;
2685 displayStatsBackground(backgroundColor, horizontalOffset, 0, 165, lines * STATS_PELS_PER_LINE + 10);
2686 horizontalOffset += 5;
2687
2688 char serverNodes[30];
2689 sprintf(serverNodes, "Servers: %d", totalServers);
2690 char avatarNodes[30];
2691 sprintf(avatarNodes, "Avatars: %d", totalAvatars);
2692 char framesPerSecond[30];
2693 sprintf(framesPerSecond, "Framerate: %3.0f FPS", _fps);
2694
2695 verticalOffset += STATS_PELS_PER_LINE;
2696 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, serverNodes, WHITE_TEXT);
2697 verticalOffset += STATS_PELS_PER_LINE;
2698 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarNodes, WHITE_TEXT);
2699 verticalOffset += STATS_PELS_PER_LINE;
2700 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, framesPerSecond, WHITE_TEXT);
2701
2702 if (_statsExpanded) {
2703 char packetsPerSecond[30];
2704 sprintf(packetsPerSecond, "Pkts/sec: %d", _packetsPerSecond);
2705 char averageMegabitsPerSecond[30];
2706 sprintf(averageMegabitsPerSecond, "Mbps: %3.2f", (float)_bytesPerSecond * 8.f / 1000000.f);
2707
2708 verticalOffset += STATS_PELS_PER_LINE;
2709 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, packetsPerSecond, WHITE_TEXT);
2710 verticalOffset += STATS_PELS_PER_LINE;
2711 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, averageMegabitsPerSecond, WHITE_TEXT);
2712 }
2713
2714 verticalOffset = 0;
2715 horizontalOffset += 161;
2716
2717 if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
2718 int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0;
2719
2720 NodeList* nodeList = NodeList::getInstance();
2721 SharedNodePointer audioMixerNode = nodeList->soloNodeOfType(NodeType::AudioMixer);
2722 SharedNodePointer avatarMixerNode = nodeList->soloNodeOfType(NodeType::AvatarMixer);
2723
2724 pingAudio = audioMixerNode ? audioMixerNode->getPingMs() : 0;
2725 pingAvatar = avatarMixerNode ? avatarMixerNode->getPingMs() : 0;
2726
2727 // Now handle voxel servers, since there could be more than one, we average their ping times
2728 unsigned long totalPingVoxel = 0;
2729 int voxelServerCount = 0;
2730
2731 foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
2732 if (node->getType() == NodeType::VoxelServer) {
2733 totalPingVoxel += node->getPingMs();
2734 voxelServerCount++;
2735 if (pingVoxelMax < node->getPingMs()) {
2736 pingVoxelMax = node->getPingMs();
2737 }
2738 }
2739 }
2740
2741 if (voxelServerCount) {
2742 pingVoxel = totalPingVoxel/voxelServerCount;
2743 }
2744
2745 lines = _statsExpanded ? 4 : 3;
2746 displayStatsBackground(backgroundColor, horizontalOffset, 0, 175, lines * STATS_PELS_PER_LINE + 10);
2747 horizontalOffset += 5;
2748
2749 char audioJitter[30];
2750 sprintf(audioJitter,
2751 "Buffer msecs %.1f",
2752 (float) (_audio.getNetworkBufferLengthSamplesPerChannel() + (float) _audio.getJitterBufferSamples()) /
2753 (float)_audio.getNetworkSampleRate() * 1000.f);
2754 drawText(30, _glWidget->height() - 22, 0.10f, 0.f, 2.f, audioJitter, WHITE_TEXT);
2755
2756
2757 char audioPing[30];
2758 sprintf(audioPing, "Audio ping: %d", pingAudio);
2759
2760
2761 char avatarPing[30];
2762 sprintf(avatarPing, "Avatar ping: %d", pingAvatar);
2763 char voxelAvgPing[30];
2764 sprintf(voxelAvgPing, "Voxel avg ping: %d", pingVoxel);
2765
2766 verticalOffset += STATS_PELS_PER_LINE;
2767 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, audioPing, WHITE_TEXT);
2768 verticalOffset += STATS_PELS_PER_LINE;
2769 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPing, WHITE_TEXT);
2770 verticalOffset += STATS_PELS_PER_LINE;
2771 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelAvgPing, WHITE_TEXT);
2772
2773 if (_statsExpanded) {
2774 char voxelMaxPing[30];
2775 sprintf(voxelMaxPing, "Voxel max ping: %d", pingVoxelMax);
2776
2777 verticalOffset += STATS_PELS_PER_LINE;
2778 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, voxelMaxPing, WHITE_TEXT);
2779 }
2780
2781 verticalOffset = 0;
2782 horizontalOffset += 171;
2783 }
2784
2785 glm::vec3 avatarPos = _myAvatar->getPosition();
2786
2787 lines = _statsExpanded ? 5 : 3;
2788 displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - (mirrorEnabled ? 301 : 411) - horizontalOffset, lines * STATS_PELS_PER_LINE + 10);
2789 horizontalOffset += 5;
2790
2791 char avatarPosition[200];
2792 if (mirrorEnabled) {
2793 // shorthand formatting
2794 sprintf(avatarPosition, "Pos: %.0f,%.0f,%.0f", avatarPos.x, avatarPos.y, avatarPos.z);
2795 } else {
2796 // longhand way
2797 sprintf(avatarPosition, "Position: %.1f, %.1f, %.1f", avatarPos.x, avatarPos.y, avatarPos.z);
2798 }
2799 char avatarVelocity[30];
2800 sprintf(avatarVelocity, "Velocity: %.1f", glm::length(_myAvatar->getVelocity()));
2801 char avatarBodyYaw[30];
2802 sprintf(avatarBodyYaw, "Yaw: %.1f", _myAvatar->getBodyYaw());
2803 char avatarMixerStats[200];
2804
2805 verticalOffset += STATS_PELS_PER_LINE;
2806 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarPosition, WHITE_TEXT);
2807 verticalOffset += STATS_PELS_PER_LINE;
2808 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarVelocity, WHITE_TEXT);
2809 verticalOffset += STATS_PELS_PER_LINE;
2810 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarBodyYaw, WHITE_TEXT);
2811
2812 if (_statsExpanded) {
2813 SharedNodePointer avatarMixer = NodeList::getInstance()->soloNodeOfType(NodeType::AvatarMixer);
2814 if (avatarMixer) {
2815 sprintf(avatarMixerStats, "Avatar Mixer: %.f kbps, %.f pps",
2816 roundf(avatarMixer->getAverageKilobitsPerSecond()),
2817 roundf(avatarMixer->getAveragePacketsPerSecond()));
2818 } else {
2819 sprintf(avatarMixerStats, "No Avatar Mixer");
2820 }
2821
2822 verticalOffset += STATS_PELS_PER_LINE;
2823 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, avatarMixerStats, WHITE_TEXT);
2824
2825 stringstream downloadStats;
2826 downloadStats << "Downloads: ";
2827 foreach (Resource* resource, ResourceCache::getLoadingRequests()) {
2828 const float MAXIMUM_PERCENTAGE = 100.0f;
2829 downloadStats << roundf(resource->getProgress() * MAXIMUM_PERCENTAGE) << "% ";
2830 }
2831 downloadStats << "(" << ResourceCache::getPendingRequestCount() << " pending)";
2832
2833 verticalOffset += STATS_PELS_PER_LINE;
2834 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, downloadStats.str().c_str(), WHITE_TEXT);
2835 }
2836
2837 verticalOffset = 0;
2838 horizontalOffset = _glWidget->width() - (mirrorEnabled ? 300 : 410);
2839
2840 lines = _statsExpanded ? 12 : 3;
2841 displayStatsBackground(backgroundColor, horizontalOffset, 0, _glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10);
2842 horizontalOffset += 5;
2843
2844 if (_statsExpanded) {
2845 // Local Voxel Memory Usage
2846 voxelStats.str("");
2847 voxelStats << "Voxels Memory Nodes: " << VoxelTreeElement::getTotalMemoryUsage() / 1000000.f << "MB";
2848 verticalOffset += STATS_PELS_PER_LINE;
2849 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2850
2851 voxelStats.str("");
2852 voxelStats <<
2853 "Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB / " <<
2854 "VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB";
2855 if (_voxels.hasVoxelMemoryUsageGPU()) {
2856 voxelStats << " / GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB";
2857 }
2858 verticalOffset += STATS_PELS_PER_LINE;
2859 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2860
2861 // Voxel Rendering
2862 voxelStats.str("");
2863 voxelStats.precision(4);
2864 voxelStats << "Voxel Rendering Slots Max: " << _voxels.getMaxVoxels() / 1000.f << "K";
2865 verticalOffset += STATS_PELS_PER_LINE;
2866 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2867 }
2868
2869 voxelStats.str("");
2870 voxelStats.precision(4);
2871 voxelStats << "Drawn: " << _voxels.getVoxelsWritten() / 1000.f << "K " <<
2872 "Abandoned: " << _voxels.getAbandonedVoxels() / 1000.f << "K ";
2873 verticalOffset += STATS_PELS_PER_LINE;
2874 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2875
2876 // iterate all the current voxel stats, and list their sending modes, and total voxel counts
2877 std::stringstream sendingMode("");
2878 sendingMode << "Octree Sending Mode: [";
2879 int serverCount = 0;
2880 int movingServerCount = 0;
2881 unsigned long totalNodes = 0;
2882 unsigned long totalInternal = 0;
2883 unsigned long totalLeaves = 0;
2884 for(NodeToOctreeSceneStatsIterator i = _octreeServerSceneStats.begin(); i != _octreeServerSceneStats.end(); i++) {
2885 //const QUuid& uuid = i->first;
2886 OctreeSceneStats& stats = i->second;
2887 serverCount++;
2888 if (_statsExpanded) {
2889 if (serverCount > 1) {
2890 sendingMode << ",";
2891 }
2892 if (stats.isMoving()) {
2893 sendingMode << "M";
2894 movingServerCount++;
2895 } else {
2896 sendingMode << "S";
2897 }
2898 }
2899
2900 // calculate server node totals
2901 totalNodes += stats.getTotalElements();
2902 if (_statsExpanded) {
2903 totalInternal += stats.getTotalInternal();
2904 totalLeaves += stats.getTotalLeaves();
2905 }
2906 }
2907 if (_statsExpanded) {
2908 if (serverCount == 0) {
2909 sendingMode << "---";
2910 }
2911 sendingMode << "] " << serverCount << " servers";
2912 if (movingServerCount > 0) {
2913 sendingMode << " <SCENE NOT STABLE>";
2914 } else {
2915 sendingMode << " <SCENE STABLE>";
2916 }
2917 verticalOffset += STATS_PELS_PER_LINE;
2918 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)sendingMode.str().c_str(), WHITE_TEXT);
2919 }
2920
2921 // Incoming packets
2922 int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount();
2923 if (_statsExpanded) {
2924 voxelStats.str("");
2925 QString packetsString = locale.toString((int)voxelPacketsToProcess);
2926 QString maxString = locale.toString((int)_recentMaxPackets);
2927 voxelStats << "Voxel Packets to Process: " << qPrintable(packetsString)
2928 << " [Recent Max: " << qPrintable(maxString) << "]";
2929 verticalOffset += STATS_PELS_PER_LINE;
2930 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2931 }
2932
2933 if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) {
2934 _recentMaxPackets = 0;
2935 _resetRecentMaxPacketsSoon = false;
2936 }
2937 if (voxelPacketsToProcess == 0) {
2938 _resetRecentMaxPacketsSoon = true;
2939 } else {
2940 if (voxelPacketsToProcess > _recentMaxPackets) {
2941 _recentMaxPackets = voxelPacketsToProcess;
2942 }
2943 }
2944
2945 verticalOffset += (_statsExpanded ? STATS_PELS_PER_LINE : 0);
2946
2947 QString serversTotalString = locale.toString((uint)totalNodes); // consider adding: .rightJustified(10, ' ');
2948
2949 // Server Voxels
2950 voxelStats.str("");
2951 voxelStats << "Server voxels: " << qPrintable(serversTotalString);
2952 verticalOffset += STATS_PELS_PER_LINE;
2953 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2954
2955 if (_statsExpanded) {
2956 QString serversInternalString = locale.toString((uint)totalInternal);
2957 QString serversLeavesString = locale.toString((uint)totalLeaves);
2958
2959 voxelStats.str("");
2960 voxelStats <<
2961 "Internal: " << qPrintable(serversInternalString) << " " <<
2962 "Leaves: " << qPrintable(serversLeavesString) << "";
2963 verticalOffset += STATS_PELS_PER_LINE;
2964 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2965 }
2966
2967 unsigned long localTotal = VoxelTreeElement::getNodeCount();
2968 QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' ');
2969
2970 // Local Voxels
2971 voxelStats.str("");
2972 voxelStats << "Local voxels: " << qPrintable(localTotalString);
2973 verticalOffset += STATS_PELS_PER_LINE;
2974 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2975
2976 if (_statsExpanded) {
2977 unsigned long localInternal = VoxelTreeElement::getInternalNodeCount();
2978 unsigned long localLeaves = VoxelTreeElement::getLeafNodeCount();
2979 QString localInternalString = locale.toString((uint)localInternal);
2980 QString localLeavesString = locale.toString((uint)localLeaves);
2981
2982 voxelStats.str("");
2983 voxelStats <<
2984 "Internal: " << qPrintable(localInternalString) << " " <<
2985 "Leaves: " << qPrintable(localLeavesString) << "";
2986 verticalOffset += STATS_PELS_PER_LINE;
2987 drawText(horizontalOffset, verticalOffset, 0.10f, 0, 2, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2988 }
2989
2990 // LOD Details
2991 if (_statsExpanded) {
2992 voxelStats.str("");
2993 QString displayLODDetails = Menu::getInstance()->getLODFeedbackText();
2994 voxelStats << "LOD: You can see " << qPrintable(displayLODDetails.trimmed());
2995 verticalOffset += STATS_PELS_PER_LINE;
2996 drawText(horizontalOffset, verticalOffset, 0.10f, 0.f, 2.f, (char*)voxelStats.str().c_str(), WHITE_TEXT);
2997 }
2998}
2999
3000// called on mouse click release
3001// check for clicks over stats in order to expand or contract them
3002void Application::checkStatsClick() {
3003 if (0 != glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY)))) {
3004 // not worried about dragging on stats
3005 return;
3006 }
3007
3008 int statsHeight = 0, statsWidth = 0, statsX = 0, statsY = 0, lines = 0;
3009
3010 if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
3011 statsX += MIRROR_VIEW_WIDTH;
3012 }
3013
3014 // top-left stats click
3015 lines = _statsExpanded ? 5 : 3;
3016 statsHeight = lines * STATS_PELS_PER_LINE + 10;
3017 statsWidth = 165;
3018 if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) {
3019 toggleStatsExpanded();
3020 return;
3021 }
3022
3023 // ping stats click
3024 lines = _statsExpanded ? 4 : 3;
3025 statsX += statsWidth;
3026 statsHeight = lines * STATS_PELS_PER_LINE + 10;
3027 statsWidth = 175;
3028 if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) {
3029 toggleStatsExpanded();
3030 return;
3031 }
3032
3033 // top-center stats panel click
3034 lines = _statsExpanded ? 4 : 3;
3035 statsX += statsWidth;
3036 statsHeight = lines * STATS_PELS_PER_LINE + 10;
3037 statsWidth = _glWidget->width() - 411 - statsX;
3038 if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) {
3039 toggleStatsExpanded();
3040 return;
3041 }
3042
3043 // top-right stats click
3044 lines = _statsExpanded ? 11 : 3;
3045 statsX = _glWidget->width() - 410;
3046 statsHeight = lines * STATS_PELS_PER_LINE + 10;
3047 statsWidth = _glWidget->width() - statsX;
3048 if (_mouseX > statsX && _mouseX < statsX + statsWidth && _mouseY > statsY && _mouseY < statsY + statsHeight) {
3049 toggleStatsExpanded();
3050 return;
3051 }
3052}
3053
3054void Application::toggleStatsExpanded() {
3055 _statsExpanded = !_statsExpanded;
3056}
3057
3058glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {2760glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
3059 float horizontalScale = _glWidget->width() / 2.0f;2761 float horizontalScale = _glWidget->width() / 2.0f;
3060 float verticalScale = _glWidget->height() / 2.0f;2762 float verticalScale = _glWidget->height() / 2.0f;
@@ -3339,6 +3041,7 @@ void Application::resetSensors() { · 278 unmodified lines
3339 _mouseX = _glWidget->width() / 2;3041 _mouseX = _glWidget->width() / 2;
3340 _mouseY = _glWidget->height() / 2;3042 _mouseY = _glWidget->height() / 2;
3341 3043
3044 _faceplus.reset();
3342 _faceshift.reset();3045 _faceshift.reset();
3343 _visage.reset();3046 _visage.reset();
3344 3047
@@ -3378,8 +3081,7 @@ void Application::updateWindowTitle(){ · 33 unmodified lines
3378 3081
3379 QString username = AccountManager::getInstance().getUsername();3082 QString username = AccountManager::getInstance().getUsername();
3380 QString title = QString() + (!username.isEmpty() ? username + " " : QString()) + nodeList->getSessionUUID().toString()3083 QString title = QString() + (!username.isEmpty() ? username + " " : QString()) + nodeList->getSessionUUID().toString()
3381 + " @ " + nodeList->getDomainInfo().getHostname() + buildVersion;3084 + " @ " + nodeList->getDomainHandler().getHostname() + buildVersion;
3382
3383 qDebug("Application title set to: %s", title.toStdString().c_str());3085 qDebug("Application title set to: %s", title.toStdString().c_str());
3384 _window->setWindowTitle(title);3086 _window->setWindowTitle(title);
3385}3087}
@@ -3431,7 +3133,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 45 unmodified lines
3431 VoxelPositionSize rootDetails;3133 VoxelPositionSize rootDetails;
3432 voxelDetailsForCode(rootCode, rootDetails);3134 voxelDetailsForCode(rootCode, rootDetails);
3433 3135
3434 printf("voxel server going away...... v[%f, %f, %f, %f]\n",3136 qDebug("voxel server going away...... v[%f, %f, %f, %f]",
3435 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);3137 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
3436 3138
3437 // Add the jurisditionDetails object to the list of "fade outs"3139 // Add the jurisditionDetails object to the list of "fade outs"
@@ -3462,7 +3164,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 24 unmodified lines
3462 VoxelPositionSize rootDetails;3164 VoxelPositionSize rootDetails;
3463 voxelDetailsForCode(rootCode, rootDetails);3165 voxelDetailsForCode(rootCode, rootDetails);
3464 3166
3465 printf("particle server going away...... v[%f, %f, %f, %f]\n",3167 qDebug("particle server going away...... v[%f, %f, %f, %f]",
3466 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);3168 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
3467 3169
3468 // Add the jurisditionDetails object to the list of "fade outs"3170 // Add the jurisditionDetails object to the list of "fade outs"
@@ -3543,7 +3245,7 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 74 unmodified lines
3543 3245
3544 3246
3545 if (jurisdiction->find(nodeUUID) == jurisdiction->end()) {3247 if (jurisdiction->find(nodeUUID) == jurisdiction->end()) {
3546 printf("stats from new server... v[%f, %f, %f, %f]\n",3248 qDebug("stats from new server... v[%f, %f, %f, %f]",
3547 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);3249 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
3548 3250
3549 // Add the jurisditionDetails object to the list of "fade outs"3251 // Add the jurisditionDetails object to the list of "fade outs"
@@ -3572,35 +3274,36 @@ void Application::packetSent(quint64 length) { · 22 unmodified lines
3572 3274
3573void Application::loadScripts() {3275void Application::loadScripts() {
3574 // loads all saved scripts3276 // loads all saved scripts
3575 QSettings* settings = new QSettings(this);3277 int size = lockSettings()->beginReadArray("Settings");
3576 int size = settings->beginReadArray("Settings");3278 unlockSettings();
3577
3578 for (int i = 0; i < size; ++i){3279 for (int i = 0; i < size; ++i){
3579 settings->setArrayIndex(i);3280 lockSettings()->setArrayIndex(i);
3580 QString string = settings->value("script").toString();3281 QString string = _settings->value("script").toString();
3581 loadScript(string);3282 unlockSettings();
3283 if (!string.isEmpty()) {
3284 loadScript(string);
3285 }
3582 }3286 }
3583 3287
3584 settings->endArray();3288 QMutexLocker locker(&_settingsMutex);
3289 _settings->endArray();
3585}3290}
3586 3291
3587void Application::clearScriptsBeforeRunning() {3292void Application::clearScriptsBeforeRunning() {
3588 // clears all scripts from the settings3293 // clears all scripts from the settings
3589 QSettings* settings = new QSettings(this);3294 QMutexLocker locker(&_settingsMutex);
3590 settings->beginWriteArray("Settings");3295 _settings->remove("Settings");
3591 settings->endArray();
3592}3296}
3593 3297
3594void Application::saveScripts() {3298void Application::saveScripts() {
3595 // saves all current running scripts3299 // saves all current running scripts
3596 QSettings* settings = new QSettings(this);3300 QMutexLocker locker(&_settingsMutex);
3597 settings->beginWriteArray("Settings");3301 _settings->beginWriteArray("Settings");
3598 for (int i = 0; i < getRunningScripts().size(); ++i){3302 for (int i = 0; i < getRunningScripts().size(); ++i){
3599 settings->setArrayIndex(i);3303 _settings->setArrayIndex(i);
3600 settings->setValue("script", getRunningScripts().at(i));3304 _settings->setValue("script", getRunningScripts().at(i));
3601 }3305 }
3602 3306 _settings->endArray();
3603 settings->endArray();
3604}3307}
3605 3308
3606void Application::stopAllScripts() {3309void Application::stopAllScripts() {
@@ -3611,14 +3314,17 @@ void Application::stopAllScripts() { · 4 unmodified lines
3611 }3314 }
3612 _scriptEnginesHash.clear();3315 _scriptEnginesHash.clear();
3613 _runningScriptsWidget->setRunningScripts(getRunningScripts());3316 _runningScriptsWidget->setRunningScripts(getRunningScripts());
3317 bumpSettings();
3614}3318}
3615 3319
3616void Application::stopScript(const QString &scriptName)3320void Application::stopScript(const QString &scriptName) {
3617{3321 if (_scriptEnginesHash.contains(scriptName)) {
3618 _scriptEnginesHash.value(scriptName)->stop();3322 _scriptEnginesHash.value(scriptName)->stop();
3619 qDebug() << "stopping script..." << scriptName;3323 qDebug() << "stopping script..." << scriptName;
3620 _scriptEnginesHash.remove(scriptName);3324 _scriptEnginesHash.remove(scriptName);
3621 _runningScriptsWidget->setRunningScripts(getRunningScripts());3325 _runningScriptsWidget->setRunningScripts(getRunningScripts());
3326 bumpSettings();
3327 }
3622}3328}
3623 3329
3624void Application::reloadAllScripts() {3330void Application::reloadAllScripts() {
@@ -3659,10 +3365,13 @@ void Application::toggleRunningScriptsWidget() · 34 unmodified lines
3659}3365}
3660 3366
3661void Application::uploadFST(bool isHead) {3367void Application::uploadFST(bool isHead) {
3662 FstReader reader(isHead);3368 ModelUploader* uploader = new ModelUploader(isHead);
3663 if (reader.zip()) {3369 QThread* thread = new QThread();
3664 reader.send();3370 thread->connect(uploader, SIGNAL(destroyed()), SLOT(quit()));
3665 }3371 thread->connect(thread, SIGNAL(finished()), SLOT(deleteLater()));
3372 uploader->connect(thread, SIGNAL(started()), SLOT(send()));
3373
3374 thread->start();
3666}3375}
3667 3376
3668void Application::uploadHead() {3377void Application::uploadHead() {
@@ -3673,7 +3382,10 @@ void Application::uploadSkeleton() { · 4 unmodified lines
3673 uploadFST(false);3382 uploadFST(false);
3674}3383}
3675 3384
3676void Application::loadScript(const QString& scriptName) {3385ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor) {
3386 if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptName) && !_scriptEnginesHash[scriptName]->isFinished()){
3387 return _scriptEnginesHash[scriptName];
3388 }
3677 3389
3678 // start the script on a new thread...3390 // start the script on a new thread...
3679 ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), &_controllerScriptingInterface);3391 ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), &_controllerScriptingInterface);
@@ -3681,7 +3393,7 @@ void Application::loadScript(const QString& scriptName) { · 1 unmodified line
3681 3393
3682 if (!scriptEngine->hasScript()) {3394 if (!scriptEngine->hasScript()) {
3683 qDebug() << "Application::loadScript(), script failed to load...";3395 qDebug() << "Application::loadScript(), script failed to load...";
3684 return;3396 return NULL;
3685 }3397 }
3686 _runningScriptsWidget->setRunningScripts(getRunningScripts());3398 _runningScriptsWidget->setRunningScripts(getRunningScripts());
3687 3399
@@ -3689,6 +3401,7 @@ void Application::loadScript(const QString& scriptName) { · 1 unmodified line
3689 // we can use the same ones from the application.3401 // we can use the same ones from the application.
3690 scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);3402 scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);
3691 scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree());3403 scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree());
3404 scriptEngine->getVoxelsScriptingInterface()->setUndoStack(&_undoStack);
3692 scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);3405 scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
3693 scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree());3406 scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree());
3694 3407
@@ -3707,6 +3420,8 @@ void Application::loadScript(const QString& scriptName) { · 12 unmodified lines
3707 scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());3420 scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
3708 scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());3421 scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
3709 scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());3422 scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
3423 scriptEngine->registerGlobalObject("AnimationCache", &_animationCache);
3424 scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector);
3710 3425
3711 QThread* workerThread = new QThread(this);3426 QThread* workerThread = new QThread(this);
3712 3427
@@ -3726,7 +3441,12 @@ void Application::loadScript(const QString& scriptName) { · 13 unmodified lines
3726 workerThread->start();3441 workerThread->start();
3727 3442
3728 // restore the main window's active state3443 // restore the main window's active state
3729 _window->activateWindow();3444 if (!loadScriptFromEditor) {
3445 _window->activateWindow();
3446 }
3447 bumpSettings();
3448
3449 return scriptEngine;
3730}3450}
3731 3451
3732void Application::loadDialog() {3452void Application::loadDialog() {
@@ -3734,7 +3454,10 @@ void Application::loadDialog() { · 1 unmodified line
3734 3454
3735 if (_previousScriptLocation.isEmpty()) {3455 if (_previousScriptLocation.isEmpty()) {
3736 QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);3456 QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
3457// Temporary fix to Qt bug: http://stackoverflow.com/questions/16194475
3458#ifdef __APPLE__
3737 suggestedName = desktopLocation.append("/script.js");3459 suggestedName = desktopLocation.append("/script.js");
3460#endif
3738 } else {3461 } else {
3739 suggestedName = _previousScriptLocation;3462 suggestedName = _previousScriptLocation;
3740 }3463 }
@@ -3743,9 +3466,11 @@ void Application::loadDialog() { · 2 unmodified lines
3743 tr("JavaScript Files (*.js)"));3466 tr("JavaScript Files (*.js)"));
3744 if (!fileNameString.isEmpty()) {3467 if (!fileNameString.isEmpty()) {
3745 _previousScriptLocation = fileNameString;3468 _previousScriptLocation = fileNameString;
3746 }3469 QMutexLocker locker(&_settingsMutex);
3470 _settings->setValue("LastScriptLocation", _previousScriptLocation);
3747 3471
3748 loadScript(fileNameString);3472 loadScript(fileNameString);
3473 }
3749}3474}
3750 3475
3751void Application::loadScriptURLDialog() {3476void Application::loadScriptURLDialog() {
@@ -3863,3 +3588,38 @@ void Application::takeSnapshot() { · 111 unmodified lines
3863 3588
3864 Snapshot::saveSnapshot(_glWidget, _myAvatar);3589 Snapshot::saveSnapshot(_glWidget, _myAvatar);
3865}3590}
3591
3592void Application::urlGoTo(int argc, const char * constArgv[]) {
3593 //Gets the url (hifi://domain/destination/orientation)
3594 QString customUrl = getCmdOption(argc, constArgv, "-url");
3595
3596 if (customUrl.startsWith("hifi://")) {
3597 QStringList urlParts = customUrl.remove(0, CUSTOM_URL_SCHEME.length() + 2).split('/', QString::SkipEmptyParts);
3598 if (urlParts.count() > 1) {
3599 // if url has 2 or more parts, the first one is domain name
3600 QString domain = urlParts[0];
3601
3602 // second part is either a destination coordinate or
3603 // a place name
3604 QString destination = urlParts[1];
3605
3606 // any third part is an avatar orientation.
3607 QString orientation = urlParts.count() > 2 ? urlParts[2] : QString();
3608
3609 Menu::goToDomain(domain);
3610
3611 // goto either @user, #place, or x-xx,y-yy,z-zz
3612 // style co-ordinate.
3613 Menu::goTo(destination);
3614
3615 if (!orientation.isEmpty()) {
3616 // location orientation
3617 Menu::goToOrientation(orientation);
3618 }
3619 } else if (urlParts.count() == 1) {
3620 // location coordinates or place name
3621 QString destination = urlParts[0];
3622 Menu::goTo(destination);
3623 }
3624 }
3625}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t