Showing the changes to interface/src/Application.cpp (1 of 312 files). Show all
Unified · Split
| @@ -74,6 +74,7 @@ · 73 unmodified lines | ||
| 74 | 74 | #include "devices/TV3DManager.h" |
| 75 | 75 | #include "renderer/ProgramObject.h" |
| 76 | 76 | |
| 77 | +#include "scripting/AccountScriptingInterface.h" | |
| 77 | 78 | #include "scripting/AudioDeviceScriptingInterface.h" |
| 78 | 79 | #include "scripting/ClipboardScriptingInterface.h" |
| 79 | 80 | #include "scripting/MenuScriptingInterface.h" |
| @@ -103,18 +104,11 @@ const int STARTUP_JITTER_SAMPLES = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / 2 · 23 unmodified lines | ||
| 103 | 104 | // Startup optimistically with small jitter buffer that |
| 104 | 105 | // will start playback on the second received audio packet. |
| 105 | 106 | |
| 106 | −const int MIRROR_VIEW_TOP_PADDING = 5; | |
| 107 | −const int MIRROR_VIEW_LEFT_PADDING = 10; | |
| 108 | −const int MIRROR_VIEW_WIDTH = 265; | |
| 109 | −const int MIRROR_VIEW_HEIGHT = 215; | |
| 110 | −const float MIRROR_FULLSCREEN_DISTANCE = 0.35f; | |
| 111 | −const float MIRROR_REARVIEW_DISTANCE = 0.65f; | |
| 112 | −const float MIRROR_REARVIEW_BODY_DISTANCE = 2.3f; | |
| 113 | −const float MIRROR_FIELD_OF_VIEW = 30.0f; | |
| 114 | − | |
| 115 | 107 | const QString CHECK_VERSION_URL = "https://highfidelity.io/latestVersion.xml"; |
| 116 | 108 | const QString SKIP_FILENAME = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/hifi.skipversion"; |
| 117 | 109 | |
| 110 | +const QString DEFAULT_SCRIPTS_JS_URL = "http://public.highfidelity.io/scripts/defaultScripts.js"; | |
| 111 | + | |
| 118 | 112 | void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) { |
| 119 | 113 | if (message.size() > 0) { |
| 120 | 114 | QString dateString = QDateTime::currentDateTime().toTimeSpec(Qt::LocalTime).toString(Qt::ISODate); |
| @@ -141,7 +135,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 20 unmodified lines | ||
| 141 | 135 | _nodeThread(new QThread(this)), |
| 142 | 136 | _datagramProcessor(), |
| 143 | 137 | _frameCount(0), |
| 144 | − _fps(120.0f), | |
| 138 | + _fps(60.0f), | |
| 145 | 139 | _justStarted(true), |
| 146 | 140 | _voxelImporter(NULL), |
| 147 | 141 | _importSucceded(false), |
| @@ -158,6 +152,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 10 unmodified lines | ||
| 158 | 152 | _mouseX(0), |
| 159 | 153 | _mouseY(0), |
| 160 | 154 | _lastMouseMove(usecTimestampNow()), |
| 155 | + _lastMouseMoveType(QEvent::MouseMove), | |
| 161 | 156 | _mouseHidden(false), |
| 162 | 157 | _seenMouseMove(false), |
| 163 | 158 | _touchAvgX(0.0f), |
| @@ -166,14 +161,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 2 unmodified lines | ||
| 166 | 161 | _mousePressed(false), |
| 167 | 162 | _audio(STARTUP_JITTER_SAMPLES), |
| 168 | 163 | _enableProcessVoxelsThread(true), |
| 169 | − _voxelProcessor(), | |
| 164 | + _octreeProcessor(), | |
| 170 | 165 | _voxelHideShowThread(&_voxels), |
| 171 | 166 | _packetsPerSecond(0), |
| 172 | 167 | _bytesPerSecond(0), |
| 173 | 168 | _nodeBoundsDisplay(this), |
| 174 | 169 | _previousScriptLocation(), |
| 175 | − _runningScriptsWidget(new RunningScriptsWidget(_window)), | |
| 176 | − _runningScriptsWidgetWasVisible(false) | |
| 170 | + _applicationOverlay(), | |
| 171 | + _runningScriptsWidget(NULL), | |
| 172 | + _runningScriptsWidgetWasVisible(false), | |
| 173 | + _trayIcon(new QSystemTrayIcon(_window)), | |
| 174 | + _lastNackTime(usecTimestampNow()) | |
| 177 | 175 | { |
| 178 | 176 | // read the ApplicationInfo.ini file for Name/Version/Domain information |
| 179 | 177 | QSettings applicationInfo(Application::resourcesPath() + "info/ApplicationInfo.ini", QSettings::IniFormat); |
| @@ -204,6 +202,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 24 unmodified lines | ||
| 204 | 202 | // call Menu getInstance static method to set up the menu |
| 205 | 203 | _window->setMenuBar(Menu::getInstance()); |
| 206 | 204 | |
| 205 | + _runningScriptsWidget = new RunningScriptsWidget(_window); | |
| 206 | + | |
| 207 | 207 | unsigned int listenPort = 0; // bind to an ephemeral port by default |
| 208 | 208 | const char** constArgv = const_cast<const char**>(argv); |
| 209 | 209 | const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); |
| @@ -238,7 +238,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 28 unmodified lines | ||
| 238 | 238 | connect(&nodeList->getDomainHandler(), SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); |
| 239 | 239 | |
| 240 | 240 | // update our location every 5 seconds in the data-server, assuming that we are authenticated with one |
| 241 | − const float DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5.0f * 1000.0f; | |
| 241 | + const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; | |
| 242 | 242 | |
| 243 | 243 | QTimer* locationUpdateTimer = new QTimer(this); |
| 244 | 244 | connect(locationUpdateTimer, &QTimer::timeout, this, &Application::updateLocationInServer); |
| @@ -255,6 +255,15 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 10 unmodified lines | ||
| 255 | 255 | |
| 256 | 256 | // connect to appropriate slots on AccountManager |
| 257 | 257 | AccountManager& accountManager = AccountManager::getInstance(); |
| 258 | + | |
| 259 | + const qint64 BALANCE_UPDATE_INTERVAL_MSECS = 5 * 1000; | |
| 260 | + | |
| 261 | + QTimer* balanceUpdateTimer = new QTimer(this); | |
| 262 | + connect(balanceUpdateTimer, &QTimer::timeout, &accountManager, &AccountManager::updateBalance); | |
| 263 | + balanceUpdateTimer->start(BALANCE_UPDATE_INTERVAL_MSECS); | |
| 264 | + | |
| 265 | + connect(&accountManager, &AccountManager::balanceChanged, this, &Application::updateWindowTitle); | |
| 266 | + | |
| 258 | 267 | connect(&accountManager, &AccountManager::authRequired, Menu::getInstance(), &Menu::loginForCurrentDomain); |
| 259 | 268 | connect(&accountManager, &AccountManager::usernameChanged, this, &Application::updateWindowTitle); |
| 260 | 269 | |
| @@ -289,8 +298,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 28 unmodified lines | ||
| 289 | 298 | // move the silentNodeTimer to the _nodeThread |
| 290 | 299 | QTimer* silentNodeTimer = new QTimer(); |
| 291 | 300 | connect(silentNodeTimer, SIGNAL(timeout()), nodeList, SLOT(removeSilentNodes())); |
| 292 | − silentNodeTimer->moveToThread(_nodeThread); | |
| 293 | 301 | silentNodeTimer->start(NODE_SILENCE_THRESHOLD_MSECS); |
| 302 | + silentNodeTimer->moveToThread(_nodeThread); | |
| 294 | 303 | |
| 295 | 304 | // send the identity packet for our avatar each second to our avatar mixer |
| 296 | 305 | QTimer* identityPacketTimer = new QTimer(); |
| @@ -361,7 +370,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 64 unmodified lines | ||
| 361 | 370 | qDebug() << "This is a first run..."; |
| 362 | 371 | // clear the scripts, and set out script to our default scripts |
| 363 | 372 | clearScriptsBeforeRunning(); |
| 364 | − loadScript("http://public.highfidelity.io/scripts/defaultScripts.js"); | |
| 373 | + loadScript(DEFAULT_SCRIPTS_JS_URL); | |
| 365 | 374 | |
| 366 | 375 | QMutexLocker locker(&_settingsMutex); |
| 367 | 376 | _settings->setValue("firstRun",QVariant(false)); |
| @@ -383,6 +392,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 15 unmodified lines | ||
| 383 | 392 | OAuthWebViewHandler::getInstance(); |
| 384 | 393 | // make sure the High Fidelity root CA is in our list of trusted certs |
| 385 | 394 | OAuthWebViewHandler::addHighFidelityRootCAToSSLConfig(); |
| 395 | + | |
| 396 | + _trayIcon->show(); | |
| 386 | 397 | } |
| 387 | 398 | |
| 388 | 399 | Application::~Application() { |
| @@ -412,7 +423,7 @@ Application::~Application() { · 23 unmodified lines | ||
| 412 | 423 | _audio.thread()->quit(); |
| 413 | 424 | _audio.thread()->wait(); |
| 414 | 425 | |
| 415 | − _voxelProcessor.terminate(); | |
| 426 | + _octreeProcessor.terminate(); | |
| 416 | 427 | _voxelHideShowThread.terminate(); |
| 417 | 428 | _voxelEditSender.terminate(); |
| 418 | 429 | _particleEditSender.terminate(); |
| @@ -511,7 +522,7 @@ void Application::initializeGL() { · 92 unmodified lines | ||
| 511 | 522 | qDebug( "init() complete."); |
| 512 | 523 | |
| 513 | 524 | // create thread for parsing of voxel data independent of the main network and rendering threads |
| 514 | − _voxelProcessor.initialize(_enableProcessVoxelsThread); | |
| 525 | + _octreeProcessor.initialize(_enableProcessVoxelsThread); | |
| 515 | 526 | _voxelEditSender.initialize(_enableProcessVoxelsThread); |
| 516 | 527 | _voxelHideShowThread.initialize(_enableProcessVoxelsThread); |
| 517 | 528 | _particleEditSender.initialize(_enableProcessVoxelsThread); |
| @@ -543,26 +554,20 @@ void Application::initializeGL() { · 25 unmodified lines | ||
| 543 | 554 | } |
| 544 | 555 | |
| 545 | 556 | // update before the first render |
| 546 | − update(0.0f); | |
| 557 | + update(1.f / _fps); | |
| 547 | 558 | |
| 548 | 559 | InfoView::showFirstTime(); |
| 549 | 560 | } |
| 550 | 561 | |
| 551 | 562 | void Application::paintGL() { |
| 563 | + PerformanceTimer perfTimer("paintGL"); | |
| 564 | + | |
| 552 | 565 | PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); |
| 553 | 566 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 554 | 567 | PerformanceWarning warn(showWarnings, "Application::paintGL()"); |
| 555 | 568 | |
| 556 | 569 | glEnable(GL_LINE_SMOOTH); |
| 557 | 570 | |
| 558 | − float pushback = 0.0f; | |
| 559 | − float pushbackFocalLength = 0.0f; | |
| 560 | − if (OculusManager::isConnected()) { | |
| 561 | − _myCamera.setUpShift(0.0f); | |
| 562 | − _myCamera.setDistance(0.0f); | |
| 563 | − _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing | |
| 564 | − } | |
| 565 | − | |
| 566 | 571 | if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { |
| 567 | 572 | _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay |
| 568 | 573 | _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); |
| @@ -577,39 +582,25 @@ void Application::paintGL() { · 8 unmodified lines | ||
| 577 | 582 | _myCamera.setTightness(0.0f); |
| 578 | 583 | glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); |
| 579 | 584 | float headHeight = eyePosition.y - _myAvatar->getPosition().y; |
| 580 | − _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _myAvatar->getScale() * _scaleMirror); | |
| 585 | + _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); | |
| 581 | 586 | _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); |
| 582 | 587 | _myCamera.setTargetRotation(_myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); |
| 588 | + } | |
| 583 | 589 | |
| 584 | − // if the head would intersect the near clip plane, we must push the camera out | |
| 585 | − glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) * | |
| 586 | − (eyePosition - _myCamera.getTargetPosition()); | |
| 587 | − const float BASE_PUSHBACK_RADIUS = 0.2f; | |
| 588 | − float pushbackRadius = _myCamera.getNearClip() + _myAvatar->getScale() * BASE_PUSHBACK_RADIUS; | |
| 589 | − pushback = relativePosition.z + pushbackRadius - _myCamera.getDistance(); | |
| 590 | − pushbackFocalLength = _myCamera.getDistance(); | |
| 591 | − } | |
| 592 | − | |
| 593 | − // handle pushback, if any | |
| 594 | − if (pushbackFocalLength > 0.0f) { | |
| 595 | − const float PUSHBACK_DECAY = 0.5f; | |
| 596 | − _cameraPushback = qMax(pushback, _cameraPushback * PUSHBACK_DECAY); | |
| 597 | − if (_cameraPushback > EPSILON) { | |
| 598 | − _myCamera.setTargetPosition(_myCamera.getTargetPosition() + | |
| 599 | − _myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, _cameraPushback)); | |
| 600 | − float enlargement = pushbackFocalLength / (pushbackFocalLength + _cameraPushback); | |
| 601 | − _myCamera.setFieldOfView(glm::degrees(2.0f * atanf(enlargement * tanf( | |
| 602 | − glm::radians(Menu::getInstance()->getFieldOfView() * 0.5f))))); | |
| 603 | − } else { | |
| 604 | − _myCamera.setFieldOfView(Menu::getInstance()->getFieldOfView()); | |
| 590 | + if (OculusManager::isConnected()) { | |
| 591 | + // Oculus in third person causes nausea, so only allow it if option is checked in dev menu | |
| 592 | + if (!Menu::getInstance()->isOptionChecked(MenuOption::AllowOculusCameraModeChange) || _myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { | |
| 593 | + _myCamera.setDistance(0.0f); | |
| 594 | + _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); | |
| 595 | + _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); | |
| 605 | 596 | } |
| 606 | − updateProjectionMatrix(_myCamera, true); | |
| 597 | + _myCamera.setUpShift(0.0f); | |
| 598 | + _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing | |
| 607 | 599 | } |
| 608 | 600 | |
| 609 | 601 | // Update camera position |
| 610 | 602 | _myCamera.update( 1.f/_fps ); |
| 611 | 603 | |
| 612 | − | |
| 613 | 604 | // Note: whichCamera is used to pick between the normal camera myCamera for our |
| 614 | 605 | // main camera, vs, an alternate camera. The alternate camera we support right now |
| 615 | 606 | // is the viewFrustumOffsetCamera. But theoretically, we could use this same mechanism |
| @@ -635,16 +626,18 @@ void Application::paintGL() { · 19 unmodified lines | ||
| 635 | 626 | whichCamera = _viewFrustumOffsetCamera; |
| 636 | 627 | } |
| 637 | 628 | |
| 638 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { | |
| 629 | + if (Menu::getInstance()->getShadowsEnabled()) { | |
| 639 | 630 | updateShadowMap(); |
| 640 | 631 | } |
| 641 | 632 | |
| 642 | 633 | if (OculusManager::isConnected()) { |
| 643 | 634 | OculusManager::display(whichCamera); |
| 635 | + | |
| 644 | 636 | } else if (TV3DManager::isConnected()) { |
| 645 | 637 | _glowEffect.prepare(); |
| 646 | 638 | TV3DManager::display(whichCamera); |
| 647 | 639 | _glowEffect.render(); |
| 640 | + | |
| 648 | 641 | } else { |
| 649 | 642 | _glowEffect.prepare(); |
| 650 | 643 | |
| @@ -663,7 +656,17 @@ void Application::paintGL() { · 12 unmodified lines | ||
| 663 | 656 | _rearMirrorTools->render(true); |
| 664 | 657 | } |
| 665 | 658 | |
| 666 | − displayOverlay(); | |
| 659 | + { | |
| 660 | + PerformanceTimer perfTimer("paintGL/renderOverlay"); | |
| 661 | + //If alpha is 1, we can render directly to the screen. | |
| 662 | + if (_applicationOverlay.getAlpha() == 1.0f) { | |
| 663 | + _applicationOverlay.renderOverlay(); | |
| 664 | + } else { | |
| 665 | + //Render to to texture so we can fade it | |
| 666 | + _applicationOverlay.renderOverlay(true); | |
| 667 | + _applicationOverlay.displayOverlayTexture(); | |
| 668 | + } | |
| 669 | + } | |
| 667 | 670 | } |
| 668 | 671 | |
| 669 | 672 | _frameCount++; |
| @@ -1103,6 +1106,16 @@ void Application::focusOutEvent(QFocusEvent* event) { · 433 unmodified lines | ||
| 1103 | 1106 | } |
| 1104 | 1107 | |
| 1105 | 1108 | void Application::mouseMoveEvent(QMouseEvent* event) { |
| 1109 | + | |
| 1110 | + bool showMouse = true; | |
| 1111 | + // If this mouse move event is emitted by a controller, dont show the mouse cursor | |
| 1112 | + if (event->type() == CONTROLLER_MOVE_EVENT) { | |
| 1113 | + showMouse = false; | |
| 1114 | + } | |
| 1115 | + | |
| 1116 | + // Used by application overlay to determine how to draw cursor(s) | |
| 1117 | + _lastMouseMoveType = event->type(); | |
| 1118 | + | |
| 1106 | 1119 | _controllerScriptingInterface.emitMouseMoveEvent(event); // send events to any registered scripts |
| 1107 | 1120 | |
| 1108 | 1121 | // if one of our scripts have asked to capture this event, then stop processing it |
| @@ -1110,9 +1123,9 @@ void Application::mouseMoveEvent(QMouseEvent* event) { · 1 unmodified line | ||
| 1110 | 1123 | return; |
| 1111 | 1124 | } |
| 1112 | 1125 | |
| 1113 | − | |
| 1114 | 1126 | _lastMouseMove = usecTimestampNow(); |
| 1115 | − if (_mouseHidden) { | |
| 1127 | + | |
| 1128 | + if (_mouseHidden && showMouse && !OculusManager::isConnected()) { | |
| 1116 | 1129 | getGLWidget()->setCursor(Qt::ArrowCursor); |
| 1117 | 1130 | _mouseHidden = false; |
| 1118 | 1131 | _seenMouseMove = true; |
| @@ -1308,11 +1321,13 @@ void Application::timer() { · 189 unmodified lines | ||
| 1308 | 1321 | } |
| 1309 | 1322 | |
| 1310 | 1323 | void Application::idle() { |
| 1324 | + PerformanceTimer perfTimer("idle"); | |
| 1325 | + | |
| 1311 | 1326 | // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing |
| 1312 | 1327 | // details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing |
| 1313 | 1328 | // details normally. |
| 1314 | 1329 | bool showWarnings = getLogger()->extraDebugging(); |
| 1315 | − PerformanceWarning warn(showWarnings, "Application::idle()"); | |
| 1330 | + PerformanceWarning warn(showWarnings, "idle()"); | |
| 1316 | 1331 | |
| 1317 | 1332 | // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran |
| 1318 | 1333 | |
| @@ -1320,15 +1335,18 @@ void Application::idle() { · 1 unmodified line | ||
| 1320 | 1335 | if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { |
| 1321 | 1336 | _lastTimeUpdated.start(); |
| 1322 | 1337 | { |
| 1338 | + PerformanceTimer perfTimer("idle/update"); | |
| 1323 | 1339 | PerformanceWarning warn(showWarnings, "Application::idle()... update()"); |
| 1324 | 1340 | const float BIGGEST_DELTA_TIME_SECS = 0.25f; |
| 1325 | 1341 | update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); |
| 1326 | 1342 | } |
| 1327 | 1343 | { |
| 1344 | + PerformanceTimer perfTimer("idle/updateGL"); | |
| 1328 | 1345 | PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()"); |
| 1329 | 1346 | _glWidget->updateGL(); |
| 1330 | 1347 | } |
| 1331 | 1348 | { |
| 1349 | + PerformanceTimer perfTimer("idle/rest"); | |
| 1332 | 1350 | PerformanceWarning warn(showWarnings, "Application::idle()... rest of it"); |
| 1333 | 1351 | _idleLoopStdev.addValue(timeSinceLastUpdate); |
| 1334 | 1352 | |
| @@ -1340,14 +1358,16 @@ void Application::idle() { · 5 unmodified lines | ||
| 1340 | 1358 | } |
| 1341 | 1359 | |
| 1342 | 1360 | if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) { |
| 1361 | + PerformanceTimer perfTimer("idle/rest/_buckyBalls"); | |
| 1343 | 1362 | _buckyBalls.simulate(timeSinceLastUpdate / 1000.f, Application::getInstance()->getAvatar()->getHandData()); |
| 1344 | 1363 | } |
| 1345 | 1364 | |
| 1346 | 1365 | // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. |
| 1347 | 1366 | idleTimer->start(2); |
| 1348 | − } | |
| 1349 | − if (_numChangedSettings > 0) { | |
| 1350 | − saveSettings(); | |
| 1367 | + | |
| 1368 | + if (_numChangedSettings > 0) { | |
| 1369 | + saveSettings(); | |
| 1370 | + } | |
| 1351 | 1371 | } |
| 1352 | 1372 | } |
| 1353 | 1373 | } |
| @@ -1375,6 +1395,9 @@ void Application::setEnable3DTVMode(bool enable3DTVMode) { · 21 unmodified lines | ||
| 1375 | 1395 | resizeGL(_glWidget->width(),_glWidget->height()); |
| 1376 | 1396 | } |
| 1377 | 1397 | |
| 1398 | +void Application::setEnableVRMode(bool enableVRMode) { | |
| 1399 | + resizeGL(_glWidget->width(), _glWidget->height()); | |
| 1400 | +} | |
| 1378 | 1401 | |
| 1379 | 1402 | void Application::setRenderVoxels(bool voxelRender) { |
| 1380 | 1403 | _voxelEditSender.setShouldSend(voxelRender); |
| @@ -1504,10 +1527,10 @@ void Application::importVoxels() { · 123 unmodified lines | ||
| 1504 | 1527 | } |
| 1505 | 1528 | |
| 1506 | 1529 | if (!_voxelImporter->exec()) { |
| 1507 | − qDebug() << "[DEBUG] Import succeeded." << endl; | |
| 1530 | + qDebug() << "Import succeeded." << endl; | |
| 1508 | 1531 | _importSucceded = true; |
| 1509 | 1532 | } else { |
| 1510 | − qDebug() << "[DEBUG] Import failed." << endl; | |
| 1533 | + qDebug() << "Import failed." << endl; | |
| 1511 | 1534 | if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) { |
| 1512 | 1535 | _sharedVoxelSystem.killLocalVoxels(); |
| 1513 | 1536 | _sharedVoxelSystem.changeTree(&_clipboard); |
| @@ -1749,6 +1772,7 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) { · 235 unmodified lines | ||
| 1749 | 1772 | } |
| 1750 | 1773 | |
| 1751 | 1774 | void Application::updateLOD() { |
| 1775 | + PerformanceTimer perfTimer("idle/update/updateLOD"); | |
| 1752 | 1776 | // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode |
| 1753 | 1777 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) { |
| 1754 | 1778 | Menu::getInstance()->autoAdjustLOD(_fps); |
| @@ -1758,6 +1782,7 @@ void Application::updateLOD() { · 3 unmodified lines | ||
| 1758 | 1782 | } |
| 1759 | 1783 | |
| 1760 | 1784 | void Application::updateMouseRay() { |
| 1785 | + PerformanceTimer perfTimer("idle/update/updateMouseRay"); | |
| 1761 | 1786 | |
| 1762 | 1787 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1763 | 1788 | PerformanceWarning warn(showWarnings, "Application::updateMouseRay()"); |
| @@ -1790,6 +1815,7 @@ void Application::updateMouseRay() { · 26 unmodified lines | ||
| 1790 | 1815 | } |
| 1791 | 1816 | |
| 1792 | 1817 | void Application::updateFaceshift() { |
| 1818 | + PerformanceTimer perfTimer("idle/update/updateFaceshift"); | |
| 1793 | 1819 | |
| 1794 | 1820 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1795 | 1821 | PerformanceWarning warn(showWarnings, "Application::updateFaceshift()"); |
| @@ -1804,6 +1830,7 @@ void Application::updateFaceshift() { · 8 unmodified lines | ||
| 1804 | 1830 | } |
| 1805 | 1831 | |
| 1806 | 1832 | void Application::updateVisage() { |
| 1833 | + PerformanceTimer perfTimer("idle/update/updateVisage"); | |
| 1807 | 1834 | |
| 1808 | 1835 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1809 | 1836 | PerformanceWarning warn(showWarnings, "Application::updateVisage()"); |
| @@ -1813,6 +1840,7 @@ void Application::updateVisage() { · 3 unmodified lines | ||
| 1813 | 1840 | } |
| 1814 | 1841 | |
| 1815 | 1842 | void Application::updateMyAvatarLookAtPosition() { |
| 1843 | + PerformanceTimer perfTimer("idle/update/updateMyAvatarLookAtPosition"); | |
| 1816 | 1844 | |
| 1817 | 1845 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1818 | 1846 | PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); |
| @@ -1844,7 +1872,8 @@ void Application::updateMyAvatarLookAtPosition() { · 25 unmodified lines | ||
| 1844 | 1872 | } |
| 1845 | 1873 | } else { |
| 1846 | 1874 | // I am not looking at anyone else, so just look forward |
| 1847 | − lookAtSpot = _myAvatar->getHead()->calculateAverageEyePosition() + (_myAvatar->getHead()->getFinalOrientation() * glm::vec3(0.f, 0.f, -TREE_SCALE)); | |
| 1875 | + lookAtSpot = _myAvatar->getHead()->calculateAverageEyePosition() + | |
| 1876 | + (_myAvatar->getHead()->getFinalOrientationInWorldFrame() * glm::vec3(0.f, 0.f, -TREE_SCALE)); | |
| 1848 | 1877 | } |
| 1849 | 1878 | // TODO: Add saccade to mouse pointer when stable, IF not looking at someone (since we know we are looking at it) |
| 1850 | 1879 | /* |
| @@ -1878,12 +1907,13 @@ void Application::updateMyAvatarLookAtPosition() { · 27 unmodified lines | ||
| 1878 | 1907 | } |
| 1879 | 1908 | |
| 1880 | 1909 | void Application::updateThreads(float deltaTime) { |
| 1910 | + PerformanceTimer perfTimer("idle/update/updateThreads"); | |
| 1881 | 1911 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1882 | 1912 | PerformanceWarning warn(showWarnings, "Application::updateThreads()"); |
| 1883 | 1913 | |
| 1884 | 1914 | // parse voxel packets |
| 1885 | 1915 | if (!_enableProcessVoxelsThread) { |
| 1886 | − _voxelProcessor.threadRoutine(); | |
| 1916 | + _octreeProcessor.threadRoutine(); | |
| 1887 | 1917 | _voxelHideShowThread.threadRoutine(); |
| 1888 | 1918 | _voxelEditSender.threadRoutine(); |
| 1889 | 1919 | _particleEditSender.threadRoutine(); |
| @@ -1892,6 +1922,7 @@ void Application::updateThreads(float deltaTime) { · 2 unmodified lines | ||
| 1892 | 1922 | } |
| 1893 | 1923 | |
| 1894 | 1924 | void Application::updateMetavoxels(float deltaTime) { |
| 1925 | + PerformanceTimer perfTimer("idle/update/updateMetavoxels"); | |
| 1895 | 1926 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1896 | 1927 | PerformanceWarning warn(showWarnings, "Application::updateMetavoxels()"); |
| 1897 | 1928 | |
| @@ -1921,6 +1952,7 @@ void Application::cameraMenuChanged() { · 23 unmodified lines | ||
| 1921 | 1952 | } |
| 1922 | 1953 | |
| 1923 | 1954 | void Application::updateCamera(float deltaTime) { |
| 1955 | + PerformanceTimer perfTimer("idle/update/updateCamera"); | |
| 1924 | 1956 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1925 | 1957 | PerformanceWarning warn(showWarnings, "Application::updateCamera()"); |
| 1926 | 1958 | |
| @@ -1938,6 +1970,7 @@ void Application::updateCamera(float deltaTime) { · 11 unmodified lines | ||
| 1938 | 1970 | } |
| 1939 | 1971 | |
| 1940 | 1972 | void Application::updateDialogs(float deltaTime) { |
| 1973 | + PerformanceTimer perfTimer("idle/update/updateDialogs"); | |
| 1941 | 1974 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1942 | 1975 | PerformanceWarning warn(showWarnings, "Application::updateDialogs()"); |
| 1943 | 1976 | |
| @@ -1954,6 +1987,7 @@ void Application::updateDialogs(float deltaTime) { · 10 unmodified lines | ||
| 1954 | 1987 | } |
| 1955 | 1988 | |
| 1956 | 1989 | void Application::updateCursor(float deltaTime) { |
| 1990 | + PerformanceTimer perfTimer("idle/update/updateCursor"); | |
| 1957 | 1991 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1958 | 1992 | PerformanceWarning warn(showWarnings, "Application::updateCursor()"); |
| 1959 | 1993 | |
| @@ -1978,51 +2012,87 @@ void Application::updateCursor(float deltaTime) { · 18 unmodified lines | ||
| 1978 | 2012 | } |
| 1979 | 2013 | |
| 1980 | 2014 | void Application::update(float deltaTime) { |
| 2015 | + //PerformanceTimer perfTimer("idle/update"); // NOTE: we track this above in Application::idle() | |
| 2016 | + | |
| 1981 | 2017 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1982 | 2018 | PerformanceWarning warn(showWarnings, "Application::update()"); |
| 1983 | 2019 | |
| 1984 | 2020 | updateLOD(); |
| 1985 | − | |
| 1986 | − // check what's under the mouse and update the mouse voxel | |
| 1987 | − updateMouseRay(); | |
| 1988 | − | |
| 2021 | + updateMouseRay(); // check what's under the mouse and update the mouse voxel | |
| 1989 | 2022 | updateFaceshift(); |
| 1990 | 2023 | updateVisage(); |
| 1991 | − _myAvatar->updateLookAtTargetAvatar(); | |
| 2024 | + | |
| 2025 | + { | |
| 2026 | + PerformanceTimer perfTimer("idle/update/updateLookAtTargetAvatar"); | |
| 2027 | + _myAvatar->updateLookAtTargetAvatar(); | |
| 2028 | + } | |
| 1992 | 2029 | updateMyAvatarLookAtPosition(); |
| 1993 | − _sixenseManager.update(deltaTime); | |
| 1994 | − _joystickManager.update(); | |
| 1995 | − _prioVR.update(deltaTime); | |
| 1996 | − updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes | |
| 2030 | + { | |
| 2031 | + PerformanceTimer perfTimer("idle/update/sixense,joystick,prioVR"); | |
| 2032 | + _sixenseManager.update(deltaTime); | |
| 2033 | + _joystickManager.update(); | |
| 2034 | + _prioVR.update(deltaTime); | |
| 2035 | + } | |
| 2036 | + | |
| 2037 | + { | |
| 2038 | + PerformanceTimer perfTimer("idle/update/updateMyAvatar"); | |
| 2039 | + updateMyAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes | |
| 2040 | + } | |
| 2041 | + | |
| 1997 | 2042 | updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... |
| 1998 | − _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... | |
| 2043 | + | |
| 2044 | + { | |
| 2045 | + PerformanceTimer perfTimer("idle/update/_avatarManager"); | |
| 2046 | + _avatarManager.updateOtherAvatars(deltaTime); //loop through all the other avatars and simulate them... | |
| 2047 | + } | |
| 1999 | 2048 | updateMetavoxels(deltaTime); // update metavoxels |
| 2000 | 2049 | updateCamera(deltaTime); // handle various camera tweaks like off axis projection |
| 2001 | 2050 | updateDialogs(deltaTime); // update various stats dialogs if present |
| 2002 | 2051 | updateCursor(deltaTime); // Handle cursor updates |
| 2003 | 2052 | |
| 2004 | − _particles.update(); // update the particles... | |
| 2005 | − _particleCollisionSystem.update(); // collide the particles... | |
| 2053 | + { | |
| 2054 | + PerformanceTimer perfTimer("idle/update/_particles"); | |
| 2055 | + _particles.update(); // update the particles... | |
| 2056 | + } | |
| 2057 | + { | |
| 2058 | + PerformanceTimer perfTimer("idle/update/_particleCollisionSystem"); | |
| 2059 | + _particleCollisionSystem.update(); // collide the particles... | |
| 2060 | + } | |
| 2006 | 2061 | |
| 2007 | − _models.update(); // update the models... | |
| 2062 | + { | |
| 2063 | + PerformanceTimer perfTimer("idle/update/_models"); | |
| 2064 | + _models.update(); // update the models... | |
| 2065 | + } | |
| 2008 | 2066 | |
| 2009 | − _overlays.update(deltaTime); | |
| 2067 | + { | |
| 2068 | + PerformanceTimer perfTimer("idle/update/_overlays"); | |
| 2069 | + _overlays.update(deltaTime); | |
| 2070 | + } | |
| 2010 | 2071 | |
| 2011 | − // let external parties know we're updating | |
| 2012 | − emit simulating(deltaTime); | |
| 2072 | + { | |
| 2073 | + PerformanceTimer perfTimer("idle/update/emit simulating"); | |
| 2074 | + // let external parties know we're updating | |
| 2075 | + emit simulating(deltaTime); | |
| 2076 | + } | |
| 2013 | 2077 | } |
| 2014 | 2078 | |
| 2015 | 2079 | void Application::updateMyAvatar(float deltaTime) { |
| 2080 | + PerformanceTimer perfTimer("updateMyAvatar"); | |
| 2016 | 2081 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 2017 | 2082 | PerformanceWarning warn(showWarnings, "Application::updateMyAvatar()"); |
| 2018 | 2083 | |
| 2019 | − _myAvatar->update(deltaTime); | |
| 2020 | − | |
| 2021 | − // send head/hand data to the avatar mixer and voxel server | |
| 2022 | − QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData); | |
| 2023 | − packet.append(_myAvatar->toByteArray()); | |
| 2084 | + { | |
| 2085 | + PerformanceTimer perfTimer("updateMyAvatar/_myAvatar->update()"); | |
| 2086 | + _myAvatar->update(deltaTime); | |
| 2087 | + } | |
| 2024 | 2088 | |
| 2025 | − controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer); | |
| 2089 | + { | |
| 2090 | + // send head/hand data to the avatar mixer and voxel server | |
| 2091 | + PerformanceTimer perfTimer("updateMyAvatar/sendToAvatarMixer"); | |
| 2092 | + QByteArray packet = byteArrayWithPopulatedHeader(PacketTypeAvatarData); | |
| 2093 | + packet.append(_myAvatar->toByteArray()); | |
| 2094 | + controlledBroadcastToNodes(packet, NodeSet() << NodeType::AvatarMixer); | |
| 2095 | + } | |
| 2026 | 2096 | |
| 2027 | 2097 | // Update _viewFrustum with latest camera and view frustum data... |
| 2028 | 2098 | // NOTE: we get this from the view frustum, to make it simpler, since the |
| @@ -2030,25 +2100,121 @@ void Application::updateMyAvatar(float deltaTime) { · 1 unmodified line | ||
| 2030 | 2100 | // We could optimize this to not actually load the viewFrustum, since we don't |
| 2031 | 2101 | // actually need to calculate the view frustum planes to send these details |
| 2032 | 2102 | // to the server. |
| 2033 | − loadViewFrustum(_myCamera, _viewFrustum); | |
| 2103 | + { | |
| 2104 | + PerformanceTimer perfTimer("updateMyAvatar/loadViewFrustum"); | |
| 2105 | + loadViewFrustum(_myCamera, _viewFrustum); | |
| 2106 | + } | |
| 2034 | 2107 | |
| 2035 | 2108 | // Update my voxel servers with my current voxel query... |
| 2036 | − quint64 now = usecTimestampNow(); | |
| 2037 | − quint64 sinceLastQuery = now - _lastQueriedTime; | |
| 2038 | − const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; | |
| 2039 | − bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; | |
| 2040 | − bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); | |
| 2109 | + { | |
| 2110 | + PerformanceTimer perfTimer("updateMyAvatar/queryOctree"); | |
| 2111 | + quint64 now = usecTimestampNow(); | |
| 2112 | + quint64 sinceLastQuery = now - _lastQueriedTime; | |
| 2113 | + const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; | |
| 2114 | + bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; | |
| 2115 | + bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); | |
| 2041 | 2116 | |
| 2042 | − // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it | |
| 2043 | − if (queryIsDue || viewIsDifferentEnough) { | |
| 2044 | − _lastQueriedTime = now; | |
| 2045 | − queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); | |
| 2046 | − queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions); | |
| 2047 | − queryOctree(NodeType::ModelServer, PacketTypeModelQuery, _modelServerJurisdictions); | |
| 2048 | − _lastQueriedViewFrustum = _viewFrustum; | |
| 2117 | + // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it | |
| 2118 | + if (queryIsDue || viewIsDifferentEnough) { | |
| 2119 | + _lastQueriedTime = now; | |
| 2120 | + queryOctree(NodeType::VoxelServer, PacketTypeVoxelQuery, _voxelServerJurisdictions); | |
| 2121 | + queryOctree(NodeType::ParticleServer, PacketTypeParticleQuery, _particleServerJurisdictions); | |
| 2122 | + queryOctree(NodeType::ModelServer, PacketTypeModelQuery, _modelServerJurisdictions); | |
| 2123 | + _lastQueriedViewFrustum = _viewFrustum; | |
| 2124 | + } | |
| 2125 | + } | |
| 2126 | + | |
| 2127 | + // sent nack packets containing missing sequence numbers of received packets from nodes | |
| 2128 | + { | |
| 2129 | + quint64 now = usecTimestampNow(); | |
| 2130 | + quint64 sinceLastNack = now - _lastNackTime; | |
| 2131 | + const quint64 TOO_LONG_SINCE_LAST_NACK = 1 * USECS_PER_SECOND; | |
| 2132 | + if (sinceLastNack > TOO_LONG_SINCE_LAST_NACK) { | |
| 2133 | + _lastNackTime = now; | |
| 2134 | + sendNackPackets(); | |
| 2135 | + } | |
| 2049 | 2136 | } |
| 2050 | 2137 | } |
| 2051 | 2138 | |
| 2139 | +int Application::sendNackPackets() { | |
| 2140 | + | |
| 2141 | + if (Menu::getInstance()->isOptionChecked(MenuOption::DisableNackPackets)) { | |
| 2142 | + return 0; | |
| 2143 | + } | |
| 2144 | + | |
| 2145 | + int packetsSent = 0; | |
| 2146 | + char packet[MAX_PACKET_SIZE]; | |
| 2147 | + | |
| 2148 | + // iterates thru all nodes in NodeList | |
| 2149 | + foreach(const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { | |
| 2150 | + | |
| 2151 | + if (node->getActiveSocket() && | |
| 2152 | + ( node->getType() == NodeType::VoxelServer | |
| 2153 | + || node->getType() == NodeType::ParticleServer | |
| 2154 | + || node->getType() == NodeType::ModelServer) | |
| 2155 | + ) { | |
| 2156 | + | |
| 2157 | + QUuid nodeUUID = node->getUUID(); | |
| 2158 | + | |
| 2159 | + // if there are octree packets from this node that are waiting to be processed, | |
| 2160 | + // don't send a NACK since the missing packets may be among those waiting packets. | |
| 2161 | + if (_octreeProcessor.hasPacketsToProcessFrom(nodeUUID)) { | |
| 2162 | + continue; | |
| 2163 | + } | |
| 2164 | + | |
| 2165 | + _octreeSceneStatsLock.lockForRead(); | |
| 2166 | + | |
| 2167 | + // retreive octree scene stats of this node | |
| 2168 | + if (_octreeServerSceneStats.find(nodeUUID) == _octreeServerSceneStats.end()) { | |
| 2169 | + _octreeSceneStatsLock.unlock(); | |
| 2170 | + continue; | |
| 2171 | + } | |
| 2172 | + OctreeSceneStats& stats = _octreeServerSceneStats[nodeUUID]; | |
| 2173 | + | |
| 2174 | + // make copy of missing sequence numbers from stats | |
| 2175 | + const QSet<OCTREE_PACKET_SEQUENCE> missingSequenceNumbers = stats.getMissingSequenceNumbers(); | |
| 2176 | + | |
| 2177 | + _octreeSceneStatsLock.unlock(); | |
| 2178 | + | |
| 2179 | + // construct nack packet(s) for this node | |
| 2180 | + int numSequenceNumbersAvailable = missingSequenceNumbers.size(); | |
| 2181 | + QSet<OCTREE_PACKET_SEQUENCE>::const_iterator missingSequenceNumbersIterator = missingSequenceNumbers.constBegin(); | |
| 2182 | + while (numSequenceNumbersAvailable > 0) { | |
| 2183 | + | |
| 2184 | + char* dataAt = packet; | |
| 2185 | + int bytesRemaining = MAX_PACKET_SIZE; | |
| 2186 | + | |
| 2187 | + // pack header | |
| 2188 | + int numBytesPacketHeader = populatePacketHeader(packet, PacketTypeOctreeDataNack); | |
| 2189 | + dataAt += numBytesPacketHeader; | |
| 2190 | + bytesRemaining -= numBytesPacketHeader; | |
| 2191 | + | |
| 2192 | + // calculate and pack the number of sequence numbers | |
| 2193 | + int numSequenceNumbersRoomFor = (bytesRemaining - sizeof(uint16_t)) / sizeof(OCTREE_PACKET_SEQUENCE); | |
| 2194 | + uint16_t numSequenceNumbers = min(numSequenceNumbersAvailable, numSequenceNumbersRoomFor); | |
| 2195 | + uint16_t* numSequenceNumbersAt = (uint16_t*)dataAt; | |
| 2196 | + *numSequenceNumbersAt = numSequenceNumbers; | |
| 2197 | + dataAt += sizeof(uint16_t); | |
| 2198 | + | |
| 2199 | + // pack sequence numbers | |
| 2200 | + for (int i = 0; i < numSequenceNumbers; i++) { | |
| 2201 | + OCTREE_PACKET_SEQUENCE* sequenceNumberAt = (OCTREE_PACKET_SEQUENCE*)dataAt; | |
| 2202 | + *sequenceNumberAt = *missingSequenceNumbersIterator; | |
| 2203 | + dataAt += sizeof(OCTREE_PACKET_SEQUENCE); | |
| 2204 | + | |
| 2205 | + missingSequenceNumbersIterator++; | |
| 2206 | + } | |
| 2207 | + numSequenceNumbersAvailable -= numSequenceNumbers; | |
| 2208 | + | |
| 2209 | + // send it | |
| 2210 | + NodeList::getInstance()->writeUnverifiedDatagram(packet, dataAt - packet, node); | |
| 2211 | + packetsSent++; | |
| 2212 | + } | |
| 2213 | + } | |
| 2214 | + } | |
| 2215 | + return packetsSent; | |
| 2216 | +} | |
| 2217 | + | |
| 2052 | 2218 | void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { |
| 2053 | 2219 | |
| 2054 | 2220 | // if voxels are disabled, then don't send this at all... |
| @@ -2104,10 +2270,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node · 49 unmodified lines | ||
| 2104 | 2270 | if (rootCode) { |
| 2105 | 2271 | VoxelPositionSize rootDetails; |
| 2106 | 2272 | voxelDetailsForCode(rootCode, rootDetails); |
| 2107 | − AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); | |
| 2273 | + AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); | |
| 2108 | 2274 | serverBounds.scale(TREE_SCALE); |
| 2109 | 2275 | |
| 2110 | − ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); | |
| 2276 | + ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds); | |
| 2111 | 2277 | |
| 2112 | 2278 | if (serverFrustumLocation != ViewFrustum::OUTSIDE) { |
| 2113 | 2279 | inViewServers++; |
| @@ -2170,10 +2336,10 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node · 56 unmodified lines | ||
| 2170 | 2336 | if (rootCode) { |
| 2171 | 2337 | VoxelPositionSize rootDetails; |
| 2172 | 2338 | voxelDetailsForCode(rootCode, rootDetails); |
| 2173 | − AABox serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); | |
| 2339 | + AACube serverBounds(glm::vec3(rootDetails.x, rootDetails.y, rootDetails.z), rootDetails.s); | |
| 2174 | 2340 | serverBounds.scale(TREE_SCALE); |
| 2175 | 2341 | |
| 2176 | − ViewFrustum::location serverFrustumLocation = _viewFrustum.boxInFrustum(serverBounds); | |
| 2342 | + ViewFrustum::location serverFrustumLocation = _viewFrustum.cubeInFrustum(serverBounds); | |
| 2177 | 2343 | if (serverFrustumLocation != ViewFrustum::OUTSIDE) { |
| 2178 | 2344 | inView = true; |
| 2179 | 2345 | } else { |
| @@ -2273,88 +2439,122 @@ glm::vec3 Application::getSunDirection() { · 93 unmodified lines | ||
| 2273 | 2439 | } |
| 2274 | 2440 | |
| 2275 | 2441 | void Application::updateShadowMap() { |
| 2442 | + PerformanceTimer perfTimer("paintGL/updateShadowMap"); | |
| 2276 | 2443 | QOpenGLFramebufferObject* fbo = _textureCache.getShadowFramebufferObject(); |
| 2277 | 2444 | fbo->bind(); |
| 2278 | 2445 | glEnable(GL_DEPTH_TEST); |
| 2279 | 2446 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); |
| 2280 | 2447 | |
| 2281 | − glViewport(0, 0, fbo->width(), fbo->height()); | |
| 2282 | − | |
| 2283 | 2448 | glm::vec3 lightDirection = -getSunDirection(); |
| 2284 | 2449 | glm::quat rotation = rotationBetween(IDENTITY_FRONT, lightDirection); |
| 2285 | 2450 | glm::quat inverseRotation = glm::inverse(rotation); |
| 2286 | − float nearScale = 0.0f; | |
| 2287 | − const float MAX_SHADOW_DISTANCE = 2.0f; | |
| 2288 | − float farScale = (MAX_SHADOW_DISTANCE - _viewFrustum.getNearClip()) / | |
| 2289 | − (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); | |
| 2451 | + | |
| 2452 | + const float SHADOW_MATRIX_DISTANCES[] = { 0.0f, 2.0f, 6.0f, 14.0f, 30.0f }; | |
| 2453 | + const glm::vec2 MAP_COORDS[] = { glm::vec2(0.0f, 0.0f), glm::vec2(0.5f, 0.0f), | |
| 2454 | + glm::vec2(0.0f, 0.5f), glm::vec2(0.5f, 0.5f) }; | |
| 2455 | + | |
| 2456 | + float frustumScale = 1.0f / (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); | |
| 2290 | 2457 | loadViewFrustum(_myCamera, _viewFrustum); |
| 2291 | − glm::vec3 points[] = { | |
| 2292 | − glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), | |
| 2293 | − glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), | |
| 2294 | − glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale), | |
| 2295 | − glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale), | |
| 2296 | − glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale), | |
| 2297 | − glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale), | |
| 2298 | − glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale), | |
| 2299 | − glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) }; | |
| 2300 | − glm::vec3 center; | |
| 2301 | − for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { | |
| 2302 | − center += points[i]; | |
| 2303 | − } | |
| 2304 | − center /= (float)(sizeof(points) / sizeof(points[0])); | |
| 2305 | − float radius = 0.0f; | |
| 2306 | − for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { | |
| 2307 | − radius = qMax(radius, glm::distance(points[i], center)); | |
| 2308 | − } | |
| 2309 | − center = inverseRotation * center; | |
| 2310 | − glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); | |
| 2311 | − glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); | |
| 2312 | − | |
| 2313 | − // stretch out our extents in z so that we get all of the avatars | |
| 2314 | − minima.z -= _viewFrustum.getFarClip() * 0.5f; | |
| 2315 | − maxima.z += _viewFrustum.getFarClip() * 0.5f; | |
| 2316 | − | |
| 2317 | − // save the combined matrix for rendering | |
| 2318 | − _shadowMatrix = glm::transpose(glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * | |
| 2319 | − glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); | |
| 2320 | − | |
| 2321 | − // update the shadow view frustum | |
| 2322 | − _shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f)); | |
| 2323 | − _shadowViewFrustum.setOrientation(rotation); | |
| 2324 | − _shadowViewFrustum.setOrthographic(true); | |
| 2325 | − _shadowViewFrustum.setWidth(maxima.x - minima.x); | |
| 2326 | − _shadowViewFrustum.setHeight(maxima.y - minima.y); | |
| 2327 | − _shadowViewFrustum.setNearClip(minima.z); | |
| 2328 | − _shadowViewFrustum.setFarClip(maxima.z); | |
| 2329 | − _shadowViewFrustum.setEyeOffsetPosition(glm::vec3()); | |
| 2330 | − _shadowViewFrustum.setEyeOffsetOrientation(glm::quat()); | |
| 2331 | − _shadowViewFrustum.calculate(); | |
| 2458 | + | |
| 2459 | + int matrixCount = 1; | |
| 2460 | + int targetSize = fbo->width(); | |
| 2461 | + float targetScale = 1.0f; | |
| 2462 | + if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { | |
| 2463 | + matrixCount = CASCADED_SHADOW_MATRIX_COUNT; | |
| 2464 | + targetSize = fbo->width() / 2; | |
| 2465 | + targetScale = 0.5f; | |
| 2466 | + } | |
| 2467 | + for (int i = 0; i < matrixCount; i++) { | |
| 2468 | + const glm::vec2& coord = MAP_COORDS[i]; | |
| 2469 | + glViewport(coord.s * fbo->width(), coord.t * fbo->height(), targetSize, targetSize); | |
| 2470 | + | |
| 2471 | + float nearScale = SHADOW_MATRIX_DISTANCES[i] * frustumScale; | |
| 2472 | + float farScale = SHADOW_MATRIX_DISTANCES[i + 1] * frustumScale; | |
| 2473 | + glm::vec3 points[] = { | |
| 2474 | + glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), | |
| 2475 | + glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), | |
| 2476 | + glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale), | |
| 2477 | + glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale), | |
| 2478 | + glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale), | |
| 2479 | + glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale), | |
| 2480 | + glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale), | |
| 2481 | + glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) }; | |
| 2482 | + glm::vec3 center; | |
| 2483 | + for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) { | |
| 2484 | + center += points[j]; | |
| 2485 | + } | |
| 2486 | + center /= (float)(sizeof(points) / sizeof(points[0])); | |
| 2487 | + float radius = 0.0f; | |
| 2488 | + for (size_t j = 0; j < sizeof(points) / sizeof(points[0]); j++) { | |
| 2489 | + radius = qMax(radius, glm::distance(points[j], center)); | |
| 2490 | + } | |
| 2491 | + if (i < 3) { | |
| 2492 | + const float RADIUS_SCALE = 0.5f; | |
| 2493 | + _shadowDistances[i] = -glm::distance(_viewFrustum.getPosition(), center) - radius * RADIUS_SCALE; | |
| 2494 | + } | |
| 2495 | + center = inverseRotation * center; | |
| 2496 | + | |
| 2497 | + // to reduce texture "shimmer," move in texel increments | |
| 2498 | + float texelSize = (2.0f * radius) / targetSize; | |
| 2499 | + center = glm::vec3(roundf(center.x / texelSize) * texelSize, roundf(center.y / texelSize) * texelSize, | |
| 2500 | + roundf(center.z / texelSize) * texelSize); | |
| 2501 | + | |
| 2502 | + glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); | |
| 2503 | + glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); | |
| 2504 | + | |
| 2505 | + // stretch out our extents in z so that we get all of the avatars | |
| 2506 | + minima.z -= _viewFrustum.getFarClip() * 0.5f; | |
| 2507 | + maxima.z += _viewFrustum.getFarClip() * 0.5f; | |
| 2508 | + | |
| 2509 | + // save the combined matrix for rendering | |
| 2510 | + _shadowMatrices[i] = glm::transpose(glm::translate(glm::vec3(coord, 0.0f)) * | |
| 2511 | + glm::scale(glm::vec3(targetScale, targetScale, 1.0f)) * | |
| 2512 | + glm::translate(glm::vec3(0.5f, 0.5f, 0.5f)) * glm::scale(glm::vec3(0.5f, 0.5f, 0.5f)) * | |
| 2513 | + glm::ortho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z) * glm::mat4_cast(inverseRotation)); | |
| 2514 | + | |
| 2515 | + // update the shadow view frustum | |
| 2516 | + _shadowViewFrustum.setPosition(rotation * ((minima + maxima) * 0.5f)); | |
| 2517 | + _shadowViewFrustum.setOrientation(rotation); | |
| 2518 | + _shadowViewFrustum.setOrthographic(true); | |
| 2519 | + _shadowViewFrustum.setWidth(maxima.x - minima.x); | |
| 2520 | + _shadowViewFrustum.setHeight(maxima.y - minima.y); | |
| 2521 | + _shadowViewFrustum.setNearClip(minima.z); | |
| 2522 | + _shadowViewFrustum.setFarClip(maxima.z); | |
| 2523 | + _shadowViewFrustum.setEyeOffsetPosition(glm::vec3()); | |
| 2524 | + _shadowViewFrustum.setEyeOffsetOrientation(glm::quat()); | |
| 2525 | + _shadowViewFrustum.calculate(); | |
| 2526 | + | |
| 2527 | + glMatrixMode(GL_PROJECTION); | |
| 2528 | + glPushMatrix(); | |
| 2529 | + glLoadIdentity(); | |
| 2530 | + glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); | |
| 2332 | 2531 | |
| 2333 | − glMatrixMode(GL_PROJECTION); | |
| 2334 | − glPushMatrix(); | |
| 2335 | − glLoadIdentity(); | |
| 2336 | − glOrtho(minima.x, maxima.x, minima.y, maxima.y, -maxima.z, -minima.z); | |
| 2532 | + glMatrixMode(GL_MODELVIEW); | |
| 2533 | + glPushMatrix(); | |
| 2534 | + glLoadIdentity(); | |
| 2535 | + glm::vec3 axis = glm::axis(inverseRotation); | |
| 2536 | + glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); | |
| 2337 | 2537 | |
| 2338 | − glMatrixMode(GL_MODELVIEW); | |
| 2339 | − glPushMatrix(); | |
| 2340 | − glLoadIdentity(); | |
| 2341 | − glm::vec3 axis = glm::axis(inverseRotation); | |
| 2342 | − glRotatef(glm::degrees(glm::angle(inverseRotation)), axis.x, axis.y, axis.z); | |
| 2538 | + // store view matrix without translation, which we'll use for precision-sensitive objects | |
| 2539 | + updateUntranslatedViewMatrix(); | |
| 2343 | 2540 | |
| 2344 | − // store view matrix without translation, which we'll use for precision-sensitive objects | |
| 2345 | − updateUntranslatedViewMatrix(); | |
| 2541 | + glEnable(GL_POLYGON_OFFSET_FILL); | |
| 2542 | + glPolygonOffset(1.1f, 4.0f); // magic numbers courtesy http://www.eecs.berkeley.edu/~ravir/6160/papers/shadowmaps.ppt | |
| 2346 | 2543 | |
| 2347 | − _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); | |
| 2348 | − _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); | |
| 2349 | − _models.render(OctreeRenderer::SHADOW_RENDER_MODE); | |
| 2544 | + _avatarManager.renderAvatars(Avatar::SHADOW_RENDER_MODE); | |
| 2545 | + _particles.render(OctreeRenderer::SHADOW_RENDER_MODE); | |
| 2546 | + _models.render(OctreeRenderer::SHADOW_RENDER_MODE); | |
| 2350 | 2547 | |
| 2351 | − glPopMatrix(); | |
| 2548 | + glDisable(GL_POLYGON_OFFSET_FILL); | |
| 2352 | 2549 | |
| 2353 | − glMatrixMode(GL_PROJECTION); | |
| 2354 | − glPopMatrix(); | |
| 2550 | + glPopMatrix(); | |
| 2355 | 2551 | |
| 2356 | − glMatrixMode(GL_MODELVIEW); | |
| 2552 | + glMatrixMode(GL_PROJECTION); | |
| 2553 | + glPopMatrix(); | |
| 2357 | 2554 | |
| 2555 | + glMatrixMode(GL_MODELVIEW); | |
| 2556 | + } | |
| 2557 | + | |
| 2358 | 2558 | fbo->release(); |
| 2359 | 2559 | |
| 2360 | 2560 | glViewport(0, 0, _glWidget->width(), _glWidget->height()); |
| @@ -2401,6 +2601,7 @@ QImage Application::renderAvatarBillboard() { · 40 unmodified lines | ||
| 2401 | 2601 | } |
| 2402 | 2602 | |
| 2403 | 2603 | void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { |
| 2604 | + PerformanceTimer perfTimer("paintGL/displaySide"); | |
| 2404 | 2605 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()"); |
| 2405 | 2606 | // transform by eye offset |
| 2406 | 2607 | |
| @@ -2433,9 +2634,27 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 26 unmodified lines | ||
| 2433 | 2634 | glTranslatef(_viewMatrixTranslation.x, _viewMatrixTranslation.y, _viewMatrixTranslation.z); |
| 2434 | 2635 | |
| 2435 | 2636 | // Setup 3D lights (after the camera transform, so that they are positioned in world space) |
| 2436 | − setupWorldLight(); | |
| 2637 | + { | |
| 2638 | + PerformanceTimer perfTimer("paintGL/displaySide/setupWorldLight"); | |
| 2639 | + setupWorldLight(); | |
| 2640 | + } | |
| 2641 | + | |
| 2642 | + // setup shadow matrices (again, after the camera transform) | |
| 2643 | + int shadowMatrixCount = 0; | |
| 2644 | + if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) { | |
| 2645 | + shadowMatrixCount = 1; | |
| 2646 | + } else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { | |
| 2647 | + shadowMatrixCount = CASCADED_SHADOW_MATRIX_COUNT; | |
| 2648 | + } | |
| 2649 | + for (int i = shadowMatrixCount - 1; i >= 0; i--) { | |
| 2650 | + glActiveTexture(GL_TEXTURE0 + i); | |
| 2651 | + glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][0]); | |
| 2652 | + glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][1]); | |
| 2653 | + glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&_shadowMatrices[i][2]); | |
| 2654 | + } | |
| 2437 | 2655 | |
| 2438 | 2656 | if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Stars)) { |
| 2657 | + PerformanceTimer perfTimer("paintGL/displaySide/stars"); | |
| 2439 | 2658 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2440 | 2659 | "Application::displaySide() ... stars..."); |
| 2441 | 2660 | if (!_stars.isStarsLoaded()) { |
| @@ -2464,6 +2683,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 22 unmodified lines | ||
| 2464 | 2683 | |
| 2465 | 2684 | // draw the sky dome |
| 2466 | 2685 | if (!selfAvatarOnly && Menu::getInstance()->isOptionChecked(MenuOption::Atmosphere)) { |
| 2686 | + PerformanceTimer perfTimer("paintGL/displaySide/atmosphere"); | |
| 2467 | 2687 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2468 | 2688 | "Application::displaySide() ... atmosphere..."); |
| 2469 | 2689 | _environment.renderAtmospheres(whichCamera); |
| @@ -2483,10 +2703,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 13 unmodified lines | ||
| 2483 | 2703 | glMaterialfv(GL_FRONT, GL_SPECULAR, NO_SPECULAR_COLOR); |
| 2484 | 2704 | |
| 2485 | 2705 | // draw the audio reflector overlay |
| 2486 | − _audioReflector.render(); | |
| 2487 | − | |
| 2706 | + { | |
| 2707 | + PerformanceTimer perfTimer("paintGL/displaySide/audioReflector"); | |
| 2708 | + _audioReflector.render(); | |
| 2709 | + } | |
| 2710 | + | |
| 2488 | 2711 | // Draw voxels |
| 2489 | 2712 | if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { |
| 2713 | + PerformanceTimer perfTimer("paintGL/displaySide/voxels"); | |
| 2490 | 2714 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2491 | 2715 | "Application::displaySide() ... voxels..."); |
| 2492 | 2716 | _voxels.render(); |
| @@ -2494,12 +2718,14 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 1 unmodified line | ||
| 2494 | 2718 | |
| 2495 | 2719 | // also, metavoxels |
| 2496 | 2720 | if (Menu::getInstance()->isOptionChecked(MenuOption::Metavoxels)) { |
| 2721 | + PerformanceTimer perfTimer("paintGL/displaySide/metavoxels"); | |
| 2497 | 2722 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2498 | 2723 | "Application::displaySide() ... metavoxels..."); |
| 2499 | 2724 | _metavoxels.render(); |
| 2500 | 2725 | } |
| 2501 | 2726 | |
| 2502 | 2727 | if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) { |
| 2728 | + PerformanceTimer perfTimer("paintGL/displaySide/buckyBalls"); | |
| 2503 | 2729 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2504 | 2730 | "Application::displaySide() ... bucky balls..."); |
| 2505 | 2731 | _buckyBalls.render(); |
| @@ -2507,6 +2733,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 1 unmodified line | ||
| 2507 | 2733 | |
| 2508 | 2734 | // render particles... |
| 2509 | 2735 | if (Menu::getInstance()->isOptionChecked(MenuOption::Particles)) { |
| 2736 | + PerformanceTimer perfTimer("paintGL/displaySide/particles"); | |
| 2510 | 2737 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2511 | 2738 | "Application::displaySide() ... particles..."); |
| 2512 | 2739 | _particles.render(); |
| @@ -2514,6 +2741,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 1 unmodified line | ||
| 2514 | 2741 | |
| 2515 | 2742 | // render models... |
| 2516 | 2743 | if (Menu::getInstance()->isOptionChecked(MenuOption::Models)) { |
| 2744 | + PerformanceTimer perfTimer("paintGL/displaySide/models"); | |
| 2517 | 2745 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2518 | 2746 | "Application::displaySide() ... models..."); |
| 2519 | 2747 | _models.render(); |
| @@ -2521,6 +2749,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 1 unmodified line | ||
| 2521 | 2749 | |
| 2522 | 2750 | // render the ambient occlusion effect if enabled |
| 2523 | 2751 | if (Menu::getInstance()->isOptionChecked(MenuOption::AmbientOcclusion)) { |
| 2752 | + PerformanceTimer perfTimer("paintGL/displaySide/AmbientOcclusion"); | |
| 2524 | 2753 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2525 | 2754 | "Application::displaySide() ... AmbientOcclusion..."); |
| 2526 | 2755 | _ambientOcclusionEffect.render(); |
| @@ -2534,16 +2763,21 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 7 unmodified lines | ||
| 2534 | 2763 | } |
| 2535 | 2764 | |
| 2536 | 2765 | bool mirrorMode = (whichCamera.getInterpolatedMode() == CAMERA_MODE_MIRROR); |
| 2537 | − _avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly); | |
| 2766 | + { | |
| 2767 | + PerformanceTimer perfTimer("paintGL/displaySide/renderAvatars"); | |
| 2768 | + _avatarManager.renderAvatars(mirrorMode ? Avatar::MIRROR_RENDER_MODE : Avatar::NORMAL_RENDER_MODE, selfAvatarOnly); | |
| 2769 | + } | |
| 2538 | 2770 | |
| 2539 | 2771 | if (!selfAvatarOnly) { |
| 2540 | 2772 | // Render the world box |
| 2541 | 2773 | if (whichCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { |
| 2774 | + PerformanceTimer perfTimer("paintGL/displaySide/renderWorldBox"); | |
| 2542 | 2775 | renderWorldBox(); |
| 2543 | 2776 | } |
| 2544 | 2777 | |
| 2545 | − // brad's frustum for debugging | |
| 2778 | + // view frustum for debugging | |
| 2546 | 2779 | if (Menu::getInstance()->isOptionChecked(MenuOption::DisplayFrustum) && whichCamera.getMode() != CAMERA_MODE_MIRROR) { |
| 2780 | + PerformanceTimer perfTimer("paintGL/displaySide/ViewFrustum"); | |
| 2547 | 2781 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2548 | 2782 | "Application::displaySide() ... renderViewFrustum..."); |
| 2549 | 2783 | renderViewFrustum(_viewFrustum); |
| @@ -2551,8 +2785,10 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 1 unmodified line | ||
| 2551 | 2785 | |
| 2552 | 2786 | // render voxel fades if they exist |
| 2553 | 2787 | if (_voxelFades.size() > 0) { |
| 2788 | + PerformanceTimer perfTimer("paintGL/displaySide/voxel fades"); | |
| 2554 | 2789 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2555 | 2790 | "Application::displaySide() ... voxel fades..."); |
| 2791 | + _voxelFadesLock.lockForWrite(); | |
| 2556 | 2792 | for(std::vector<VoxelFade>::iterator fade = _voxelFades.begin(); fade != _voxelFades.end();) { |
| 2557 | 2793 | fade->render(); |
| 2558 | 2794 | if(fade->isDone()) { |
| @@ -2561,13 +2797,20 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { · 2 unmodified lines | ||
| 2561 | 2797 | ++fade; |
| 2562 | 2798 | } |
| 2563 | 2799 | } |
| 2800 | + _voxelFadesLock.unlock(); | |
| 2564 | 2801 | } |
| 2565 | 2802 | |
| 2566 | 2803 | // give external parties a change to hook in |
| 2567 | − emit renderingInWorldInterface(); | |
| 2804 | + { | |
| 2805 | + PerformanceTimer perfTimer("paintGL/displaySide/inWorldInterface"); | |
| 2806 | + emit renderingInWorldInterface(); | |
| 2807 | + } | |
| 2568 | 2808 | |
| 2569 | 2809 | // render JS/scriptable overlays |
| 2570 | − _overlays.render3D(); | |
| 2810 | + { | |
| 2811 | + PerformanceTimer perfTimer("paintGL/displaySide/3dOverlays"); | |
| 2812 | + _overlays.render3D(); | |
| 2813 | + } | |
| 2571 | 2814 | } |
| 2572 | 2815 | } |
| 2573 | 2816 | |
| @@ -2597,183 +2840,6 @@ void Application::computeOffAxisFrustum(float& left, float& right, float& bottom · 23 unmodified lines | ||
| 2597 | 2840 | _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); |
| 2598 | 2841 | } |
| 2599 | 2842 | |
| 2600 | −const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; | |
| 2601 | − | |
| 2602 | −void Application::displayOverlay() { | |
| 2603 | − PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displayOverlay()"); | |
| 2604 | − | |
| 2605 | − // Render 2D overlay: I/O level bar graphs and text | |
| 2606 | − glMatrixMode(GL_PROJECTION); | |
| 2607 | − glPushMatrix(); | |
| 2608 | − | |
| 2609 | − glLoadIdentity(); | |
| 2610 | − gluOrtho2D(0, _glWidget->width(), _glWidget->height(), 0); | |
| 2611 | − glDisable(GL_DEPTH_TEST); | |
| 2612 | − glDisable(GL_LIGHTING); | |
| 2613 | − | |
| 2614 | − // Display a single screen-size quad to create an alpha blended 'collision' flash | |
| 2615 | − if (_audio.getCollisionFlashesScreen()) { | |
| 2616 | − float collisionSoundMagnitude = _audio.getCollisionSoundMagnitude(); | |
| 2617 | − const float VISIBLE_COLLISION_SOUND_MAGNITUDE = 0.5f; | |
| 2618 | − if (collisionSoundMagnitude > VISIBLE_COLLISION_SOUND_MAGNITUDE) { | |
| 2619 | − renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude()); | |
| 2620 | − } | |
| 2621 | − } | |
| 2622 | − | |
| 2623 | − // Audio VU Meter and Mute Icon | |
| 2624 | − const int MUTE_ICON_SIZE = 24; | |
| 2625 | − const int AUDIO_METER_INSET = 2; | |
| 2626 | − const int MUTE_ICON_PADDING = 10; | |
| 2627 | − const int AUDIO_METER_WIDTH = MIRROR_VIEW_WIDTH - MUTE_ICON_SIZE - AUDIO_METER_INSET - MUTE_ICON_PADDING; | |
| 2628 | − const int AUDIO_METER_SCALE_WIDTH = AUDIO_METER_WIDTH - 2 * AUDIO_METER_INSET; | |
| 2629 | − const int AUDIO_METER_HEIGHT = 8; | |
| 2630 | − const int AUDIO_METER_GAP = 5; | |
| 2631 | − const int AUDIO_METER_X = MIRROR_VIEW_LEFT_PADDING + MUTE_ICON_SIZE + AUDIO_METER_INSET + AUDIO_METER_GAP; | |
| 2632 | − | |
| 2633 | − int audioMeterY; | |
| 2634 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | |
| 2635 | − audioMeterY = MIRROR_VIEW_HEIGHT + AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 2636 | − } else { | |
| 2637 | − audioMeterY = AUDIO_METER_GAP + MUTE_ICON_PADDING; | |
| 2638 | − } | |
| 2639 | − | |
| 2640 | − const float AUDIO_METER_BLUE[] = {0.0, 0.0, 1.0}; | |
| 2641 | − const float AUDIO_METER_GREEN[] = {0.0, 1.0, 0.0}; | |
| 2642 | − const float AUDIO_METER_RED[] = {1.0, 0.0, 0.0}; | |
| 2643 | − const float AUDIO_GREEN_START = 0.25 * AUDIO_METER_SCALE_WIDTH; | |
| 2644 | − const float AUDIO_RED_START = 0.80 * AUDIO_METER_SCALE_WIDTH; | |
| 2645 | − const float CLIPPING_INDICATOR_TIME = 1.0f; | |
| 2646 | − const float AUDIO_METER_AVERAGING = 0.5; | |
| 2647 | − const float LOG2 = log(2.f); | |
| 2648 | − const float METER_LOUDNESS_SCALE = 2.8f / 5.f; | |
| 2649 | − const float LOG2_LOUDNESS_FLOOR = 11.f; | |
| 2650 | − float audioLevel = 0.f; | |
| 2651 | − float loudness = _audio.getLastInputLoudness() + 1.f; | |
| 2652 | − | |
| 2653 | − _trailingAudioLoudness = AUDIO_METER_AVERAGING * _trailingAudioLoudness + (1.f - AUDIO_METER_AVERAGING) * loudness; | |
| 2654 | − float log2loudness = log(_trailingAudioLoudness) / LOG2; | |
| 2655 | − | |
| 2656 | − if (log2loudness <= LOG2_LOUDNESS_FLOOR) { | |
| 2657 | − audioLevel = (log2loudness / LOG2_LOUDNESS_FLOOR) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH; | |
| 2658 | − } else { | |
| 2659 | − audioLevel = (log2loudness - (LOG2_LOUDNESS_FLOOR - 1.f)) * METER_LOUDNESS_SCALE * AUDIO_METER_SCALE_WIDTH; | |
| 2660 | − } | |
| 2661 | − if (audioLevel > AUDIO_METER_SCALE_WIDTH) { | |
| 2662 | − audioLevel = AUDIO_METER_SCALE_WIDTH; | |
| 2663 | − } | |
| 2664 | − bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)); | |
| 2665 | − | |
| 2666 | − if ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) { | |
| 2667 | − const float MAX_MAGNITUDE = 0.7f; | |
| 2668 | − float magnitude = MAX_MAGNITUDE * (1 - _audio.getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME); | |
| 2669 | − renderCollisionOverlay(_glWidget->width(), _glWidget->height(), magnitude, 1.0f); | |
| 2670 | − } | |
| 2671 | − | |
| 2672 | − _audio.renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, | |
| 2673 | − audioMeterY, | |
| 2674 | − Menu::getInstance()->isOptionChecked(MenuOption::Mirror)); | |
| 2675 | − | |
| 2676 | − _audio.renderScope(_glWidget->width(), _glWidget->height()); | |
| 2677 | − | |
| 2678 | − glBegin(GL_QUADS); | |
| 2679 | − if (isClipping) { | |
| 2680 | − glColor3f(1, 0, 0); | |
| 2681 | − } else { | |
| 2682 | − glColor3f(0.475f, 0.475f, 0.475f); | |
| 2683 | − } | |
| 2684 | − | |
| 2685 | − audioMeterY += AUDIO_METER_HEIGHT; | |
| 2686 | − | |
| 2687 | − glColor3f(0, 0, 0); | |
| 2688 | − // Draw audio meter background Quad | |
| 2689 | − glVertex2i(AUDIO_METER_X, audioMeterY); | |
| 2690 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY); | |
| 2691 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_WIDTH, audioMeterY + AUDIO_METER_HEIGHT); | |
| 2692 | − glVertex2i(AUDIO_METER_X, audioMeterY + AUDIO_METER_HEIGHT); | |
| 2693 | − | |
| 2694 | − | |
| 2695 | − if (audioLevel > AUDIO_RED_START) { | |
| 2696 | − if (!isClipping) { | |
| 2697 | − glColor3fv(AUDIO_METER_RED); | |
| 2698 | − } else { | |
| 2699 | − glColor3f(1, 1, 1); | |
| 2700 | − } | |
| 2701 | − // Draw Red Quad | |
| 2702 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_INSET); | |
| 2703 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET); | |
| 2704 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); | |
| 2705 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_RED_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); | |
| 2706 | − audioLevel = AUDIO_RED_START; | |
| 2707 | − } | |
| 2708 | − if (audioLevel > AUDIO_GREEN_START) { | |
| 2709 | − if (!isClipping) { | |
| 2710 | − glColor3fv(AUDIO_METER_GREEN); | |
| 2711 | − } else { | |
| 2712 | − glColor3f(1, 1, 1); | |
| 2713 | − } | |
| 2714 | − // Draw Green Quad | |
| 2715 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_INSET); | |
| 2716 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET); | |
| 2717 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); | |
| 2718 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + AUDIO_GREEN_START, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); | |
| 2719 | − audioLevel = AUDIO_GREEN_START; | |
| 2720 | − } | |
| 2721 | − // Draw Blue Quad | |
| 2722 | − if (!isClipping) { | |
| 2723 | − glColor3fv(AUDIO_METER_BLUE); | |
| 2724 | − } else { | |
| 2725 | − glColor3f(1, 1, 1); | |
| 2726 | − } | |
| 2727 | − // Draw Blue (low level) quad | |
| 2728 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_INSET); | |
| 2729 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_INSET); | |
| 2730 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET + audioLevel, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); | |
| 2731 | − glVertex2i(AUDIO_METER_X + AUDIO_METER_INSET, audioMeterY + AUDIO_METER_HEIGHT - AUDIO_METER_INSET); | |
| 2732 | − glEnd(); | |
| 2733 | − | |
| 2734 | − | |
| 2735 | − if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { | |
| 2736 | − _myAvatar->renderHeadMouse(_glWidget->width(), _glWidget->height()); | |
| 2737 | − } | |
| 2738 | − | |
| 2739 | − // Display stats and log text onscreen | |
| 2740 | − glLineWidth(1.0f); | |
| 2741 | − glPointSize(1.0f); | |
| 2742 | − | |
| 2743 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { | |
| 2744 | − // let's set horizontal offset to give stats some margin to mirror | |
| 2745 | − int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2; | |
| 2746 | − int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); | |
| 2747 | − // Onscreen text about position, servers, etc | |
| 2748 | − Stats::getInstance()->display(WHITE_TEXT, horizontalOffset, _fps, _packetsPerSecond, _bytesPerSecond, voxelPacketsToProcess); | |
| 2749 | − // Bandwidth meter | |
| 2750 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) { | |
| 2751 | − Stats::drawBackground(0x33333399, _glWidget->width() - 296, _glWidget->height() - 68, 296, 68); | |
| 2752 | − _bandwidthMeter.render(_glWidget->width(), _glWidget->height()); | |
| 2753 | − } | |
| 2754 | − } | |
| 2755 | − | |
| 2756 | − // Show on-screen msec timer | |
| 2757 | − if (Menu::getInstance()->isOptionChecked(MenuOption::FrameTimer)) { | |
| 2758 | − char frameTimer[10]; | |
| 2759 | − quint64 mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5); | |
| 2760 | − sprintf(frameTimer, "%d\n", (int)(mSecsNow % 1000)); | |
| 2761 | − int timerBottom = | |
| 2762 | − (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && | |
| 2763 | − Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) | |
| 2764 | − ? 80 : 20; | |
| 2765 | − drawText(_glWidget->width() - 100, _glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT); | |
| 2766 | − } | |
| 2767 | − _nodeBoundsDisplay.drawOverlay(); | |
| 2768 | − | |
| 2769 | − // give external parties a change to hook in | |
| 2770 | − emit renderingOverlay(); | |
| 2771 | − | |
| 2772 | − _overlays.render2D(); | |
| 2773 | − | |
| 2774 | − glPopMatrix(); | |
| 2775 | −} | |
| 2776 | − | |
| 2777 | 2843 | glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { |
| 2778 | 2844 | float horizontalScale = _glWidget->width() / 2.0f; |
| 2779 | 2845 | float verticalScale = _glWidget->height() / 2.0f; |
| @@ -2845,16 +2911,19 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { · 65 unmodified lines | ||
| 2845 | 2911 | glm::vec3 absoluteSkeletonTranslation = _myAvatar->getSkeletonModel().getTranslation(); |
| 2846 | 2912 | glm::vec3 absoluteFaceTranslation = _myAvatar->getHead()->getFaceModel().getTranslation(); |
| 2847 | 2913 | |
| 2848 | − // get the eye positions relative to the neck and use them to set the face translation | |
| 2849 | − glm::vec3 leftEyePosition, rightEyePosition; | |
| 2850 | − _myAvatar->getHead()->getFaceModel().setTranslation(glm::vec3()); | |
| 2851 | − _myAvatar->getHead()->getFaceModel().getEyePositions(leftEyePosition, rightEyePosition); | |
| 2852 | − _myAvatar->getHead()->getFaceModel().setTranslation((leftEyePosition + rightEyePosition) * -0.5f); | |
| 2853 | − | |
| 2854 | − // get the neck position relative to the body and use it to set the skeleton translation | |
| 2914 | + // get the neck position so we can translate the face relative to it | |
| 2855 | 2915 | glm::vec3 neckPosition; |
| 2856 | 2916 | _myAvatar->getSkeletonModel().setTranslation(glm::vec3()); |
| 2857 | 2917 | _myAvatar->getSkeletonModel().getNeckPosition(neckPosition); |
| 2918 | + | |
| 2919 | + // get the eye position relative to the body | |
| 2920 | + glm::vec3 eyePosition = _myAvatar->getHead()->calculateAverageEyePosition(); | |
| 2921 | + float eyeHeight = eyePosition.y - _myAvatar->getPosition().y; | |
| 2922 | + | |
| 2923 | + // set the translation of the face relative to the neck position | |
| 2924 | + _myAvatar->getHead()->getFaceModel().setTranslation(neckPosition - glm::vec3(0, eyeHeight, 0)); | |
| 2925 | + | |
| 2926 | + // translate the neck relative to the face | |
| 2858 | 2927 | _myAvatar->getSkeletonModel().setTranslation(_myAvatar->getHead()->getFaceModel().getTranslation() - |
| 2859 | 2928 | neckPosition); |
| 2860 | 2929 | |
| @@ -3122,6 +3191,17 @@ void Application::updateWindowTitle(){ · 261 unmodified lines | ||
| 3122 | 3191 | QString username = AccountManager::getInstance().getAccountInfo().getUsername(); |
| 3123 | 3192 | QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) |
| 3124 | 3193 | + nodeList->getDomainHandler().getHostname() + buildVersion; |
| 3194 | + | |
| 3195 | + AccountManager& accountManager = AccountManager::getInstance(); | |
| 3196 | + if (accountManager.getAccountInfo().hasBalance()) { | |
| 3197 | + float creditBalance = accountManager.getAccountInfo().getBalance() / SATOSHIS_PER_CREDIT; | |
| 3198 | + | |
| 3199 | + QString creditBalanceString; | |
| 3200 | + creditBalanceString.sprintf("%.8f", creditBalance); | |
| 3201 | + | |
| 3202 | + title += " - ₵" + creditBalanceString; | |
| 3203 | + } | |
| 3204 | + | |
| 3125 | 3205 | qDebug("Application title set to: %s", title.toStdString().c_str()); |
| 3126 | 3206 | _window->setWindowTitle(title); |
| 3127 | 3207 | } |
| @@ -3161,9 +3241,15 @@ void Application::domainChanged(const QString& domainHostname) { · 33 unmodified lines | ||
| 3161 | 3241 | _environment.resetToDefault(); |
| 3162 | 3242 | |
| 3163 | 3243 | // reset our node to stats and node to jurisdiction maps... since these must be changing... |
| 3244 | + _voxelServerJurisdictions.lockForWrite(); | |
| 3164 | 3245 | _voxelServerJurisdictions.clear(); |
| 3246 | + _voxelServerJurisdictions.unlock(); | |
| 3247 | + | |
| 3165 | 3248 | _octreeServerSceneStats.clear(); |
| 3249 | + | |
| 3250 | + _particleServerJurisdictions.lockForWrite(); | |
| 3166 | 3251 | _particleServerJurisdictions.clear(); |
| 3252 | + _particleServerJurisdictions.unlock(); | |
| 3167 | 3253 | |
| 3168 | 3254 | // reset the particle renderer |
| 3169 | 3255 | _particles.clear(); |
| @@ -3199,13 +3285,26 @@ void Application::nodeAdded(SharedNodePointer node) { · 29 unmodified lines | ||
| 3199 | 3285 | } |
| 3200 | 3286 | |
| 3201 | 3287 | void Application::nodeKilled(SharedNodePointer node) { |
| 3288 | + | |
| 3289 | + // These are here because connecting NodeList::nodeKilled to OctreePacketProcessor::nodeKilled doesn't work: | |
| 3290 | + // OctreePacketProcessor::nodeKilled is not being called when NodeList::nodeKilled is emitted. | |
| 3291 | + // This may have to do with GenericThread::threadRoutine() blocking the QThread event loop | |
| 3292 | + | |
| 3293 | + _octreeProcessor.nodeKilled(node); | |
| 3294 | + | |
| 3295 | + _voxelEditSender.nodeKilled(node); | |
| 3296 | + _particleEditSender.nodeKilled(node); | |
| 3297 | + _modelEditSender.nodeKilled(node); | |
| 3298 | + | |
| 3202 | 3299 | if (node->getType() == NodeType::VoxelServer) { |
| 3203 | 3300 | QUuid nodeUUID = node->getUUID(); |
| 3204 | 3301 | // see if this is the first we've heard of this node... |
| 3302 | + _voxelServerJurisdictions.lockForRead(); | |
| 3205 | 3303 | if (_voxelServerJurisdictions.find(nodeUUID) != _voxelServerJurisdictions.end()) { |
| 3206 | 3304 | unsigned char* rootCode = _voxelServerJurisdictions[nodeUUID].getRootOctalCode(); |
| 3207 | 3305 | VoxelPositionSize rootDetails; |
| 3208 | 3306 | voxelDetailsForCode(rootCode, rootDetails); |
| 3307 | + _voxelServerJurisdictions.unlock(); | |
| 3209 | 3308 | |
| 3210 | 3309 | qDebug("voxel server going away...... v[%f, %f, %f, %f]", |
| 3211 | 3310 | rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); |
| @@ -3216,12 +3315,16 @@ void Application::nodeKilled(SharedNodePointer node) { · 4 unmodified lines | ||
| 3216 | 3315 | fade.voxelDetails = rootDetails; |
| 3217 | 3316 | const float slightly_smaller = 0.99f; |
| 3218 | 3317 | fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; |
| 3318 | + _voxelFadesLock.lockForWrite(); | |
| 3219 | 3319 | _voxelFades.push_back(fade); |
| 3320 | + _voxelFadesLock.unlock(); | |
| 3220 | 3321 | } |
| 3221 | 3322 | |
| 3222 | 3323 | // If the voxel server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server |
| 3324 | + _voxelServerJurisdictions.lockForWrite(); | |
| 3223 | 3325 | _voxelServerJurisdictions.erase(_voxelServerJurisdictions.find(nodeUUID)); |
| 3224 | 3326 | } |
| 3327 | + _voxelServerJurisdictions.unlock(); | |
| 3225 | 3328 | |
| 3226 | 3329 | // also clean up scene stats for that server |
| 3227 | 3330 | _octreeSceneStatsLock.lockForWrite(); |
| @@ -3233,10 +3336,12 @@ void Application::nodeKilled(SharedNodePointer node) { · 5 unmodified lines | ||
| 3233 | 3336 | } else if (node->getType() == NodeType::ParticleServer) { |
| 3234 | 3337 | QUuid nodeUUID = node->getUUID(); |
| 3235 | 3338 | // see if this is the first we've heard of this node... |
| 3339 | + _particleServerJurisdictions.lockForRead(); | |
| 3236 | 3340 | if (_particleServerJurisdictions.find(nodeUUID) != _particleServerJurisdictions.end()) { |
| 3237 | 3341 | unsigned char* rootCode = _particleServerJurisdictions[nodeUUID].getRootOctalCode(); |
| 3238 | 3342 | VoxelPositionSize rootDetails; |
| 3239 | 3343 | voxelDetailsForCode(rootCode, rootDetails); |
| 3344 | + _particleServerJurisdictions.unlock(); | |
| 3240 | 3345 | |
| 3241 | 3346 | qDebug("particle server going away...... v[%f, %f, %f, %f]", |
| 3242 | 3347 | rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); |
| @@ -3247,12 +3352,16 @@ void Application::nodeKilled(SharedNodePointer node) { · 4 unmodified lines | ||
| 3247 | 3352 | fade.voxelDetails = rootDetails; |
| 3248 | 3353 | const float slightly_smaller = 0.99f; |
| 3249 | 3354 | fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; |
| 3355 | + _voxelFadesLock.lockForWrite(); | |
| 3250 | 3356 | _voxelFades.push_back(fade); |
| 3357 | + _voxelFadesLock.unlock(); | |
| 3251 | 3358 | } |
| 3252 | 3359 | |
| 3253 | 3360 | // If the particle server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server |
| 3361 | + _particleServerJurisdictions.lockForWrite(); | |
| 3254 | 3362 | _particleServerJurisdictions.erase(_particleServerJurisdictions.find(nodeUUID)); |
| 3255 | 3363 | } |
| 3364 | + _particleServerJurisdictions.unlock(); | |
| 3256 | 3365 | |
| 3257 | 3366 | // also clean up scene stats for that server |
| 3258 | 3367 | _octreeSceneStatsLock.lockForWrite(); |
| @@ -3265,10 +3374,12 @@ void Application::nodeKilled(SharedNodePointer node) { · 6 unmodified lines | ||
| 3265 | 3374 | |
| 3266 | 3375 | QUuid nodeUUID = node->getUUID(); |
| 3267 | 3376 | // see if this is the first we've heard of this node... |
| 3377 | + _modelServerJurisdictions.lockForRead(); | |
| 3268 | 3378 | if (_modelServerJurisdictions.find(nodeUUID) != _modelServerJurisdictions.end()) { |
| 3269 | 3379 | unsigned char* rootCode = _modelServerJurisdictions[nodeUUID].getRootOctalCode(); |
| 3270 | 3380 | VoxelPositionSize rootDetails; |
| 3271 | 3381 | voxelDetailsForCode(rootCode, rootDetails); |
| 3382 | + _modelServerJurisdictions.unlock(); | |
| 3272 | 3383 | |
| 3273 | 3384 | qDebug("model server going away...... v[%f, %f, %f, %f]", |
| 3274 | 3385 | rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); |
| @@ -3279,12 +3390,16 @@ void Application::nodeKilled(SharedNodePointer node) { · 4 unmodified lines | ||
| 3279 | 3390 | fade.voxelDetails = rootDetails; |
| 3280 | 3391 | const float slightly_smaller = 0.99f; |
| 3281 | 3392 | fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; |
| 3393 | + _voxelFadesLock.lockForWrite(); | |
| 3282 | 3394 | _voxelFades.push_back(fade); |
| 3395 | + _voxelFadesLock.unlock(); | |
| 3283 | 3396 | } |
| 3284 | 3397 | |
| 3285 | 3398 | // If the model server is going away, remove it from our jurisdiction map so we don't send voxels to a dead server |
| 3399 | + _modelServerJurisdictions.lockForWrite(); | |
| 3286 | 3400 | _modelServerJurisdictions.erase(_modelServerJurisdictions.find(nodeUUID)); |
| 3287 | 3401 | } |
| 3402 | + _modelServerJurisdictions.unlock(); | |
| 3288 | 3403 | |
| 3289 | 3404 | // also clean up scene stats for that server |
| 3290 | 3405 | _octreeSceneStatsLock.lockForWrite(); |
| @@ -3354,7 +3469,10 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 63 unmodified lines | ||
| 3354 | 3469 | serverType = "Model"; |
| 3355 | 3470 | } |
| 3356 | 3471 | |
| 3472 | + jurisdiction->lockForRead(); | |
| 3357 | 3473 | if (jurisdiction->find(nodeUUID) == jurisdiction->end()) { |
| 3474 | + jurisdiction->unlock(); | |
| 3475 | + | |
| 3358 | 3476 | qDebug("stats from new %s server... [%f, %f, %f, %f]", |
| 3359 | 3477 | qPrintable(serverType), rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s); |
| 3360 | 3478 | |
| @@ -3364,8 +3482,12 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 3 unmodified lines | ||
| 3364 | 3482 | fade.voxelDetails = rootDetails; |
| 3365 | 3483 | const float slightly_smaller = 0.99f; |
| 3366 | 3484 | fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller; |
| 3485 | + _voxelFadesLock.lockForWrite(); | |
| 3367 | 3486 | _voxelFades.push_back(fade); |
| 3487 | + _voxelFadesLock.unlock(); | |
| 3368 | 3488 | } |
| 3489 | + } else { | |
| 3490 | + jurisdiction->unlock(); | |
| 3369 | 3491 | } |
| 3370 | 3492 | // store jurisdiction details for later use |
| 3371 | 3493 | // This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it |
| @@ -3373,7 +3495,9 @@ int Application::parseOctreeStats(const QByteArray& packet, const SharedNodePoin · 1 unmodified line | ||
| 3373 | 3495 | // details from the OctreeSceneStats to construct the JurisdictionMap |
| 3374 | 3496 | JurisdictionMap jurisdictionMap; |
| 3375 | 3497 | jurisdictionMap.copyContents(temp.getJurisdictionRoot(), temp.getJurisdictionEndNodes()); |
| 3498 | + jurisdiction->lockForWrite(); | |
| 3376 | 3499 | (*jurisdiction)[nodeUUID] = jurisdictionMap; |
| 3500 | + jurisdiction->unlock(); | |
| 3377 | 3501 | } |
| 3378 | 3502 | return statsMessageLength; |
| 3379 | 3503 | } |
| @@ -3416,21 +3540,31 @@ void Application::saveScripts() { · 36 unmodified lines | ||
| 3416 | 3540 | _settings->endArray(); |
| 3417 | 3541 | } |
| 3418 | 3542 | |
| 3419 | −ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor) { | |
| 3420 | − if(loadScriptFromEditor && _scriptEnginesHash.contains(scriptName) && !_scriptEnginesHash[scriptName]->isFinished()){ | |
| 3421 | − return _scriptEnginesHash[scriptName]; | |
| 3543 | +ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScriptFromEditor, bool activateMainWindow) { | |
| 3544 | + QUrl scriptUrl(scriptName); | |
| 3545 | + const QString& scriptURLString = scriptUrl.toString(); | |
| 3546 | + if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor | |
| 3547 | + && !_scriptEnginesHash[scriptURLString]->isFinished()) { | |
| 3548 | + | |
| 3549 | + return _scriptEnginesHash[scriptURLString]; | |
| 3422 | 3550 | } |
| 3423 | 3551 | |
| 3424 | − // start the script on a new thread... | |
| 3425 | − QUrl scriptUrl(scriptName); | |
| 3426 | − ScriptEngine* scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface); | |
| 3427 | − _scriptEnginesHash.insert(scriptUrl.toString(), scriptEngine); | |
| 3552 | + ScriptEngine* scriptEngine; | |
| 3553 | + if (scriptName.isNull()) { | |
| 3554 | + scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); | |
| 3555 | + } else { | |
| 3556 | + // start the script on a new thread... | |
| 3557 | + scriptEngine = new ScriptEngine(scriptUrl, &_controllerScriptingInterface); | |
| 3558 | + | |
| 3559 | + if (!scriptEngine->hasScript()) { | |
| 3560 | + qDebug() << "Application::loadScript(), script failed to load..."; | |
| 3561 | + QMessageBox::warning(getWindow(), "Error Loading Script", scriptURLString + " failed to load."); | |
| 3562 | + return NULL; | |
| 3563 | + } | |
| 3428 | 3564 | |
| 3429 | − if (!scriptEngine->hasScript()) { | |
| 3430 | − qDebug() << "Application::loadScript(), script failed to load..."; | |
| 3431 | − return NULL; | |
| 3565 | + _scriptEnginesHash.insertMulti(scriptURLString, scriptEngine); | |
| 3566 | + _runningScriptsWidget->setRunningScripts(getRunningScripts()); | |
| 3432 | 3567 | } |
| 3433 | − _runningScriptsWidget->setRunningScripts(getRunningScripts()); | |
| 3434 | 3568 | |
| 3435 | 3569 | // setup the packet senders and jurisdiction listeners of the script engine's scripting interfaces so |
| 3436 | 3570 | // we can use the same ones from the application. |
| @@ -3471,6 +3605,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript · 34 unmodified lines | ||
| 3471 | 3605 | scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); |
| 3472 | 3606 | scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); |
| 3473 | 3607 | scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); |
| 3608 | + scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); | |
| 3474 | 3609 | |
| 3475 | 3610 | QThread* workerThread = new QThread(this); |
| 3476 | 3611 | |
| @@ -3490,7 +3625,7 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript · 13 unmodified lines | ||
| 3490 | 3625 | workerThread->start(); |
| 3491 | 3626 | |
| 3492 | 3627 | // restore the main window's active state |
| 3493 | − if (!loadScriptFromEditor) { | |
| 3628 | + if (activateMainWindow && !loadScriptFromEditor) { | |
| 3494 | 3629 | _window->activateWindow(); |
| 3495 | 3630 | } |
| 3496 | 3631 | bumpSettings(); |
| @@ -3499,7 +3634,9 @@ ScriptEngine* Application::loadScript(const QString& scriptName, bool loadScript · 2 unmodified lines | ||
| 3499 | 3634 | } |
| 3500 | 3635 | |
| 3501 | 3636 | void Application::scriptFinished(const QString& scriptName) { |
| 3502 | − if (_scriptEnginesHash.remove(scriptName)) { | |
| 3637 | + QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptName); | |
| 3638 | + if (it != _scriptEnginesHash.end()) { | |
| 3639 | + _scriptEnginesHash.erase(it); | |
| 3503 | 3640 | _runningScriptsWidget->scriptStopped(scriptName); |
| 3504 | 3641 | _runningScriptsWidget->setRunningScripts(getRunningScripts()); |
| 3505 | 3642 | bumpSettings(); |
| @@ -3529,6 +3666,12 @@ void Application::reloadAllScripts() { · 23 unmodified lines | ||
| 3529 | 3666 | stopAllScripts(true); |
| 3530 | 3667 | } |
| 3531 | 3668 | |
| 3669 | +void Application::loadDefaultScripts() { | |
| 3670 | + if (!_scriptEnginesHash.contains(DEFAULT_SCRIPTS_JS_URL)) { | |
| 3671 | + loadScript(DEFAULT_SCRIPTS_JS_URL); | |
| 3672 | + } | |
| 3673 | +} | |
| 3674 | + | |
| 3532 | 3675 | void Application::manageRunningScriptsWidgetVisibility(bool shown) { |
| 3533 | 3676 | if (_runningScriptsWidgetWasVisible && shown) { |
| 3534 | 3677 | _runningScriptsWidget->show(); |