Showing the changes to interface/src/Application.cpp (1 of 645 files). Show all
Unified · Split
| @@ -1,13 +1,13 @@ | ||
| 1 | 1 | // |
| 2 | 2 | // Application.cpp |
| 3 | −// interface | |
| 3 | +// interface/src | |
| 4 | 4 | // |
| 5 | 5 | // Created by Andrzej Kapolka on 5/10/13. |
| 6 | −// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. | |
| 7 | − | |
| 8 | −#ifdef WIN32 | |
| 9 | −#include <Systime.h> | |
| 10 | −#endif | |
| 6 | +// Copyright 2013 High Fidelity, Inc. | |
| 7 | +// | |
| 8 | +// Distributed under the Apache License, Version 2.0. | |
| 9 | +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | |
| 10 | +// | |
| 11 | 11 | |
| 12 | 12 | #include <sstream> |
| 13 | 13 | |
| @@ -62,7 +62,7 @@ · 48 unmodified lines | ||
| 62 | 62 | #include <UUID.h> |
| 63 | 63 | #include <OctreeSceneStats.h> |
| 64 | 64 | #include <LocalVoxelsList.h> |
| 65 | −#include <FstReader.h> | |
| 65 | +#include <ModelUploader.h> | |
| 66 | 66 | |
| 67 | 67 | #include "Application.h" |
| 68 | 68 | #include "InterfaceVersion.h" |
| @@ -80,6 +80,7 @@ · 11 unmodified lines | ||
| 80 | 80 | #include "ui/InfoView.h" |
| 81 | 81 | #include "ui/Snapshot.h" |
| 82 | 82 | #include "ui/TextRenderer.h" |
| 83 | +#include "ui/Stats.h" | |
| 83 | 84 | |
| 84 | 85 | using namespace std; |
| 85 | 86 | |
| @@ -106,13 +107,9 @@ const float MIRROR_REARVIEW_DISTANCE = 0.65f; · 20 unmodified lines | ||
| 106 | 107 | const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; |
| 107 | 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 | 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 | 113 | void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { |
| 117 | 114 | if (message.size() > 0) { |
| 118 | 115 | QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate); |
| @@ -132,11 +129,10 @@ QString& Application::resourcesPath() { · 13 unmodified lines | ||
| 132 | 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 | 133 | QApplication(argc, argv), |
| 137 | 134 | _window(new MainWindow(desktop())), |
| 138 | 135 | _glWidget(new GLCanvas()), |
| 139 | − _statsExpanded(false), | |
| 140 | 136 | _nodeThread(new QThread(this)), |
| 141 | 137 | _datagramProcessor(), |
| 142 | 138 | _frameCount(0), |
| @@ -149,9 +145,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 6 unmodified lines | ||
| 149 | 145 | _viewFrustum(), |
| 150 | 146 | _lastQueriedViewFrustum(), |
| 151 | 147 | _lastQueriedTime(usecTimestampNow()), |
| 152 | − _audioScope(256, 200, true), | |
| 153 | − _trailingAudioLoudness(0.f), | |
| 154 | 148 | _mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)), |
| 149 | + _cameraPushback(0.0f), | |
| 155 | 150 | _mouseX(0), |
| 156 | 151 | _mouseY(0), |
| 157 | 152 | _lastMouseMove(usecTimestampNow()), |
| @@ -161,19 +156,20 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 3 unmodified lines | ||
| 161 | 156 | _touchAvgY(0.0f), |
| 162 | 157 | _isTouchPressed(false), |
| 163 | 158 | _mousePressed(false), |
| 164 | − _audio(&_audioScope, STARTUP_JITTER_SAMPLES), | |
| 159 | + _audio(STARTUP_JITTER_SAMPLES), | |
| 165 | 160 | _enableProcessVoxelsThread(true), |
| 166 | 161 | _voxelProcessor(), |
| 167 | 162 | _voxelHideShowThread(&_voxels), |
| 168 | 163 | _packetsPerSecond(0), |
| 169 | 164 | _bytesPerSecond(0), |
| 170 | − _recentMaxPackets(0), | |
| 171 | − _resetRecentMaxPacketsSoon(true), | |
| 172 | 165 | _previousScriptLocation(), |
| 173 | 166 | _logger(new FileLogger(this)), |
| 174 | 167 | _runningScriptsWidget(new RunningScriptsWidget), |
| 175 | 168 | _runningScriptsWidgetWasVisible(false) |
| 176 | 169 | { |
| 170 | + // init GnuTLS for DTLS with domain-servers | |
| 171 | + DTLSClientSession::globalInit(); | |
| 172 | + | |
| 177 | 173 | // read the ApplicationInfo.ini file for Name/Version/Domain information |
| 178 | 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 | 228 | audioThread->start(); |
| 233 | 229 | |
| 234 | − connect(&nodeList->getDomainInfo(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); | |
| 235 | − connect(&nodeList->getDomainInfo(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); | |
| 230 | + connect(&nodeList->getDomainHandler(), SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); | |
| 231 | + connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); | |
| 236 | 232 | |
| 237 | 233 | connect(nodeList, &NodeList::nodeAdded, this, &Application::nodeAdded); |
| 238 | 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 | 236 | connect(nodeList, SIGNAL(nodeAdded(SharedNodePointer)), &_voxels, SLOT(nodeAdded(SharedNodePointer))); |
| 241 | 237 | connect(nodeList, SIGNAL(nodeKilled(SharedNodePointer)), &_voxels, SLOT(nodeKilled(SharedNodePointer))); |
| 242 | 238 | connect(nodeList, &NodeList::uuidChanged, this, &Application::updateWindowTitle); |
| 239 | + connect(nodeList, SIGNAL(uuidChanged(const QUuid&)), _myAvatar, SLOT(setSessionUUID(const QUuid&))); | |
| 243 | 240 | connect(nodeList, &NodeList::limitOfSilentDomainCheckInsReached, nodeList, &NodeList::reset); |
| 244 | 241 | |
| 245 | 242 | // connect to appropriate slots on AccountManager |
| @@ -254,6 +251,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 8 unmodified lines | ||
| 254 | 251 | QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection); |
| 255 | 252 | |
| 256 | 253 | _settings = new QSettings(this); |
| 254 | + _numChangedSettings = 0; | |
| 257 | 255 | |
| 258 | 256 | // Check to see if the user passed in a command line option for loading a local |
| 259 | 257 | // Voxel File. |
| @@ -277,7 +275,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 17 unmodified lines | ||
| 277 | 275 | QTimer* silentNodeTimer = new QTimer(); |
| 278 | 276 | connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); |
| 279 | 277 | silentNodeTimer->moveToThread(_nodeThread); |
| 280 | − silentNodeTimer->start(NODE_SILENCE_THRESHOLD_USECS / 1000); | |
| 278 | + silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS); | |
| 281 | 279 | |
| 282 | 280 | // send the identity packet for our avatar each second to our avatar mixer |
| 283 | 281 | QTimer* identityPacketTimer = new QTimer(); |
| @@ -346,15 +344,22 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : · 62 unmodified lines | ||
| 346 | 344 | clearScriptsBeforeRunning(); |
| 347 | 345 | loadScript("http://public.highfidelity.io/scripts/defaultScripts.js"); |
| 348 | 346 | |
| 347 | + QMutexLocker locker(&_settingsMutex); | |
| 349 | 348 | _settings->setValue("firstRun",QVariant(false)); |
| 350 | 349 | } else { |
| 351 | 350 | // do this as late as possible so that all required subsystems are inialized |
| 352 | 351 | loadScripts(); |
| 352 | + | |
| 353 | + QMutexLocker locker(&_settingsMutex); | |
| 354 | + _previousScriptLocation = _settings->value("LastScriptLocation", QVariant("")).toString(); | |
| 353 | 355 | } |
| 354 | 356 | |
| 355 | 357 | connect(_window, &MainWindow::windowGeometryChanged, |
| 356 | 358 | _runningScriptsWidget, &RunningScriptsWidget::setBoundary); |
| 357 | 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 | 365 | Application::~Application() { |
| @@ -404,37 +409,50 @@ Application::~Application() { · 43 unmodified lines | ||
| 404 | 409 | delete _glWidget; |
| 405 | 410 | |
| 406 | 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 | 428 | void Application::restoreSizeAndPosition() { |
| 410 | − QSettings* settings = new QSettings(this); | |
| 411 | 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); | |
| 416 | − int y = (int)loadSetting(settings, "y", 0); | |
| 434 | + int x = (int)loadSetting(_settings, "x", 0); | |
| 435 | + int y = (int)loadSetting(_settings, "y", 0); | |
| 417 | 436 | _window->move(x, y); |
| 418 | 437 | |
| 419 | − int width = (int)loadSetting(settings, "width", available.width()); | |
| 420 | − int height = (int)loadSetting(settings, "height", available.height()); | |
| 438 | + int width = (int)loadSetting(_settings, "width", available.width()); | |
| 439 | + int height = (int)loadSetting(_settings, "height", available.height()); | |
| 421 | 440 | _window->resize(width, height); |
| 422 | 441 | |
| 423 | − settings->endGroup(); | |
| 442 | + _settings->endGroup(); | |
| 424 | 443 | } |
| 425 | 444 | |
| 426 | 445 | void Application::storeSizeAndPosition() { |
| 427 | − QSettings* settings = new QSettings(this); | |
| 428 | − | |
| 429 | − settings->beginGroup("Window"); | |
| 446 | + QMutexLocker locker(&_settingsMutex); | |
| 447 | + _settings->beginGroup("Window"); | |
| 430 | 448 | |
| 431 | − settings->setValue("width", _window->rect().width()); | |
| 432 | − settings->setValue("height", _window->rect().height()); | |
| 449 | + _settings->setValue("width", _window->rect().width()); | |
| 450 | + _settings->setValue("height", _window->rect().height()); | |
| 433 | 451 | |
| 434 | − settings->setValue("x", _window->pos().x()); | |
| 435 | − settings->setValue("y", _window->pos().y()); | |
| 452 | + _settings->setValue("x", _window->pos().x()); | |
| 453 | + _settings->setValue("y", _window->pos().y()); | |
| 436 | 454 | |
| 437 | − settings->endGroup(); | |
| 455 | + _settings->endGroup(); | |
| 438 | 456 | } |
| 439 | 457 | |
| 440 | 458 | void Application::initializeGL() { |
| @@ -495,7 +513,7 @@ void Application::initializeGL() { · 54 unmodified lines | ||
| 495 | 513 | _idleLoopStdev.reset(); |
| 496 | 514 | |
| 497 | 515 | if (_justStarted) { |
| 498 | − float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime)) / 1000000.0; | |
| 516 | + float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0; | |
| 499 | 517 | _justStarted = false; |
| 500 | 518 | qDebug("Startup time: %4.2f seconds.", startupTime); |
| 501 | 519 | const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time"; |
| @@ -517,18 +535,55 @@ void Application::paintGL() { · 15 unmodified lines | ||
| 517 | 535 | |
| 518 | 536 | glEnable(GL_LINE_SMOOTH); |
| 519 | 537 | |
| 538 | + float pushback = 0.0f; | |
| 539 | + float pushbackFocalLength = 0.0f; | |
| 520 | 540 | if (OculusManager::isConnected()) { |
| 521 | 541 | _myCamera.setUpShift(0.0f); |
| 522 | 542 | _myCamera.setDistance(0.0f); |
| 523 | 543 | _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing |
| 524 | 544 | _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); |
| 525 | − _myCamera.setTargetRotation(_myAvatar->getHead()->getOrientation()); | |
| 545 | + _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); | |
| 526 | 546 | |
| 527 | 547 | } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { |
| 528 | 548 | _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay |
| 529 | 549 | _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); |
| 530 | 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 | 587 | } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { |
| 533 | 588 | _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing |
| 534 | 589 | _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition()); |
| @@ -536,10 +591,35 @@ void Application::paintGL() { · 1 unmodified line | ||
| 536 | 591 | |
| 537 | 592 | } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { |
| 538 | 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 | 596 | _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale()); |
| 541 | 597 | _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight, 0)); |
| 542 | 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 | 625 | // Update camera position |
| @@ -630,6 +710,13 @@ void Application::resizeGL(int width, int height) { · 84 unmodified lines | ||
| 630 | 710 | _window->geometry().topLeft().y(), |
| 631 | 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 | 722 | void Application::updateProjectionMatrix() { |
| @@ -699,26 +786,9 @@ bool Application::event(QEvent* event) { · 63 unmodified lines | ||
| 699 | 786 | // handle custom URL |
| 700 | 787 | if (event->type() == QEvent::FileOpen) { |
| 701 | 788 | QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event); |
| 702 | − if (!fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME)) { | |
| 703 | − QString destination = fileEvent->url().toLocalFile().remove(CUSTOM_URL_SCHEME); | |
| 704 | − QStringList urlParts = destination.split('/', QString::SkipEmptyParts); | |
| 705 | − | |
| 706 | − if (urlParts.count() > 1) { | |
| 707 | − // if url has 2 or more parts, the first one is domain name | |
| 708 | − Menu::getInstance()->goToDomain(urlParts[0]); | |
| 709 | − | |
| 710 | − // location coordinates | |
| 711 | − Menu::getInstance()->goToDestination(urlParts[1]); | |
| 712 | − if (urlParts.count() > 2) { | |
| 713 | − | |
| 714 | − // location orientation | |
| 715 | − Menu::getInstance()->goToOrientation(urlParts[2]); | |
| 716 | − } | |
| 717 | − } else if (urlParts.count() == 1) { | |
| 718 | − | |
| 719 | − // location coordinates | |
| 720 | − Menu::getInstance()->goToDestination(urlParts[0]); | |
| 721 | − } | |
| 789 | + bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME); | |
| 790 | + if (isHifiSchemeURL) { | |
| 791 | + Menu::getInstance()->goTo(fileEvent->url().toString()); | |
| 722 | 792 | } |
| 723 | 793 | |
| 724 | 794 | return false; |
| @@ -740,6 +810,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 15 unmodified lines | ||
| 740 | 810 | if (activeWindow() == _window) { |
| 741 | 811 | bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier); |
| 742 | 812 | bool isMeta = event->modifiers().testFlag(Qt::ControlModifier); |
| 813 | + bool isOption = event->modifiers().testFlag(Qt::AltModifier); | |
| 743 | 814 | switch (event->key()) { |
| 744 | 815 | break; |
| 745 | 816 | case Qt::Key_BracketLeft: |
| @@ -754,9 +825,6 @@ void Application::keyPressEvent(QKeyEvent* event) { · 8 unmodified lines | ||
| 754 | 825 | case Qt::Key_Period: |
| 755 | 826 | Menu::getInstance()->handleViewFrustumOffsetKeyModifier(event->key()); |
| 756 | 827 | break; |
| 757 | − case Qt::Key_Apostrophe: | |
| 758 | − _audioScope.inputPaused = !_audioScope.inputPaused; | |
| 759 | − break; | |
| 760 | 828 | case Qt::Key_L: |
| 761 | 829 | if (isShifted) { |
| 762 | 830 | Menu::getInstance()->triggerOption(MenuOption::LodTools); |
| @@ -766,6 +834,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 3 unmodified lines | ||
| 766 | 834 | break; |
| 767 | 835 | |
| 768 | 836 | case Qt::Key_E: |
| 837 | + case Qt::Key_PageUp: | |
| 769 | 838 | if (!_myAvatar->getDriveKeys(UP)) { |
| 770 | 839 | _myAvatar->jump(); |
| 771 | 840 | } |
| @@ -777,6 +846,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 5 unmodified lines | ||
| 777 | 846 | break; |
| 778 | 847 | |
| 779 | 848 | case Qt::Key_C: |
| 849 | + case Qt::Key_PageDown: | |
| 780 | 850 | _myAvatar->setDriveKeys(DOWN, 1.f); |
| 781 | 851 | break; |
| 782 | 852 | |
| @@ -785,9 +855,11 @@ void Application::keyPressEvent(QKeyEvent* event) { · 2 unmodified lines | ||
| 785 | 855 | break; |
| 786 | 856 | |
| 787 | 857 | case Qt::Key_S: |
| 788 | − if (isShifted && isMeta) { | |
| 858 | + if (isShifted && isMeta && !isOption) { | |
| 789 | 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 | 863 | takeSnapshot(); |
| 792 | 864 | } else { |
| 793 | 865 | _myAvatar->setDriveKeys(BACK, 1.f); |
| @@ -963,10 +1035,12 @@ void Application::keyReleaseEvent(QKeyEvent* event) { · 169 unmodified lines | ||
| 963 | 1035 | |
| 964 | 1036 | switch (event->key()) { |
| 965 | 1037 | case Qt::Key_E: |
| 1038 | + case Qt::Key_PageUp: | |
| 966 | 1039 | _myAvatar->setDriveKeys(UP, 0.f); |
| 967 | 1040 | break; |
| 968 | 1041 | |
| 969 | 1042 | case Qt::Key_C: |
| 1043 | + case Qt::Key_PageDown: | |
| 970 | 1044 | _myAvatar->setDriveKeys(DOWN, 0.f); |
| 971 | 1045 | break; |
| 972 | 1046 | |
| @@ -1089,7 +1163,11 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { · 116 unmodified lines | ||
| 1089 | 1163 | _mousePressed = false; |
| 1090 | 1164 | checkBandwidthMeterClick(); |
| 1091 | 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 | 1233 | if (_controllerScriptingInterface.isTouchCaptured()) { |
| 1156 | 1234 | return; |
| 1157 | 1235 | } |
| 1158 | − | |
| 1159 | 1236 | // put any application specific touch behavior below here.. |
| 1160 | 1237 | _touchDragStartedAvgX = _touchAvgX; |
| 1161 | 1238 | _touchDragStartedAvgY = _touchAvgY; |
| @@ -1209,26 +1286,24 @@ void Application::sendPingPackets() { · 47 unmodified lines | ||
| 1209 | 1286 | |
| 1210 | 1287 | // Every second, check the frame rates and other stuff |
| 1211 | 1288 | void Application::timer() { |
| 1212 | − gettimeofday(&_timerEnd, NULL); | |
| 1213 | − | |
| 1214 | 1289 | if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { |
| 1215 | 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); | |
| 1221 | − _bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); | |
| 1297 | + _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / diffTime; | |
| 1298 | + _bytesPerSecond = (float) _datagramProcessor.getByteCount() / diffTime; | |
| 1222 | 1299 | _frameCount = 0; |
| 1223 | 1300 | |
| 1224 | 1301 | _datagramProcessor.resetCounters(); |
| 1225 | 1302 | |
| 1226 | − gettimeofday(&_timerStart, NULL); | |
| 1303 | + _timerStart.start(); | |
| 1227 | 1304 | |
| 1228 | 1305 | // ask the node list to check in with the domain server |
| 1229 | 1306 | NodeList::getInstance()->sendDomainServerCheckIn(); |
| 1230 | − | |
| 1231 | − | |
| 1232 | 1307 | } |
| 1233 | 1308 | |
| 1234 | 1309 | void Application::idle() { |
| @@ -1238,13 +1313,11 @@ void Application::idle() { · 3 unmodified lines | ||
| 1238 | 1313 | bool showWarnings = getLogger()->extraDebugging(); |
| 1239 | 1314 | PerformanceWarning warn(showWarnings, "Application::idle()"); |
| 1240 | 1315 | |
| 1241 | − timeval check; | |
| 1242 | − gettimeofday(&check, NULL); | |
| 1243 | − | |
| 1244 | 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 | 1319 | if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { |
| 1320 | + _lastTimeUpdated.start(); | |
| 1248 | 1321 | { |
| 1249 | 1322 | PerformanceWarning warn(showWarnings, "Application::idle()... update()"); |
| 1250 | 1323 | const float BIGGEST_DELTA_TIME_SECS = 0.25f; |
| @@ -1256,7 +1329,6 @@ void Application::idle() { · 5 unmodified lines | ||
| 1256 | 1329 | } |
| 1257 | 1330 | { |
| 1258 | 1331 | PerformanceWarning warn(showWarnings, "Application::idle()... rest of it"); |
| 1259 | − _lastTimeUpdated = check; | |
| 1260 | 1332 | _idleLoopStdev.addValue(timeSinceLastUpdate); |
| 1261 | 1333 | |
| 1262 | 1334 | // Record standard deviation and reset counter if needed |
| @@ -1273,6 +1345,9 @@ void Application::idle() { · 10 unmodified lines | ||
| 1273 | 1345 | // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. |
| 1274 | 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 | 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 | 1437 | struct SendVoxelsOperationArgs { |
| 1357 | 1438 | const unsigned char* newBaseOctCode; |
| 1358 | 1439 | }; |
| @@ -1563,8 +1644,8 @@ void Application::init() { · 204 unmodified lines | ||
| 1563 | 1644 | Qt::QueuedConnection); |
| 1564 | 1645 | } |
| 1565 | 1646 | |
| 1566 | − gettimeofday(&_timerStart, NULL); | |
| 1567 | − gettimeofday(&_lastTimeUpdated, NULL); | |
| 1647 | + _timerStart.start(); | |
| 1648 | + _lastTimeUpdated.start(); | |
| 1568 | 1649 | |
| 1569 | 1650 | Menu::getInstance()->loadSettings(); |
| 1570 | 1651 | if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) { |
| @@ -1572,8 +1653,9 @@ void Application::init() { · 1 unmodified line | ||
| 1572 | 1653 | } |
| 1573 | 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 | 1657 | _faceshift.init(); |
| 1658 | + _faceplus.init(); | |
| 1577 | 1659 | _visage.init(); |
| 1578 | 1660 | |
| 1579 | 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 | 1676 | _particleCollisionSystem.init(&_particleEditSender, _particles.getTree(), _voxels.getTree(), &_audio, &_avatarManager); |
| 1595 | 1677 | |
| 1596 | − // connect the _particleCollisionSystem to our script engine's ParticleScriptingInterface | |
| 1597 | − connect(&_particleCollisionSystem, | |
| 1598 | − SIGNAL(particleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&)), | |
| 1599 | − ScriptEngine::getParticlesScriptingInterface(), | |
| 1600 | − SLOT(forwardParticleCollisionWithVoxel(const ParticleID&, const VoxelDetail&, const glm::vec3&))); | |
| 1678 | + // connect the _particleCollisionSystem to our script engine's ParticlesScriptingInterface | |
| 1679 | + connect(&_particleCollisionSystem, &ParticleCollisionSystem::particleCollisionWithVoxel, | |
| 1680 | + ScriptEngine::getParticlesScriptingInterface(), &ParticlesScriptingInterface::particleCollisionWithVoxel); | |
| 1601 | 1681 | |
| 1602 | − connect(&_particleCollisionSystem, | |
| 1603 | − SIGNAL(particleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&)), | |
| 1604 | − ScriptEngine::getParticlesScriptingInterface(), | |
| 1605 | − SLOT(forwardParticleCollisionWithParticle(const ParticleID&, const ParticleID&, const glm::vec3&))); | |
| 1682 | + connect(&_particleCollisionSystem, &ParticleCollisionSystem::particleCollisionWithParticle, | |
| 1683 | + ScriptEngine::getParticlesScriptingInterface(), &ParticlesScriptingInterface::particleCollisionWithParticle); | |
| 1606 | 1684 | |
| 1607 | 1685 | _audio.init(_glWidget); |
| 1608 | 1686 | |
| @@ -1612,6 +1690,20 @@ void Application::init() { · 3 unmodified lines | ||
| 1612 | 1690 | connect(_rearMirrorTools, SIGNAL(restoreView()), SLOT(restoreMirrorView())); |
| 1613 | 1691 | connect(_rearMirrorTools, SIGNAL(shrinkView()), SLOT(shrinkMirrorView())); |
| 1614 | 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 | 1709 | void Application::closeMirrorView() { |
| @@ -1737,19 +1829,11 @@ void Application::updateMyAvatarLookAtPosition() { · 119 unmodified lines | ||
| 1737 | 1829 | glm::distance(_mouseRayOrigin, _myAvatar->getHead()->calculateAverageEyePosition())); |
| 1738 | 1830 | lookAtSpot = _mouseRayOrigin + _mouseRayDirection * qMax(minEyeDistance, distance); |
| 1739 | 1831 | } |
| 1740 | − bool trackerActive = false; | |
| 1741 | − float eyePitch, eyeYaw; | |
| 1742 | − if (_faceshift.isActive()) { | |
| 1743 | − eyePitch = _faceshift.getEstimatedEyePitch(); | |
| 1744 | − eyeYaw = _faceshift.getEstimatedEyeYaw(); | |
| 1745 | − trackerActive = true; | |
| 1832 | + FaceTracker* tracker = getActiveFaceTracker(); | |
| 1833 | + if (tracker) { | |
| 1834 | + float eyePitch = tracker->getEstimatedEyePitch(); | |
| 1835 | + float eyeYaw = tracker->getEstimatedEyeYaw(); | |
| 1746 | 1836 | |
| 1747 | − } else if (_visage.isActive()) { | |
| 1748 | − eyePitch = _visage.getEstimatedEyePitch(); | |
| 1749 | − eyeYaw = _visage.getEstimatedEyeYaw(); | |
| 1750 | − trackerActive = true; | |
| 1751 | − } | |
| 1752 | − if (trackerActive) { | |
| 1753 | 1837 | // deflect using Faceshift gaze data |
| 1754 | 1838 | glm::vec3 origin = _myAvatar->getHead()->calculateAverageEyePosition(); |
| 1755 | 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 | 1919 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1836 | 1920 | PerformanceWarning warn(showWarnings, "Application::updateCamera()"); |
| 1837 | 1921 | |
| 1838 | − if (!OculusManager::isConnected() && !TV3DManager::isConnected()) { | |
| 1839 | − if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { | |
| 1840 | − float xSign = _myCamera.getMode() == CAMERA_MODE_MIRROR ? 1.0f : -1.0f; | |
| 1841 | − if (_faceshift.isActive()) { | |
| 1842 | − const float EYE_OFFSET_SCALE = 0.025f; | |
| 1843 | − glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE; | |
| 1844 | − _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z)); | |
| 1845 | − updateProjectionMatrix(); | |
| 1846 | − } | |
| 1922 | + if (!OculusManager::isConnected() && !TV3DManager::isConnected() && | |
| 1923 | + Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { | |
| 1924 | + FaceTracker* tracker = getActiveFaceTracker(); | |
| 1925 | + if (tracker) { | |
| 1926 | + const float EYE_OFFSET_SCALE = 0.025f; | |
| 1927 | + glm::vec3 position = tracker->getHeadTranslation() * EYE_OFFSET_SCALE; | |
| 1928 | + float xSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? 1.0f : -1.0f; | |
| 1929 | + _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, -position.z)); | |
| 1930 | + updateProjectionMatrix(); | |
| 1847 | 1931 | } |
| 1848 | 1932 | } |
| 1849 | 1933 | } |
| @@ -2137,7 +2221,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node · 287 unmodified lines | ||
| 2137 | 2221 | int packetLength = endOfQueryPacket - queryPacket; |
| 2138 | 2222 | |
| 2139 | 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 | 2226 | // Feed number of bytes to corresponding channel of the bandwidth meter |
| 2143 | 2227 | _bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength); |
| @@ -2252,8 +2336,7 @@ void Application::updateShadowMap() { · 108 unmodified lines | ||
| 2252 | 2336 | glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); |
| 2253 | 2337 | |
| 2254 | 2338 | // store view matrix without translation, which we'll use for precision-sensitive objects |
| 2255 | − glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); | |
| 2256 | − _viewMatrixTranslation = glm::vec3(); | |
| 2339 | + updateUntranslatedViewMatrix(); | |
| 2257 | 2340 | |
| 2258 | 2341 | _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); |
| 2259 | 2342 | _particles.render(); |
| @@ -2338,8 +2421,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 78 unmodified lines | ||
| 2338 | 2421 | glRotatef(-glm::degrees(glm::angle(rotation)), axis.x, axis.y, axis.z); |
| 2339 | 2422 | |
| 2340 | 2423 | // store view matrix without translation, which we'll use for precision-sensitive objects |
| 2341 | − glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat*)&_untranslatedViewMatrix); | |
| 2342 | − _viewMatrixTranslation = -whichCamera.getPosition(); | |
| 2424 | + updateUntranslatedViewMatrix(-whichCamera.getPosition()); | |
| 2343 | 2425 | |
| 2344 | 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 | 2476 | // disable specular lighting for ground and voxels |
| 2395 | 2477 | glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR); |
| 2396 | 2478 | |
| 2479 | + // draw the audio reflector overlay | |
| 2480 | + _audioReflector.render(); | |
| 2481 | + | |
| 2397 | 2482 | // Draw voxels |
| 2398 | 2483 | if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { |
| 2399 | 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 | 2563 | void Application::loadTranslatedViewMatrix(const glm::vec3& translation) { |
| 2474 | 2564 | glLoadMatrixf((const GLfloat*)&_untranslatedViewMatrix); |
| 2475 | 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 | 2607 | // Audio VU Meter and Mute Icon |
| 2527 | 2608 | const int MUTE_ICON_SIZE = 24; |
| 2528 | 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 | 2612 | const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET; |
| 2531 | 2613 | const int AUDIO_METER_HEIGHT = 8; |
| 2532 | − const int AUDIO_METER_Y_GAP = 8; | |
| 2533 | − const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET; | |
| 2614 | + const int AUDIO_METER_GAP = 5; | |
| 2615 | + const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP; | |
| 2534 | 2616 | |
| 2535 | 2617 | int audioMeterY; |
| 2536 | 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 | 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 | 2624 | const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0}; |
| 2545 | 2625 | const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0}; |
| @@ -2549,29 +2629,53 @@ void Application::displayOverlay() { · 3 unmodified lines | ||
| 2549 | 2629 | const float CLIPPING_INDICATOR_TIME = 1.0f; |
| 2550 | 2630 | const float AUDIO_METER_AVERAGING = 0.5; |
| 2551 | 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 | 2634 | float audioLevel = 0.f; |
| 2554 | 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 | 2638 | float log2loudness = log(_trailingAudioLoudness) / LOG2; |
| 2558 | 2639 | |
| 2559 | − audioLevel = log2loudness / MAX_LOG2_SAMPLE * AUDIO_METER_SCALE_WIDTH; | |
| 2560 | − | |
| 2640 | + if (log2loudness <= LOG2_LOUDNESS_FLOOR) { | |
| 2641 | + audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH; | |
| 2642 | + } else { | |
| 2643 | + audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.f)) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH; | |
| 2644 | + } | |
| 2645 | + if (audioLevel > AUDIO_METER_SCALE_WIDTH) { | |
| 2646 | + audioLevel = AUDIO_METER_SCALE_WIDTH; | |
| 2647 | + } | |
| 2561 | 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 | 2662 | glBegin(GL_QUADS); |
| 2564 | 2663 | if (isClipping) { |
| 2565 | 2664 | glColor3f(1, 0, 0); |
| 2566 | 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 | 2672 | // Draw audio meter background Quad |
| 2570 | 2673 | glVertex2i(AUDIO_METER_X, audioMeterY); |
| 2571 | 2674 | glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY); |
| 2572 | 2675 | glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT); |
| 2573 | 2676 | glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT); |
| 2574 | 2677 | |
| 2678 | + | |
| 2575 | 2679 | if (audioLevel > AUDIO_RED_START) { |
| 2576 | 2680 | if (!isClipping) { |
| 2577 | 2681 | glColor3fv(AUDIO_METER_RED); |
| @@ -2611,6 +2715,7 @@ void Application::displayOverlay() { · 33 unmodified lines | ||
| 2611 | 2715 | glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); |
| 2612 | 2716 | glEnd(); |
| 2613 | 2717 | |
| 2718 | + | |
| 2614 | 2719 | if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { |
| 2615 | 2720 | _myAvatar->renderHeadMouse(); |
| 2616 | 2721 | } |
| @@ -2620,11 +2725,17 @@ void Application::displayOverlay() { · 3 unmodified lines | ||
| 2620 | 2725 | glPointSize(1.0f); |
| 2621 | 2726 | |
| 2622 | 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 | 2734 | // Onscreen text about position, servers, etc |
| 2624 | − displayStats(); | |
| 2735 | + Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess); | |
| 2625 | 2736 | // Bandwidth meter |
| 2626 | 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 | 2739 | _bandwidthMeter.render(_glWidget->width(), _glWidget->height()); |
| 2629 | 2740 | } |
| 2630 | 2741 | } |
| @@ -2638,7 +2749,7 @@ void Application::displayOverlay() { · 7 unmodified lines | ||
| 2638 | 2749 | (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && |
| 2639 | 2750 | Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) |
| 2640 | 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 | 2755 | _overlays.render2D(); |
| @@ -2646,415 +2757,6 @@ void Application::displayOverlay() { · 1 unmodified line | ||
| 2646 | 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 | 2760 | glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { |
| 3059 | 2761 | float horizontalScale = _glWidget->width() / 2.0f; |
| 3060 | 2762 | float verticalScale = _glWidget->height() / 2.0f; |
| @@ -3339,6 +3041,7 @@ void Application::resetSensors() { · 278 unmodified lines | ||
| 3339 | 3041 | _mouseX = _glWidget->width() / 2; |
| 3340 | 3042 | _mouseY = _glWidget->height() / 2; |
| 3341 | 3043 | |
| 3044 | + _faceplus.reset(); | |
| 3342 | 3045 | _faceshift.reset(); |
| 3343 | 3046 | _visage.reset(); |
| 3344 | 3047 | |
| @@ -3378,8 +3081,7 @@ void Application::updateWindowTitle(){ · 33 unmodified lines | ||
| 3378 | 3081 | |
| 3379 | 3082 | QString username = AccountManager::getInstance().getUsername(); |
| 3380 | 3083 | QString title = QString() + (!username.isEmpty() ? username + " " : QString()) + nodeList->getSessionUUID().toString() |
| 3381 | − + " @ " + nodeList->getDomainInfo().getHostname() + buildVersion; | |
| 3382 | − | |
| 3084 | + + " @ " + nodeList->getDomainHandler().getHostname() + buildVersion; | |
| 3383 | 3085 | qDebug("Application title set to: %s", title.toStdString().c_str()); |
| 3384 | 3086 | _window->setWindowTitle(title); |
| 3385 | 3087 | } |
| @@ -3431,7 +3133,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 45 unmodified lines | ||
| 3431 | 3133 | VoxelPositionSize rootDetails; |
| 3432 | 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 | 3137 | rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); |
| 3436 | 3138 | |
| 3437 | 3139 | // Add the jurisditionDetails object to the list of "fade outs" |
| @@ -3462,7 +3164,7 @@ void Application::nodeKilled(SharedNodePointer node) { · 24 unmodified lines | ||
| 3462 | 3164 | VoxelPositionSize rootDetails; |
| 3463 | 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 | 3168 | rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); |
| 3467 | 3169 | |
| 3468 | 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 | 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 | 3249 | rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); |
| 3548 | 3250 | |
| 3549 | 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 | 3275 | void Application::loadScripts() { |
| 3574 | 3276 | // loads all saved scripts |
| 3575 | − QSettings* settings = new QSettings(this); | |
| 3576 | − int size = settings->beginReadArray("Settings"); | |
| 3577 | − | |
| 3277 | + int size = lockSettings()->beginReadArray("Settings"); | |
| 3278 | + unlockSettings(); | |
| 3578 | 3279 | for (int i = 0; i < size; ++i){ |
| 3579 | − settings->setArrayIndex(i); | |
| 3580 | − QString string = settings->value("script").toString(); | |
| 3581 | − loadScript(string); | |
| 3280 | + lockSettings()->setArrayIndex(i); | |
| 3281 | + QString string = _settings->value("script").toString(); | |
| 3282 | + unlockSettings(); | |
| 3283 | + if (!string.isEmpty()) { | |
| 3284 | + loadScript(string); | |
| 3285 | + } | |
| 3582 | 3286 | } |
| 3583 | 3287 | |
| 3584 | − settings->endArray(); | |
| 3288 | + QMutexLocker locker(&_settingsMutex); | |
| 3289 | + _settings->endArray(); | |
| 3585 | 3290 | } |
| 3586 | 3291 | |
| 3587 | 3292 | void Application::clearScriptsBeforeRunning() { |
| 3588 | 3293 | // clears all scripts from the settings |
| 3589 | − QSettings* settings = new QSettings(this); | |
| 3590 | − settings->beginWriteArray("Settings"); | |
| 3591 | − settings->endArray(); | |
| 3294 | + QMutexLocker locker(&_settingsMutex); | |
| 3295 | + _settings->remove("Settings"); | |
| 3592 | 3296 | } |
| 3593 | 3297 | |
| 3594 | 3298 | void Application::saveScripts() { |
| 3595 | 3299 | // saves all current running scripts |
| 3596 | − QSettings* settings = new QSettings(this); | |
| 3597 | − settings->beginWriteArray("Settings"); | |
| 3300 | + QMutexLocker locker(&_settingsMutex); | |
| 3301 | + _settings->beginWriteArray("Settings"); | |
| 3598 | 3302 | for (int i = 0; i < getRunningScripts().size(); ++i){ |
| 3599 | − settings->setArrayIndex(i); | |
| 3600 | − settings->setValue("script", getRunningScripts().at(i)); | |
| 3303 | + _settings->setArrayIndex(i); | |
| 3304 | + _settings->setValue("script", getRunningScripts().at(i)); | |
| 3601 | 3305 | } |
| 3602 | − | |
| 3603 | − settings->endArray(); | |
| 3306 | + _settings->endArray(); | |
| 3604 | 3307 | } |
| 3605 | 3308 | |
| 3606 | 3309 | void Application::stopAllScripts() { |
| @@ -3611,14 +3314,17 @@ void Application::stopAllScripts() { · 4 unmodified lines | ||
| 3611 | 3314 | } |
| 3612 | 3315 | _scriptEnginesHash.clear(); |
| 3613 | 3316 | _runningScriptsWidget->setRunningScripts(getRunningScripts()); |
| 3317 | + bumpSettings(); | |
| 3614 | 3318 | } |
| 3615 | 3319 | |
| 3616 | −void Application::stopScript(const QString &scriptName) | |
| 3617 | −{ | |
| 3618 | − _scriptEnginesHash.value(scriptName)->stop(); | |
| 3619 | − qDebug() << "stopping script..." << scriptName; | |
| 3620 | − _scriptEnginesHash.remove(scriptName); | |
| 3621 | − _runningScriptsWidget->setRunningScripts(getRunningScripts()); | |
| 3320 | +void Application::stopScript(const QString &scriptName) { | |
| 3321 | + if (_scriptEnginesHash.contains(scriptName)) { | |
| 3322 | + _scriptEnginesHash.value(scriptName)->stop(); | |
| 3323 | + qDebug() << "stopping script..." << scriptName; | |
| 3324 | + _scriptEnginesHash.remove(scriptName); | |
| 3325 | + _runningScriptsWidget->setRunningScripts(getRunningScripts()); | |
| 3326 | + bumpSettings(); | |
| 3327 | + } | |
| 3622 | 3328 | } |
| 3623 | 3329 | |
| 3624 | 3330 | void Application::reloadAllScripts() { |
| @@ -3659,10 +3365,13 @@ void Application::toggleRunningScriptsWidget() · 34 unmodified lines | ||
| 3659 | 3365 | } |
| 3660 | 3366 | |
| 3661 | 3367 | void Application::uploadFST(bool isHead) { |
| 3662 | − FstReader reader(isHead); | |
| 3663 | − if (reader.zip()) { | |
| 3664 | − reader.send(); | |
| 3665 | − } | |
| 3368 | + ModelUploader* uploader = new ModelUploader(isHead); | |
| 3369 | + QThread* thread = new QThread(); | |
| 3370 | + thread->connect(uploader, SIGNAL(destroyed()), SLOT(quit())); | |
| 3371 | + thread->connect(thread, SIGNAL(finished()), SLOT(deleteLater())); | |
| 3372 | + uploader->connect(thread, SIGNAL(started()), SLOT(send())); | |
| 3373 | + | |
| 3374 | + thread->start(); | |
| 3666 | 3375 | } |
| 3667 | 3376 | |
| 3668 | 3377 | void Application::uploadHead() { |
| @@ -3673,7 +3382,10 @@ void Application::uploadSkeleton() { · 4 unmodified lines | ||
| 3673 | 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 | 3390 | // start the script on a new thread... |
| 3679 | 3391 | ScriptEngine* scriptEngine = new ScriptEngine(QUrl(scriptName), &_controllerScriptingInterface); |
| @@ -3681,7 +3393,7 @@ void Application::loadScript(const QString& scriptName) { · 1 unmodified line | ||
| 3681 | 3393 | |
| 3682 | 3394 | if (!scriptEngine->hasScript()) { |
| 3683 | 3395 | qDebug() << "Application::loadScript(), script failed to load..."; |
| 3684 | − return; | |
| 3396 | + return NULL; | |
| 3685 | 3397 | } |
| 3686 | 3398 | _runningScriptsWidget->setRunningScripts(getRunningScripts()); |
| 3687 | 3399 | |
| @@ -3689,6 +3401,7 @@ void Application::loadScript(const QString& scriptName) { · 1 unmodified line | ||
| 3689 | 3401 | // we can use the same ones from the application. |
| 3690 | 3402 | scriptEngine->getVoxelsScriptingInterface()->setPacketSender(&_voxelEditSender); |
| 3691 | 3403 | scriptEngine->getVoxelsScriptingInterface()->setVoxelTree(_voxels.getTree()); |
| 3404 | + scriptEngine->getVoxelsScriptingInterface()->setUndoStack(&_undoStack); | |
| 3692 | 3405 | scriptEngine->getParticlesScriptingInterface()->setPacketSender(&_particleEditSender); |
| 3693 | 3406 | scriptEngine->getParticlesScriptingInterface()->setParticleTree(_particles.getTree()); |
| 3694 | 3407 | |
| @@ -3707,6 +3420,8 @@ void Application::loadScript(const QString& scriptName) { · 12 unmodified lines | ||
| 3707 | 3420 | scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance()); |
| 3708 | 3421 | scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); |
| 3709 | 3422 | scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); |
| 3423 | + scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); | |
| 3424 | + scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); | |
| 3710 | 3425 | |
| 3711 | 3426 | QThread* workerThread = new QThread(this); |
| 3712 | 3427 | |
| @@ -3726,7 +3441,12 @@ void Application::loadScript(const QString& scriptName) { · 13 unmodified lines | ||
| 3726 | 3441 | workerThread->start(); |
| 3727 | 3442 | |
| 3728 | 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 | 3452 | void Application::loadDialog() { |
| @@ -3734,7 +3454,10 @@ void Application::loadDialog() { · 1 unmodified line | ||
| 3734 | 3454 | |
| 3735 | 3455 | if (_previousScriptLocation.isEmpty()) { |
| 3736 | 3456 | QString desktopLocation = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); |
| 3457 | +// Temporary fix to Qt bug: http://stackoverflow.com/questions/16194475 | |
| 3458 | +#ifdef __APPLE__ | |
| 3737 | 3459 | suggestedName = desktopLocation.append("/script.js"); |
| 3460 | +#endif | |
| 3738 | 3461 | } else { |
| 3739 | 3462 | suggestedName = _previousScriptLocation; |
| 3740 | 3463 | } |
| @@ -3743,9 +3466,11 @@ void Application::loadDialog() { · 2 unmodified lines | ||
| 3743 | 3466 | tr("JavaScript Files (*.js)")); |
| 3744 | 3467 | if (!fileNameString.isEmpty()) { |
| 3745 | 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 | 3476 | void Application::loadScriptURLDialog() { |
| @@ -3863,3 +3588,38 @@ void Application::takeSnapshot() { · 111 unmodified lines | ||
| 3863 | 3588 | |
| 3864 | 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 | +} | |