History

merge from upstream

Seth Alves committed 9 years ago

Commit dc996be2 parents c4d1bee 61c60fc179 files · +5988 −1551Browse files

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

Unified · Split

interface/src/Application.cpp+707−85
@@ -42,16 +42,20 @@ · 41 unmodified lines
42#include <QtMultimedia/QMediaPlayer>42#include <QtMultimedia/QMediaPlayer>
43 43
44#include <QProcessEnvironment>44#include <QProcessEnvironment>
45#include <QTemporaryDir>
45 46
46#include <gl/QOpenGLContextWrapper.h>47#include <gl/QOpenGLContextWrapper.h>
47 48
48#include <shared/GlobalAppProperties.h>49#include <shared/GlobalAppProperties.h>
50#include <StatTracker.h>
51#include <Trace.h>
49#include <ResourceScriptingInterface.h>52#include <ResourceScriptingInterface.h>
50#include <AccountManager.h>53#include <AccountManager.h>
51#include <AddressManager.h>54#include <AddressManager.h>
52#include <AnimDebugDraw.h>55#include <AnimDebugDraw.h>
53#include <BuildInfo.h>56#include <BuildInfo.h>
54#include <AssetClient.h>57#include <AssetClient.h>
58#include <AssetUpload.h>
55#include <AutoUpdater.h>59#include <AutoUpdater.h>
56#include <AudioInjectorManager.h>60#include <AudioInjectorManager.h>
57#include <CursorManager.h>61#include <CursorManager.h>
@@ -77,6 +81,7 @@ · 19 unmodified lines
77#include <UserActivityLoggerScriptingInterface.h>81#include <UserActivityLoggerScriptingInterface.h>
78#include <LogHandler.h>82#include <LogHandler.h>
79#include <MainWindow.h>83#include <MainWindow.h>
84#include <MappingRequest.h>
80#include <MessagesClient.h>85#include <MessagesClient.h>
81#include <ModelEntityItem.h>86#include <ModelEntityItem.h>
82#include <NetworkAccessManager.h>87#include <NetworkAccessManager.h>
@@ -156,6 +161,7 @@ · 73 unmodified lines
156#include "ui/DialogsManager.h"161#include "ui/DialogsManager.h"
157#include "ui/LoginDialog.h"162#include "ui/LoginDialog.h"
158#include "ui/overlays/Cube3DOverlay.h"163#include "ui/overlays/Cube3DOverlay.h"
164#include "ui/overlays/Web3DOverlay.h"
159#include "ui/Snapshot.h"165#include "ui/Snapshot.h"
160#include "ui/SnapshotAnimated.h"166#include "ui/SnapshotAnimated.h"
161#include "ui/StandAloneJSConsole.h"167#include "ui/StandAloneJSConsole.h"
@@ -178,6 +184,8 @@ extern "C" { · 16 unmodified lines
178}184}
179#endif185#endif
180 186
187Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse")
188
181using namespace std;189using namespace std;
182 190
183static QTimer locationUpdateTimer;191static QTimer locationUpdateTimer;
@@ -424,6 +432,8 @@ bool setupEssentials(int& argc, char** argv) { · 240 unmodified lines
424 steamClient->init();432 steamClient->init();
425 }433 }
426 434
435 DependencyManager::set<tracing::Tracer>();
436
427#if defined(Q_OS_WIN)437#if defined(Q_OS_WIN)
428 // Select appropriate audio DLL438 // Select appropriate audio DLL
429 QString audioDLLPath = QCoreApplication::applicationDirPath();439 QString audioDLLPath = QCoreApplication::applicationDirPath();
@@ -446,6 +456,7 @@ bool setupEssentials(int& argc, char** argv) { · 16 unmodified lines
446 456
447 // Set dependencies457 // Set dependencies
448 DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));458 DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp));
459 DependencyManager::set<StatTracker>();
449 DependencyManager::set<ScriptEngines>();460 DependencyManager::set<ScriptEngines>();
450 DependencyManager::set<Preferences>();461 DependencyManager::set<Preferences>();
451 DependencyManager::set<recording::Deck>();462 DependencyManager::set<recording::Deck>();
@@ -559,6 +570,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 107 unmodified lines
559 570
560 {571 {
561 const QString TEST_SCRIPT = "--testScript";572 const QString TEST_SCRIPT = "--testScript";
573 const QString TRACE_FILE = "--traceFile";
562 const QStringList args = arguments();574 const QStringList args = arguments();
563 for (int i = 0; i < args.size() - 1; ++i) {575 for (int i = 0; i < args.size() - 1; ++i) {
564 if (args.at(i) == TEST_SCRIPT) {576 if (args.at(i) == TEST_SCRIPT) {
@@ -566,6 +578,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 1 unmodified line
566 if (QFileInfo(testScriptPath).exists()) {578 if (QFileInfo(testScriptPath).exists()) {
567 setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath));579 setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath));
568 }580 }
581 } else if (args.at(i) == TRACE_FILE) {
582 QString traceFilePath = args.at(i + 1);
583 setProperty(hifi::properties::TRACING, traceFilePath);
584 DependencyManager::get<tracing::Tracer>()->startTracing();
569 }585 }
570 }586 }
571 }587 }
@@ -1180,11 +1196,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 608 unmodified lines
1180 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();1196 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
1181 connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,1197 connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity,
1182 [this](const EntityItemID& entityItemID, const PointerEvent& event) {1198 [this](const EntityItemID& entityItemID, const PointerEvent& event) {
1199 setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
1183 setKeyboardFocusEntity(entityItemID);1200 setKeyboardFocusEntity(entityItemID);
1184 });1201 });
1185 1202
1186 connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [=](const EntityItemID& entityItemID) {1203 connect(entityScriptingInterface.data(), &EntityScriptingInterface::deletingEntity, [=](const EntityItemID& entityItemID) {
1187 if (entityItemID == _keyboardFocusedItem.get()) {1204 if (entityItemID == _keyboardFocusedEntity.get()) {
1188 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);1205 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
1189 }1206 }
1190 });1207 });
@@ -1194,7 +1211,26 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 3 unmodified lines
1194 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);1211 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
1195 });1212 });
1196 1213
1214 // Keyboard focus handling for Web overlays.
1215 auto overlays = &(qApp->getOverlays());
1216
1217 connect(overlays, &Overlays::mousePressOnOverlay, [=](unsigned int overlayID, const PointerEvent& event) {
1218 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
1219 setKeyboardFocusOverlay(overlayID);
1220 });
1221
1222 connect(overlays, &Overlays::overlayDeleted, [=](unsigned int overlayID) {
1223 if (overlayID == _keyboardFocusedOverlay.get()) {
1224 setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
1225 }
1226 });
1227
1228 connect(overlays, &Overlays::mousePressOffOverlay, [=]() {
1229 setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
1230 });
1231
1197 connect(this, &Application::aboutToQuit, [=]() {1232 connect(this, &Application::aboutToQuit, [=]() {
1233 setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
1198 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);1234 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
1199 });1235 });
1200 1236
@@ -1381,16 +1417,31 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 180 unmodified lines
1381 }1417 }
1382 qCDebug(interfaceapp) << "Server content version: " << contentVersion;1418 qCDebug(interfaceapp) << "Server content version: " << contentVersion;
1383 1419
1384 bool hasTutorialContent = contentVersion >= 1;1420 static const int MIN_VIVE_CONTENT_VERSION = 1;
1421 static const int MIN_OCULUS_TOUCH_CONTENT_VERSION = 27;
1422
1423 bool hasSufficientTutorialContent = false;
1424 bool hasHandControllers = false;
1425
1426 // Only specific hand controllers are currently supported, so only send users to the tutorial
1427 // if they have one of those hand controllers.
1428 if (PluginUtils::isViveControllerAvailable()) {
1429 hasHandControllers = true;
1430 hasSufficientTutorialContent = contentVersion >= MIN_VIVE_CONTENT_VERSION;
1431 } else if (PluginUtils::isOculusTouchControllerAvailable()) {
1432 hasHandControllers = true;
1433 hasSufficientTutorialContent = contentVersion >= MIN_OCULUS_TOUCH_CONTENT_VERSION;
1434 }
1385 1435
1386 Setting::Handle<bool> firstRun { Settings::firstRun, true };1436 Setting::Handle<bool> firstRun { Settings::firstRun, true };
1387 bool hasHMDAndHandControllers = PluginUtils::isHMDAvailable("OpenVR (Vive)") && PluginUtils::isHandControllerAvailable();1437
1438 bool hasHMDAndHandControllers = PluginUtils::isHMDAvailable() && hasHandControllers;
1388 Setting::Handle<bool> tutorialComplete { "tutorialComplete", false };1439 Setting::Handle<bool> tutorialComplete { "tutorialComplete", false };
1389 1440
1390 bool shouldGoToTutorial = hasHMDAndHandControllers && hasTutorialContent && !tutorialComplete.get();1441 bool shouldGoToTutorial = hasHMDAndHandControllers && hasSufficientTutorialContent && !tutorialComplete.get();
1391 1442
1392 qCDebug(interfaceapp) << "Has HMD + Hand Controllers: " << hasHMDAndHandControllers << ", current plugin: " << _displayPlugin->getName();1443 qCDebug(interfaceapp) << "Has HMD + Hand Controllers: " << hasHMDAndHandControllers << ", current plugin: " << _displayPlugin->getName();
1393 qCDebug(interfaceapp) << "Has tutorial content: " << hasTutorialContent;1444 qCDebug(interfaceapp) << "Has sufficient tutorial content (" << contentVersion << ") : " << hasSufficientTutorialContent;
1394 qCDebug(interfaceapp) << "Tutorial complete: " << tutorialComplete.get();1445 qCDebug(interfaceapp) << "Tutorial complete: " << tutorialComplete.get();
1395 qCDebug(interfaceapp) << "Should go to tutorial: " << shouldGoToTutorial;1446 qCDebug(interfaceapp) << "Should go to tutorial: " << shouldGoToTutorial;
1396 1447
@@ -1451,6 +1502,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 54 unmodified lines
1451 // After all of the constructor is completed, then set firstRun to false.1502 // After all of the constructor is completed, then set firstRun to false.
1452 firstRun.set(false);1503 firstRun.set(false);
1453 }1504 }
1505
1506 // Monitor model assets (e.g., from Clara.io) added to the world that may need resizing.
1507 static const int ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS = 1000;
1508 _addAssetToWorldResizeTimer.setInterval(ADD_ASSET_TO_WORLD_TIMER_INTERVAL_MS);
1509 connect(&_addAssetToWorldResizeTimer, &QTimer::timeout, this, &Application::addAssetToWorldCheckModelSize);
1510
1511 // Auto-update and close adding asset to world info message box.
1512 static const int ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS = 5000;
1513 _addAssetToWorldInfoTimer.setInterval(ADD_ASSET_TO_WORLD_INFO_TIMEOUT_MS);
1514 _addAssetToWorldInfoTimer.setSingleShot(true);
1515 connect(&_addAssetToWorldInfoTimer, &QTimer::timeout, this, &Application::addAssetToWorldInfoTimeout);
1516 static const int ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS = 8000;
1517 _addAssetToWorldErrorTimer.setInterval(ADD_ASSET_TO_WORLD_ERROR_TIMEOUT_MS);
1518 _addAssetToWorldErrorTimer.setSingleShot(true);
1519 connect(&_addAssetToWorldErrorTimer, &QTimer::timeout, this, &Application::addAssetToWorldErrorTimeout);
1520
1521 connect(this, &QCoreApplication::aboutToQuit, this, &Application::addAssetToWorldMessageClose);
1522 connect(&domainHandler, &DomainHandler::hostnameChanged, this, &Application::addAssetToWorldMessageClose);
1454}1523}
1455 1524
1456void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {1525void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {
@@ -1579,6 +1648,13 @@ void Application::cleanupBeforeQuit() { · 122 unmodified lines
1579 QString webengineRemoteDebugging = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING", "false");1648 QString webengineRemoteDebugging = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING", "false");
1580 qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebugging;1649 qCDebug(interfaceapp) << "QTWEBENGINE_REMOTE_DEBUGGING =" << webengineRemoteDebugging;
1581 1650
1651 if (tracing::enabled()) {
1652 auto tracer = DependencyManager::get<tracing::Tracer>();
1653 tracer->stopTracing();
1654 auto outputFile = property(hifi::properties::TRACING).toString();
1655 tracer->serialize(outputFile);
1656 }
1657
1582 // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash.1658 // Stop third party processes so that they're not left running in the event of a subsequent shutdown crash.
1583#ifdef HAVE_DDE1659#ifdef HAVE_DDE
1584 DependencyManager::get<DdeFaceTracker>()->setEnabled(false);1660 DependencyManager::get<DdeFaceTracker>()->setEnabled(false);
@@ -1753,7 +1829,7 @@ void Application::initializeGL() { · 168 unmodified lines
1753 // Set up the render engine1829 // Set up the render engine
1754 render::CullFunctor cullFunctor = LODManager::shouldRender;1830 render::CullFunctor cullFunctor = LODManager::shouldRender;
1755 _renderEngine->addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);1831 _renderEngine->addJob<RenderShadowTask>("RenderShadowTask", cullFunctor);
1756 static const QString RENDER_FORWARD = "RENDER_FORWARD";1832 static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD";
1757 if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) {1833 if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) {
1758 _renderEngine->addJob<RenderForwardTask>("RenderForwardTask", cullFunctor);1834 _renderEngine->addJob<RenderForwardTask>("RenderForwardTask", cullFunctor);
1759 } else {1835 } else {
@@ -1838,9 +1914,9 @@ void Application::initializeUi() { · 78 unmodified lines
1838 rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());1914 rootContext->setContextProperty("AudioStats", DependencyManager::get<AudioClient>()->getStats().data());
1839 rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());1915 rootContext->setContextProperty("Controller", DependencyManager::get<controller::ScriptingInterface>().data());
1840 rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());1916 rootContext->setContextProperty("Entities", DependencyManager::get<EntityScriptingInterface>().data());
1841 FileScriptingInterface* fileDownload = new FileScriptingInterface(engine);1917 _fileDownload = new FileScriptingInterface(engine);
1842 rootContext->setContextProperty("File", fileDownload);1918 rootContext->setContextProperty("File", _fileDownload);
1843 connect(fileDownload, &FileScriptingInterface::unzipSuccess, this, &Application::showAssetServerWidget);1919 connect(_fileDownload, &FileScriptingInterface::unzipResult, this, &Application::handleUnzip);
1844 rootContext->setContextProperty("MyAvatar", getMyAvatar().get());1920 rootContext->setContextProperty("MyAvatar", getMyAvatar().get());
1845 rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());1921 rootContext->setContextProperty("Messages", DependencyManager::get<MessagesClient>().data());
1846 rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());1922 rootContext->setContextProperty("Recording", DependencyManager::get<RecordingScriptingInterface>().data());
@@ -1856,6 +1932,7 @@ void Application::initializeUi() { · 9 unmodified lines
1856 rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface());1932 rootContext->setContextProperty("Assets", new AssetMappingsScriptingInterface());
1857 1933
1858 rootContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());1934 rootContext->setContextProperty("AvatarList", DependencyManager::get<AvatarManager>().data());
1935 rootContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
1859 1936
1860 rootContext->setContextProperty("Camera", &_myCamera);1937 rootContext->setContextProperty("Camera", &_myCamera);
1861 1938
@@ -1945,7 +2022,7 @@ void Application::paintGL() { · 83 unmodified lines
1945 _frameCount++;2022 _frameCount++;
1946 2023
1947 auto lastPaintBegin = usecTimestampNow();2024 auto lastPaintBegin = usecTimestampNow();
1948 PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);2025 PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
1949 PerformanceTimer perfTimer("paintGL");2026 PerformanceTimer perfTimer("paintGL");
1950 2027
1951 if (nullptr == _displayPlugin) {2028 if (nullptr == _displayPlugin) {
@@ -2122,7 +2199,7 @@ void Application::paintGL() { · 170 unmodified lines
2122 auto finalFramebuffer = framebufferCache->getFramebuffer();2199 auto finalFramebuffer = framebufferCache->getFramebuffer();
2123 2200
2124 {2201 {
2125 PROFILE_RANGE(__FUNCTION__ "/mainRender");2202 PROFILE_RANGE(render, "/mainRender");
2126 PerformanceTimer perfTimer("mainRender");2203 PerformanceTimer perfTimer("mainRender");
2127 renderArgs._boomOffset = boomOffset;2204 renderArgs._boomOffset = boomOffset;
2128 // Viewport is assigned to the size of the framebuffer2205 // Viewport is assigned to the size of the framebuffer
@@ -2177,7 +2254,7 @@ void Application::paintGL() { · 48 unmodified lines
2177 frame->overlay = _applicationOverlay.getOverlayTexture();2254 frame->overlay = _applicationOverlay.getOverlayTexture();
2178 // deliver final scene rendering commands to the display plugin2255 // deliver final scene rendering commands to the display plugin
2179 {2256 {
2180 PROFILE_RANGE(__FUNCTION__ "/pluginOutput");2257 PROFILE_RANGE(render, "/pluginOutput");
2181 PerformanceTimer perfTimer("pluginOutput");2258 PerformanceTimer perfTimer("pluginOutput");
2182 _frameCounter.increment();2259 _frameCounter.increment();
2183 displayPlugin->submitFrame(frame);2260 displayPlugin->submitFrame(frame);
@@ -2265,7 +2342,7 @@ void Application::resizeEvent(QResizeEvent* event) { · 81 unmodified lines
2265}2342}
2266 2343
2267void Application::resizeGL() {2344void Application::resizeGL() {
2268 PROFILE_RANGE(__FUNCTION__);2345 PROFILE_RANGE(render, __FUNCTION__);
2269 if (nullptr == _displayPlugin) {2346 if (nullptr == _displayPlugin) {
2270 return;2347 return;
2271 }2348 }
@@ -2320,7 +2397,6 @@ bool Application::importSVOFromURL(const QString& urlString) { · 48 unmodified lines
2320}2397}
2321 2398
2322bool Application::event(QEvent* event) {2399bool Application::event(QEvent* event) {
2323
2324 if (!Menu::getInstance()) {2400 if (!Menu::getInstance()) {
2325 return false;2401 return false;
2326 }2402 }
@@ -2368,26 +2444,49 @@ bool Application::event(QEvent* event) { · 41 unmodified lines
2368 }2444 }
2369 2445
2370 {2446 {
2371 if (!_keyboardFocusedItem.get().isInvalidID()) {2447 if (!_keyboardFocusedEntity.get().isInvalidID()) {
2372 switch (event->type()) {2448 switch (event->type()) {
2373 case QEvent::KeyPress:2449 case QEvent::KeyPress:
2374 case QEvent::KeyRelease: {2450 case QEvent::KeyRelease: {
2375 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();2451 //auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
2376 auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedItem.get());2452 auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get());
2377 if (entity && entity->getEventHandler()) {2453 if (entity && entity->getEventHandler()) {
2378 event->setAccepted(false);2454 event->setAccepted(false);
2379 QCoreApplication::sendEvent(entity->getEventHandler(), event);2455 QCoreApplication::sendEvent(entity->getEventHandler(), event);
2380 if (event->isAccepted()) {2456 if (event->isAccepted()) {
2381 _lastAcceptedKeyPress = usecTimestampNow();2457 _lastAcceptedKeyPress = usecTimestampNow();
2382 return true;2458 return true;
2459 }
2383 }2460 }
2461 break;
2384 }2462 }
2385 break;2463 default:
2386 }2464 break;
2465 }
2466 }
2467 }
2387 2468
2388 default:2469 {
2389 break;2470 if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) {
2390 }2471 switch (event->type()) {
2472 case QEvent::KeyPress:
2473 case QEvent::KeyRelease: {
2474 // Only Web overlays can have focus.
2475 auto overlay =
2476 std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get()));
2477 if (overlay && overlay->getEventHandler()) {
2478 event->setAccepted(false);
2479 QCoreApplication::sendEvent(overlay->getEventHandler(), event);
2480 if (event->isAccepted()) {
2481 _lastAcceptedKeyPress = usecTimestampNow();
2482 return true;
2483 }
2484 }
2485 break;
2486 }
2487 default:
2488 break;
2489 }
2391 }2490 }
2392 }2491 }
2393 2492
@@ -2911,7 +3010,7 @@ void Application::maybeToggleMenuVisible(QMouseEvent* event) const { · 517 unmodified lines
2911}3010}
2912 3011
2913void Application::mouseMoveEvent(QMouseEvent* event) {3012void Application::mouseMoveEvent(QMouseEvent* event) {
2914 PROFILE_RANGE(__FUNCTION__);3013 PROFILE_RANGE(app_input_mouse, __FUNCTION__);
2915 3014
2916 if (_aboutToQuit) {3015 if (_aboutToQuit) {
2917 return;3016 return;
@@ -2947,6 +3046,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { · 29 unmodified lines
2947 3046
2948 if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||3047 if (compositor.getReticleVisible() || !isHMDMode() || !compositor.getReticleOverDesktop() ||
2949 getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y()))) {3048 getOverlays().getOverlayAtPoint(glm::vec2(transformedPos.x(), transformedPos.y()))) {
3049 getOverlays().mouseMoveEvent(&mappedEvent);
2950 getEntities()->mouseMoveEvent(&mappedEvent);3050 getEntities()->mouseMoveEvent(&mappedEvent);
2951 }3051 }
2952 _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts3052 _controllerScriptingInterface->emitMouseMoveEvent(&mappedEvent); // send events to any registered scripts
@@ -2959,7 +3059,6 @@ void Application::mouseMoveEvent(QMouseEvent* event) { · 6 unmodified lines
2959 if (_keyboardMouseDevice->isActive()) {3059 if (_keyboardMouseDevice->isActive()) {
2960 _keyboardMouseDevice->mouseMoveEvent(event);3060 _keyboardMouseDevice->mouseMoveEvent(event);
2961 }3061 }
2962
2963}3062}
2964 3063
2965void Application::mousePressEvent(QMouseEvent* event) {3064void Application::mousePressEvent(QMouseEvent* event) {
@@ -2981,6 +3080,7 @@ void Application::mousePressEvent(QMouseEvent* event) { · 15 unmodified lines
2981 event->buttons(), event->modifiers());3080 event->buttons(), event->modifiers());
2982 3081
2983 if (!_aboutToQuit) {3082 if (!_aboutToQuit) {
3083 getOverlays().mousePressEvent(&mappedEvent);
2984 getEntities()->mousePressEvent(&mappedEvent);3084 getEntities()->mousePressEvent(&mappedEvent);
2985 }3085 }
2986 3086
@@ -2991,7 +3091,6 @@ void Application::mousePressEvent(QMouseEvent* event) { · 4 unmodified lines
2991 return;3091 return;
2992 }3092 }
2993 3093
2994
2995 if (hasFocus()) {3094 if (hasFocus()) {
2996 if (_keyboardMouseDevice->isActive()) {3095 if (_keyboardMouseDevice->isActive()) {
2997 _keyboardMouseDevice->mousePressEvent(event);3096 _keyboardMouseDevice->mousePressEvent(event);
@@ -3002,7 +3101,6 @@ void Application::mousePressEvent(QMouseEvent* event) { · 4 unmodified lines
3002 HFActionEvent actionEvent(HFActionEvent::startType(),3101 HFActionEvent actionEvent(HFActionEvent::startType(),
3003 computePickRay(mappedEvent.x(), mappedEvent.y()));3102 computePickRay(mappedEvent.x(), mappedEvent.y()));
3004 sendEvent(this, &actionEvent);3103 sendEvent(this, &actionEvent);
3005
3006 }3104 }
3007 }3105 }
3008}3106}
@@ -3027,6 +3125,7 @@ void Application::mouseReleaseEvent(QMouseEvent* event) { · 18 unmodified lines
3027 event->buttons(), event->modifiers());3125 event->buttons(), event->modifiers());
3028 3126
3029 if (!_aboutToQuit) {3127 if (!_aboutToQuit) {
3128 getOverlays().mouseReleaseEvent(&mappedEvent);
3030 getEntities()->mouseReleaseEvent(&mappedEvent);3129 getEntities()->mouseReleaseEvent(&mappedEvent);
3031 }3130 }
3032 3131
@@ -3205,6 +3304,7 @@ bool Application::shouldPaint(float nsecsElapsed) { · 172 unmodified lines
3205}3304}
3206 3305
3207void Application::idle(float nsecsElapsed) {3306void Application::idle(float nsecsElapsed) {
3307 PerformanceTimer perfTimer("idle");
3208 3308
3209 // Update the deadlock watchdog3309 // Update the deadlock watchdog
3210 updateHeartbeat();3310 updateHeartbeat();
@@ -3219,7 +3319,17 @@ void Application::idle(float nsecsElapsed) { · 8 unmodified lines
3219 connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);3319 connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
3220 }3320 }
3221 3321
3222 PROFILE_RANGE(__FUNCTION__);3322 PROFILE_COUNTER(app, "fps", { { "fps", _frameCounter.rate() } });
3323 PROFILE_COUNTER(app, "downloads", {
3324 { "current", ResourceCache::getLoadingRequests().length() },
3325 { "pending", ResourceCache::getPendingRequestCount() }
3326 });
3327 PROFILE_COUNTER(app, "processing", {
3328 { "current", DependencyManager::get<StatTracker>()->getStat("Processing") },
3329 { "pending", DependencyManager::get<StatTracker>()->getStat("PendingProcessing") }
3330 });
3331
3332 PROFILE_RANGE(app, __FUNCTION__);
3223 3333
3224 if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {3334 if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
3225 steamClient->runCallbacks();3335 steamClient->runCallbacks();
@@ -3241,8 +3351,6 @@ void Application::idle(float nsecsElapsed) { · 15 unmodified lines
3241 3351
3242 _simCounter.increment();3352 _simCounter.increment();
3243 3353
3244 PerformanceTimer perfTimer("idle");
3245
3246 // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing3354 // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing
3247 // details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing3355 // details if we're in ExtraDebugging mode. However, the ::update() and its subcomponents will show their timing
3248 // details normally.3356 // details normally.
@@ -3257,20 +3365,30 @@ void Application::idle(float nsecsElapsed) { · 8 unmodified lines
3257 }3365 }
3258 3366
3259 3367
3260 // Drop focus from _keyboardFocusedItem if no keyboard messages for 30 seconds3368 // Update focus highlight for entity or overlay.
3261 {3369 {
3262 if (!_keyboardFocusedItem.get().isInvalidID()) {3370 if (!_keyboardFocusedEntity.get().isInvalidID() || _keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) {
3263 const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus3371 const quint64 LOSE_FOCUS_AFTER_ELAPSED_TIME = 30 * USECS_PER_SECOND; // if idle for 30 seconds, drop focus
3264 quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress;3372 quint64 elapsedSinceAcceptedKeyPress = usecTimestampNow() - _lastAcceptedKeyPress;
3265 if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) {3373 if (elapsedSinceAcceptedKeyPress > LOSE_FOCUS_AFTER_ELAPSED_TIME) {
3266 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);3374 setKeyboardFocusEntity(UNKNOWN_ENTITY_ID);
3375 setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID);
3267 } else {3376 } else {
3268 // update position of highlight overlay3377 // update position of highlight overlay
3269 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();3378 if (!_keyboardFocusedEntity.get().isInvalidID()) {
3270 auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedItem.get());3379 auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get());
3271 if (entity && _keyboardFocusHighlight) {3380 if (entity && _keyboardFocusHighlight) {
3272 _keyboardFocusHighlight->setRotation(entity->getRotation());3381 _keyboardFocusHighlight->setRotation(entity->getRotation());
3273 _keyboardFocusHighlight->setPosition(entity->getPosition());3382 _keyboardFocusHighlight->setPosition(entity->getPosition());
3383 }
3384 } else {
3385 // Only Web overlays can have focus.
3386 auto overlay =
3387 std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get()));
3388 if (overlay && _keyboardFocusHighlight) {
3389 _keyboardFocusHighlight->setRotation(overlay->getRotation());
3390 _keyboardFocusHighlight->setPosition(overlay->getPosition());
3391 }
3274 }3392 }
3275 }3393 }
3276 }3394 }
@@ -3858,8 +3976,31 @@ void Application::rotationModeChanged() const { · 581 unmodified lines
3858 }3976 }
3859}3977}
3860 3978
3979void Application::setKeyboardFocusHighlight(const glm::vec3& position, const glm::quat& rotation, const glm::vec3& dimensions) {
3980 // Create focus
3981 if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {
3982 _keyboardFocusHighlight = std::make_shared<Cube3DOverlay>();
3983 _keyboardFocusHighlight->setAlpha(1.0f);
3984 _keyboardFocusHighlight->setBorderSize(1.0f);
3985 _keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 });
3986 _keyboardFocusHighlight->setIsSolid(false);
3987 _keyboardFocusHighlight->setPulseMin(0.5);
3988 _keyboardFocusHighlight->setPulseMax(1.0);
3989 _keyboardFocusHighlight->setColorPulse(1.0);
3990 _keyboardFocusHighlight->setIgnoreRayIntersection(true);
3991 _keyboardFocusHighlight->setDrawInFront(false);
3992 _keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight);
3993 }
3994
3995 // Position focus
3996 _keyboardFocusHighlight->setRotation(rotation);
3997 _keyboardFocusHighlight->setPosition(position);
3998 _keyboardFocusHighlight->setDimensions(dimensions);
3999 _keyboardFocusHighlight->setVisible(true);
4000}
4001
3861QUuid Application::getKeyboardFocusEntity() const {4002QUuid Application::getKeyboardFocusEntity() const {
3862 return _keyboardFocusedItem.get();4003 return _keyboardFocusedEntity.get();
3863}4004}
3864 4005
3865void Application::setKeyboardFocusEntity(QUuid id) {4006void Application::setKeyboardFocusEntity(QUuid id) {
@@ -3867,21 +4008,21 @@ void Application::setKeyboardFocusEntity(QUuid id) { · 1 unmodified line
3867 setKeyboardFocusEntity(entityItemID);4008 setKeyboardFocusEntity(entityItemID);
3868}4009}
3869 4010
4011static const float FOCUS_HIGHLIGHT_EXPANSION_FACTOR = 1.05f;
4012
3870void Application::setKeyboardFocusEntity(EntityItemID entityItemID) {4013void Application::setKeyboardFocusEntity(EntityItemID entityItemID) {
3871 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();4014 if (_keyboardFocusedEntity.get() != entityItemID) {
3872 if (_keyboardFocusedItem.get() != entityItemID) {4015 _keyboardFocusedEntity.set(entityItemID);
3873 // reset focused entity4016
3874 _keyboardFocusedItem.set(UNKNOWN_ENTITY_ID);4017 if (_keyboardFocusHighlight && _keyboardFocusedOverlay.get() == UNKNOWN_OVERLAY_ID) {
3875 if (_keyboardFocusHighlight) {
3876 _keyboardFocusHighlight->setVisible(false);4018 _keyboardFocusHighlight->setVisible(false);
3877 }4019 }
3878 4020
3879 // if invalid, return without expensive (locking) operations
3880 if (entityItemID == UNKNOWN_ENTITY_ID) {4021 if (entityItemID == UNKNOWN_ENTITY_ID) {
3881 return;4022 return;
3882 }4023 }
3883 4024
3884 // if valid, query properties4025 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
3885 auto properties = entityScriptingInterface->getEntityProperties(entityItemID);4026 auto properties = entityScriptingInterface->getEntityProperties(entityItemID);
3886 if (!properties.getLocked() && properties.getVisible()) {4027 if (!properties.getLocked() && properties.getVisible()) {
3887 auto entity = getEntities()->getTree()->findEntityByID(entityItemID);4028 auto entity = getEntities()->getTree()->findEntityByID(entityItemID);
@@ -3890,30 +4031,45 @@ void Application::setKeyboardFocusEntity(EntityItemID entityItemID) { · 2 unmodified lines
3890 if (_keyboardMouseDevice->isActive()) {4031 if (_keyboardMouseDevice->isActive()) {
3891 _keyboardMouseDevice->pluginFocusOutEvent();4032 _keyboardMouseDevice->pluginFocusOutEvent();
3892 }4033 }
3893 _keyboardFocusedItem.set(entityItemID);
3894 _lastAcceptedKeyPress = usecTimestampNow();4034 _lastAcceptedKeyPress = usecTimestampNow();
3895 4035
3896 // create a focus4036 setKeyboardFocusHighlight(entity->getPosition(), entity->getRotation(),
3897 if (_keyboardFocusHighlightID < 0 || !getOverlays().isAddedOverlay(_keyboardFocusHighlightID)) {4037 entity->getDimensions() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR);
3898 _keyboardFocusHighlight = std::make_shared<Cube3DOverlay>();4038 }
3899 _keyboardFocusHighlight->setAlpha(1.0f);4039 }
3900 _keyboardFocusHighlight->setBorderSize(1.0f);4040 }
3901 _keyboardFocusHighlight->setColor({ 0xFF, 0xEF, 0x00 });4041}
3902 _keyboardFocusHighlight->setIsSolid(false);4042
3903 _keyboardFocusHighlight->setPulseMin(0.5);4043unsigned int Application::getKeyboardFocusOverlay() {
3904 _keyboardFocusHighlight->setPulseMax(1.0);4044 return _keyboardFocusedOverlay.get();
3905 _keyboardFocusHighlight->setColorPulse(1.0);4045}
3906 _keyboardFocusHighlight->setIgnoreRayIntersection(true);4046
3907 _keyboardFocusHighlight->setDrawInFront(false);4047void Application::setKeyboardFocusOverlay(unsigned int overlayID) {
3908 _keyboardFocusHighlightID = getOverlays().addOverlay(_keyboardFocusHighlight);4048 if (overlayID != _keyboardFocusedOverlay.get()) {
3909 }4049 _keyboardFocusedOverlay.set(overlayID);
4050
4051 if (_keyboardFocusHighlight && _keyboardFocusedEntity.get() == UNKNOWN_ENTITY_ID) {
4052 _keyboardFocusHighlight->setVisible(false);
4053 }
4054
4055 if (overlayID == UNKNOWN_OVERLAY_ID) {
4056 return;
4057 }
4058
4059 auto overlayType = getOverlays().getOverlayType(overlayID);
4060 auto isVisible = getOverlays().getProperty(overlayID, "visible").value.toBool();
4061 if (overlayType == Web3DOverlay::TYPE && isVisible) {
4062 auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(overlayID));
4063 overlay->setProxyWindow(_window->windowHandle());
3910 4064
3911 // position the focus4065 if (_keyboardMouseDevice->isActive()) {
3912 _keyboardFocusHighlight->setRotation(entity->getRotation());4066 _keyboardMouseDevice->pluginFocusOutEvent();
3913 _keyboardFocusHighlight->setPosition(entity->getPosition());
3914 _keyboardFocusHighlight->setDimensions(entity->getDimensions() * 1.05f);
3915 _keyboardFocusHighlight->setVisible(true);
3916 }4067 }
4068 _lastAcceptedKeyPress = usecTimestampNow();
4069
4070 auto size = overlay->getSize() * FOCUS_HIGHLIGHT_EXPANSION_FACTOR;
4071 const float OVERLAY_DEPTH = 0.0105f;
4072 setKeyboardFocusHighlight(overlay->getPosition(), overlay->getRotation(), glm::vec3(size.x, size.y, OVERLAY_DEPTH));
3917 }4073 }
3918 }4074 }
3919}4075}
@@ -3936,9 +4092,11 @@ void Application::updateDialogs(float deltaTime) const { · 16 unmodified lines
3936 }4092 }
3937}4093}
3938 4094
4095static bool domainLoadingInProgress = false;
4096
3939void Application::update(float deltaTime) {4097void Application::update(float deltaTime) {
3940 4098
3941 PROFILE_RANGE_EX(__FUNCTION__, 0xffff0000, (uint64_t)_frameCount + 1);4099 PROFILE_RANGE_EX(app, __FUNCTION__, 0xffff0000, (uint64_t)_frameCount + 1);
3942 4100
3943 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);4101 bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
3944 PerformanceWarning warn(showWarnings, "Application::update()");4102 PerformanceWarning warn(showWarnings, "Application::update()");
@@ -3946,6 +4104,11 @@ void Application::update(float deltaTime) { · 1 unmodified line
3946 updateLOD();4104 updateLOD();
3947 4105
3948 if (!_physicsEnabled) {4106 if (!_physicsEnabled) {
4107 if (!domainLoadingInProgress) {
4108 PROFILE_ASYNC_BEGIN(app, "Scene Loading", "");
4109 domainLoadingInProgress = true;
4110 }
4111
3949 // we haven't yet enabled physics. we wait until we think we have all the collision information4112 // we haven't yet enabled physics. we wait until we think we have all the collision information
3950 // for nearby entities before starting bullet up.4113 // for nearby entities before starting bullet up.
3951 quint64 now = usecTimestampNow();4114 quint64 now = usecTimestampNow();
@@ -3975,6 +4138,9 @@ void Application::update(float deltaTime) { · 23 unmodified lines
3975 }4138 }
3976 }4139 }
3977 }4140 }
4141 } else if (domainLoadingInProgress) {
4142 domainLoadingInProgress = false;
4143 PROFILE_ASYNC_END(app, "Scene Loading", "");
3978 }4144 }
3979 4145
3980 {4146 {
@@ -4068,12 +4234,12 @@ void Application::update(float deltaTime) { · 87 unmodified lines
4068 QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();4234 QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>();
4069 4235
4070 if (_physicsEnabled) {4236 if (_physicsEnabled) {
4071 PROFILE_RANGE_EX("Physics", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());4237 PROFILE_RANGE_EX(simulation_physics, "Physics", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
4072 4238
4073 PerformanceTimer perfTimer("physics");4239 PerformanceTimer perfTimer("physics");
4074 4240
4075 {4241 {
4076 PROFILE_RANGE_EX("UpdateStats", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());4242 PROFILE_RANGE_EX(simulation_physics, "UpdateStats", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());
4077 4243
4078 PerformanceTimer perfTimer("updateStates)");4244 PerformanceTimer perfTimer("updateStates)");
4079 static VectorOfMotionStates motionStates;4245 static VectorOfMotionStates motionStates;
@@ -4107,14 +4273,14 @@ void Application::update(float deltaTime) { · 27 unmodified lines
4107 });4273 });
4108 }4274 }
4109 {4275 {
4110 PROFILE_RANGE_EX("StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount());4276 PROFILE_RANGE_EX(simulation_physics, "StepSimulation", 0xffff8000, (uint64_t)getActiveDisplayPlugin()->presentCount());
4111 PerformanceTimer perfTimer("stepSimulation");4277 PerformanceTimer perfTimer("stepSimulation");
4112 getEntities()->getTree()->withWriteLock([&] {4278 getEntities()->getTree()->withWriteLock([&] {
4113 _physicsEngine->stepSimulation();4279 _physicsEngine->stepSimulation();
4114 });4280 });
4115 }4281 }
4116 {4282 {
4117 PROFILE_RANGE_EX("HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());4283 PROFILE_RANGE_EX(simulation_physics, "HarvestChanges", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount());
4118 PerformanceTimer perfTimer("harvestChanges");4284 PerformanceTimer perfTimer("harvestChanges");
4119 if (_physicsEngine->hasOutgoingChanges()) {4285 if (_physicsEngine->hasOutgoingChanges()) {
4120 getEntities()->getTree()->withWriteLock([&] {4286 getEntities()->getTree()->withWriteLock([&] {
@@ -4156,20 +4322,20 @@ void Application::update(float deltaTime) { · 35 unmodified lines
4156 _avatarSimCounter.increment();4322 _avatarSimCounter.increment();
4157 4323
4158 {4324 {
4159 PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());4325 PROFILE_RANGE_EX(simulation, "OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
4160 avatarManager->updateOtherAvatars(deltaTime);4326 avatarManager->updateOtherAvatars(deltaTime);
4161 }4327 }
4162 4328
4163 qApp->updateMyAvatarLookAtPosition();4329 qApp->updateMyAvatarLookAtPosition();
4164 4330
4165 {4331 {
4166 PROFILE_RANGE_EX("MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());4332 PROFILE_RANGE_EX(simulation, "MyAvatar", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
4167 avatarManager->updateMyAvatar(deltaTime);4333 avatarManager->updateMyAvatar(deltaTime);
4168 }4334 }
4169 }4335 }
4170 4336
4171 {4337 {
4172 PROFILE_RANGE_EX("Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());4338 PROFILE_RANGE_EX(app, "Overlays", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
4173 PerformanceTimer perfTimer("overlays");4339 PerformanceTimer perfTimer("overlays");
4174 _overlays.update(deltaTime);4340 _overlays.update(deltaTime);
4175 }4341 }
@@ -4189,7 +4355,7 @@ void Application::update(float deltaTime) { · 13 unmodified lines
4189 4355
4190 // Update my voxel servers with my current voxel query...4356 // Update my voxel servers with my current voxel query...
4191 {4357 {
4192 PROFILE_RANGE_EX("QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());4358 PROFILE_RANGE_EX(app, "QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount());
4193 QMutexLocker viewLocker(&_viewMutex);4359 QMutexLocker viewLocker(&_viewMutex);
4194 PerformanceTimer perfTimer("queryOctree");4360 PerformanceTimer perfTimer("queryOctree");
4195 quint64 sinceLastQuery = now - _lastQueriedTime;4361 quint64 sinceLastQuery = now - _lastQueriedTime;
@@ -4229,7 +4395,7 @@ void Application::update(float deltaTime) { · 33 unmodified lines
4229 avatarManager->postUpdate(deltaTime);4395 avatarManager->postUpdate(deltaTime);
4230 4396
4231 {4397 {
4232 PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0);4398 PROFILE_RANGE_EX(app, "PreRenderLambdas", 0xffff0000, (uint64_t)0);
4233 4399
4234 std::unique_lock<std::mutex> guard(_postUpdateLambdasLock);4400 std::unique_lock<std::mutex> guard(_postUpdateLambdasLock);
4235 for (auto& iter : _postUpdateLambdas) {4401 for (auto& iter : _postUpdateLambdas) {
@@ -4506,8 +4672,6 @@ QRect Application::getDesirableApplicationGeometry() const { · 270 unmodified lines
4506// or the "myCamera".4672// or the "myCamera".
4507//4673//
4508void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {4674void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) {
4509 PerformanceTimer perfTimer("loadViewFrustum");
4510 PROFILE_RANGE(__FUNCTION__);
4511 // We will use these below, from either the camera or head vectors calculated above4675 // We will use these below, from either the camera or head vectors calculated above
4512 viewFrustum.setProjection(camera.getProjection());4676 viewFrustum.setProjection(camera.getProjection());
4513 4677
@@ -4683,7 +4847,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 169 unmodified lines
4683 myAvatar->preDisplaySide(renderArgs);4847 myAvatar->preDisplaySide(renderArgs);
4684 4848
4685 activeRenderingThread = QThread::currentThread();4849 activeRenderingThread = QThread::currentThread();
4686 PROFILE_RANGE(__FUNCTION__);4850 PROFILE_RANGE(render, __FUNCTION__);
4687 PerformanceTimer perfTimer("display");4851 PerformanceTimer perfTimer("display");
4688 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");4852 PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");
4689 4853
@@ -5468,6 +5632,464 @@ void Application::showAssetServerWidget(QString filePath) { · 778 unmodified lines
5468 startUpload(nullptr, nullptr);5632 startUpload(nullptr, nullptr);
5469}5633}
5470 5634
5635void Application::addAssetToWorldFromURL(QString url) {
5636 qInfo(interfaceapp) << "Download asset and add to world from" << url;
5637
5638 QString filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL.
5639
5640 if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
5641 QString errorInfo = "You do not have permissions to write to the Asset Server.";
5642 qWarning(interfaceapp) << "Error downloading asset: " + errorInfo;
5643 addAssetToWorldError(filename, errorInfo);
5644 return;
5645 }
5646
5647 addAssetToWorldInfo(filename, "Downloading asset file " + filename + ".");
5648
5649 auto request = ResourceManager::createResourceRequest(nullptr, QUrl(url));
5650 connect(request, &ResourceRequest::finished, this, &Application::addAssetToWorldFromURLRequestFinished);
5651 request->send();
5652}
5653
5654void Application::addAssetToWorldFromURLRequestFinished() {
5655 auto request = qobject_cast<ResourceRequest*>(sender());
5656 auto url = request->getUrl().toString();
5657 auto result = request->getResult();
5658
5659 QString filename = url.section("filename=", 1, 1); // Filename from trailing "?filename=" URL parameter.
5660
5661 if (result == ResourceRequest::Success) {
5662 qInfo(interfaceapp) << "Downloaded asset from" << url;
5663 QTemporaryDir temporaryDir;
5664 temporaryDir.setAutoRemove(false);
5665 if (temporaryDir.isValid()) {
5666 QString temporaryDirPath = temporaryDir.path();
5667 QString downloadPath = temporaryDirPath + "/" + filename;
5668 qInfo(interfaceapp) << "Download path:" << downloadPath;
5669
5670 QFile tempFile(downloadPath);
5671 if (tempFile.open(QIODevice::WriteOnly)) {
5672 tempFile.write(request->getData());
5673 addAssetToWorldInfoClear(filename); // Remove message from list; next one added will have a different key.
5674 qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true);
5675 } else {
5676 QString errorInfo = "Couldn't open temporary file for download";
5677 qWarning(interfaceapp) << errorInfo;
5678 addAssetToWorldError(filename, errorInfo);
5679 }
5680 } else {
5681 QString errorInfo = "Couldn't create temporary directory for download";
5682 qWarning(interfaceapp) << errorInfo;
5683 addAssetToWorldError(filename, errorInfo);
5684 }
5685 } else {
5686 qWarning(interfaceapp) << "Error downloading" << url << ":" << request->getResultString();
5687 addAssetToWorldError(filename, "Error downloading " + filename + " : " + request->getResultString());
5688 }
5689
5690 request->deleteLater();
5691}
5692
5693
5694QString filenameFromPath(QString filePath) {
5695 return filePath.right(filePath.length() - filePath.lastIndexOf("/") - 1);
5696}
5697
5698void Application::addAssetToWorldUnzipFailure(QString filePath) {
5699 QString filename = filenameFromPath(QUrl(filePath).toLocalFile());
5700 qWarning(interfaceapp) << "Couldn't unzip file" << filePath;
5701 addAssetToWorldError(filename, "Couldn't unzip file " + filename + ".");
5702}
5703
5704void Application::addAssetToWorld(QString filePath) {
5705 // Automatically upload and add asset to world as an alternative manual process initiated by showAssetServerWidget().
5706
5707 QString path = QUrl(filePath).toLocalFile();
5708 QString filename = filenameFromPath(path);
5709 QString mapping = "/" + filename;
5710
5711 // Test repeated because possibly different code paths.
5712 if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
5713 QString errorInfo = "You do not have permissions to write to the Asset Server.";
5714 qWarning(interfaceapp) << "Error downloading asset: " + errorInfo;
5715 addAssetToWorldError(filename, errorInfo);
5716 return;
5717 }
5718
5719 addAssetToWorldInfo(filename, "Adding " + mapping.mid(1) + " to the Asset Server.");
5720
5721 addAssetToWorldWithNewMapping(path, mapping, 0);
5722}
5723
5724void Application::addAssetToWorldWithNewMapping(QString filePath, QString mapping, int copy) {
5725 auto request = DependencyManager::get<AssetClient>()->createGetMappingRequest(mapping);
5726
5727 QObject::connect(request, &GetMappingRequest::finished, this, [=](GetMappingRequest* request) mutable {
5728 const int MAX_COPY_COUNT = 100; // Limit number of duplicate assets; recursion guard.
5729 auto result = request->getError();
5730 if (result == GetMappingRequest::NotFound) {
5731 addAssetToWorldUpload(filePath, mapping);
5732 } else if (result != GetMappingRequest::NoError) {
5733 QString errorInfo = "Could not map asset name: "
5734 + mapping.left(mapping.length() - QString::number(copy).length() - 1);
5735 qWarning(interfaceapp) << "Error downloading asset: " + errorInfo;
5736 addAssetToWorldError(filenameFromPath(filePath), errorInfo);
5737 } else if (copy < MAX_COPY_COUNT - 1) {
5738 if (copy > 0) {
5739 mapping = mapping.remove(mapping.lastIndexOf("-"), QString::number(copy).length() + 1);
5740 }
5741 copy++;
5742 mapping = mapping.insert(mapping.lastIndexOf("."), "-" + QString::number(copy));
5743 addAssetToWorldWithNewMapping(filePath, mapping, copy);
5744 } else {
5745 QString errorInfo = "Too many copies of asset name: "
5746 + mapping.left(mapping.length() - QString::number(copy).length() - 1);
5747 qWarning(interfaceapp) << "Error downloading asset: " + errorInfo;
5748 addAssetToWorldError(filenameFromPath(filePath), errorInfo);
5749 }
5750 request->deleteLater();
5751 });
5752
5753 request->start();
5754}
5755
5756void Application::addAssetToWorldUpload(QString filePath, QString mapping) {
5757 qInfo(interfaceapp) << "Uploading" << filePath << "to Asset Server as" << mapping;
5758 auto upload = DependencyManager::get<AssetClient>()->createUpload(filePath);
5759 QObject::connect(upload, &AssetUpload::finished, this, [=](AssetUpload* upload, const QString& hash) mutable {
5760 if (upload->getError() != AssetUpload::NoError) {
5761 QString errorInfo = "Could not upload asset to the Asset Server.";
5762 qWarning(interfaceapp) << "Error downloading asset: " + errorInfo;
5763 addAssetToWorldError(filenameFromPath(filePath), errorInfo);
5764 } else {
5765 addAssetToWorldSetMapping(filePath, mapping, hash);
5766 }
5767
5768 // Remove temporary directory created by Clara.io market place download.
5769 int index = filePath.lastIndexOf("/model_repo/");
5770 if (index > 0) {
5771 QString tempDir = filePath.left(index);
5772 qCDebug(interfaceapp) << "Removing temporary directory at: " + tempDir;
5773 QDir(tempDir).removeRecursively();
5774 }
5775
5776 upload->deleteLater();
5777 });
5778
5779 upload->start();
5780}
5781
5782void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, QString hash) {
5783 auto request = DependencyManager::get<AssetClient>()->createSetMappingRequest(mapping, hash);
5784 connect(request, &SetMappingRequest::finished, this, [=](SetMappingRequest* request) mutable {
5785 if (request->getError() != SetMappingRequest::NoError) {
5786 QString errorInfo = "Could not set asset mapping.";
5787 qWarning(interfaceapp) << "Error downloading asset: " + errorInfo;
5788 addAssetToWorldError(filenameFromPath(filePath), errorInfo);
5789 } else {
5790 addAssetToWorldAddEntity(filePath, mapping);
5791 }
5792 request->deleteLater();
5793 });
5794
5795 request->start();
5796}
5797
5798void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) {
5799 EntityItemProperties properties;
5800 properties.setType(EntityTypes::Model);
5801 properties.setName(mapping.right(mapping.length() - 1));
5802 properties.setModelURL("atp:" + mapping);
5803 properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND);
5804 properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar.
5805 properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions.
5806 properties.setPosition(getMyAvatar()->getPosition() + getMyAvatar()->getOrientation() * glm::vec3(0.0f, 0.0f, -2.0f));
5807 properties.setGravity(glm::vec3(0.0f, 0.0f, 0.0f));
5808 auto entityID = DependencyManager::get<EntityScriptingInterface>()->addEntity(properties);
5809
5810 // Note: Model dimensions are not available here; model is scaled per FBX mesh in RenderableModelEntityItem::update() later
5811 // on. But FBX dimensions may be in cm, so we monitor for the dimension change and rescale again if warranted.
5812
5813 if (entityID == QUuid()) {
5814 QString errorInfo = "Could not add asset " + mapping + " to world.";
5815 qWarning(interfaceapp) << "Could not add asset to world: " + errorInfo;
5816 addAssetToWorldError(filenameFromPath(filePath), errorInfo);
5817 } else {
5818 // Monitor when asset is rendered in world so that can resize if necessary.
5819 _addAssetToWorldResizeList.insert(entityID, 0); // List value is count of checks performed.
5820 if (!_addAssetToWorldResizeTimer.isActive()) {
5821 _addAssetToWorldResizeTimer.start();
5822 }
5823
5824 // Close progress message box.
5825 addAssetToWorldInfoDone(filenameFromPath(filePath));
5826 }
5827}
5828
5829void Application::addAssetToWorldCheckModelSize() {
5830 if (_addAssetToWorldResizeList.size() == 0) {
5831 return;
5832 }
5833
5834 auto item = _addAssetToWorldResizeList.begin();
5835 while (item != _addAssetToWorldResizeList.end()) {
5836 auto entityID = item.key();
5837
5838 EntityPropertyFlags propertyFlags;
5839 propertyFlags += PROP_NAME;
5840 propertyFlags += PROP_DIMENSIONS;
5841 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
5842 auto properties = entityScriptingInterface->getEntityProperties(entityID, propertyFlags);
5843 auto name = properties.getName();
5844 auto dimensions = properties.getDimensions();
5845
5846 const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}";
5847 bool doResize = false;
5848
5849 const glm::vec3 DEFAULT_DIMENSIONS = glm::vec3(0.1f, 0.1f, 0.1f);
5850 if (dimensions != DEFAULT_DIMENSIONS) {
5851
5852 // Scale model so that its maximum is exactly specific size.
5853 const float MAXIMUM_DIMENSION = 1.0f;
5854 auto previousDimensions = dimensions;
5855 auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y,
5856 MAXIMUM_DIMENSION / dimensions.z));
5857 dimensions *= scale;
5858 qInfo(interfaceapp) << "Asset" << name << "auto-resized from" << previousDimensions << " to " << dimensions;
5859 doResize = true;
5860
5861 item = _addAssetToWorldResizeList.erase(item); // Finished with this entity; advance to next.
5862 } else {
5863 // Increment count of checks done.
5864 _addAssetToWorldResizeList[entityID]++;
5865
5866 const int CHECK_MODEL_SIZE_MAX_CHECKS = 300;
5867 if (_addAssetToWorldResizeList[entityID] > CHECK_MODEL_SIZE_MAX_CHECKS) {
5868 // Have done enough checks; model was either the default size or something's gone wrong.
5869
5870 // Rescale all dimensions.
5871 const glm::vec3 UNIT_DIMENSIONS = glm::vec3(1.0f, 1.0f, 1.0f);
5872 dimensions = UNIT_DIMENSIONS;
5873 qInfo(interfaceapp) << "Asset" << name << "auto-resize timed out; resized to " << dimensions;
5874 doResize = true;
5875
5876 item = _addAssetToWorldResizeList.erase(item); // Finished with this entity; advance to next.
5877 } else {
5878 // No action on this entity; advance to next.
5879 ++item;
5880 }
5881 }
5882
5883 if (doResize) {
5884 EntityItemProperties properties;
5885 properties.setDimensions(dimensions);
5886 properties.setVisible(true);
5887 properties.setCollisionless(false);
5888 properties.setUserData(GRABBABLE_USER_DATA);
5889 properties.setLastEdited(usecTimestampNow());
5890 entityScriptingInterface->editEntity(entityID, properties);
5891 }
5892 }
5893
5894 // Stop timer if nothing in list to check.
5895 if (_addAssetToWorldResizeList.size() == 0) {
5896 _addAssetToWorldResizeTimer.stop();
5897 }
5898}
5899
5900
5901void Application::addAssetToWorldInfo(QString modelName, QString infoText) {
5902 // Displays the most recent info message, subject to being overridden by error messages.
5903
5904 if (_aboutToQuit) {
5905 return;
5906 }
5907
5908 /*
5909 Cancel info timer if running.
5910 If list has an entry for modelName, delete it (just one).
5911 Append modelName, infoText to list.
5912 Display infoText in message box unless an error is being displayed (i.e., error timer is running).
5913 Show message box if not already visible.
5914 */
5915
5916 _addAssetToWorldInfoTimer.stop();
5917
5918 addAssetToWorldInfoClear(modelName);
5919
5920 _addAssetToWorldInfoKeys.append(modelName);
5921 _addAssetToWorldInfoMessages.append(infoText);
5922
5923 if (!_addAssetToWorldErrorTimer.isActive()) {
5924 if (!_addAssetToWorldMessageBox) {
5925 _addAssetToWorldMessageBox = DependencyManager::get<OffscreenUi>()->createMessageBox(OffscreenUi::ICON_INFORMATION,
5926 "Downloading Asset", "", QMessageBox::NoButton, QMessageBox::NoButton);
5927 connect(_addAssetToWorldMessageBox, SIGNAL(destroyed()), this, SLOT(onAssetToWorldMessageBoxClosed()));
5928 }
5929
5930 _addAssetToWorldMessageBox->setProperty("text", "\n" + infoText);
5931 _addAssetToWorldMessageBox->setVisible(true);
5932 }
5933}
5934
5935void Application::addAssetToWorldInfoClear(QString modelName) {
5936 // Clears modelName entry from message list without affecting message currently displayed.
5937
5938 if (_aboutToQuit) {
5939 return;
5940 }
5941
5942 /*
5943 Delete entry for modelName from list.
5944 */
5945
5946 auto index = _addAssetToWorldInfoKeys.indexOf(modelName);
5947 if (index > -1) {
5948 _addAssetToWorldInfoKeys.removeAt(index);
5949 _addAssetToWorldInfoMessages.removeAt(index);
5950 }
5951}
5952
5953void Application::addAssetToWorldInfoDone(QString modelName) {
5954 // Continues to display this message if the latest for a few seconds, then deletes it and displays the next latest.
5955
5956 if (_aboutToQuit) {
5957 return;
5958 }
5959
5960 /*
5961 Delete entry for modelName from list.
5962 (Re)start the info timer to update message box. ... onAddAssetToWorldInfoTimeout()
5963 */
5964
5965 addAssetToWorldInfoClear(modelName);
5966 _addAssetToWorldInfoTimer.start();
5967}
5968
5969void Application::addAssetToWorldInfoTimeout() {
5970 if (_aboutToQuit) {
5971 return;
5972 }
5973
5974 /*
5975 If list not empty, display last message in list (may already be displayed ) unless an error is being displayed.
5976 If list empty, close the message box unless an error is being displayed.
5977 */
5978
5979 if (!_addAssetToWorldErrorTimer.isActive() && _addAssetToWorldMessageBox) {
5980 if (_addAssetToWorldInfoKeys.length() > 0) {
5981 _addAssetToWorldMessageBox->setProperty("text", "\n" + _addAssetToWorldInfoMessages.last());
5982 } else {
5983 disconnect(_addAssetToWorldMessageBox);
5984 _addAssetToWorldMessageBox->setVisible(false);
5985 _addAssetToWorldMessageBox->deleteLater();
5986 _addAssetToWorldMessageBox = nullptr;
5987 }
5988 }
5989}
5990
5991
5992void Application::addAssetToWorldError(QString modelName, QString errorText) {
5993 // Displays the most recent error message for a few seconds.
5994
5995 if (_aboutToQuit) {
5996 return;
5997 }
5998
5999 /*
6000 If list has an entry for modelName, delete it.
6001 Display errorText in message box.
6002 Show message box if not already visible.
6003 (Re)start error timer. ... onAddAssetToWorldErrorTimeout()
6004 */
6005
6006 addAssetToWorldInfoClear(modelName);
6007
6008 if (!_addAssetToWorldMessageBox) {
6009 _addAssetToWorldMessageBox = DependencyManager::get<OffscreenUi>()->createMessageBox(OffscreenUi::ICON_INFORMATION,
6010 "Downloading Asset", "", QMessageBox::NoButton, QMessageBox::NoButton);
6011 connect(_addAssetToWorldMessageBox, SIGNAL(destroyed()), this, SLOT(onAssetToWorldMessageBoxClosed()));
6012 }
6013
6014 _addAssetToWorldMessageBox->setProperty("text", "\n" + errorText);
6015 _addAssetToWorldMessageBox->setVisible(true);
6016
6017 _addAssetToWorldErrorTimer.start();
6018}
6019
6020void Application::addAssetToWorldErrorTimeout() {
6021 if (_aboutToQuit) {
6022 return;
6023 }
6024
6025 /*
6026 If list is not empty, display message from last entry.
6027 If list is empty, close the message box.
6028 */
6029
6030 if (_addAssetToWorldMessageBox) {
6031 if (_addAssetToWorldInfoKeys.length() > 0) {
6032 _addAssetToWorldMessageBox->setProperty("text", "\n" + _addAssetToWorldInfoMessages.last());
6033 } else {
6034 disconnect(_addAssetToWorldMessageBox);
6035 _addAssetToWorldMessageBox->setVisible(false);
6036 _addAssetToWorldMessageBox->deleteLater();
6037 _addAssetToWorldMessageBox = nullptr;
6038 }
6039 }
6040}
6041
6042
6043void Application::addAssetToWorldMessageClose() {
6044 // Clear messages, e.g., if Interface is being closed or domain changes.
6045
6046 /*
6047 Call if user manually closes message box.
6048 Call if domain changes.
6049 Call if application is shutting down.
6050
6051 Stop timers.
6052 Close the message box if open.
6053 Clear lists.
6054 */
6055
6056 _addAssetToWorldInfoTimer.stop();
6057 _addAssetToWorldErrorTimer.stop();
6058
6059 if (_addAssetToWorldMessageBox) {
6060 disconnect(_addAssetToWorldMessageBox);
6061 _addAssetToWorldMessageBox->setVisible(false);
6062 _addAssetToWorldMessageBox->deleteLater();
6063 _addAssetToWorldMessageBox = nullptr;
6064 }
6065
6066 _addAssetToWorldInfoKeys.clear();
6067 _addAssetToWorldInfoMessages.clear();
6068}
6069
6070void Application::onAssetToWorldMessageBoxClosed() {
6071 if (_addAssetToWorldMessageBox) {
6072 // User manually closed message box; perhaps because it has become stuck, so reset all messages.
6073 qInfo(interfaceapp) << "User manually closed download status message box";
6074 disconnect(_addAssetToWorldMessageBox);
6075 _addAssetToWorldMessageBox = nullptr;
6076 addAssetToWorldMessageClose();
6077 }
6078}
6079
6080
6081void Application::handleUnzip(QString zipFile, QString unzipFile, bool autoAdd) {
6082 if (autoAdd) {
6083 if (!unzipFile.isEmpty()) {
6084 addAssetToWorld(unzipFile);
6085 } else {
6086 addAssetToWorldUnzipFailure(zipFile);
6087 }
6088 } else {
6089 showAssetServerWidget(unzipFile);
6090 }
6091}
6092
5471void Application::packageModel() {6093void Application::packageModel() {
5472 ModelPackager::package();6094 ModelPackager::package();
5473}6095}