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 @@
11 //
22 // Application.cpp
3−// interface
3+// interface/src
44 //
55 // Created by Andrzej Kapolka on 5/10/13.
6−// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
7−
8−#ifdef WIN32
9−#include <Systime.h>
10−#endif
6+// Copyright 2013 High Fidelity, Inc.
7+//
8+// Distributed under the Apache License, Version 2.0.
9+// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10+//
1111
1212 #include <sstream>
1313
@@ -62,7 +62,7 @@ · 48 unmodified lines
6262 #include <UUID.h>
6363 #include <OctreeSceneStats.h>
6464 #include <LocalVoxelsList.h>
65−#include <FstReader.h>
65+#include <ModelUploader.h>
6666
6767 #include "Application.h"
6868 #include "InterfaceVersion.h"
@@ -80,6 +80,7 @@ · 11 unmodified lines
8080 #include "ui/InfoView.h"
8181 #include "ui/Snapshot.h"
8282 #include "ui/TextRenderer.h"
83+#include "ui/Stats.h"
8384
8485 using namespace std;
8586
@@ -106,13 +107,9 @@ const float MIRROR_REARVIEW_DISTANCE = 0.65f; · 20 unmodified lines
106107 const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f;
107108 const float MIRROR_FIELD_OF_VIEW = 30.0f;
108109
109−const QString CHECK_VERSION_URL = "http://highfidelity.io/latestVersion.xml";
110+const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml";
110111 const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion";
111112
112−const int STATS_PELS_PER_LINE = 20;
113−
114−const QString CUSTOM_URL_SCHEME = "hifi:";
115−
116113 void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
117114 if (message.size() > 0) {
118115 QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate);
@@ -132,11 +129,10 @@ QString& Application::resourcesPath() { · 13 unmodified lines
132129 return staticResourcePath;
133130 }
134131
135−Application::Application(int& argc, char** argv, timeval &startup_time) :
132+Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
136133 QApplication(argc, argv),
137134 _window(new MainWindow(desktop())),
138135 _glWidget(new GLCanvas()),
139− _statsExpanded(false),
140136 _nodeThread(new QThread(this)),
141137 _datagramProcessor(),
142138 _frameCount(0),
@@ -149,9 +145,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 6 unmodified lines
149145 _viewFrustum(),
150146 _lastQueriedViewFrustum(),
151147 _lastQueriedTime(usecTimestampNow()),
152− _audioScope(256, 200, true),
153− _trailingAudioLoudness(0.f),
154148 _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
149+ _cameraPushback(0.0f),
155150 _mouseX(0),
156151 _mouseY(0),
157152 _lastMouseMove(usecTimestampNow()),
@@ -161,19 +156,20 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 3 unmodified lines
161156 _touchAvgY(0.0f),
162157 _isTouchPressed(false),
163158 _mousePressed(false),
164− _audio(&_audioScope, STARTUP_JITTER_SAMPLES),
159+ _audio(STARTUP_JITTER_SAMPLES),
165160 _enableProcessVoxelsThread(true),
166161 _voxelProcessor(),
167162 _voxelHideShowThread(&_voxels),
168163 _packetsPerSecond(0),
169164 _bytesPerSecond(0),
170− _recentMaxPackets(0),
171− _resetRecentMaxPacketsSoon(true),
172165 _previousScriptLocation(),
173166 _logger(new FileLogger(this)),
174167 _runningScriptsWidget(new RunningScriptsWidget),
175168 _runningScriptsWidgetWasVisible(false)
176169 {
170+ // init GnuTLS for DTLS with domain-servers
171+ DTLSClientSession::globalInit();
172+
177173 // read the ApplicationInfo.ini file for Name/Version/Domain information
178174 QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat);
179175
@@ -231,8 +227,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 51 unmodified lines
231227
232228 audioThread->start();
233229
234− connect(&nodeList->getDomainInfo(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
235− connect(&nodeList->getDomainInfo(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));
230+ connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&)));
231+ connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&)));
236232
237233 connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded);
238234 connect(nodeList, &NodeList::nodeKilled, this, &Application::nodeKilled);
@@ -240,6 +236,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 1 unmodified line
240236 connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer)));
241237 connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer)));
242238 connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle);
239+ connect(nodeList, SIGNAL(uuidChanged(const QUuid&)), _myAvatar, SLOT(setSessionUUID(const QUuid&)));
243240 connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset);
244241
245242 // connect to appropriate slots on AccountManager
@@ -254,6 +251,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 8 unmodified lines
254251 QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
255252
256253 _settings = new QSettings(this);
254+ _numChangedSettings = 0;
257255
258256 // Check to see if the user passed in a command line option for loading a local
259257 // Voxel File.
@@ -277,7 +275,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 17 unmodified lines
277275 QTimer* silentNodeTimer = new QTimer();
278276 connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes()));
279277 silentNodeTimer->moveToThread(_nodeThread);
280− silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000);
278+ silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS);
281279
282280 // send the identity packet for our avatar each second to our avatar mixer
283281 QTimer* identityPacketTimer = new QTimer();
@@ -346,15 +344,22 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 62 unmodified lines
346344 clearScriptsBeforeRunning();
347345 loadScript("http://public.highfidelity.io/scripts/defaultScripts.js");
348346
347+ QMutexLocker locker(&_settingsMutex);
349348 _settings->setValue("firstRun",QVariant(false));
350349 } else {
351350 // do this as late as possible so that all required subsystems are inialized
352351 loadScripts();
352+
353+ QMutexLocker locker(&_settingsMutex);
354+ _previousScriptLocation = _settings->value("LastScriptLocation", QVariant("")).toString();
353355 }
354356
355357 connect(_window, &MainWindow::windowGeometryChanged,
356358 _runningScriptsWidget, &RunningScriptsWidget::setBoundary);
357359 connect(_window, &MainWindow::windowShown, this, &Application::manageRunningScriptsWidgetVisibility);
360+
361+ //When -url in command line, teleport to location
362+ urlGoTo(argc, constArgv);
358363 }
359364
360365 Application::~Application() {
@@ -404,37 +409,50 @@ Application::~Application() { · 43 unmodified lines
404409 delete _glWidget;
405410
406411 AccountManager::getInstance().destroy();
412+
413+ DTLSClientSession::globalDeinit();
407414 }
408415
416+void 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+
409428 void Application::restoreSizeAndPosition() {
410− QSettings* settings = new QSettings(this);
411429 QRect available = desktop()->availableGeometry();
412430
413− settings->beginGroup("Window");
431+ QMutexLocker locker(&_settingsMutex);
432+ _settings->beginGroup("Window");
414433
415− int x = (int)loadSetting(settings, "x", 0);
416− int y = (int)loadSetting(settings, "y", 0);
434+ int x = (int)loadSetting(_settings, "x", 0);
435+ int y = (int)loadSetting(_settings, "y", 0);
417436 _window->move(x, y);
418437
419− int width = (int)loadSetting(settings, "width", available.width());
420− int height = (int)loadSetting(settings, "height", available.height());
438+ int width = (int)loadSetting(_settings, "width", available.width());
439+ int height = (int)loadSetting(_settings, "height", available.height());
421440 _window->resize(width, height);
422441
423− settings->endGroup();
442+ _settings->endGroup();
424443 }
425444
426445 void Application::storeSizeAndPosition() {
427− QSettings* settings = new QSettings(this);
428−
429− settings->beginGroup("Window");
446+ QMutexLocker locker(&_settingsMutex);
447+ _settings->beginGroup("Window");
430448
431− settings->setValue("width", _window->rect().width());
432− settings->setValue("height", _window->rect().height());
449+ _settings->setValue("width", _window->rect().width());
450+ _settings->setValue("height", _window->rect().height());
433451
434− settings->setValue("x", _window->pos().x());
435− settings->setValue("y", _window->pos().y());
452+ _settings->setValue("x", _window->pos().x());
453+ _settings->setValue("y", _window->pos().y());
436454
437− settings->endGroup();
455+ _settings->endGroup();
438456 }
439457
440458 void Application::initializeGL() {
@@ -495,7 +513,7 @@ void Application::initializeGL() { · 54 unmodified lines
495513 _idleLoopStdev.reset();
496514
497515 if (_justStarted) {
498− float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime)) / 1000000.0;
516+ float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0;
499517 _justStarted = false;
500518 qDebug("Startup time: %4.2f seconds.", startupTime);
501519 const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time";
@@ -517,18 +535,55 @@ void Application::paintGL() { · 15 unmodified lines
517535
518536 glEnable(GL_LINE_SMOOTH);
519537
538+ float pushback = 0.0f;
539+ float pushbackFocalLength = 0.0f;
520540 if (OculusManager::isConnected()) {
521541 _myCamera.setUpShift(0.0f);
522542 _myCamera.setDistance(0.0f);
523543 _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
524544 _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
525− _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation());
545+ _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
526546
527547 } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) {
528548 _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay
529549 _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
530550 _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
531551
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+
532587 } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
533588 _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
534589 _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition());
@@ -536,10 +591,35 @@ void Application::paintGL() { · 1 unmodified line
536591
537592 } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
538593 _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;
540596 _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale());
541597 _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0));
542598 _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);
543623 }
544624
545625 // Update camera position
@@ -630,6 +710,13 @@ void Application::resizeGL(int width, int height) { · 84 unmodified lines
630710 _window->geometry().topLeft().y(),
631711 _runningScriptsWidget->width(), _window->height());
632712 }
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);
633720 }
634721
635722 void Application::updateProjectionMatrix() {
@@ -699,26 +786,9 @@ bool Application::event(QEvent* event) { · 63 unmodified lines
699786 // handle custom URL
700787 if (event->type() == QEvent::FileOpen) {
701788 QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
702− if (!fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME)) {
703− QString destination = fileEvent->url().toLocalFile().remove(CUSTOM_URL_SCHEME);
704− QStringList urlParts = destination.split('/', QString::SkipEmptyParts);
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− }
789+ bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME);
790+ if (isHifiSchemeURL) {
791+ Menu::getInstance()->goTo(fileEvent->url().toString());
722792 }
723793
724794 return false;
@@ -740,6 +810,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 15 unmodified lines
740810 if (activeWindow() == _window) {
741811 bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);
742812 bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);
813+ bool isOption = event->modifiers().testFlag(Qt::AltModifier);
743814 switch (event->key()) {
744815 break;
745816 case Qt::Key_BracketLeft:
@@ -754,9 +825,6 @@ void Application::keyPressEvent(QKeyEvent* event) { · 8 unmodified lines
754825 case Qt::Key_Period:
755826 Menu::getInstance()->handleViewFrustumOffsetKeyModifier(event->key());
756827 break;
757− case Qt::Key_Apostrophe:
758− _audioScope.inputPaused = !_audioScope.inputPaused;
759− break;
760828 case Qt::Key_L:
761829 if (isShifted) {
762830 Menu::getInstance()->triggerOption(MenuOption::LodTools);
@@ -766,6 +834,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 3 unmodified lines
766834 break;
767835
768836 case Qt::Key_E:
837+ case Qt::Key_PageUp:
769838 if (!_myAvatar->getDriveKeys(UP)) {
770839 _myAvatar->jump();
771840 }
@@ -777,6 +846,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 5 unmodified lines
777846 break;
778847
779848 case Qt::Key_C:
849+ case Qt::Key_PageDown:
780850 _myAvatar->setDriveKeys(DOWN, 1.f);
781851 break;
782852
@@ -785,9 +855,11 @@ void Application::keyPressEvent(QKeyEvent* event) { · 2 unmodified lines
785855 break;
786856
787857 case Qt::Key_S:
788− if (isShifted && isMeta) {
858+ if (isShifted && isMeta && !isOption) {
789859 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) {
791863 takeSnapshot();
792864 } else {
793865 _myAvatar->setDriveKeys(BACK, 1.f);
@@ -963,10 +1035,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) { · 169 unmodified lines
9631035
9641036 switch (event->key()) {
9651037 case Qt::Key_E:
1038+ case Qt::Key_PageUp:
9661039 _myAvatar->setDriveKeys(UP, 0.f);
9671040 break;
9681041
9691042 case Qt::Key_C:
1043+ case Qt::Key_PageDown:
9701044 _myAvatar->setDriveKeys(DOWN, 0.f);
9711045 break;
9721046
@@ -1089,7 +1163,11 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { · 116 unmodified lines
10891163 _mousePressed = false;
10901164 checkBandwidthMeterClick();
10911165 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);
10931171 }
10941172 }
10951173 }
@@ -1155,7 +1233,6 @@ void Application::touchEndEvent(QTouchEvent* event) { · 59 unmodified lines
11551233 if (_controllerScriptingInterface.isTouchCaptured()) {
11561234 return;
11571235 }
1158−
11591236 // put any application specific touch behavior below here..
11601237 _touchDragStartedAvgX = _touchAvgX;
11611238 _touchDragStartedAvgY = _touchAvgY;
@@ -1209,26 +1286,24 @@ void Application::sendPingPackets() { · 47 unmodified lines
12091286
12101287 // Every second, check the frame rates and other stuff
12111288 void Application::timer() {
1212− gettimeofday(&_timerEnd, NULL);
1213−
12141289 if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
12151290 sendPingPackets();
12161291 }
12171292
1218− _fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
1293+ float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f;
1294+
1295+ _fps = (float)_frameCount / diffTime;
12191296
1220− _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
1221− _bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f);
1297+ _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / diffTime;
1298+ _bytesPerSecond = (float) _datagramProcessor.getByteCount() / diffTime;
12221299 _frameCount = 0;
12231300
12241301 _datagramProcessor.resetCounters();
12251302
1226− gettimeofday(&_timerStart, NULL);
1303+ _timerStart.start();
12271304
12281305 // ask the node list to check in with the domain server
12291306 NodeList::getInstance()->sendDomainServerCheckIn();
1230−
1231−
12321307 }
12331308
12341309 void Application::idle() {
@@ -1238,13 +1313,11 @@ void Application::idle() { · 3 unmodified lines
12381313 bool showWarnings = getLogger()->extraDebugging();
12391314 PerformanceWarning warn(showWarnings, "Application::idle()");
12401315
1241− timeval check;
1242− gettimeofday(&check, NULL);
1243−
12441316 // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran
12451317
1246− double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check);
1318+ double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0;
12471319 if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) {
1320+ _lastTimeUpdated.start();
12481321 {
12491322 PerformanceWarning warn(showWarnings, "Application::idle()... update()");
12501323 const float BIGGEST_DELTA_TIME_SECS = 0.25f;
@@ -1256,7 +1329,6 @@ void Application::idle() { · 5 unmodified lines
12561329 }
12571330 {
12581331 PerformanceWarning warn(showWarnings, "Application::idle()... rest of it");
1259− _lastTimeUpdated = check;
12601332 _idleLoopStdev.addValue(timeSinceLastUpdate);
12611333
12621334 // Record standard deviation and reset counter if needed
@@ -1273,6 +1345,9 @@ void Application::idle() { · 10 unmodified lines
12731345 // After finishing all of the above work, restart the idle timer, allowing 2ms to process events.
12741346 idleTimer->start(2);
12751347 }
1348+ if (_numChangedSettings > 0) {
1349+ saveSettings();
1350+ }
12761351 }
12771352 }
12781353
@@ -1353,6 +1428,12 @@ glm::vec3 Application::getMouseVoxelWorldCoordinates(const VoxelDetail& mouseVox · 74 unmodified lines
13531428 (mouseVoxel.z + mouseVoxel.s / 2.f) * TREE_SCALE);
13541429 }
13551430
1431+FaceTracker* 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+
13561437 struct SendVoxelsOperationArgs {
13571438 const unsigned char* newBaseOctCode;
13581439 };
@@ -1563,8 +1644,8 @@ void Application::init() { · 204 unmodified lines
15631644 Qt::QueuedConnection);
15641645 }
15651646
1566− gettimeofday(&_timerStart, NULL);
1567− gettimeofday(&_lastTimeUpdated, NULL);
1647+ _timerStart.start();
1648+ _lastTimeUpdated.start();
15681649
15691650 Menu::getInstance()->loadSettings();
15701651 if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) {
@@ -1572,8 +1653,9 @@ void Application::init() { · 1 unmodified line
15721653 }
15731654 qDebug("Loaded settings");
15741655
1575− // initialize Visage and Faceshift after loading the menu settings
1656+ // initialize our face trackers after loading the menu settings
15761657 _faceshift.init();
1658+ _faceplus.init();
15771659 _visage.init();
15781660
15791661 // fire off an immediate domain-server check in now that settings are loaded
@@ -1593,16 +1675,12 @@ void Application::init() { · 13 unmodified lines
15931675
15941676 _particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager);
15951677
1596− // connect the _particleCollisionSystem to our script engine's ParticleScriptingInterface
1597− connect(&_particleCollisionSystem,
1598− SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)),
1599− ScriptEngine::getParticlesScriptingInterface(),
1600− SLOT(forwardParticleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)));
1678+ // connect the _particleCollisionSystem to our script engine's ParticlesScriptingInterface
1679+ connect(&_particleCollisionSystem, &ParticleCollisionSystem::particleCollisionWithVoxel,
1680+ ScriptEngine::getParticlesScriptingInterface(), &ParticlesScriptingInterface::particleCollisionWithVoxel);
16011681
1602− connect(&_particleCollisionSystem,
1603− SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)),
1604− ScriptEngine::getParticlesScriptingInterface(),
1605− SLOT(forwardParticleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)));
1682+ connect(&_particleCollisionSystem, &ParticleCollisionSystem::particleCollisionWithParticle,
1683+ ScriptEngine::getParticlesScriptingInterface(), &ParticlesScriptingInterface::particleCollisionWithParticle);
16061684
16071685 _audio.init(_glWidget);
16081686
@@ -1612,6 +1690,20 @@ void Application::init() { · 3 unmodified lines
16121690 connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView()));
16131691 connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView()));
16141692 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);
16151707 }
16161708
16171709 void Application::closeMirrorView() {
@@ -1737,19 +1829,11 @@ void Application::updateMyAvatarLookAtPosition() { · 119 unmodified lines
17371829 glm::distance(_mouseRayOrigin, _myAvatar->getHead()->calculateAverageEyePosition()));
17381830 lookAtSpot = _mouseRayOrigin + _mouseRayDirection * qMax(minEyeDistance, distance);
17391831 }
1740− bool trackerActive = false;
1741− float eyePitch, eyeYaw;
1742− if (_faceshift.isActive()) {
1743− eyePitch = _faceshift.getEstimatedEyePitch();
1744− eyeYaw = _faceshift.getEstimatedEyeYaw();
1745− trackerActive = true;
1832+ FaceTracker* tracker = getActiveFaceTracker();
1833+ if (tracker) {
1834+ float eyePitch = tracker->getEstimatedEyePitch();
1835+ float eyeYaw = tracker->getEstimatedEyeYaw();
17461836
1747− } else if (_visage.isActive()) {
1748− eyePitch = _visage.getEstimatedEyePitch();
1749− eyeYaw = _visage.getEstimatedEyeYaw();
1750− trackerActive = true;
1751− }
1752− if (trackerActive) {
17531837 // deflect using Faceshift gaze data
17541838 glm::vec3 origin = _myAvatar->getHead()->calculateAverageEyePosition();
17551839 float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f;
@@ -1835,15 +1919,15 @@ void Application::updateCamera(float deltaTime) { · 79 unmodified lines
18351919 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
18361920 PerformanceWarning warn(showWarnings, "Application::updateCamera()");
18371921
1838− if (!OculusManager::isConnected() && !TV3DManager::isConnected()) {
1839− if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) {
1840− float xSign = _myCamera.getMode() == CAMERA_MODE_MIRROR ? 1.0f : -1.0f;
1841− if (_faceshift.isActive()) {
1842− const float EYE_OFFSET_SCALE = 0.025f;
1843− glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE;
1844− _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z));
1845− updateProjectionMatrix();
1846− }
1922+ if (!OculusManager::isConnected() && !TV3DManager::isConnected() &&
1923+ Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) {
1924+ FaceTracker* tracker = getActiveFaceTracker();
1925+ if (tracker) {
1926+ const float EYE_OFFSET_SCALE = 0.025f;
1927+ glm::vec3 position = tracker->getHeadTranslation() * EYE_OFFSET_SCALE;
1928+ float xSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? 1.0f : -1.0f;
1929+ _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z));
1930+ updateProjectionMatrix();
18471931 }
18481932 }
18491933 }
@@ -2137,7 +2221,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node · 287 unmodified lines
21372221 int packetLength = endOfQueryPacket - queryPacket;
21382222
21392223 // 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);
21412225
21422226 // Feed number of bytes to corresponding channel of the bandwidth meter
21432227 _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength);
@@ -2252,8 +2336,7 @@ void Application::updateShadowMap() { · 108 unmodified lines
22522336 glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z);
22532337
22542338 // store view matrix without translation, which we'll use for precision-sensitive objects
2255− glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);
2256− _viewMatrixTranslation = glm::vec3();
2339+ updateUntranslatedViewMatrix();
22572340
22582341 _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE);
22592342 _particles.render();
@@ -2338,8 +2421,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 78 unmodified lines
23382421 glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z);
23392422
23402423 // store view matrix without translation, which we'll use for precision-sensitive objects
2341− glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);
2342− _viewMatrixTranslation = -whichCamera.getPosition();
2424+ updateUntranslatedViewMatrix(-whichCamera.getPosition());
23432425
23442426 glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z);
23452427
@@ -2394,6 +2476,9 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 48 unmodified lines
23942476 // disable specular lighting for ground and voxels
23952477 glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR);
23962478
2479+ // draw the audio reflector overlay
2480+ _audioReflector.render();
2481+
23972482 // Draw voxels
23982483 if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
23992484 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
@@ -2470,6 +2555,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 70 unmodified lines
24702555 }
24712556 }
24722557
2558+void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation) {
2559+ glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix);
2560+ _viewMatrixTranslation = viewMatrixTranslation;
2561+}
2562+
24732563 void Application::loadTranslatedViewMatrix(const glm::vec3& translation) {
24742564 glLoadMatrixf((const GLfloat*)&_untranslatedViewMatrix);
24752565 glTranslatef(translation.x + _viewMatrixTranslation.x, translation.y + _viewMatrixTranslation.y,
@@ -2514,32 +2604,22 @@ void Application::displayOverlay() { · 38 unmodified lines
25142604 }
25152605 }
25162606
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−
25262607 // Audio VU Meter and Mute Icon
25272608 const int MUTE_ICON_SIZE = 24;
25282609 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;
25302612 const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET;
25312613 const int AUDIO_METER_HEIGHT = 8;
2532− const int AUDIO_METER_Y_GAP = 8;
2533− const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET;
2614+ const int AUDIO_METER_GAP = 5;
2615+ const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP;
25342616
25352617 int audioMeterY;
25362618 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;
25382620 } else {
2539− audioMeterY = AUDIO_METER_Y_GAP;
2621+ audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING;
25402622 }
2541− _audio.renderMuteIcon(MIRROR_VIEW_LEFT_PADDING, audioMeterY);
2542−
25432623
25442624 const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0};
25452625 const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0};
@@ -2549,29 +2629,53 @@ void Application::displayOverlay() { · 3 unmodified lines
25492629 const float CLIPPING_INDICATOR_TIME = 1.0f;
25502630 const float AUDIO_METER_AVERAGING = 0.5;
25512631 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;
25532634 float audioLevel = 0.f;
25542635 float loudness = _audio.getLastInputLoudness() + 1.f;
2555− _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
25562636
2637+ _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness;
25572638 float log2loudness = log(_trailingAudioLoudness) / LOG2;
25582639
2559− audioLevel = log2loudness / MAX_LOG2_SAMPLE * AUDIO_METER_SCALE_WIDTH;
2560−
2640+ if (log2loudness <= LOG2_LOUDNESS_FLOOR) {
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+ }
25612648 bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
25622649
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+
25632662 glBegin(GL_QUADS);
25642663 if (isClipping) {
25652664 glColor3f(1, 0, 0);
25662665 } else {
2567− glColor3f(0, 0, 0);
2666+ glColor3f(0.475f, 0.475f, 0.475f);
25682667 }
2668+
2669+ audioMeterY += AUDIO_METER_HEIGHT;
2670+
2671+ glColor3f(0, 0, 0);
25692672 // Draw audio meter background Quad
25702673 glVertex2i(AUDIO_METER_X, audioMeterY);
25712674 glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY);
25722675 glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT);
25732676 glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT);
25742677
2678+
25752679 if (audioLevel > AUDIO_RED_START) {
25762680 if (!isClipping) {
25772681 glColor3fv(AUDIO_METER_RED);
@@ -2611,6 +2715,7 @@ void Application::displayOverlay() { · 33 unmodified lines
26112715 glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET);
26122716 glEnd();
26132717
2718+
26142719 if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) {
26152720 _myAvatar->renderHeadMouse();
26162721 }
@@ -2620,11 +2725,17 @@ void Application::displayOverlay() { · 3 unmodified lines
26202725 glPointSize(1.0f);
26212726
26222727 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();
26232734 // Onscreen text about position, servers, etc
2624− displayStats();
2735+ Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess);
26252736 // Bandwidth meter
26262737 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);
26282739 _bandwidthMeter.render(_glWidget->width(), _glWidget->height());
26292740 }
26302741 }
@@ -2638,7 +2749,7 @@ void Application::displayOverlay() { · 7 unmodified lines
26382749 (Menu::getInstance()->isOptionChecked(MenuOption::Stats) &&
26392750 Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth))
26402751 ? 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);
26422753 }
26432754
26442755 _overlays.render2D();
@@ -2646,415 +2757,6 @@ void Application::displayOverlay() { · 1 unmodified line
26462757 glPopMatrix();
26472758 }
26482759
2649−// translucent background box that makes stats more readable
2650−void 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−
2666−void 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
3002−void 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−
3054−void Application::toggleStatsExpanded() {
3055− _statsExpanded = !_statsExpanded;
3056−}
3057−
30582760 glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) {
30592761 float horizontalScale = _glWidget->width() / 2.0f;
30602762 float verticalScale = _glWidget->height() / 2.0f;
@@ -3339,6 +3041,7 @@ void Application::resetSensors() { · 278 unmodified lines
33393041 _mouseX = _glWidget->width() / 2;
33403042 _mouseY = _glWidget->height() / 2;
33413043
3044+ _faceplus.reset();
33423045 _faceshift.reset();
33433046 _visage.reset();
33443047
@@ -3378,8 +3081,7 @@ void Application::updateWindowTitle(){ · 33 unmodified lines
33783081
33793082 QString username = AccountManager::getInstance().getUsername();
33803083 QString title = QString() + (!username.isEmpty() ? username + " " : QString()) + nodeList->getSessionUUID().toString()
3381− + " @ " + nodeList->getDomainInfo().getHostname() + buildVersion;
3382−
3084+ + " @ " + nodeList->getDomainHandler().getHostname() + buildVersion;
33833085 qDebug("Application title set to: %s", title.toStdString().c_str());
33843086 _window->setWindowTitle(title);
33853087 }
@@ -3431,7 +3133,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 45 unmodified lines
34313133 VoxelPositionSize rootDetails;
34323134 voxelDetailsForCode(rootCode, rootDetails);
34333135
3434− printf("voxel server going away...... v[%f, %f, %f, %f]\n",
3136+ qDebug("voxel server going away...... v[%f, %f, %f, %f]",
34353137 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
34363138
34373139 // Add the jurisditionDetails object to the list of "fade outs"
@@ -3462,7 +3164,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 24 unmodified lines
34623164 VoxelPositionSize rootDetails;
34633165 voxelDetailsForCode(rootCode, rootDetails);
34643166
3465− printf("particle server going away...... v[%f, %f, %f, %f]\n",
3167+ qDebug("particle server going away...... v[%f, %f, %f, %f]",
34663168 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
34673169
34683170 // 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
35433245
35443246
35453247 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]",
35473249 rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
35483250
35493251 // Add the jurisditionDetails object to the list of "fade outs"
@@ -3572,35 +3274,36 @@ void Application::packetSent(quint64 length) { · 22 unmodified lines
35723274
35733275 void Application::loadScripts() {
35743276 // loads all saved scripts
3575− QSettings* settings = new QSettings(this);
3576− int size = settings->beginReadArray("Settings");
3577−
3277+ int size = lockSettings()->beginReadArray("Settings");
3278+ unlockSettings();
35783279 for (int i = 0; i < size; ++i){
3579− settings->setArrayIndex(i);
3580− QString string = settings->value("script").toString();
3581− loadScript(string);
3280+ lockSettings()->setArrayIndex(i);
3281+ QString string = _settings->value("script").toString();
3282+ unlockSettings();
3283+ if (!string.isEmpty()) {
3284+ loadScript(string);
3285+ }
35823286 }
35833287
3584− settings->endArray();
3288+ QMutexLocker locker(&_settingsMutex);
3289+ _settings->endArray();
35853290 }
35863291
35873292 void Application::clearScriptsBeforeRunning() {
35883293 // clears all scripts from the settings
3589− QSettings* settings = new QSettings(this);
3590− settings->beginWriteArray("Settings");
3591− settings->endArray();
3294+ QMutexLocker locker(&_settingsMutex);
3295+ _settings->remove("Settings");
35923296 }
35933297
35943298 void Application::saveScripts() {
35953299 // saves all current running scripts
3596− QSettings* settings = new QSettings(this);
3597− settings->beginWriteArray("Settings");
3300+ QMutexLocker locker(&_settingsMutex);
3301+ _settings->beginWriteArray("Settings");
35983302 for (int i = 0; i < getRunningScripts().size(); ++i){
3599− settings->setArrayIndex(i);
3600− settings->setValue("script", getRunningScripts().at(i));
3303+ _settings->setArrayIndex(i);
3304+ _settings->setValue("script", getRunningScripts().at(i));
36013305 }
3602−
3603− settings->endArray();
3306+ _settings->endArray();
36043307 }
36053308
36063309 void Application::stopAllScripts() {
@@ -3611,14 +3314,17 @@ void Application::stopAllScripts() { · 4 unmodified lines
36113314 }
36123315 _scriptEnginesHash.clear();
36133316 _runningScriptsWidget->setRunningScripts(getRunningScripts());
3317+ bumpSettings();
36143318 }
36153319
3616−void Application::stopScript(const QString &scriptName)
3617−{
3618− _scriptEnginesHash.value(scriptName)->stop();
3619− qDebug() << "stopping script..." << scriptName;
3620− _scriptEnginesHash.remove(scriptName);
3621− _runningScriptsWidget->setRunningScripts(getRunningScripts());
3320+void Application::stopScript(const QString &scriptName) {
3321+ if (_scriptEnginesHash.contains(scriptName)) {
3322+ _scriptEnginesHash.value(scriptName)->stop();
3323+ qDebug() << "stopping script..." << scriptName;
3324+ _scriptEnginesHash.remove(scriptName);
3325+ _runningScriptsWidget->setRunningScripts(getRunningScripts());
3326+ bumpSettings();
3327+ }
36223328 }
36233329
36243330 void Application::reloadAllScripts() {
@@ -3659,10 +3365,13 @@ void Application::toggleRunningScriptsWidget() · 34 unmodified lines
36593365 }
36603366
36613367 void Application::uploadFST(bool isHead) {
3662− FstReader reader(isHead);
3663− if (reader.zip()) {
3664− reader.send();
3665− }
3368+ ModelUploader* uploader = new ModelUploader(isHead);
3369+ QThread* thread = new QThread();
3370+ thread->connect(uploader, SIGNAL(destroyed()), SLOT(quit()));
3371+ thread->connect(thread, SIGNAL(finished()), SLOT(deleteLater()));
3372+ uploader->connect(thread, SIGNAL(started()), SLOT(send()));
3373+
3374+ thread->start();
36663375 }
36673376
36683377 void Application::uploadHead() {
@@ -3673,7 +3382,10 @@ void Application::uploadSkeleton() { · 4 unmodified lines
36733382 uploadFST(false);
36743383 }
36753384
3676−void Application::loadScript(const QString& scriptName) {
3385+ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor) {
3386+ if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptName) && !_scriptEnginesHash[scriptName]->isFinished()){
3387+ return _scriptEnginesHash[scriptName];
3388+ }
36773389
36783390 // start the script on a new thread...
36793391 ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), &_controllerScriptingInterface);
@@ -3681,7 +3393,7 @@ void Application::loadScript(const QString& scriptName) { · 1 unmodified line
36813393
36823394 if (!scriptEngine->hasScript()) {
36833395 qDebug() << "Application::loadScript(), script failed to load...";
3684− return;
3396+ return NULL;
36853397 }
36863398 _runningScriptsWidget->setRunningScripts(getRunningScripts());
36873399
@@ -3689,6 +3401,7 @@ void Application::loadScript(const QString& scriptName) { · 1 unmodified line
36893401 // we can use the same ones from the application.
36903402 scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender);
36913403 scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree());
3404+ scriptEngine->getVoxelsScriptingInterface()->setUndoStack(&_undoStack);
36923405 scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender);
36933406 scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree());
36943407
@@ -3707,6 +3420,8 @@ void Application::loadScript(const QString& scriptName) { · 12 unmodified lines
37073420 scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
37083421 scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance());
37093422 scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance());
3423+ scriptEngine->registerGlobalObject("AnimationCache", &_animationCache);
3424+ scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector);
37103425
37113426 QThread* workerThread = new QThread(this);
37123427
@@ -3726,7 +3441,12 @@ void Application::loadScript(const QString& scriptName) { · 13 unmodified lines
37263441 workerThread->start();
37273442
37283443 // restore the main window's active state
3729− _window->activateWindow();
3444+ if (!loadScriptFromEditor) {
3445+ _window->activateWindow();
3446+ }
3447+ bumpSettings();
3448+
3449+ return scriptEngine;
37303450 }
37313451
37323452 void Application::loadDialog() {
@@ -3734,7 +3454,10 @@ void Application::loadDialog() { · 1 unmodified line
37343454
37353455 if (_previousScriptLocation.isEmpty()) {
37363456 QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
3457+// Temporary fix to Qt bug: http://stackoverflow.com/questions/16194475
3458+#ifdef __APPLE__
37373459 suggestedName = desktopLocation.append("/script.js");
3460+#endif
37383461 } else {
37393462 suggestedName = _previousScriptLocation;
37403463 }
@@ -3743,9 +3466,11 @@ void Application::loadDialog() { · 2 unmodified lines
37433466 tr("JavaScript Files (*.js)"));
37443467 if (!fileNameString.isEmpty()) {
37453468 _previousScriptLocation = fileNameString;
3746− }
3469+ QMutexLocker locker(&_settingsMutex);
3470+ _settings->setValue("LastScriptLocation", _previousScriptLocation);
37473471
3748− loadScript(fileNameString);
3472+ loadScript(fileNameString);
3473+ }
37493474 }
37503475
37513476 void Application::loadScriptURLDialog() {
@@ -3863,3 +3588,38 @@ void Application::takeSnapshot() { · 111 unmodified lines
38633588
38643589 Snapshot::saveSnapshot(_glWidget, _myAvatar);
38653590 }
3591+
3592+void 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