Showing the changes to interface/src/Application.cpp (1 of 645 files). Show all
Unified · Split
| @@ -1,13 +1,13 @@ | |||
| 1 | // | 1 | // |
| 2 | // Application.cpp | 2 | // Application.cpp |
| 3 | // interface | 3 | // 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 WIN32 | 8 | // 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 | #endif | 10 | // |
| 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 | ||
| 84 | using namespace std; | 85 | using namespace std; |
| 85 | 86 | ||
| @@ -106,13 +107,9 @@ const float MIRROR_REARVIEW_DISTANCE = 0.65f; · 20 unmodified lines | |||
| 106 | const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; | 107 | const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; |
| 107 | const float MIRROR_FIELD_OF_VIEW = 30.0f; | 108 | const float MIRROR_FIELD_OF_VIEW = 30.0f; |
| 108 | 109 | ||
| 109 | const QString CHECK_VERSION_URL = "http://highfidelity.io/latestVersion.xml"; | 110 | const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml"; |
| 110 | const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion"; | 111 | const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion"; |
| 111 | 112 | ||
| 112 | const int STATS_PELS_PER_LINE = 20; | ||
| 113 | |||
| 114 | const QString CUSTOM_URL_SCHEME = "hifi:"; | ||
| 115 | |||
| 116 | void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { | 113 | void 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 | ||
| 135 | Application::Application(int& argc, char** argv, timeval &startup_time) : | 132 | Application::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 information | 173 | // 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 AccountManager | 242 | // 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 local | 256 | // 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 mixer | 280 | // 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 inialized | 350 | // 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 | ||
| 360 | Application::~Application() { | 365 | Application::~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 | ||
| 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 | |||
| 409 | void Application::restoreSizeAndPosition() { | 428 | void 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 | ||
| 426 | void Application::storeSizeAndPosition() { | 445 | void 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 | ||
| 440 | void Application::initializeGL() { | 458 | void 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 smoothing | 543 | _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 delay | 548 | _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 smoothing | 588 | _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 position | 625 | // 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 | ||
| 635 | void Application::updateProjectionMatrix() { | 722 | void Application::updateProjectionMatrix() { |
| @@ -699,26 +786,9 @@ bool Application::event(QEvent* event) { · 63 unmodified lines | |||
| 699 | // handle custom URL | 786 | // 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 stuff | 1287 | // Every second, check the frame rates and other stuff |
| 1211 | void Application::timer() { | 1288 | void 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 server | 1305 | // 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 | ||
| 1234 | void Application::idle() { | 1309 | void 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 ran | 1316 | // 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 needed | 1334 | // 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 | ||
| 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 | |||
| 1356 | struct SendVoxelsOperationArgs { | 1437 | struct 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 settings | 1656 | // 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 loaded | 1661 | // 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 ParticleScriptingInterface | 1678 | // 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 | ||
| 1617 | void Application::closeMirrorView() { | 1709 | void 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 data | 1837 | // 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 socket | 2223 | // 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 meter | 2226 | // 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 objects | 2338 | // 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 objects | 2423 | // 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 voxels | 2476 | // 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 voxels | 2482 | // 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 | ||
| 2558 | void Application::updateUntranslatedViewMatrix(const glm::vec3& viewMatrixTranslation) { | ||
| 2559 | glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); | ||
| 2560 | _viewMatrixTranslation = viewMatrixTranslation; | ||
| 2561 | } | ||
| 2562 | |||
| 2473 | void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { | 2563 | void 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 Icon | 2607 | // 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 Quad | 2672 | // 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, etc | 2734 | // Onscreen text about position, servers, etc |
| 2624 | displayStats(); | 2735 | Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess); |
| 2625 | // Bandwidth meter | 2736 | // 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 | ||
| 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 | |||
| 3058 | glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { | 2760 | glm::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 | ||
| 3573 | void Application::loadScripts() { | 3275 | void Application::loadScripts() { |
| 3574 | // loads all saved scripts | 3276 | // 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 | ||
| 3587 | void Application::clearScriptsBeforeRunning() { | 3292 | void Application::clearScriptsBeforeRunning() { |
| 3588 | // clears all scripts from the settings | 3293 | // 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 | ||
| 3594 | void Application::saveScripts() { | 3298 | void Application::saveScripts() { |
| 3595 | // saves all current running scripts | 3299 | // 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 | ||
| 3606 | void Application::stopAllScripts() { | 3309 | void 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 | ||
| 3616 | void Application::stopScript(const QString &scriptName) | 3320 | void 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 | ||
| 3624 | void Application::reloadAllScripts() { | 3330 | void Application::reloadAllScripts() { |
| @@ -3659,10 +3365,13 @@ void Application::toggleRunningScriptsWidget() · 34 unmodified lines | |||
| 3659 | } | 3365 | } |
| 3660 | 3366 | ||
| 3661 | void Application::uploadFST(bool isHead) { | 3367 | void 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 | ||
| 3668 | void Application::uploadHead() { | 3377 | void Application::uploadHead() { |
| @@ -3673,7 +3382,10 @@ void Application::uploadSkeleton() { · 4 unmodified lines | |||
| 3673 | uploadFST(false); | 3382 | uploadFST(false); |
| 3674 | } | 3383 | } |
| 3675 | 3384 | ||
| 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 | } | ||
| 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 state | 3443 | // 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 | ||
| 3732 | void Application::loadDialog() { | 3452 | void 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 | ||
| 3751 | void Application::loadScriptURLDialog() { | 3476 | void 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 | |||
| 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 | } | ||