# Conflicts: # interface/src/Application.cpp # interface/src/scripting/LimitlessVoiceRecognitionScriptingInterface.cpp
Showing the changes to interface/src/Application.cpp (1 of 1575 files). Show all
Unified · Split
| @@ -144,6 +144,7 @@ · 143 unmodified lines | |||
| 144 | #include <trackers/EyeTracker.h> | 144 | #include <trackers/EyeTracker.h> |
| 145 | #include <avatars-renderer/ScriptAvatar.h> | 145 | #include <avatars-renderer/ScriptAvatar.h> |
| 146 | #include <RenderableEntityItem.h> | 146 | #include <RenderableEntityItem.h> |
| 147 | #include <procedural/ProceduralSkybox.h> | ||
| 147 | 148 | ||
| 148 | #include "AudioClient.h" | 149 | #include "AudioClient.h" |
| 149 | #include "audio/AudioScope.h" | 150 | #include "audio/AudioScope.h" |
| @@ -218,14 +219,16 @@ · 68 unmodified lines | |||
| 218 | #include "webbrowser/WebBrowserSuggestionsEngine.h" | 219 | #include "webbrowser/WebBrowserSuggestionsEngine.h" |
| 219 | #include <DesktopPreviewProvider.h> | 220 | #include <DesktopPreviewProvider.h> |
| 220 | 221 | ||
| 222 | #include "AboutUtil.h" | ||
| 223 | |||
| 221 | #if defined(Q_OS_WIN) | 224 | #if defined(Q_OS_WIN) |
| 222 | #include <VersionHelpers.h> | 225 | #include <VersionHelpers.h> |
| 223 | 226 | ||
| 224 | #ifdef DEBUG_EVENT_QUEUE | 227 | #ifdef DEBUG_EVENT_QUEUE |
| 225 | // This is a HACK that uses private headers included with the qt source distrubution. | 228 | // This is a HACK that uses private headers included with the qt source distrubution. |
| 226 | // To use this feature you need to add these directores to your include path: | 229 | // To use this feature you need to add these directores to your include path: |
| 227 | // E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1/QtCore | 230 | // E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1/QtCore |
| 228 | // E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1 | 231 | // E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1 |
| 229 | #define QT_BOOTSTRAPPED | 232 | #define QT_BOOTSTRAPPED |
| 230 | #include <private/qthread_p.h> | 233 | #include <private/qthread_p.h> |
| 231 | #include <private/qobject_p.h> | 234 | #include <private/qobject_p.h> |
| @@ -241,6 +244,7 @@ extern "C" { · 9 unmodified lines | |||
| 241 | 244 | ||
| 242 | #if defined(Q_OS_ANDROID) | 245 | #if defined(Q_OS_ANDROID) |
| 243 | #include <android/log.h> | 246 | #include <android/log.h> |
| 247 | #include "AndroidHelper.h" | ||
| 244 | #endif | 248 | #endif |
| 245 | 249 | ||
| 246 | enum ApplicationEvent { | 250 | enum ApplicationEvent { |
| @@ -329,7 +333,11 @@ static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" }; · 82 unmodified lines | |||
| 329 | static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD); | 333 | static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD); |
| 330 | #endif | 334 | #endif |
| 331 | 335 | ||
| 336 | #if !defined(Q_OS_ANDROID) | ||
| 332 | static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; | 337 | static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; |
| 338 | #else | ||
| 339 | static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4; | ||
| 340 | #endif | ||
| 333 | 341 | ||
| 334 | // For processing on QThreadPool, we target a number of threads after reserving some | 342 | // For processing on QThreadPool, we target a number of threads after reserving some |
| 335 | // based on how many are being consumed by the application and the display plugin. However, | 343 | // based on how many are being consumed by the application and the display plugin. However, |
| @@ -373,7 +381,7 @@ Setting::Handle<int> maxOctreePacketsPerSecond("maxOctreePPS", DEFAULT_MAX_OCTRE · 37 unmodified lines | |||
| 373 | static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com"; | 381 | static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com"; |
| 374 | static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds | 382 | static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds |
| 375 | static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop"; | 383 | static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop"; |
| 376 | 384 | static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin"; | |
| 377 | static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; | 385 | static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system"; |
| 378 | 386 | ||
| 379 | const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions { | 387 | const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions { |
| @@ -489,7 +497,7 @@ public: · 109 unmodified lines | |||
| 489 | // Don't actually crash in debug builds, in case this apparent deadlock is simply from | 497 | // Don't actually crash in debug builds, in case this apparent deadlock is simply from |
| 490 | // the developer actively debugging code | 498 | // the developer actively debugging code |
| 491 | #ifdef NDEBUG | 499 | #ifdef NDEBUG |
| 492 | deadlockDetectionCrash(); | 500 | deadlockDetectionCrash(); |
| 493 | #endif | 501 | #endif |
| 494 | } | 502 | } |
| 495 | } | 503 | } |
| @@ -687,6 +695,34 @@ private: · 191 unmodified lines | |||
| 687 | } | 695 | } |
| 688 | }; | 696 | }; |
| 689 | 697 | ||
| 698 | /**jsdoc | ||
| 699 | * <p>The <code>Controller.Hardware.Application</code> object has properties representing Interface's state. The property | ||
| 700 | * values are integer IDs, uniquely identifying each output. <em>Read-only.</em> These can be mapped to actions or functions or | ||
| 701 | * <code>Controller.Standard</code> items in a {@link RouteObject} mapping (e.g., using the {@link RouteObject#when} method). | ||
| 702 | * Each data value is either <code>1.0</code> for "true" or <code>0.0</code> for "false".</p> | ||
| 703 | * <table> | ||
| 704 | * <thead> | ||
| 705 | * <tr><th>Property</th><th>Type</th><th>Data</th><th>Description</th></tr> | ||
| 706 | * </thead> | ||
| 707 | * <tbody> | ||
| 708 | * <tr><td><code>CameraFirstPerson</code></td><td>number</td><td>number</td><td>The camera is in first-person mode. | ||
| 709 | * </td></tr> | ||
| 710 | * <tr><td><code>CameraThirdPerson</code></td><td>number</td><td>number</td><td>The camera is in third-person mode. | ||
| 711 | * </td></tr> | ||
| 712 | * <tr><td><code>CameraFSM</code></td><td>number</td><td>number</td><td>The camera is in full screen mirror mode.</td></tr> | ||
| 713 | * <tr><td><code>CameraIndependent</code></td><td>number</td><td>number</td><td>The camera is in independent mode.</td></tr> | ||
| 714 | * <tr><td><code>CameraEntity</code></td><td>number</td><td>number</td><td>The camera is in entity mode.</td></tr> | ||
| 715 | * <tr><td><code>InHMD</code></td><td>number</td><td>number</td><td>The user is in HMD mode.</td></tr> | ||
| 716 | * <tr><td><code>AdvancedMovement</code></td><td>number</td><td>number</td><td>Advanced movement controls are enabled. | ||
| 717 | * </td></tr> | ||
| 718 | * <tr><td><code>SnapTurn</code></td><td>number</td><td>number</td><td>Snap turn is enabled.</td></tr> | ||
| 719 | * <tr><td><code>Grounded</code></td><td>number</td><td>number</td><td>The user's avatar is on the ground.</td></tr> | ||
| 720 | * <tr><td><code>NavigationFocused</code></td><td>number</td><td>number</td><td><em>Not used.</em></td></tr> | ||
| 721 | * </tbody> | ||
| 722 | * </table> | ||
| 723 | * @typedef {object} Controller.Hardware-Application | ||
| 724 | */ | ||
| 725 | |||
| 690 | static const QString STATE_IN_HMD = "InHMD"; | 726 | static const QString STATE_IN_HMD = "InHMD"; |
| 691 | static const QString STATE_CAMERA_FULL_SCREEN_MIRROR = "CameraFSM"; | 727 | static const QString STATE_CAMERA_FULL_SCREEN_MIRROR = "CameraFSM"; |
| 692 | static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson"; | 728 | static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson"; |
| @@ -703,6 +739,11 @@ extern DisplayPluginList getDisplayPlugins(); · 10 unmodified lines | |||
| 703 | extern InputPluginList getInputPlugins(); | 739 | extern InputPluginList getInputPlugins(); |
| 704 | extern void saveInputPluginSettings(const InputPluginList& plugins); | 740 | extern void saveInputPluginSettings(const InputPluginList& plugins); |
| 705 | 741 | ||
| 742 | // Parameters used for running tests from teh command line | ||
| 743 | const QString TEST_SCRIPT_COMMAND{ "--testScript" }; | ||
| 744 | const QString TEST_QUIT_WHEN_FINISHED_OPTION{ "quitWhenFinished" }; | ||
| 745 | const QString TEST_RESULTS_LOCATION_COMMAND{ "--testResultsLocation" }; | ||
| 746 | |||
| 706 | bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { | 747 | bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { |
| 707 | const char** constArgv = const_cast<const char**>(argv); | 748 | const char** constArgv = const_cast<const char**>(argv); |
| 708 | 749 | ||
| @@ -737,7 +778,22 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 28 unmodified lines | |||
| 737 | 778 | ||
| 738 | static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; | 779 | static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; |
| 739 | bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET); | 780 | bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET); |
| 740 | bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); | 781 | |
| 782 | // Ignore any previous crashes if running from command line with a test script. | ||
| 783 | bool inTestMode { false }; | ||
| 784 | for (int i = 0; i < argc; ++i) { | ||
| 785 | QString parameter(argv[i]); | ||
| 786 | if (parameter == TEST_SCRIPT_COMMAND) { | ||
| 787 | inTestMode = true; | ||
| 788 | break; | ||
| 789 | } | ||
| 790 | } | ||
| 791 | |||
| 792 | bool previousSessionCrashed { false }; | ||
| 793 | if (!inTestMode) { | ||
| 794 | previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); | ||
| 795 | } | ||
| 796 | |||
| 741 | // get dir to use for cache | 797 | // get dir to use for cache |
| 742 | static const auto CACHE_SWITCH = "--cache"; | 798 | static const auto CACHE_SWITCH = "--cache"; |
| 743 | QString cacheDir = getCmdOption(argc, const_cast<const char**>(argv), CACHE_SWITCH); | 799 | QString cacheDir = getCmdOption(argc, const_cast<const char**>(argv), CACHE_SWITCH); |
| @@ -745,15 +801,8 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 1 unmodified line | |||
| 745 | qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir); | 801 | qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir); |
| 746 | } | 802 | } |
| 747 | 803 | ||
| 748 | // FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove | ||
| 749 | // this conditional exclusion | ||
| 750 | #if !defined(Q_OS_OSX) | ||
| 751 | { | 804 | { |
| 752 | #if defined(Q_OS_ANDROID) | 805 | const QString resourcesBinaryFile = PathUtils::getRccPath(); |
| 753 | const QString resourcesBinaryFile = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/resources.rcc"; | ||
| 754 | #else | ||
| 755 | const QString resourcesBinaryFile = QCoreApplication::applicationDirPath() + "/resources.rcc"; | ||
| 756 | #endif | ||
| 757 | if (!QFile::exists(resourcesBinaryFile)) { | 806 | if (!QFile::exists(resourcesBinaryFile)) { |
| 758 | throw std::runtime_error("Unable to find primary resources"); | 807 | throw std::runtime_error("Unable to find primary resources"); |
| 759 | } | 808 | } |
| @@ -761,7 +810,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 1 unmodified line | |||
| 761 | throw std::runtime_error("Unable to load primary resources"); | 810 | throw std::runtime_error("Unable to load primary resources"); |
| 762 | } | 811 | } |
| 763 | } | 812 | } |
| 764 | #endif | ||
| 765 | 813 | ||
| 766 | // Tell the plugin manager about our statically linked plugins | 814 | // Tell the plugin manager about our statically linked plugins |
| 767 | auto pluginManager = PluginManager::getInstance(); | 815 | auto pluginManager = PluginManager::getInstance(); |
| @@ -772,7 +820,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 4 unmodified lines | |||
| 772 | steamClient->init(); | 820 | steamClient->init(); |
| 773 | } | 821 | } |
| 774 | 822 | ||
| 775 | DependencyManager::set<tracing::Tracer>(); | ||
| 776 | PROFILE_SET_THREAD_NAME("Main Thread"); | 823 | PROFILE_SET_THREAD_NAME("Main Thread"); |
| 777 | 824 | ||
| 778 | #if defined(Q_OS_WIN) | 825 | #if defined(Q_OS_WIN) |
| @@ -801,7 +848,11 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 22 unmodified lines | |||
| 801 | DependencyManager::set<Cursor::Manager>(); | 848 | DependencyManager::set<Cursor::Manager>(); |
| 802 | DependencyManager::set<VirtualPad::Manager>(); | 849 | DependencyManager::set<VirtualPad::Manager>(); |
| 803 | DependencyManager::set<DesktopPreviewProvider>(); | 850 | DependencyManager::set<DesktopPreviewProvider>(); |
| 851 | #if defined(Q_OS_ANDROID) | ||
| 852 | DependencyManager::set<AccountManager>(); // use the default user agent getter | ||
| 853 | #else | ||
| 804 | DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp)); | 854 | DependencyManager::set<AccountManager>(std::bind(&Application::getUserAgent, qApp)); |
| 855 | #endif | ||
| 805 | DependencyManager::set<StatTracker>(); | 856 | DependencyManager::set<StatTracker>(); |
| 806 | DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT); | 857 | DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT); |
| 807 | DependencyManager::set<ScriptInitializerMixin, NativeScriptInitializers>(); | 858 | DependencyManager::set<ScriptInitializerMixin, NativeScriptInitializers>(); |
| @@ -853,7 +904,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 45 unmodified lines | |||
| 853 | DependencyManager::set<DiscoverabilityManager>(); | 904 | DependencyManager::set<DiscoverabilityManager>(); |
| 854 | DependencyManager::set<SceneScriptingInterface>(); | 905 | DependencyManager::set<SceneScriptingInterface>(); |
| 855 | DependencyManager::set<OffscreenUi>(); | 906 | DependencyManager::set<OffscreenUi>(); |
| 856 | DependencyManager::set<AutoUpdater>(); | ||
| 857 | DependencyManager::set<Midi>(); | 907 | DependencyManager::set<Midi>(); |
| 858 | DependencyManager::set<PathUtils>(); | 908 | DependencyManager::set<PathUtils>(); |
| 859 | DependencyManager::set<InterfaceDynamicFactory>(); | 909 | DependencyManager::set<InterfaceDynamicFactory>(); |
| @@ -927,7 +977,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 67 unmodified lines | |||
| 927 | _entitySimulation(new PhysicalEntitySimulation()), | 977 | _entitySimulation(new PhysicalEntitySimulation()), |
| 928 | _physicsEngine(new PhysicsEngine(Vectors::ZERO)), | 978 | _physicsEngine(new PhysicsEngine(Vectors::ZERO)), |
| 929 | _entityClipboard(new EntityTree()), | 979 | _entityClipboard(new EntityTree()), |
| 930 | _lastQueriedTime(usecTimestampNow()), | ||
| 931 | _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), | 980 | _previousScriptLocation("LastScriptLocation", DESKTOP_LOCATION), |
| 932 | _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), | 981 | _fieldOfView("fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES), |
| 933 | _hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT), | 982 | _hmdTabletScale("hmdTabletScale", DEFAULT_HMD_TABLET_SCALE_PERCENT), |
| @@ -956,21 +1005,35 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 22 unmodified lines | |||
| 956 | auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); | 1005 | auto steamClient = PluginManager::getInstance()->getSteamClientPlugin(); |
| 957 | setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); | 1006 | setProperty(hifi::properties::STEAM, (steamClient && steamClient->isRunning())); |
| 958 | setProperty(hifi::properties::CRASHED, _previousSessionCrashed); | 1007 | setProperty(hifi::properties::CRASHED, _previousSessionCrashed); |
| 959 | |||
| 960 | { | 1008 | { |
| 961 | const QString TEST_SCRIPT = "--testScript"; | ||
| 962 | const QString TRACE_FILE = "--traceFile"; | ||
| 963 | const QStringList args = arguments(); | 1009 | const QStringList args = arguments(); |
| 1010 | |||
| 964 | for (int i = 0; i < args.size() - 1; ++i) { | 1011 | for (int i = 0; i < args.size() - 1; ++i) { |
| 965 | if (args.at(i) == TEST_SCRIPT) { | 1012 | if (args.at(i) == TEST_SCRIPT_COMMAND && (i + 1) < args.size()) { |
| 966 | QString testScriptPath = args.at(i + 1); | 1013 | QString testScriptPath = args.at(i + 1); |
| 967 | if (QFileInfo(testScriptPath).exists()) { | 1014 | |
| 1015 | // If the URL scheme is http(s) or ftp, then use as is, else - treat it as a local file | ||
| 1016 | // This is done so as not break previous command line scripts | ||
| 1017 | if (testScriptPath.left(URL_SCHEME_HTTP.length()) == URL_SCHEME_HTTP || | ||
| 1018 | testScriptPath.left(URL_SCHEME_FTP.length()) == URL_SCHEME_FTP) { | ||
| 1019 | |||
| 1020 | setProperty(hifi::properties::TEST, QUrl::fromUserInput(testScriptPath)); | ||
| 1021 | } else if (QFileInfo(testScriptPath).exists()) { | ||
| 968 | setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath)); | 1022 | setProperty(hifi::properties::TEST, QUrl::fromLocalFile(testScriptPath)); |
| 969 | } | 1023 | } |
| 970 | } else if (args.at(i) == TRACE_FILE) { | 1024 | |
| 971 | QString traceFilePath = args.at(i + 1); | 1025 | // quite when finished parameter must directly follow the test script |
| 972 | setProperty(hifi::properties::TRACING, traceFilePath); | 1026 | if ((i + 2) < args.size() && args.at(i + 2) == TEST_QUIT_WHEN_FINISHED_OPTION) { |
| 973 | DependencyManager::get<tracing::Tracer>()->startTracing(); | 1027 | quitWhenFinished = true; |
| 1028 | } | ||
| 1029 | } else if (args.at(i) == TEST_RESULTS_LOCATION_COMMAND) { | ||
| 1030 | // Set test snapshot location only if it is a writeable directory | ||
| 1031 | QString path(args.at(i + 1)); | ||
| 1032 | |||
| 1033 | QFileInfo fileInfo(path); | ||
| 1034 | if (fileInfo.isDir() && fileInfo.isWritable()) { | ||
| 1035 | TestScriptingInterface::getInstance()->setTestResultsLocation(path); | ||
| 1036 | } | ||
| 974 | } | 1037 | } |
| 975 | } | 1038 | } |
| 976 | } | 1039 | } |
| @@ -1016,6 +1079,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 39 unmodified lines | |||
| 1016 | auto nodeList = DependencyManager::get<NodeList>(); | 1079 | auto nodeList = DependencyManager::get<NodeList>(); |
| 1017 | nodeList->startThread(); | 1080 | nodeList->startThread(); |
| 1018 | 1081 | ||
| 1082 | const char** constArgv = const_cast<const char**>(argv); | ||
| 1083 | if (cmdOptionExists(argc, constArgv, "--disableWatchdog")) { | ||
| 1084 | DISABLE_WATCHDOG = true; | ||
| 1085 | } | ||
| 1019 | // Set up a watchdog thread to intentionally crash the application on deadlocks | 1086 | // Set up a watchdog thread to intentionally crash the application on deadlocks |
| 1020 | if (!DISABLE_WATCHDOG) { | 1087 | if (!DISABLE_WATCHDOG) { |
| 1021 | (new DeadlockWatchdogThread())->start(); | 1088 | (new DeadlockWatchdogThread())->start(); |
| @@ -1033,10 +1100,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 11 unmodified lines | |||
| 1033 | if (steamClient) { | 1100 | if (steamClient) { |
| 1034 | qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID(); | 1101 | qCDebug(interfaceapp) << "[VERSION] SteamVR buildID:" << steamClient->getSteamVRBuildID(); |
| 1035 | } | 1102 | } |
| 1103 | setCrashAnnotation("steam", property(hifi::properties::STEAM).toBool() ? "1" : "0"); | ||
| 1104 | |||
| 1036 | qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); | 1105 | qCDebug(interfaceapp) << "[VERSION] Build sequence:" << qPrintable(applicationVersion()); |
| 1037 | qCDebug(interfaceapp) << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION; | 1106 | qCDebug(interfaceapp) << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION; |
| 1038 | qCDebug(interfaceapp) << "[VERSION] VERSION:" << BuildInfo::VERSION; | 1107 | qCDebug(interfaceapp) << "[VERSION] VERSION:" << BuildInfo::VERSION; |
| 1039 | qCDebug(interfaceapp) << "[VERSION] BUILD_BRANCH:" << BuildInfo::BUILD_BRANCH; | 1108 | qCDebug(interfaceapp) << "[VERSION] BUILD_TYPE_STRING:" << BuildInfo::BUILD_TYPE_STRING; |
| 1040 | qCDebug(interfaceapp) << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES; | 1109 | qCDebug(interfaceapp) << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES; |
| 1041 | #if USE_STABLE_GLOBAL_SERVICES | 1110 | #if USE_STABLE_GLOBAL_SERVICES |
| 1042 | qCDebug(interfaceapp) << "[VERSION] We will use STABLE global services."; | 1111 | qCDebug(interfaceapp) << "[VERSION] We will use STABLE global services."; |
| @@ -1100,10 +1169,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 57 unmodified lines | |||
| 1100 | auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>(); | 1169 | auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>(); |
| 1101 | auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldPosition(); | 1170 | auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldPosition(); |
| 1102 | float distance = glm::distance(myAvatarPosition, position); | 1171 | float distance = glm::distance(myAvatarPosition, position); |
| 1103 | bool shouldMute = !audioClient->isMuted() && (distance < radius); | ||
| 1104 | 1172 | ||
| 1105 | if (shouldMute) { | 1173 | if (distance < radius) { |
| 1106 | audioClient->toggleMute(); | 1174 | audioClient->setMuted(true); |
| 1107 | audioScriptingInterface->environmentMuted(); | 1175 | audioScriptingInterface->environmentMuted(); |
| 1108 | } | 1176 | } |
| 1109 | }); | 1177 | }); |
| @@ -1119,6 +1187,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 9 unmodified lines | |||
| 1119 | const DomainHandler& domainHandler = nodeList->getDomainHandler(); | 1187 | const DomainHandler& domainHandler = nodeList->getDomainHandler(); |
| 1120 | 1188 | ||
| 1121 | connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl))); | 1189 | connect(&domainHandler, SIGNAL(domainURLChanged(QUrl)), SLOT(domainURLChanged(QUrl))); |
| 1190 | connect(&domainHandler, &DomainHandler::domainURLChanged, [](QUrl domainURL){ | ||
| 1191 | setCrashAnnotation("domain", domainURL.toString().toStdString()); | ||
| 1192 | }); | ||
| 1122 | connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); | 1193 | connect(&domainHandler, SIGNAL(resetting()), SLOT(resettingDomain())); |
| 1123 | connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); | 1194 | connect(&domainHandler, SIGNAL(connectedToDomain(QUrl)), SLOT(updateWindowTitle())); |
| 1124 | connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); | 1195 | connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); |
| @@ -1162,8 +1233,17 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 37 unmodified lines | |||
| 1162 | nodeList.data(), SLOT(reset())); | 1233 | nodeList.data(), SLOT(reset())); |
| 1163 | 1234 | ||
| 1164 | auto dialogsManager = DependencyManager::get<DialogsManager>(); | 1235 | auto dialogsManager = DependencyManager::get<DialogsManager>(); |
| 1236 | #if defined(Q_OS_ANDROID) | ||
| 1237 | connect(accountManager.data(), &AccountManager::authRequired, this, []() { | ||
| 1238 | AndroidHelper::instance().showLoginDialog(); | ||
| 1239 | }); | ||
| 1240 | #else | ||
| 1165 | connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); | 1241 | connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); |
| 1242 | #endif | ||
| 1166 | connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle); | 1243 | connect(accountManager.data(), &AccountManager::usernameChanged, this, &Application::updateWindowTitle); |
| 1244 | connect(accountManager.data(), &AccountManager::usernameChanged, [](QString username){ | ||
| 1245 | setCrashAnnotation("username", username.toStdString()); | ||
| 1246 | }); | ||
| 1167 | 1247 | ||
| 1168 | // set the account manager's root URL and trigger a login request if we don't have the access token | 1248 | // set the account manager's root URL and trigger a login request if we don't have the access token |
| 1169 | accountManager->setIsAgent(true); | 1249 | accountManager->setIsAgent(true); |
| @@ -1181,6 +1261,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 11 unmodified lines | |||
| 1181 | connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); | 1261 | connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateThreadPoolCount); |
| 1182 | connect(this, &Application::activeDisplayPluginChanged, this, [](){ | 1262 | connect(this, &Application::activeDisplayPluginChanged, this, [](){ |
| 1183 | qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); | 1263 | qApp->setProperty(hifi::properties::HMD, qApp->isHMDMode()); |
| 1264 | auto displayPlugin = qApp->getActiveDisplayPlugin(); | ||
| 1265 | setCrashAnnotation("display_plugin", displayPlugin->getName().toStdString()); | ||
| 1266 | setCrashAnnotation("hmd", displayPlugin->isHmd() ? "1" : "0"); | ||
| 1184 | }); | 1267 | }); |
| 1185 | connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); | 1268 | connect(this, &Application::activeDisplayPluginChanged, this, &Application::updateSystemTabletMode); |
| 1186 | 1269 | ||
| @@ -1188,6 +1271,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 1 unmodified line | |||
| 1188 | connect(myAvatar.get(), &MyAvatar::positionGoneTo, | 1271 | connect(myAvatar.get(), &MyAvatar::positionGoneTo, |
| 1189 | DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress); | 1272 | DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress); |
| 1190 | 1273 | ||
| 1274 | connect(myAvatar.get(), &MyAvatar::skeletonModelURLChanged, [](){ | ||
| 1275 | QUrl avatarURL = qApp->getMyAvatar()->getSkeletonModelURL(); | ||
| 1276 | setCrashAnnotation("avatar", avatarURL.toString().toStdString()); | ||
| 1277 | }); | ||
| 1278 | |||
| 1279 | |||
| 1191 | // Inititalize sample before registering | 1280 | // Inititalize sample before registering |
| 1192 | _sampleSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/sample.wav")); | 1281 | _sampleSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/sample.wav")); |
| 1193 | 1282 | ||
| @@ -1205,6 +1294,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 11 unmodified lines | |||
| 1205 | 1294 | ||
| 1206 | connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, [this] { | 1295 | connect(scriptEngines, &ScriptEngines::scriptsReloading, scriptEngines, [this] { |
| 1207 | getEntities()->reloadEntityScripts(); | 1296 | getEntities()->reloadEntityScripts(); |
| 1297 | loadAvatarScripts(getMyAvatar()->getScriptUrls()); | ||
| 1208 | }, Qt::QueuedConnection); | 1298 | }, Qt::QueuedConnection); |
| 1209 | 1299 | ||
| 1210 | connect(scriptEngines, &ScriptEngines::scriptLoadError, | 1300 | connect(scriptEngines, &ScriptEngines::scriptLoadError, |
| @@ -1225,7 +1315,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 14 unmodified lines | |||
| 1225 | connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent); | 1315 | connect(&_entityEditSender, &EntityEditPacketSender::packetSent, this, &Application::packetSent); |
| 1226 | connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, &Application::addingEntityWithCertificate); | 1316 | connect(&_entityEditSender, &EntityEditPacketSender::addingEntityWithCertificate, this, &Application::addingEntityWithCertificate); |
| 1227 | 1317 | ||
| 1228 | const char** constArgv = const_cast<const char**>(argv); | ||
| 1229 | QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads"); | 1318 | QString concurrentDownloadsStr = getCmdOption(argc, constArgv, "--concurrent-downloads"); |
| 1230 | bool success; | 1319 | bool success; |
| 1231 | int concurrentDownloads = concurrentDownloadsStr.toInt(&success); | 1320 | int concurrentDownloads = concurrentDownloadsStr.toInt(&success); |
| @@ -1268,67 +1357,88 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 36 unmodified lines | |||
| 1268 | // Make sure the window is set to the correct size by processing the pending events | 1357 | // Make sure the window is set to the correct size by processing the pending events |
| 1269 | QCoreApplication::processEvents(); | 1358 | QCoreApplication::processEvents(); |
| 1270 | _glWidget->createContext(); | 1359 | _glWidget->createContext(); |
| 1271 | _glWidget->makeCurrent(); | ||
| 1272 | 1360 | ||
| 1361 | // Create the main thread context, the GPU backend | ||
| 1273 | initializeGL(); | 1362 | initializeGL(); |
| 1363 | qCDebug(interfaceapp, "Initialized GL"); | ||
| 1364 | |||
| 1365 | // Initialize the display plugin architecture | ||
| 1366 | initializeDisplayPlugins(); | ||
| 1367 | qCDebug(interfaceapp, "Initialized Display"); | ||
| 1368 | |||
| 1369 | // Create the rendering engine. This can be slow on some machines due to lots of | ||
| 1370 | // GPU pipeline creation. | ||
| 1371 | initializeRenderEngine(); | ||
| 1372 | qCDebug(interfaceapp, "Initialized Render Engine."); | ||
| 1373 | |||
| 1374 | // Initialize the user interface and menu system | ||
| 1375 | // Needs to happen AFTER the render engine initialization to access its configuration | ||
| 1376 | initializeUi(); | ||
| 1377 | |||
| 1378 | init(); | ||
| 1379 | qCDebug(interfaceapp, "init() complete."); | ||
| 1380 | |||
| 1381 | // create thread for parsing of octree data independent of the main network and rendering threads | ||
| 1382 | _octreeProcessor.initialize(_enableProcessOctreeThread); | ||
| 1383 | connect(&_octreeProcessor, &OctreePacketProcessor::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); | ||
| 1384 | _entityEditSender.initialize(_enableProcessOctreeThread); | ||
| 1385 | |||
| 1386 | _idleLoopStdev.reset(); | ||
| 1387 | |||
| 1388 | // update before the first render | ||
| 1389 | update(0); | ||
| 1390 | |||
| 1274 | // Make sure we don't time out during slow operations at startup | 1391 | // Make sure we don't time out during slow operations at startup |
| 1275 | updateHeartbeat(); | 1392 | updateHeartbeat(); |
| 1276 | 1393 | ||
| 1277 | // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. | 1394 | constexpr auto INSTALLER_INI_NAME = "installer.ini"; |
| 1278 | // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. | 1395 | auto iniPath = QDir(applicationDirPath()).filePath(INSTALLER_INI_NAME); |
| 1279 | static const QString TESTER = "HIFI_TESTER"; | 1396 | QFile installerFile { iniPath }; |
| 1280 | auto gpuIdent = GPUIdent::getInstance(); | 1397 | std::unordered_map<QString, QString> installerKeyValues; |
| 1281 | auto glContextData = getGLContextData(); | 1398 | if (installerFile.open(QIODevice::ReadOnly)) { |
| 1282 | QJsonObject properties = { | 1399 | while (!installerFile.atEnd()) { |
| 1283 | { "version", applicationVersion() }, | 1400 | auto line = installerFile.readLine(); |
| 1284 | { "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) }, | 1401 | if (!line.isEmpty()) { |
| 1285 | { "previousSessionCrashed", _previousSessionCrashed }, | 1402 | auto index = line.indexOf("="); |
| 1286 | { "previousSessionRuntime", sessionRunTime.get() }, | 1403 | if (index >= 0) { |
| 1287 | { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, | 1404 | installerKeyValues[line.mid(0, index).trimmed()] = line.mid(index + 1).trimmed(); |
| 1288 | { "kernel_type", QSysInfo::kernelType() }, | 1405 | } |
| 1289 | { "kernel_version", QSysInfo::kernelVersion() }, | 1406 | } |
| 1290 | { "os_type", QSysInfo::productType() }, | 1407 | } |
| 1291 | { "os_version", QSysInfo::productVersion() }, | ||
| 1292 | { "gpu_name", gpuIdent->getName() }, | ||
| 1293 | { "gpu_driver", gpuIdent->getDriver() }, | ||
| 1294 | { "gpu_memory", static_cast<qint64>(gpuIdent->getMemory()) }, | ||
| 1295 | { "gl_version_int", glVersionToInteger(glContextData.value("version").toString()) }, | ||
| 1296 | { "gl_version", glContextData["version"] }, | ||
| 1297 | { "gl_vender", glContextData["vendor"] }, | ||
| 1298 | { "gl_sl_version", glContextData["sl_version"] }, | ||
| 1299 | { "gl_renderer", glContextData["renderer"] }, | ||
| 1300 | { "ideal_thread_count", QThread::idealThreadCount() } | ||
| 1301 | }; | ||
| 1302 | auto macVersion = QSysInfo::macVersion(); | ||
| 1303 | if (macVersion != QSysInfo::MV_None) { | ||
| 1304 | properties["os_osx_version"] = QSysInfo::macVersion(); | ||
| 1305 | } | ||
| 1306 | auto windowsVersion = QSysInfo::windowsVersion(); | ||
| 1307 | if (windowsVersion != QSysInfo::WV_None) { | ||
| 1308 | properties["os_win_version"] = QSysInfo::windowsVersion(); | ||
| 1309 | } | 1408 | } |
| 1310 | 1409 | ||
| 1311 | ProcessorInfo procInfo; | 1410 | // In practice we shouldn't run across installs that don't have a known installer type. |
| 1312 | if (getProcessorInfo(procInfo)) { | 1411 | // Client or Client+Server installs should always have the installer.ini next to their |
| 1313 | properties["processor_core_count"] = procInfo.numProcessorCores; | 1412 | // respective interface.exe, and Steam installs will be detected as such. If a user were |
| 1314 | properties["logical_processor_count"] = procInfo.numLogicalProcessors; | 1413 | // to delete the installer.ini, though, and as an example, we won't know the context of the |
| 1315 | properties["processor_l1_cache_count"] = procInfo.numProcessorCachesL1; | 1414 | // original install. |
| 1316 | properties["processor_l2_cache_count"] = procInfo.numProcessorCachesL2; | 1415 | constexpr auto INSTALLER_KEY_TYPE = "type"; |
| 1317 | properties["processor_l3_cache_count"] = procInfo.numProcessorCachesL3; | 1416 | constexpr auto INSTALLER_KEY_CAMPAIGN = "campaign"; |
| 1417 | constexpr auto INSTALLER_TYPE_UNKNOWN = "unknown"; | ||
| 1418 | constexpr auto INSTALLER_TYPE_STEAM = "steam"; | ||
| 1419 | |||
| 1420 | auto typeIt = installerKeyValues.find(INSTALLER_KEY_TYPE); | ||
| 1421 | QString installerType = INSTALLER_TYPE_UNKNOWN; | ||
| 1422 | if (typeIt == installerKeyValues.end()) { | ||
| 1423 | if (property(hifi::properties::STEAM).toBool()) { | ||
| 1424 | installerType = INSTALLER_TYPE_STEAM; | ||
| 1425 | } | ||
| 1426 | } else { | ||
| 1427 | installerType = typeIt->second; | ||
| 1318 | } | 1428 | } |
| 1319 | 1429 | ||
| 1430 | auto campaignIt = installerKeyValues.find(INSTALLER_KEY_CAMPAIGN); | ||
| 1431 | QString installerCampaign = campaignIt != installerKeyValues.end() ? campaignIt->second : ""; | ||
| 1432 | |||
| 1433 | qDebug() << "Detected installer type:" << installerType; | ||
| 1434 | qDebug() << "Detected installer campaign:" << installerCampaign; | ||
| 1435 | |||
| 1320 | // add firstRun flag from settings to launch event | 1436 | // add firstRun flag from settings to launch event |
| 1321 | Setting::Handle<bool> firstRun { Settings::firstRun, true }; | 1437 | Setting::Handle<bool> firstRun { Settings::firstRun, true }; |
| 1322 | 1438 | ||
| 1323 | // once the settings have been loaded, check if we need to flip the default for UserActivityLogger | 1439 | QString machineFingerPrint = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); |
| 1324 | auto& userActivityLogger = UserActivityLogger::getInstance(); | ||
| 1325 | if (!userActivityLogger.isDisabledSettingSet()) { | ||
| 1326 | // the user activity logger is opt-out for Interface | ||
| 1327 | // but it's defaulted to disabled for other targets | ||
| 1328 | // so we need to enable it here if it has never been disabled by the user | ||
| 1329 | userActivityLogger.disable(false); | ||
| 1330 | } | ||
| 1331 | 1440 | ||
| 1441 | auto& userActivityLogger = UserActivityLogger::getInstance(); | ||
| 1332 | if (userActivityLogger.isEnabled()) { | 1442 | if (userActivityLogger.isEnabled()) { |
| 1333 | // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. | 1443 | // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. |
| 1334 | // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. | 1444 | // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. |
| @@ -1338,6 +1448,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 3 unmodified lines | |||
| 1338 | QJsonObject properties = { | 1448 | QJsonObject properties = { |
| 1339 | { "version", applicationVersion() }, | 1449 | { "version", applicationVersion() }, |
| 1340 | { "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) }, | 1450 | { "tester", QProcessEnvironment::systemEnvironment().contains(TESTER) }, |
| 1451 | { "installer_campaign", installerCampaign }, | ||
| 1452 | { "installer_type", installerType }, | ||
| 1453 | { "build_type", BuildInfo::BUILD_TYPE_STRING }, | ||
| 1341 | { "previousSessionCrashed", _previousSessionCrashed }, | 1454 | { "previousSessionCrashed", _previousSessionCrashed }, |
| 1342 | { "previousSessionRuntime", sessionRunTime.get() }, | 1455 | { "previousSessionRuntime", sessionRunTime.get() }, |
| 1343 | { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, | 1456 | { "cpu_architecture", QSysInfo::currentCpuArchitecture() }, |
| @@ -1376,11 +1489,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 32 unmodified lines | |||
| 1376 | properties["first_run"] = firstRun.get(); | 1489 | properties["first_run"] = firstRun.get(); |
| 1377 | 1490 | ||
| 1378 | // add the user's machine ID to the launch event | 1491 | // add the user's machine ID to the launch event |
| 1379 | properties["machine_fingerprint"] = uuidStringWithoutCurlyBraces(FingerprintUtils::getMachineFingerprint()); | 1492 | properties["machine_fingerprint"] = machineFingerPrint; |
| 1380 | 1493 | ||
| 1381 | userActivityLogger.logAction("launch", properties); | 1494 | userActivityLogger.logAction("launch", properties); |
| 1382 | } | 1495 | } |
| 1383 | 1496 | ||
| 1497 | setCrashAnnotation("machine_fingerprint", machineFingerPrint.toStdString()); | ||
| 1498 | |||
| 1384 | _entityEditSender.setMyAvatar(myAvatar.get()); | 1499 | _entityEditSender.setMyAvatar(myAvatar.get()); |
| 1385 | 1500 | ||
| 1386 | // The entity octree will have to know about MyAvatar for the parentJointName import | 1501 | // The entity octree will have to know about MyAvatar for the parentJointName import |
| @@ -1506,7 +1621,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 119 unmodified lines | |||
| 1506 | 1621 | ||
| 1507 | if (state) { | 1622 | if (state) { |
| 1508 | if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) { | 1623 | if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) { |
| 1509 | DependencyManager::get<AudioClient>()->toggleMute(); | 1624 | auto audioClient = DependencyManager::get<AudioClient>(); |
| 1625 | audioClient->setMuted(!audioClient->isMuted()); | ||
| 1510 | } else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) { | 1626 | } else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) { |
| 1511 | cycleCamera(); | 1627 | cycleCamera(); |
| 1512 | } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) { | 1628 | } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) { |
| @@ -1591,6 +1707,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 78 unmodified lines | |||
| 1591 | 1707 | ||
| 1592 | loadSettings(); | 1708 | loadSettings(); |
| 1593 | 1709 | ||
| 1710 | updateVerboseLogging(); | ||
| 1711 | |||
| 1594 | // Now that we've loaded the menu and thus switched to the previous display plugin | 1712 | // Now that we've loaded the menu and thus switched to the previous display plugin |
| 1595 | // we can unlock the desktop repositioning code, since all the positions will be | 1713 | // we can unlock the desktop repositioning code, since all the positions will be |
| 1596 | // relative to the desktop size for this plugin | 1714 | // relative to the desktop size for this plugin |
| @@ -1655,8 +1773,18 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 58 unmodified lines | |||
| 1655 | // If launched from Steam, let it handle updates | 1773 | // If launched from Steam, let it handle updates |
| 1656 | const QString HIFI_NO_UPDATER_COMMAND_LINE_KEY = "--no-updater"; | 1774 | const QString HIFI_NO_UPDATER_COMMAND_LINE_KEY = "--no-updater"; |
| 1657 | bool noUpdater = arguments().indexOf(HIFI_NO_UPDATER_COMMAND_LINE_KEY) != -1; | 1775 | bool noUpdater = arguments().indexOf(HIFI_NO_UPDATER_COMMAND_LINE_KEY) != -1; |
| 1658 | if (!noUpdater) { | 1776 | bool buildCanUpdate = BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable |
| 1659 | auto applicationUpdater = DependencyManager::get<AutoUpdater>(); | 1777 | || BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Master; |
| 1778 | if (!noUpdater && buildCanUpdate) { | ||
| 1779 | constexpr auto INSTALLER_TYPE_CLIENT_ONLY = "client_only"; | ||
| 1780 | |||
| 1781 | auto applicationUpdater = DependencyManager::set<AutoUpdater>(); | ||
| 1782 | |||
| 1783 | AutoUpdater::InstallerType type = installerType == INSTALLER_TYPE_CLIENT_ONLY | ||
| 1784 | ? AutoUpdater::InstallerType::CLIENT_ONLY : AutoUpdater::InstallerType::FULL; | ||
| 1785 | |||
| 1786 | applicationUpdater->setInstallerType(type); | ||
| 1787 | applicationUpdater->setInstallerCampaign(installerCampaign); | ||
| 1660 | connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); | 1788 | connect(applicationUpdater.data(), &AutoUpdater::newVersionIsAvailable, dialogsManager.data(), &DialogsManager::showUpdateDialog); |
| 1661 | applicationUpdater->checkForUpdate(); | 1789 | applicationUpdater->checkForUpdate(); |
| 1662 | } | 1790 | } |
| @@ -2035,14 +2163,24 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 372 unmodified lines | |||
| 2035 | return entityServerNode && !isPhysicsEnabled(); | 2163 | return entityServerNode && !isPhysicsEnabled(); |
| 2036 | }); | 2164 | }); |
| 2037 | 2165 | ||
| 2038 | _snapshotSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/snap.wav")); | 2166 | _snapshotSound = DependencyManager::get<SoundCache>()->getSound(PathUtils::resourcesUrl("sounds/snapshot/snap.wav")); |
| 2039 | 2167 | ||
| 2040 | QVariant testProperty = property(hifi::properties::TEST); | 2168 | QVariant testProperty = property(hifi::properties::TEST); |
| 2041 | qDebug() << testProperty; | 2169 | qDebug() << testProperty; |
| 2042 | if (testProperty.isValid()) { | 2170 | if (testProperty.isValid()) { |
| 2043 | auto scriptEngines = DependencyManager::get<ScriptEngines>(); | 2171 | auto scriptEngines = DependencyManager::get<ScriptEngines>(); |
| 2044 | const auto testScript = property(hifi::properties::TEST).toUrl(); | 2172 | const auto testScript = property(hifi::properties::TEST).toUrl(); |
| 2045 | scriptEngines->loadScript(testScript, false); | 2173 | |
| 2174 | // Set last parameter to exit interface when the test script finishes, if so requested | ||
| 2175 | scriptEngines->loadScript(testScript, false, false, false, false, quitWhenFinished); | ||
| 2176 | |||
| 2177 | // This is done so we don't get a "connection time-out" message when we haven't passed in a URL. | ||
| 2178 | if (arguments().contains("--url")) { | ||
| 2179 | auto reply = SandboxUtils::getStatus(); | ||
| 2180 | connect(reply, &QNetworkReply::finished, this, [=] { | ||
| 2181 | handleSandboxStatus(reply); | ||
| 2182 | }); | ||
| 2183 | } | ||
| 2046 | } else { | 2184 | } else { |
| 2047 | PROFILE_RANGE(render, "GetSandboxStatus"); | 2185 | PROFILE_RANGE(render, "GetSandboxStatus"); |
| 2048 | auto reply = SandboxUtils::getStatus(); | 2186 | auto reply = SandboxUtils::getStatus(); |
| @@ -2114,6 +2252,29 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 65 unmodified lines | |||
| 2114 | _pendingRenderEvent = false; | 2252 | _pendingRenderEvent = false; |
| 2115 | 2253 | ||
| 2116 | qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID()); | 2254 | qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID()); |
| 2255 | |||
| 2256 | #if defined(Q_OS_ANDROID) | ||
| 2257 | AndroidHelper::instance().init(); | ||
| 2258 | connect(&AndroidHelper::instance(), &AndroidHelper::enterBackground, this, &Application::enterBackground); | ||
| 2259 | connect(&AndroidHelper::instance(), &AndroidHelper::enterForeground, this, &Application::enterForeground); | ||
| 2260 | AndroidHelper::instance().notifyLoadComplete(); | ||
| 2261 | #endif | ||
| 2262 | } | ||
| 2263 | |||
| 2264 | void Application::updateVerboseLogging() { | ||
| 2265 | auto menu = Menu::getInstance(); | ||
| 2266 | if (!menu) { | ||
| 2267 | return; | ||
| 2268 | } | ||
| 2269 | bool enable = menu->isOptionChecked(MenuOption::VerboseLogging); | ||
| 2270 | |||
| 2271 | QString rules = | ||
| 2272 | "hifi.*.debug=%1\n" | ||
| 2273 | "hifi.*.info=%1\n" | ||
| 2274 | "hifi.audio-stream.debug=false\n" | ||
| 2275 | "hifi.audio-stream.info=false"; | ||
| 2276 | rules = rules.arg(enable ? "true" : "false"); | ||
| 2277 | QLoggingCategory::setFilterRules(rules); | ||
| 2117 | } | 2278 | } |
| 2118 | 2279 | ||
| 2119 | void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) { | 2280 | void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) { |
| @@ -2226,6 +2387,10 @@ void Application::onAboutToQuit() { · 106 unmodified lines | |||
| 2226 | } | 2387 | } |
| 2227 | } | 2388 | } |
| 2228 | 2389 | ||
| 2390 | // The active display plugin needs to be loaded before the menu system is active, | ||
| 2391 | // so its persisted explicitly here | ||
| 2392 | Setting::Handle<QString>{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME }.set(getActiveDisplayPlugin()->getName()); | ||
| 2393 | |||
| 2229 | getActiveDisplayPlugin()->deactivate(); | 2394 | getActiveDisplayPlugin()->deactivate(); |
| 2230 | if (_autoSwitchDisplayModeSupportedHMDPlugin | 2395 | if (_autoSwitchDisplayModeSupportedHMDPlugin |
| 2231 | && _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { | 2396 | && _autoSwitchDisplayModeSupportedHMDPlugin->isSessionActive()) { |
| @@ -2315,6 +2480,7 @@ void Application::cleanupBeforeQuit() { · 83 unmodified lines | |||
| 2315 | } | 2480 | } |
| 2316 | 2481 | ||
| 2317 | _window->saveGeometry(); | 2482 | _window->saveGeometry(); |
| 2483 | _gpuContext->shutdown(); | ||
| 2318 | 2484 | ||
| 2319 | // Destroy third party processes after scripts have finished using them. | 2485 | // Destroy third party processes after scripts have finished using them. |
| 2320 | #ifdef HAVE_DDE | 2486 | #ifdef HAVE_DDE |
| @@ -2432,48 +2598,171 @@ void Application::initializeGL() { · 111 unmodified lines | |||
| 2432 | _isGLInitialized = true; | 2598 | _isGLInitialized = true; |
| 2433 | } | 2599 | } |
| 2434 | 2600 | ||
| 2435 | // Build a shared canvas / context for the Chromium processes | 2601 | if (!_glWidget->makeCurrent()) { |
| 2436 | _glWidget->makeCurrent(); | 2602 | qCWarning(interfaceapp, "Unable to make window context current"); |
| 2603 | } | ||
| 2437 | 2604 | ||
| 2438 | #if !defined(DISABLE_QML) | 2605 | #if !defined(DISABLE_QML) |
| 2439 | // Chromium rendering uses some GL functions that prevent nSight from capturing | 2606 | // Build a shared canvas / context for the Chromium processes |
| 2440 | // frames, so we only create the shared context if nsight is NOT active. | 2607 | { |
| 2441 | if (!nsightActive()) { | 2608 | // Disable signed distance field font rendering on ATI/AMD GPUs, due to |
| 2442 | _chromiumShareContext = new OffscreenGLCanvas(); | 2609 | // https://highfidelity.manuscript.com/f/cases/13677/Text-showing-up-white-on-Marketplace-app |
| 2443 | _chromiumShareContext->setObjectName("ChromiumShareContext"); | 2610 | std::string vendor{ (const char*)glGetString(GL_VENDOR) }; |
| 2444 | _chromiumShareContext->create(_glWidget->qglContext()); | 2611 | if ((vendor.find("AMD") != std::string::npos) || (vendor.find("ATI") != std::string::npos)) { |
| 2445 | _chromiumShareContext->makeCurrent(); | 2612 | qputenv("QTWEBENGINE_CHROMIUM_FLAGS", QByteArray("--disable-distance-field-text")); |
| 2446 | if (!_chromiumShareContext->makeCurrent()) { | 2613 | } |
| 2447 | qCWarning(interfaceapp, "Unable to make chromium shared context current"); | 2614 | |
| 2448 | } | 2615 | // Chromium rendering uses some GL functions that prevent nSight from capturing |
| 2449 | qt_gl_set_global_share_context(_chromiumShareContext->getContext()); | 2616 | // frames, so we only create the shared context if nsight is NOT active. |
| 2450 | } else { | 2617 | if (!nsightActive()) { |
| 2451 | qCWarning(interfaceapp) << "nSIGHT detected, disabling chrome rendering"; | 2618 | _chromiumShareContext = new OffscreenGLCanvas(); |
| 2619 | _chromiumShareContext->setObjectName("ChromiumShareContext"); | ||
| 2620 | _chromiumShareContext->create(_glWidget->qglContext()); | ||
| 2621 | if (!_chromiumShareContext->makeCurrent()) { | ||
| 2622 | qCWarning(interfaceapp, "Unable to make chromium shared context current"); | ||
| 2623 | } | ||
| 2624 | qt_gl_set_global_share_context(_chromiumShareContext->getContext()); | ||
| 2625 | _chromiumShareContext->doneCurrent(); | ||
| 2626 | // Restore the GL widget context | ||
| 2627 | if (!_glWidget->makeCurrent()) { | ||
| 2628 | qCWarning(interfaceapp, "Unable to make window context current"); | ||
| 2629 | } | ||
| 2630 | } else { | ||
| 2631 | qCWarning(interfaceapp) << "nSight detected, disabling chrome rendering"; | ||
| 2632 | } | ||
| 2452 | } | 2633 | } |
| 2453 | #endif | 2634 | #endif |
| 2454 | 2635 | ||
| 2455 | // Build a shared canvas / context for the QML rendering | 2636 | // Build a shared canvas / context for the QML rendering |
| 2637 | { | ||
| 2638 | _qmlShareContext = new OffscreenGLCanvas(); | ||
| 2639 | _qmlShareContext->setObjectName("QmlShareContext"); | ||
| 2640 | _qmlShareContext->create(_glWidget->qglContext()); | ||
| 2641 | if (!_qmlShareContext->makeCurrent()) { | ||
| 2642 | qCWarning(interfaceapp, "Unable to make QML shared context current"); | ||
| 2643 | } | ||
| 2644 | OffscreenQmlSurface::setSharedContext(_qmlShareContext->getContext()); | ||
| 2645 | _qmlShareContext->doneCurrent(); | ||
| 2646 | if (!_glWidget->makeCurrent()) { | ||
| 2647 | qCWarning(interfaceapp, "Unable to make window context current"); | ||
| 2648 | } | ||
| 2649 | } | ||
| 2650 | |||
| 2651 | // Build an offscreen GL context for the main thread. | ||
| 2652 | _offscreenContext = new OffscreenGLCanvas(); | ||
| 2653 | _offscreenContext->setObjectName("MainThreadContext"); | ||
| 2654 | _offscreenContext->create(_glWidget->qglContext()); | ||
| 2655 | if (!_offscreenContext->makeCurrent()) { | ||
| 2656 | qFatal("Unable to make offscreen context current"); | ||
| 2657 | } | ||
| 2658 | _offscreenContext->doneCurrent(); | ||
| 2659 | _offscreenContext->setThreadContext(); | ||
| 2660 | |||
| 2456 | _glWidget->makeCurrent(); | 2661 | _glWidget->makeCurrent(); |
| 2457 | _qmlShareContext = new OffscreenGLCanvas(); | 2662 | glClearColor(0.2f, 0.2f, 0.2f, 1); |
| 2458 | _qmlShareContext->setObjectName("QmlShareContext"); | 2663 | glClear(GL_COLOR_BUFFER_BIT); |
| 2459 | _qmlShareContext->create(_glWidget->qglContext()); | 2664 | _glWidget->swapBuffers(); |
| 2460 | if (!_qmlShareContext->makeCurrent()) { | 2665 | |
| 2461 | qCWarning(interfaceapp, "Unable to make QML shared context current"); | 2666 | // Move the GL widget context to the render event handler thread |
| 2667 | _renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); | ||
| 2668 | if (!_offscreenContext->makeCurrent()) { | ||
| 2669 | qFatal("Unable to make offscreen context current"); | ||
| 2462 | } | 2670 | } |
| 2463 | OffscreenQmlSurface::setSharedContext(_qmlShareContext->getContext()); | ||
| 2464 | _qmlShareContext->doneCurrent(); | ||
| 2465 | 2671 | ||
| 2672 | // Create the GPU backend | ||
| 2673 | |||
| 2674 | // Requires the window context, because that's what's used in the actual rendering | ||
| 2675 | // and the GPU backend will make things like the VAO which cannot be shared across | ||
| 2676 | // contexts | ||
| 2466 | _glWidget->makeCurrent(); | 2677 | _glWidget->makeCurrent(); |
| 2467 | gpu::Context::init<gpu::gl::GLBackend>(); | 2678 | gpu::Context::init<gpu::gl::GLBackend>(); |
| 2468 | qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, | 2679 | qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, |
| 2469 | QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram))); | 2680 | QVariant::fromValue((void*)(&gpu::gl::GLBackend::makeProgram))); |
| 2470 | _gpuContext = std::make_shared<gpu::Context>(); | ||
| 2471 | // The gpu context can make child contexts for transfers, so | ||
| 2472 | // we need to restore primary rendering context | ||
| 2473 | _glWidget->makeCurrent(); | 2681 | _glWidget->makeCurrent(); |
| 2682 | _gpuContext = std::make_shared<gpu::Context>(); | ||
| 2683 | |||
| 2684 | DependencyManager::get<TextureCache>()->setGPUContext(_gpuContext); | ||
| 2685 | |||
| 2686 | // Restore the default main thread context | ||
| 2687 | _offscreenContext->makeCurrent(); | ||
| 2688 | } | ||
| 2689 | |||
| 2690 | static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" }; | ||
| 2691 | |||
| 2692 | void Application::initializeDisplayPlugins() { | ||
| 2693 | auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); | ||
| 2694 | Setting::Handle<QString> activeDisplayPluginSetting{ ACTIVE_DISPLAY_PLUGIN_SETTING_NAME, displayPlugins.at(0)->getName() }; | ||
| 2695 | auto lastActiveDisplayPluginName = activeDisplayPluginSetting.get(); | ||
| 2696 | |||
| 2697 | auto defaultDisplayPlugin = displayPlugins.at(0); | ||
| 2698 | // Once time initialization code | ||
| 2699 | DisplayPluginPointer targetDisplayPlugin; | ||
| 2700 | foreach(auto displayPlugin, displayPlugins) { | ||
| 2701 | displayPlugin->setContext(_gpuContext); | ||
| 2702 | if (displayPlugin->getName() == lastActiveDisplayPluginName) { | ||
| 2703 | targetDisplayPlugin = displayPlugin; | ||
| 2704 | } | ||
| 2705 | QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, | ||
| 2706 | [this](const QSize& size) { resizeGL(); }); | ||
| 2707 | QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset); | ||
| 2708 | } | ||
| 2709 | |||
| 2710 | // The default display plugin needs to be activated first, otherwise the display plugin thread | ||
| 2711 | // may be launched by an external plugin, which is bad | ||
| 2712 | setDisplayPlugin(defaultDisplayPlugin); | ||
| 2713 | |||
| 2714 | // Now set the desired plugin if it's not the same as the default plugin | ||
| 2715 | if (targetDisplayPlugin != defaultDisplayPlugin) { | ||
| 2716 | setDisplayPlugin(targetDisplayPlugin); | ||
| 2717 | } | ||
| 2718 | |||
| 2719 | // Submit a default frame to render until the engine starts up | ||
| 2720 | updateRenderArgs(0.0f); | ||
| 2721 | |||
| 2722 | _offscreenContext->makeCurrent(); | ||
| 2723 | |||
| 2724 | #define ENABLE_SPLASH_FRAME 0 | ||
| 2725 | #if ENABLE_SPLASH_FRAME | ||
| 2726 | { | ||
| 2727 | QMutexLocker viewLocker(&_renderArgsMutex); | ||
| 2728 | |||
| 2729 | if (_appRenderArgs._isStereo) { | ||
| 2730 | _gpuContext->enableStereo(true); | ||
| 2731 | _gpuContext->setStereoProjections(_appRenderArgs._eyeProjections); | ||
| 2732 | _gpuContext->setStereoViews(_appRenderArgs._eyeOffsets); | ||
| 2733 | } | ||
| 2734 | |||
| 2735 | // Frame resources | ||
| 2736 | auto framebufferCache = DependencyManager::get<FramebufferCache>(); | ||
| 2737 | gpu::FramebufferPointer finalFramebuffer = framebufferCache->getFramebuffer(); | ||
| 2738 | std::shared_ptr<ProceduralSkybox> procedural = std::make_shared<ProceduralSkybox>(); | ||
| 2739 | procedural->parse(SPLASH_SKYBOX); | ||
| 2740 | |||
| 2741 | _gpuContext->beginFrame(_appRenderArgs._view, _appRenderArgs._headPose); | ||
| 2742 | gpu::doInBatch("splashFrame", _gpuContext, [&](gpu::Batch& batch) { | ||
| 2743 | batch.resetStages(); | ||
| 2744 | batch.enableStereo(false); | ||
| 2745 | batch.setFramebuffer(finalFramebuffer); | ||
| 2746 | batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, { 0, 0, 0, 1 }); | ||
| 2747 | batch.enableSkybox(true); | ||
| 2748 | batch.enableStereo(_appRenderArgs._isStereo); | ||
| 2749 | batch.setViewportTransform({ 0, 0, finalFramebuffer->getSize() }); | ||
| 2750 | procedural->render(batch, _appRenderArgs._renderArgs.getViewFrustum()); | ||
| 2751 | }); | ||
| 2752 | auto frame = _gpuContext->endFrame(); | ||
| 2753 | frame->frameIndex = 0; | ||
| 2754 | frame->framebuffer = finalFramebuffer; | ||
| 2755 | frame->pose = _appRenderArgs._headPose; | ||
| 2756 | frame->framebufferRecycler = [framebufferCache, procedural](const gpu::FramebufferPointer& framebuffer) { | ||
| 2757 | framebufferCache->releaseFramebuffer(framebuffer); | ||
| 2758 | }; | ||
| 2759 | _displayPlugin->submitFrame(frame); | ||
| 2760 | } | ||
| 2761 | #endif | ||
| 2762 | } | ||
| 2474 | 2763 | ||
| 2475 | initDisplay(); | 2764 | void Application::initializeRenderEngine() { |
| 2476 | qCDebug(interfaceapp, "Initialized Display."); | 2765 | _offscreenContext->makeCurrent(); |
| 2477 | 2766 | ||
| 2478 | // FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread. | 2767 | // FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread. |
| 2479 | DeadlockWatchdogThread::withPause([&] { | 2768 | DeadlockWatchdogThread::withPause([&] { |
| @@ -2490,67 +2779,12 @@ void Application::initializeGL() { · 10 unmodified lines | |||
| 2490 | // Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success. | 2779 | // Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success. |
| 2491 | DependencyManager::get<GeometryCache>()->initializeShapePipelines(); | 2780 | DependencyManager::get<GeometryCache>()->initializeShapePipelines(); |
| 2492 | }); | 2781 | }); |
| 2493 | |||
| 2494 | _offscreenContext = new OffscreenGLCanvas(); | ||
| 2495 | _offscreenContext->setObjectName("MainThreadContext"); | ||
| 2496 | _offscreenContext->create(_glWidget->qglContext()); | ||
| 2497 | if (!_offscreenContext->makeCurrent()) { | ||
| 2498 | qFatal("Unable to make offscreen context current"); | ||
| 2499 | } | ||
| 2500 | _offscreenContext->doneCurrent(); | ||
| 2501 | _offscreenContext->setThreadContext(); | ||
| 2502 | _renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); | ||
| 2503 | |||
| 2504 | // The UI can't be created until the primary OpenGL | ||
| 2505 | // context is created, because it needs to share | ||
| 2506 | // texture resources | ||
| 2507 | // Needs to happen AFTER the render engine initialization to access its configuration | ||
| 2508 | if (!_offscreenContext->makeCurrent()) { | ||
| 2509 | qFatal("Unable to make offscreen context current"); | ||
| 2510 | } | ||
| 2511 | |||
| 2512 | initializeUi(); | ||
| 2513 | qCDebug(interfaceapp, "Initialized Offscreen UI."); | ||
| 2514 | |||
| 2515 | if (!_offscreenContext->makeCurrent()) { | ||
| 2516 | qFatal("Unable to make offscreen context current"); | ||
| 2517 | } | ||
| 2518 | init(); | ||
| 2519 | qCDebug(interfaceapp, "init() complete."); | ||
| 2520 | |||
| 2521 | // create thread for parsing of octree data independent of the main network and rendering threads | ||
| 2522 | _octreeProcessor.initialize(_enableProcessOctreeThread); | ||
| 2523 | connect(&_octreeProcessor, &OctreePacketProcessor::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); | ||
| 2524 | _entityEditSender.initialize(_enableProcessOctreeThread); | ||
| 2525 | |||
| 2526 | _idleLoopStdev.reset(); | ||
| 2527 | |||
| 2528 | |||
| 2529 | // Restore the primary GL content for the main thread | ||
| 2530 | if (!_offscreenContext->makeCurrent()) { | ||
| 2531 | qFatal("Unable to make offscreen context current"); | ||
| 2532 | } | ||
| 2533 | |||
| 2534 | // update before the first render | ||
| 2535 | update(0); | ||
| 2536 | } | 2782 | } |
| 2537 | 2783 | ||
| 2538 | extern void setupPreferences(); | 2784 | extern void setupPreferences(); |
| 2785 | static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, int index, bool active = false); | ||
| 2539 | 2786 | ||
| 2540 | void Application::initializeUi() { | 2787 | void Application::initializeUi() { |
| 2541 | // Make sure all QML surfaces share the main thread GL context | ||
| 2542 | OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext()); | ||
| 2543 | OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "OverlayWindowTest.qml" }, | ||
| 2544 | [](QQmlContext* context) { | ||
| 2545 | qDebug() << "Whitelist OverlayWindow worked"; | ||
| 2546 | context->setContextProperty("OverlayWindowTestString", "TestWorked"); | ||
| 2547 | }); | ||
| 2548 | OffscreenQmlSurface::addWhitelistContextHandler(QUrl{ "hifi/audio/Audio.qml" }, | ||
| 2549 | [](QQmlContext* context) { | ||
| 2550 | qDebug() << "QQQ" << __FUNCTION__ << "Whitelist Audio worked"; | ||
| 2551 | }); | ||
| 2552 | |||
| 2553 | |||
| 2554 | AddressBarDialog::registerType(); | 2788 | AddressBarDialog::registerType(); |
| 2555 | ErrorDialog::registerType(); | 2789 | ErrorDialog::registerType(); |
| 2556 | LoginDialog::registerType(); | 2790 | LoginDialog::registerType(); |
| @@ -2565,6 +2799,7 @@ void Application::initializeUi() { · 8 unmodified lines | |||
| 2565 | QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, | 2799 | QUrl{ "hifi/commerce/common/EmulatedMarketplaceHeader.qml" }, |
| 2566 | QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" }, | 2800 | QUrl{ "hifi/commerce/common/FirstUseTutorial.qml" }, |
| 2567 | QUrl{ "hifi/commerce/common/SortableListModel.qml" }, | 2801 | QUrl{ "hifi/commerce/common/SortableListModel.qml" }, |
| 2802 | QUrl{ "hifi/commerce/common/sendAsset/SendAsset.qml" }, | ||
| 2568 | QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, | 2803 | QUrl{ "hifi/commerce/inspectionCertificate/InspectionCertificate.qml" }, |
| 2569 | QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" }, | 2804 | QUrl{ "hifi/commerce/purchases/PurchasedItem.qml" }, |
| 2570 | QUrl{ "hifi/commerce/purchases/Purchases.qml" }, | 2805 | QUrl{ "hifi/commerce/purchases/Purchases.qml" }, |
| @@ -2577,7 +2812,6 @@ void Application::initializeUi() { · 6 unmodified lines | |||
| 2577 | QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" }, | 2812 | QUrl{ "hifi/commerce/wallet/SecurityImageChange.qml" }, |
| 2578 | QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" }, | 2813 | QUrl{ "hifi/commerce/wallet/SecurityImageModel.qml" }, |
| 2579 | QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" }, | 2814 | QUrl{ "hifi/commerce/wallet/SecurityImageSelection.qml" }, |
| 2580 | QUrl{ "hifi/commerce/wallet/sendMoney/SendMoney.qml" }, | ||
| 2581 | QUrl{ "hifi/commerce/wallet/Wallet.qml" }, | 2815 | QUrl{ "hifi/commerce/wallet/Wallet.qml" }, |
| 2582 | QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, | 2816 | QUrl{ "hifi/commerce/wallet/WalletHome.qml" }, |
| 2583 | QUrl{ "hifi/commerce/wallet/WalletSetup.qml" }, | 2817 | QUrl{ "hifi/commerce/wallet/WalletSetup.qml" }, |
| @@ -2623,6 +2857,9 @@ void Application::initializeUi() { · 39 unmodified lines | |||
| 2623 | offscreenUi->resume(); | 2857 | offscreenUi->resume(); |
| 2624 | connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ | 2858 | connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ |
| 2625 | resizeGL(); | 2859 | resizeGL(); |
| 2860 | if (_touchscreenVirtualPadDevice) { | ||
| 2861 | _touchscreenVirtualPadDevice->resize(); | ||
| 2862 | } | ||
| 2626 | }); | 2863 | }); |
| 2627 | 2864 | ||
| 2628 | // This will set up the input plugins UI | 2865 | // This will set up the input plugins UI |
| @@ -2636,6 +2873,13 @@ void Application::initializeUi() { · 7 unmodified lines | |||
| 2636 | } | 2873 | } |
| 2637 | if (TouchscreenVirtualPadDevice::NAME == inputPlugin->getName()) { | 2874 | if (TouchscreenVirtualPadDevice::NAME == inputPlugin->getName()) { |
| 2638 | _touchscreenVirtualPadDevice = std::dynamic_pointer_cast<TouchscreenVirtualPadDevice>(inputPlugin); | 2875 | _touchscreenVirtualPadDevice = std::dynamic_pointer_cast<TouchscreenVirtualPadDevice>(inputPlugin); |
| 2876 | #if defined(Q_OS_ANDROID) | ||
| 2877 | auto& virtualPadManager = VirtualPad::Manager::instance(); | ||
| 2878 | connect(&virtualPadManager, &VirtualPad::Manager::hapticFeedbackRequested, | ||
| 2879 | this, [](int duration) { | ||
| 2880 | AndroidHelper::instance().performHapticFeedback(duration); | ||
| 2881 | }); | ||
| 2882 | #endif | ||
| 2639 | } | 2883 | } |
| 2640 | } | 2884 | } |
| 2641 | 2885 | ||
| @@ -2652,6 +2896,33 @@ void Application::initializeUi() { · 10 unmodified lines | |||
| 2652 | auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>(); | 2896 | auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>(); |
| 2653 | offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1); | 2897 | offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1); |
| 2654 | offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2); | 2898 | offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2); |
| 2899 | |||
| 2900 | flushMenuUpdates(); | ||
| 2901 | |||
| 2902 | // Now that the menu is instantiated, ensure the display plugin menu is properly updated | ||
| 2903 | { | ||
| 2904 | auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); | ||
| 2905 | // first sort the plugins into groupings: standard, advanced, developer | ||
| 2906 | std::stable_sort(displayPlugins.begin(), displayPlugins.end(), | ||
| 2907 | [](const DisplayPluginPointer& a, const DisplayPluginPointer& b)->bool { return a->getGrouping() < b->getGrouping(); }); | ||
| 2908 | |||
| 2909 | int dpIndex = 1; | ||
| 2910 | // concatenate the groupings into a single list in the order: standard, advanced, developer | ||
| 2911 | for(const auto& displayPlugin : displayPlugins) { | ||
| 2912 | addDisplayPluginToMenu(displayPlugin, dpIndex, _displayPlugin == displayPlugin); | ||
| 2913 | dpIndex++; | ||
| 2914 | } | ||
| 2915 | |||
| 2916 | // after all plugins have been added to the menu, add a separator to the menu | ||
| 2917 | auto parent = getPrimaryMenu()->getMenu(MenuOption::OutputMenu); | ||
| 2918 | parent->addSeparator(); | ||
| 2919 | } | ||
| 2920 | |||
| 2921 | // The display plugins are created before the menu now, so we need to do this here to hide the menu bar | ||
| 2922 | // now that it exists | ||
| 2923 | if (_window && _window->isFullScreen()) { | ||
| 2924 | setFullscreen(nullptr, true); | ||
| 2925 | } | ||
| 2655 | } | 2926 | } |
| 2656 | 2927 | ||
| 2657 | 2928 | ||
| @@ -2731,6 +3002,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { · 73 unmodified lines | |||
| 2731 | surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data()); | 3002 | surfaceContext->setContextProperty("Selection", DependencyManager::get<SelectionScriptingInterface>().data()); |
| 2732 | surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); | 3003 | surfaceContext->setContextProperty("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); |
| 2733 | surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data()); | 3004 | surfaceContext->setContextProperty("Wallet", DependencyManager::get<WalletScriptingInterface>().data()); |
| 3005 | surfaceContext->setContextProperty("HiFiAbout", AboutUtil::getInstance()); | ||
| 2734 | 3006 | ||
| 2735 | if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { | 3007 | if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { |
| 2736 | surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); | 3008 | surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); |
| @@ -2744,9 +3016,11 @@ void Application::onDesktopRootItemCreated(QQuickItem* rootItem) { · 7 unmodified lines | |||
| 2744 | auto surfaceContext = DependencyManager::get<OffscreenUi>()->getSurfaceContext(); | 3016 | auto surfaceContext = DependencyManager::get<OffscreenUi>()->getSurfaceContext(); |
| 2745 | surfaceContext->setContextProperty("Stats", Stats::getInstance()); | 3017 | surfaceContext->setContextProperty("Stats", Stats::getInstance()); |
| 2746 | 3018 | ||
| 3019 | #if !defined(Q_OS_ANDROID) | ||
| 2747 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); | 3020 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 2748 | auto qml = PathUtils::qmlUrl("AvatarInputsBar.qml"); | 3021 | auto qml = PathUtils::qmlUrl("AvatarInputsBar.qml"); |
| 2749 | offscreenUi->show(qml, "AvatarInputsBar"); | 3022 | offscreenUi->show(qml, "AvatarInputsBar"); |
| 3023 | #endif | ||
| 2750 | } | 3024 | } |
| 2751 | 3025 | ||
| 2752 | void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { | 3026 | void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { |
| @@ -2797,7 +3071,7 @@ void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { · 44 unmodified lines | |||
| 2797 | _thirdPersonHMDCameraBoomValid = false; | 3071 | _thirdPersonHMDCameraBoomValid = false; |
| 2798 | 3072 | ||
| 2799 | _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); | 3073 | _myCamera.setOrientation(myAvatar->getHead()->getOrientation()); |
| 2800 | if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) { | 3074 | if (isOptionChecked(MenuOption::CenterPlayerInView)) { |
| 2801 | _myCamera.setPosition(myAvatar->getDefaultEyePosition() | 3075 | _myCamera.setPosition(myAvatar->getDefaultEyePosition() |
| 2802 | + _myCamera.getOrientation() * boomOffset); | 3076 | + _myCamera.getOrientation() * boomOffset); |
| 2803 | } | 3077 | } |
| @@ -2974,7 +3248,8 @@ void Application::resizeGL() { · 170 unmodified lines | |||
| 2974 | // Set the desired FBO texture size. If it hasn't changed, this does nothing. | 3248 | // Set the desired FBO texture size. If it hasn't changed, this does nothing. |
| 2975 | // Otherwise, it must rebuild the FBOs | 3249 | // Otherwise, it must rebuild the FBOs |
| 2976 | uvec2 framebufferSize = displayPlugin->getRecommendedRenderSize(); | 3250 | uvec2 framebufferSize = displayPlugin->getRecommendedRenderSize(); |
| 2977 | uvec2 renderSize = uvec2(vec2(framebufferSize) * getRenderResolutionScale()); | 3251 | float renderResolutionScale = getRenderResolutionScale(); |
| 3252 | uvec2 renderSize = uvec2(vec2(framebufferSize) * renderResolutionScale); | ||
| 2978 | if (_renderResolution != renderSize) { | 3253 | if (_renderResolution != renderSize) { |
| 2979 | _renderResolution = renderSize; | 3254 | _renderResolution = renderSize; |
| 2980 | DependencyManager::get<FramebufferCache>()->setFrameBufferSize(fromGlm(renderSize)); | 3255 | DependencyManager::get<FramebufferCache>()->setFrameBufferSize(fromGlm(renderSize)); |
| @@ -2991,13 +3266,13 @@ void Application::resizeGL() { · 10 unmodified lines | |||
| 2991 | } | 3266 | } |
| 2992 | 3267 | ||
| 2993 | DependencyManager::get<OffscreenUi>()->resize(fromGlm(displayPlugin->getRecommendedUiSize())); | 3268 | DependencyManager::get<OffscreenUi>()->resize(fromGlm(displayPlugin->getRecommendedUiSize())); |
| 3269 | displayPlugin->setRenderResolutionScale(renderResolutionScale); | ||
| 2994 | } | 3270 | } |
| 2995 | 3271 | ||
| 2996 | void Application::handleSandboxStatus(QNetworkReply* reply) { | 3272 | void Application::handleSandboxStatus(QNetworkReply* reply) { |
| 2997 | PROFILE_RANGE(render, __FUNCTION__); | 3273 | PROFILE_RANGE(render, __FUNCTION__); |
| 2998 | 3274 | ||
| 2999 | bool sandboxIsRunning = SandboxUtils::readStatus(reply->readAll()); | 3275 | bool sandboxIsRunning = SandboxUtils::readStatus(reply->readAll()); |
| 3000 | qDebug() << "HandleSandboxStatus" << sandboxIsRunning; | ||
| 3001 | 3276 | ||
| 3002 | enum HandControllerType { | 3277 | enum HandControllerType { |
| 3003 | Vive, | 3278 | Vive, |
| @@ -3050,16 +3325,17 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { · 46 unmodified lines | |||
| 3050 | // If this is a first run we short-circuit the address passed in | 3325 | // If this is a first run we short-circuit the address passed in |
| 3051 | if (firstRun.get()) { | 3326 | if (firstRun.get()) { |
| 3052 | #if !defined(Q_OS_ANDROID) | 3327 | #if !defined(Q_OS_ANDROID) |
| 3053 | showHelp(); | ||
| 3054 | #endif | ||
| 3055 | DependencyManager::get<AddressManager>()->goToEntry(); | 3328 | DependencyManager::get<AddressManager>()->goToEntry(); |
| 3056 | sentTo = SENT_TO_ENTRY; | 3329 | sentTo = SENT_TO_ENTRY; |
| 3330 | #endif | ||
| 3057 | firstRun.set(false); | 3331 | firstRun.set(false); |
| 3058 | 3332 | ||
| 3059 | } else { | 3333 | } else { |
| 3334 | #if !defined(Q_OS_ANDROID) | ||
| 3060 | qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); | 3335 | qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); |
| 3061 | DependencyManager::get<AddressManager>()->loadSettings(addressLookupString); | 3336 | DependencyManager::get<AddressManager>()->loadSettings(addressLookupString); |
| 3062 | sentTo = SENT_TO_PREVIOUS_LOCATION; | 3337 | sentTo = SENT_TO_PREVIOUS_LOCATION; |
| 3338 | #endif | ||
| 3063 | } | 3339 | } |
| 3064 | 3340 | ||
| 3065 | UserActivityLogger::getInstance().logAction("startup_sent_to", { | 3341 | UserActivityLogger::getInstance().logAction("startup_sent_to", { |
| @@ -3148,6 +3424,10 @@ void Application::loadServerlessDomain(QUrl domainURL) { · 82 unmodified lines | |||
| 3148 | tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), 0, 0, 0); | 3424 | tmpTree->sendEntities(&_entityEditSender, getEntities()->getTree(), 0, 0, 0); |
| 3149 | } | 3425 | } |
| 3150 | 3426 | ||
| 3427 | std::map<QString, QString> namedPaths = tmpTree->getNamedPaths(); | ||
| 3428 | nodeList->getDomainHandler().connectedToServerless(namedPaths); | ||
| 3429 | |||
| 3430 | |||
| 3151 | _fullSceneReceivedCounter++; | 3431 | _fullSceneReceivedCounter++; |
| 3152 | } | 3432 | } |
| 3153 | 3433 | ||
| @@ -3369,7 +3649,6 @@ void Application::keyPressEvent(QKeyEvent* event) { · 215 unmodified lines | |||
| 3369 | _keysPressed.insert(event->key()); | 3649 | _keysPressed.insert(event->key()); |
| 3370 | 3650 | ||
| 3371 | _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts | 3651 | _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts |
| 3372 | |||
| 3373 | // if one of our scripts have asked to capture this event, then stop processing it | 3652 | // if one of our scripts have asked to capture this event, then stop processing it |
| 3374 | if (_controllerScriptingInterface->isKeyCaptured(event)) { | 3653 | if (_controllerScriptingInterface->isKeyCaptured(event)) { |
| 3375 | return; | 3654 | return; |
| @@ -3395,9 +3674,21 @@ void Application::keyPressEvent(QKeyEvent* event) { · 19 unmodified lines | |||
| 3395 | } | 3674 | } |
| 3396 | break; | 3675 | break; |
| 3397 | 3676 | ||
| 3398 | case Qt::Key_1: | 3677 | case Qt::Key_1: { |
| 3399 | case Qt::Key_2: | 3678 | Menu* menu = Menu::getInstance(); |
| 3400 | case Qt::Key_3: | 3679 | menu->triggerOption(MenuOption::FirstPerson); |
| 3680 | break; | ||
| 3681 | } | ||
| 3682 | case Qt::Key_2: { | ||
| 3683 | Menu* menu = Menu::getInstance(); | ||
| 3684 | menu->triggerOption(MenuOption::FullscreenMirror); | ||
| 3685 | break; | ||
| 3686 | } | ||
| 3687 | case Qt::Key_3: { | ||
| 3688 | Menu* menu = Menu::getInstance(); | ||
| 3689 | menu->triggerOption(MenuOption::ThirdPerson); | ||
| 3690 | break; | ||
| 3691 | } | ||
| 3401 | case Qt::Key_4: | 3692 | case Qt::Key_4: |
| 3402 | case Qt::Key_5: | 3693 | case Qt::Key_5: |
| 3403 | case Qt::Key_6: | 3694 | case Qt::Key_6: |
| @@ -3447,19 +3738,28 @@ void Application::keyPressEvent(QKeyEvent* event) { · 43 unmodified lines | |||
| 3447 | if (isShifted && isMeta) { | 3738 | if (isShifted && isMeta) { |
| 3448 | Menu::getInstance()->triggerOption(MenuOption::Log); | 3739 | Menu::getInstance()->triggerOption(MenuOption::Log); |
| 3449 | } else if (isMeta) { | 3740 | } else if (isMeta) { |
| 3450 | Menu::getInstance()->triggerOption(MenuOption::AddressBar); | 3741 | auto dialogsManager = DependencyManager::get<DialogsManager>(); |
| 3742 | dialogsManager->toggleAddressBar(); | ||
| 3451 | } else if (isShifted) { | 3743 | } else if (isShifted) { |
| 3452 | Menu::getInstance()->triggerOption(MenuOption::LodTools); | 3744 | Menu::getInstance()->triggerOption(MenuOption::LodTools); |
| 3453 | } | 3745 | } |
| 3454 | break; | 3746 | break; |
| 3455 | 3747 | ||
| 3748 | case Qt::Key_R: | ||
| 3749 | if (isMeta && !event->isAutoRepeat()) { | ||
| 3750 | DependencyManager::get<ScriptEngines>()->reloadAllScripts(); | ||
| 3751 | DependencyManager::get<OffscreenUi>()->clearCache(); | ||
| 3752 | } | ||
| 3753 | break; | ||
| 3754 | |||
| 3456 | case Qt::Key_Asterisk: | 3755 | case Qt::Key_Asterisk: |
| 3457 | Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox); | 3756 | Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox); |
| 3458 | break; | 3757 | break; |
| 3459 | 3758 | ||
| 3460 | case Qt::Key_M: | 3759 | case Qt::Key_M: |
| 3461 | if (isMeta) { | 3760 | if (isMeta) { |
| 3462 | DependencyManager::get<AudioClient>()->toggleMute(); | 3761 | auto audioClient = DependencyManager::get<AudioClient>(); |
| 3762 | audioClient->setMuted(!audioClient->isMuted()); | ||
| 3463 | } | 3763 | } |
| 3464 | break; | 3764 | break; |
| 3465 | 3765 | ||
| @@ -3479,13 +3779,16 @@ void Application::keyPressEvent(QKeyEvent* event) { · 13 unmodified lines | |||
| 3479 | AudioInjectorOptions options; | 3779 | AudioInjectorOptions options; |
| 3480 | options.localOnly = true; | 3780 | options.localOnly = true; |
| 3481 | options.stereo = true; | 3781 | options.stereo = true; |
| 3482 | 3782 | Setting::Handle<bool> notificationSounds{ MenuOption::NotificationSounds, true}; | |
| 3483 | if (_snapshotSoundInjector) { | 3783 | Setting::Handle<bool> notificationSoundSnapshot{ MenuOption::NotificationSoundsSnapshot, true}; |
| 3484 | _snapshotSoundInjector->setOptions(options); | 3784 | if (notificationSounds.get() && notificationSoundSnapshot.get()) { |
| 3485 | _snapshotSoundInjector->restart(); | 3785 | if (_snapshotSoundInjector) { |
| 3486 | } else { | 3786 | _snapshotSoundInjector->setOptions(options); |
| 3487 | QByteArray samples = _snapshotSound->getByteArray(); | 3787 | _snapshotSoundInjector->restart(); |
| 3488 | _snapshotSoundInjector = AudioInjector::playSound(samples, options); | 3788 | } else { |
| 3789 | QByteArray samples = _snapshotSound->getByteArray(); | ||
| 3790 | _snapshotSoundInjector = AudioInjector::playSound(samples, options); | ||
| 3791 | } | ||
| 3489 | } | 3792 | } |
| 3490 | takeSnapshot(true); | 3793 | takeSnapshot(true); |
| 3491 | break; | 3794 | break; |
| @@ -3504,7 +3807,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 12 unmodified lines | |||
| 3504 | } else { | 3807 | } else { |
| 3505 | showCursor(Cursor::Icon::DEFAULT); | 3808 | showCursor(Cursor::Icon::DEFAULT); |
| 3506 | } | 3809 | } |
| 3507 | } else { | 3810 | } else if (!event->isAutoRepeat()){ |
| 3508 | resetSensors(true); | 3811 | resetSensors(true); |
| 3509 | } | 3812 | } |
| 3510 | break; | 3813 | break; |
| @@ -3514,68 +3817,6 @@ void Application::keyPressEvent(QKeyEvent* event) { · 3 unmodified lines | |||
| 3514 | Menu::getInstance()->triggerOption(MenuOption::Chat); | 3817 | Menu::getInstance()->triggerOption(MenuOption::Chat); |
| 3515 | break; | 3818 | break; |
| 3516 | 3819 | ||
| 3517 | #if 0 | ||
| 3518 | case Qt::Key_I: | ||
| 3519 | if (isShifted) { | ||
| 3520 | _myCamera.setEyeOffsetOrientation(glm::normalize( | ||
| 3521 | glm::quat(glm::vec3(0.002f, 0, 0)) * _myCamera.getEyeOffsetOrientation())); | ||
| 3522 | } else { | ||
| 3523 | _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0, 0.001, 0)); | ||
| 3524 | } | ||
| 3525 | updateProjectionMatrix(); | ||
| 3526 | break; | ||
| 3527 | |||
| 3528 | case Qt::Key_K: | ||
| 3529 | if (isShifted) { | ||
| 3530 | _myCamera.setEyeOffsetOrientation(glm::normalize( | ||
| 3531 | glm::quat(glm::vec3(-0.002f, 0, 0)) * _myCamera.getEyeOffsetOrientation())); | ||
| 3532 | } else { | ||
| 3533 | _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0, -0.001, 0)); | ||
| 3534 | } | ||
| 3535 | updateProjectionMatrix(); | ||
| 3536 | break; | ||
| 3537 | |||
| 3538 | case Qt::Key_J: | ||
| 3539 | if (isShifted) { | ||
| 3540 | QMutexLocker viewLocker(&_viewMutex); | ||
| 3541 | _viewFrustum.setFocalLength(_viewFrustum.getFocalLength() - 0.1f); | ||
| 3542 | } else { | ||
| 3543 | _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(-0.001, 0, 0)); | ||
| 3544 | } | ||
| 3545 | updateProjectionMatrix(); | ||
| 3546 | break; | ||
| 3547 | |||
| 3548 | case Qt::Key_M: | ||
| 3549 | if (isShifted) { | ||
| 3550 | QMutexLocker viewLocker(&_viewMutex); | ||
| 3551 | _viewFrustum.setFocalLength(_viewFrustum.getFocalLength() + 0.1f); | ||
| 3552 | } else { | ||
| 3553 | _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0.001, 0, 0)); | ||
| 3554 | } | ||
| 3555 | updateProjectionMatrix(); | ||
| 3556 | break; | ||
| 3557 | |||
| 3558 | case Qt::Key_U: | ||
| 3559 | if (isShifted) { | ||
| 3560 | _myCamera.setEyeOffsetOrientation(glm::normalize( | ||
| 3561 | glm::quat(glm::vec3(0, 0, -0.002f)) * _myCamera.getEyeOffsetOrientation())); | ||
| 3562 | } else { | ||
| 3563 | _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0, 0, -0.001)); | ||
| 3564 | } | ||
| 3565 | updateProjectionMatrix(); | ||
| 3566 | break; | ||
| 3567 | |||
| 3568 | case Qt::Key_Y: | ||
| 3569 | if (isShifted) { | ||
| 3570 | _myCamera.setEyeOffsetOrientation(glm::normalize( | ||
| 3571 | glm::quat(glm::vec3(0, 0, 0.002f)) * _myCamera.getEyeOffsetOrientation())); | ||
| 3572 | } else { | ||
| 3573 | _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0, 0, 0.001)); | ||
| 3574 | } | ||
| 3575 | updateProjectionMatrix(); | ||
| 3576 | break; | ||
| 3577 | #endif | ||
| 3578 | |||
| 3579 | case Qt::Key_Slash: | 3820 | case Qt::Key_Slash: |
| 3580 | Menu::getInstance()->triggerOption(MenuOption::Stats); | 3821 | Menu::getInstance()->triggerOption(MenuOption::Stats); |
| 3581 | break; | 3822 | break; |
| @@ -3618,6 +3859,12 @@ void Application::keyPressEvent(QKeyEvent* event) { · 36 unmodified lines | |||
| 3618 | void Application::keyReleaseEvent(QKeyEvent* event) { | 3859 | void Application::keyReleaseEvent(QKeyEvent* event) { |
| 3619 | _keysPressed.remove(event->key()); | 3860 | _keysPressed.remove(event->key()); |
| 3620 | 3861 | ||
| 3862 | #if defined(Q_OS_ANDROID) | ||
| 3863 | if (event->key() == Qt::Key_Back) { | ||
| 3864 | event->accept(); | ||
| 3865 | AndroidHelper::instance().requestActivity("Home", false); | ||
| 3866 | } | ||
| 3867 | #endif | ||
| 3621 | _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts | 3868 | _controllerScriptingInterface->emitKeyReleaseEvent(event); // send events to any registered scripts |
| 3622 | 3869 | ||
| 3623 | // if one of our scripts have asked to capture this event, then stop processing it | 3870 | // if one of our scripts have asked to capture this event, then stop processing it |
| @@ -3937,7 +4184,7 @@ bool Application::acceptSnapshot(const QString& urlString) { · 313 unmodified lines | |||
| 3937 | QUrl url(urlString); | 4184 | QUrl url(urlString); |
| 3938 | QString snapshotPath = url.toLocalFile(); | 4185 | QString snapshotPath = url.toLocalFile(); |
| 3939 | 4186 | ||
| 3940 | SnapshotMetaData* snapshotData = Snapshot::parseSnapshotData(snapshotPath); | 4187 | SnapshotMetaData* snapshotData = DependencyManager::get<Snapshot>()->parseSnapshotData(snapshotPath); |
| 3941 | if (snapshotData) { | 4188 | if (snapshotData) { |
| 3942 | if (!snapshotData->getURL().toString().isEmpty()) { | 4189 | if (!snapshotData->getURL().toString().isEmpty()) { |
| 3943 | DependencyManager::get<AddressManager>()->handleLookupString(snapshotData->getURL().toString()); | 4190 | DependencyManager::get<AddressManager>()->handleLookupString(snapshotData->getURL().toString()); |
| @@ -3952,7 +4199,7 @@ bool Application::acceptSnapshot(const QString& urlString) { · 8 unmodified lines | |||
| 3952 | static uint32_t _renderedFrameIndex { INVALID_FRAME }; | 4199 | static uint32_t _renderedFrameIndex { INVALID_FRAME }; |
| 3953 | 4200 | ||
| 3954 | bool Application::shouldPaint() const { | 4201 | bool Application::shouldPaint() const { |
| 3955 | if (_aboutToQuit) { | 4202 | if (_aboutToQuit || _window->isMinimized()) { |
| 3956 | return false; | 4203 | return false; |
| 3957 | } | 4204 | } |
| 3958 | 4205 | ||
| @@ -4348,12 +4595,6 @@ void Application::idle() { · 389 unmodified lines | |||
| 4348 | 4595 | ||
| 4349 | _overlayConductor.update(secondsSinceLastUpdate); | 4596 | _overlayConductor.update(secondsSinceLastUpdate); |
| 4350 | 4597 | ||
| 4351 | auto myAvatar = getMyAvatar(); | ||
| 4352 | if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { | ||
| 4353 | Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); | ||
| 4354 | Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); | ||
| 4355 | cameraMenuChanged(); | ||
| 4356 | } | ||
| 4357 | _gameLoopCounter.increment(); | 4598 | _gameLoopCounter.increment(); |
| 4358 | } | 4599 | } |
| 4359 | 4600 | ||
| @@ -4518,12 +4759,15 @@ void Application::loadSettings() { · 158 unmodified lines | |||
| 4518 | // DONT CHECK IN | 4759 | // DONT CHECK IN |
| 4519 | //DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false); | 4760 | //DependencyManager::get<LODManager>()->setAutomaticLODAdjust(false); |
| 4520 | 4761 | ||
| 4521 | Menu::getInstance()->loadSettings(); | 4762 | auto menu = Menu::getInstance(); |
| 4763 | menu->loadSettings(); | ||
| 4764 | |||
| 4765 | // override the menu option show overlays to always be true on startup | ||
| 4766 | menu->setIsOptionChecked(MenuOption::Overlays, true); | ||
| 4522 | 4767 | ||
| 4523 | // If there is a preferred plugin, we probably messed it up with the menu settings, so fix it. | 4768 | // If there is a preferred plugin, we probably messed it up with the menu settings, so fix it. |
| 4524 | auto pluginManager = PluginManager::getInstance(); | 4769 | auto pluginManager = PluginManager::getInstance(); |
| 4525 | auto plugins = pluginManager->getPreferredDisplayPlugins(); | 4770 | auto plugins = pluginManager->getPreferredDisplayPlugins(); |
| 4526 | auto menu = Menu::getInstance(); | ||
| 4527 | if (plugins.size() > 0) { | 4771 | if (plugins.size() > 0) { |
| 4528 | for (auto plugin : plugins) { | 4772 | for (auto plugin : plugins) { |
| 4529 | if (auto action = menu->getActionForOption(plugin->getName())) { | 4773 | if (auto action = menu->getActionForOption(plugin->getName())) { |
| @@ -4609,11 +4853,8 @@ QVector<EntityItemID> Application::pasteEntities(float x, float y, float z) { · 79 unmodified lines | |||
| 4609 | return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), x, y, z); | 4853 | return _entityClipboard->sendEntities(&_entityEditSender, getEntities()->getTree(), x, y, z); |
| 4610 | } | 4854 | } |
| 4611 | 4855 | ||
| 4612 | void Application::initDisplay() { | ||
| 4613 | } | ||
| 4614 | |||
| 4615 | void Application::init() { | 4856 | void Application::init() { |
| 4616 | 4857 | _offscreenContext->makeCurrent(); | |
| 4617 | // Make sure Login state is up to date | 4858 | // Make sure Login state is up to date |
| 4618 | DependencyManager::get<DialogsManager>()->toggleLoginDialog(); | 4859 | DependencyManager::get<DialogsManager>()->toggleLoginDialog(); |
| 4619 | if (!DISABLE_DEFERRED) { | 4860 | if (!DISABLE_DEFERRED) { |
| @@ -4688,6 +4929,31 @@ void Application::init() { · 68 unmodified lines | |||
| 4688 | }, Qt::QueuedConnection); | 4929 | }, Qt::QueuedConnection); |
| 4689 | } | 4930 | } |
| 4690 | 4931 | ||
| 4932 | void Application::loadAvatarScripts(const QVector<QString>& urls) { | ||
| 4933 | auto scriptEngines = DependencyManager::get<ScriptEngines>(); | ||
| 4934 | auto runningScripts = scriptEngines->getRunningScripts(); | ||
| 4935 | for (auto url : urls) { | ||
| 4936 | int index = runningScripts.indexOf(url); | ||
| 4937 | if (index < 0) { | ||
| 4938 | auto scriptEnginePointer = scriptEngines->loadScript(url, false); | ||
| 4939 | if (scriptEnginePointer) { | ||
| 4940 | scriptEnginePointer->setType(ScriptEngine::Type::AVATAR); | ||
| 4941 | } | ||
| 4942 | } | ||
| 4943 | } | ||
| 4944 | } | ||
| 4945 | |||
| 4946 | void Application::unloadAvatarScripts() { | ||
| 4947 | auto scriptEngines = DependencyManager::get<ScriptEngines>(); | ||
| 4948 | auto urls = scriptEngines->getRunningScripts(); | ||
| 4949 | for (auto url : urls) { | ||
| 4950 | auto scriptEngine = scriptEngines->getScriptEngine(url); | ||
| 4951 | if (scriptEngine->getType() == ScriptEngine::Type::AVATAR) { | ||
| 4952 | scriptEngines->stopScript(url, false); | ||
| 4953 | } | ||
| 4954 | } | ||
| 4955 | } | ||
| 4956 | |||
| 4691 | void Application::updateLOD(float deltaTime) const { | 4957 | void Application::updateLOD(float deltaTime) const { |
| 4692 | PerformanceTimer perfTimer("LOD"); | 4958 | PerformanceTimer perfTimer("LOD"); |
| 4693 | // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode | 4959 | // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode |
| @@ -4703,7 +4969,7 @@ void Application::updateLOD(float deltaTime) const { · 9 unmodified lines | |||
| 4703 | } | 4969 | } |
| 4704 | } | 4970 | } |
| 4705 | 4971 | ||
| 4706 | void Application::pushPostUpdateLambda(void* key, std::function<void()> func) { | 4972 | void Application::pushPostUpdateLambda(void* key, const std::function<void()>& func) { |
| 4707 | std::unique_lock<std::mutex> guard(_postUpdateLambdasLock); | 4973 | std::unique_lock<std::mutex> guard(_postUpdateLambdasLock); |
| 4708 | _postUpdateLambdas[key] = func; | 4974 | _postUpdateLambdas[key] = func; |
| 4709 | } | 4975 | } |
| @@ -4819,12 +5085,12 @@ void Application::updateThreads(float deltaTime) { · 109 unmodified lines | |||
| 4819 | 5085 | ||
| 4820 | void Application::toggleOverlays() { | 5086 | void Application::toggleOverlays() { |
| 4821 | auto menu = Menu::getInstance(); | 5087 | auto menu = Menu::getInstance(); |
| 4822 | menu->setIsOptionChecked(MenuOption::Overlays, menu->isOptionChecked(MenuOption::Overlays)); | 5088 | menu->setIsOptionChecked(MenuOption::Overlays, !menu->isOptionChecked(MenuOption::Overlays)); |
| 4823 | } | 5089 | } |
| 4824 | 5090 | ||
| 4825 | void Application::setOverlaysVisible(bool visible) { | 5091 | void Application::setOverlaysVisible(bool visible) { |
| 4826 | auto menu = Menu::getInstance(); | 5092 | auto menu = Menu::getInstance(); |
| 4827 | menu->setIsOptionChecked(MenuOption::Overlays, true); | 5093 | menu->setIsOptionChecked(MenuOption::Overlays, visible); |
| 4828 | } | 5094 | } |
| 4829 | 5095 | ||
| 4830 | void Application::centerUI() { | 5096 | void Application::centerUI() { |
| @@ -4878,6 +5144,21 @@ void Application::cameraModeChanged() { · 47 unmodified lines | |||
| 4878 | cameraMenuChanged(); | 5144 | cameraMenuChanged(); |
| 4879 | } | 5145 | } |
| 4880 | 5146 | ||
| 5147 | void Application::changeViewAsNeeded(float boomLength) { | ||
| 5148 | // Switch between first and third person views as needed | ||
| 5149 | // This is called when the boom length has changed | ||
| 5150 | bool boomLengthGreaterThanMinimum = (boomLength > MyAvatar::ZOOM_MIN); | ||
| 5151 | |||
| 5152 | if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON && boomLengthGreaterThanMinimum) { | ||
| 5153 | Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, false); | ||
| 5154 | Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, true); | ||
| 5155 | cameraMenuChanged(); | ||
| 5156 | } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON && !boomLengthGreaterThanMinimum) { | ||
| 5157 | Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, true); | ||
| 5158 | Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, false); | ||
| 5159 | cameraMenuChanged(); | ||
| 5160 | } | ||
| 5161 | } | ||
| 4881 | 5162 | ||
| 4882 | void Application::cameraMenuChanged() { | 5163 | void Application::cameraMenuChanged() { |
| 4883 | auto menu = Menu::getInstance(); | 5164 | auto menu = Menu::getInstance(); |
| @@ -4926,7 +5207,7 @@ void Application::reloadResourceCaches() { · 42 unmodified lines | |||
| 4926 | resetPhysicsReadyInformation(); | 5207 | resetPhysicsReadyInformation(); |
| 4927 | 5208 | ||
| 4928 | // Query the octree to refresh everything in view | 5209 | // Query the octree to refresh everything in view |
| 4929 | _lastQueriedTime = 0; | 5210 | _queryExpiry = SteadyClock::now(); |
| 4930 | _octreeQuery.incrementConnectionID(); | 5211 | _octreeQuery.incrementConnectionID(); |
| 4931 | 5212 | ||
| 4932 | queryOctree(NodeType::EntityServer, PacketType::EntityQuery); | 5213 | queryOctree(NodeType::EntityServer, PacketType::EntityQuery); |
| @@ -5060,6 +5341,78 @@ void Application::updateDialogs(float deltaTime) const { · 127 unmodified lines | |||
| 5060 | } | 5341 | } |
| 5061 | } | 5342 | } |
| 5062 | 5343 | ||
| 5344 | void Application::updateSecondaryCameraViewFrustum() { | ||
| 5345 | // TODO: Fix this by modeling the way the secondary camera works on how the main camera works | ||
| 5346 | // ie. Use a camera object stored in the game logic and informs the Engine on where the secondary | ||
| 5347 | // camera should be. | ||
| 5348 | |||
| 5349 | // Code based on SecondaryCameraJob | ||
| 5350 | auto renderConfig = _renderEngine->getConfiguration(); | ||
| 5351 | assert(renderConfig); | ||
| 5352 | auto camera = dynamic_cast<SecondaryCameraJobConfig*>(renderConfig->getConfig("SecondaryCamera")); | ||
| 5353 | |||
| 5354 | if (!camera || !camera->isEnabled()) { | ||
| 5355 | return; | ||
| 5356 | } | ||
| 5357 | |||
| 5358 | ViewFrustum secondaryViewFrustum; | ||
| 5359 | if (camera->mirrorProjection && !camera->attachedEntityId.isNull()) { | ||
| 5360 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | ||
| 5361 | auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId); | ||
| 5362 | glm::vec3 mirrorPropertiesPosition = entityProperties.getPosition(); | ||
| 5363 | glm::quat mirrorPropertiesRotation = entityProperties.getRotation(); | ||
| 5364 | glm::vec3 mirrorPropertiesDimensions = entityProperties.getDimensions(); | ||
| 5365 | glm::vec3 halfMirrorPropertiesDimensions = 0.5f * mirrorPropertiesDimensions; | ||
| 5366 | |||
| 5367 | // setup mirror from world as inverse of world from mirror transformation using inverted x and z for mirrored image | ||
| 5368 | // TODO: we are assuming here that UP is world y-axis | ||
| 5369 | glm::mat4 worldFromMirrorRotation = glm::mat4_cast(mirrorPropertiesRotation) * glm::scale(vec3(-1.0f, 1.0f, -1.0f)); | ||
| 5370 | glm::mat4 worldFromMirrorTranslation = glm::translate(mirrorPropertiesPosition); | ||
| 5371 | glm::mat4 worldFromMirror = worldFromMirrorTranslation * worldFromMirrorRotation; | ||
| 5372 | glm::mat4 mirrorFromWorld = glm::inverse(worldFromMirror); | ||
| 5373 | |||
| 5374 | // get mirror camera position by reflecting main camera position's z coordinate in mirror space | ||
| 5375 | glm::vec3 mainCameraPositionWorld = getCamera().getPosition(); | ||
| 5376 | glm::vec3 mainCameraPositionMirror = vec3(mirrorFromWorld * vec4(mainCameraPositionWorld, 1.0f)); | ||
| 5377 | glm::vec3 mirrorCameraPositionMirror = vec3(mainCameraPositionMirror.x, mainCameraPositionMirror.y, | ||
| 5378 | -mainCameraPositionMirror.z); | ||
| 5379 | glm::vec3 mirrorCameraPositionWorld = vec3(worldFromMirror * vec4(mirrorCameraPositionMirror, 1.0f)); | ||
| 5380 | |||
| 5381 | // set frustum position to be mirrored camera and set orientation to mirror's adjusted rotation | ||
| 5382 | glm::quat mirrorCameraOrientation = glm::quat_cast(worldFromMirrorRotation); | ||
| 5383 | secondaryViewFrustum.setPosition(mirrorCameraPositionWorld); | ||
| 5384 | secondaryViewFrustum.setOrientation(mirrorCameraOrientation); | ||
| 5385 | |||
| 5386 | // build frustum using mirror space translation of mirrored camera | ||
| 5387 | float nearClip = mirrorCameraPositionMirror.z + mirrorPropertiesDimensions.z * 2.0f; | ||
| 5388 | glm::vec3 upperRight = halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; | ||
| 5389 | glm::vec3 bottomLeft = -halfMirrorPropertiesDimensions - mirrorCameraPositionMirror; | ||
| 5390 | glm::mat4 frustum = glm::frustum(bottomLeft.x, upperRight.x, bottomLeft.y, upperRight.y, nearClip, camera->farClipPlaneDistance); | ||
| 5391 | secondaryViewFrustum.setProjection(frustum); | ||
| 5392 | } else { | ||
| 5393 | if (!camera->attachedEntityId.isNull()) { | ||
| 5394 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | ||
| 5395 | auto entityProperties = entityScriptingInterface->getEntityProperties(camera->attachedEntityId); | ||
| 5396 | secondaryViewFrustum.setPosition(entityProperties.getPosition()); | ||
| 5397 | secondaryViewFrustum.setOrientation(entityProperties.getRotation()); | ||
| 5398 | } else { | ||
| 5399 | secondaryViewFrustum.setPosition(camera->position); | ||
| 5400 | secondaryViewFrustum.setOrientation(camera->orientation); | ||
| 5401 | } | ||
| 5402 | |||
| 5403 | float aspectRatio = (float)camera->textureWidth / (float)camera->textureHeight; | ||
| 5404 | secondaryViewFrustum.setProjection(camera->vFoV, | ||
| 5405 | aspectRatio, | ||
| 5406 | camera->nearClipPlaneDistance, | ||
| 5407 | camera->farClipPlaneDistance); | ||
| 5408 | } | ||
| 5409 | // Without calculating the bound planes, the secondary camera will use the same culling frustum as the main camera, | ||
| 5410 | // which is not what we want here. | ||
| 5411 | secondaryViewFrustum.calculate(); | ||
| 5412 | |||
| 5413 | _conicalViews.push_back(secondaryViewFrustum); | ||
| 5414 | } | ||
| 5415 | |||
| 5063 | static bool domainLoadingInProgress = false; | 5416 | static bool domainLoadingInProgress = false; |
| 5064 | 5417 | ||
| 5065 | void Application::update(float deltaTime) { | 5418 | void Application::update(float deltaTime) { |
| @@ -5084,7 +5437,7 @@ void Application::update(float deltaTime) { · 18 unmodified lines | |||
| 5084 | // process octree stats packets are sent in between full sends of a scene (this isn't currently true). | 5437 | // process octree stats packets are sent in between full sends of a scene (this isn't currently true). |
| 5085 | // We keep physics disabled until we've received a full scene and everything near the avatar in that | 5438 | // We keep physics disabled until we've received a full scene and everything near the avatar in that |
| 5086 | // scene is ready to compute its collision shape. | 5439 | // scene is ready to compute its collision shape. |
| 5087 | if (nearbyEntitiesAreReadyForPhysics()) { | 5440 | if (nearbyEntitiesAreReadyForPhysics() && getMyAvatar()->isReadyForPhysics()) { |
| 5088 | _physicsEnabled = true; | 5441 | _physicsEnabled = true; |
| 5089 | getMyAvatar()->updateMotionBehaviorFromMenu(); | 5442 | getMyAvatar()->updateMotionBehaviorFromMenu(); |
| 5090 | } | 5443 | } |
| @@ -5117,7 +5470,7 @@ void Application::update(float deltaTime) { · 26 unmodified lines | |||
| 5117 | if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) { | 5470 | if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) { |
| 5118 | if (_lastFaceTrackerUpdate > 0 | 5471 | if (_lastFaceTrackerUpdate > 0 |
| 5119 | && ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { | 5472 | && ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { |
| 5120 | audioClient->toggleMute(); | 5473 | audioClient->setMuted(true); |
| 5121 | _lastFaceTrackerUpdate = 0; | 5474 | _lastFaceTrackerUpdate = 0; |
| 5122 | } | 5475 | } |
| 5123 | } else { | 5476 | } else { |
| @@ -5258,12 +5611,12 @@ void Application::update(float deltaTime) { · 134 unmodified lines | |||
| 5258 | QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>(); | 5611 | QSharedPointer<AvatarManager> avatarManager = DependencyManager::get<AvatarManager>(); |
| 5259 | 5612 | ||
| 5260 | { | 5613 | { |
| 5261 | PROFILE_RANGE(simulation_physics, "Physics"); | 5614 | PROFILE_RANGE(simulation_physics, "Simulation"); |
| 5262 | PerformanceTimer perfTimer("physics"); | 5615 | PerformanceTimer perfTimer("simulation"); |
| 5263 | if (_physicsEnabled) { | 5616 | if (_physicsEnabled) { |
| 5264 | { | 5617 | { |
| 5265 | PROFILE_RANGE(simulation_physics, "PreStep"); | 5618 | PROFILE_RANGE(simulation_physics, "PrePhysics"); |
| 5266 | PerformanceTimer perfTimer("preStep)"); | 5619 | PerformanceTimer perfTimer("prePhysics)"); |
| 5267 | { | 5620 | { |
| 5268 | const VectorOfMotionStates& motionStates = _entitySimulation->getObjectsToRemoveFromPhysics(); | 5621 | const VectorOfMotionStates& motionStates = _entitySimulation->getObjectsToRemoveFromPhysics(); |
| 5269 | _physicsEngine->removeObjects(motionStates); | 5622 | _physicsEngine->removeObjects(motionStates); |
| @@ -5297,59 +5650,63 @@ void Application::update(float deltaTime) { · 27 unmodified lines | |||
| 5297 | }); | 5650 | }); |
| 5298 | } | 5651 | } |
| 5299 | { | 5652 | { |
| 5300 | PROFILE_RANGE(simulation_physics, "Step"); | 5653 | PROFILE_RANGE(simulation_physics, "StepPhysics"); |
| 5301 | PerformanceTimer perfTimer("step"); | 5654 | PerformanceTimer perfTimer("stepPhysics"); |
| 5302 | getEntities()->getTree()->withWriteLock([&] { | 5655 | getEntities()->getTree()->withWriteLock([&] { |
| 5303 | _physicsEngine->stepSimulation(); | 5656 | _physicsEngine->stepSimulation(); |
| 5304 | }); | 5657 | }); |
| 5305 | } | 5658 | } |
| 5306 | { | 5659 | { |
| 5307 | PROFILE_RANGE(simulation_physics, "PostStep"); | ||
| 5308 | PerformanceTimer perfTimer("postStep"); | ||
| 5309 | if (_physicsEngine->hasOutgoingChanges()) { | 5660 | if (_physicsEngine->hasOutgoingChanges()) { |
| 5310 | // grab the collision events BEFORE handleOutgoingChanges() because at this point | 5661 | { |
| 5311 | // we have a better idea of which objects we own or should own. | 5662 | PROFILE_RANGE(simulation_physics, "PostPhysics"); |
| 5312 | auto& collisionEvents = _physicsEngine->getCollisionEvents(); | 5663 | PerformanceTimer perfTimer("postPhysics"); |
| 5313 | 5664 | // grab the collision events BEFORE handleChangedMotionStates() because at this point | |
| 5314 | getEntities()->getTree()->withWriteLock([&] { | 5665 | // we have a better idea of which objects we own or should own. |
| 5315 | PROFILE_RANGE(simulation_physics, "HandleChanges"); | 5666 | auto& collisionEvents = _physicsEngine->getCollisionEvents(); |
| 5316 | PerformanceTimer perfTimer("handleChanges"); | 5667 | |
| 5317 | 5668 | getEntities()->getTree()->withWriteLock([&] { | |
| 5318 | const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates(); | 5669 | PROFILE_RANGE(simulation_physics, "HandleChanges"); |
| 5319 | _entitySimulation->handleChangedMotionStates(outgoingChanges); | 5670 | PerformanceTimer perfTimer("handleChanges"); |
| 5320 | avatarManager->handleChangedMotionStates(outgoingChanges); | 5671 | |
| 5321 | 5672 | const VectorOfMotionStates& outgoingChanges = _physicsEngine->getChangedMotionStates(); | |
| 5322 | const VectorOfMotionStates& deactivations = _physicsEngine->getDeactivatedMotionStates(); | 5673 | _entitySimulation->handleChangedMotionStates(outgoingChanges); |
| 5323 | _entitySimulation->handleDeactivatedMotionStates(deactivations); | 5674 | avatarManager->handleChangedMotionStates(outgoingChanges); |
| 5324 | }); | 5675 | |
| 5676 | const VectorOfMotionStates& deactivations = _physicsEngine->getDeactivatedMotionStates(); | ||
| 5677 | _entitySimulation->handleDeactivatedMotionStates(deactivations); | ||
| 5678 | }); | ||
| 5679 | |||
| 5680 | if (!_aboutToQuit) { | ||
| 5681 | // handleCollisionEvents() AFTER handleChangedMotionStates() | ||
| 5682 | { | ||
| 5683 | PROFILE_RANGE(simulation_physics, "CollisionEvents"); | ||
| 5684 | avatarManager->handleCollisionEvents(collisionEvents); | ||
| 5685 | // Collision events (and their scripts) must not be handled when we're locked, above. (That would risk | ||
| 5686 | // deadlock.) | ||
| 5687 | _entitySimulation->handleCollisionEvents(collisionEvents); | ||
| 5688 | } | ||
| 5689 | } | ||
| 5325 | 5690 | ||
| 5326 | if (!_aboutToQuit) { | ||
| 5327 | // handleCollisionEvents() AFTER handleOutgoingChanges() | ||
| 5328 | { | 5691 | { |
| 5329 | PROFILE_RANGE(simulation_physics, "CollisionEvents"); | 5692 | PROFILE_RANGE(simulation_physics, "MyAvatar"); |
| 5330 | avatarManager->handleCollisionEvents(collisionEvents); | 5693 | myAvatar->harvestResultsFromPhysicsSimulation(deltaTime); |
| 5331 | // Collision events (and their scripts) must not be handled when we're locked, above. (That would risk | ||
| 5332 | // deadlock.) | ||
| 5333 | _entitySimulation->handleCollisionEvents(collisionEvents); | ||
| 5334 | } | 5694 | } |
| 5335 | 5695 | ||
| 5336 | // NOTE: the getEntities()->update() call below will wait for lock | 5696 | if (PerformanceTimer::isActive() && |
| 5337 | // and will simulate entity motion (the EntityTree has been given an EntitySimulation). | 5697 | Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && |
| 5338 | getEntities()->update(true); // update the models... | 5698 | Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsTiming)) { |
| 5339 | } | 5699 | _physicsEngine->harvestPerformanceStats(); |
| 5340 | 5700 | } | |
| 5341 | { | 5701 | // NOTE: the PhysicsEngine stats are written to stdout NOT to Qt log framework |
| 5342 | PROFILE_RANGE(simulation_physics, "MyAvatar"); | 5702 | _physicsEngine->dumpStatsIfNecessary(); |
| 5343 | myAvatar->harvestResultsFromPhysicsSimulation(deltaTime); | ||
| 5344 | } | 5703 | } |
| 5345 | 5704 | ||
| 5346 | if (PerformanceTimer::isActive() && | 5705 | if (!_aboutToQuit) { |
| 5347 | Menu::getInstance()->isOptionChecked(MenuOption::DisplayDebugTimingDetails) && | 5706 | // NOTE: the getEntities()->update() call below will wait for lock |
| 5348 | Menu::getInstance()->isOptionChecked(MenuOption::ExpandPhysicsSimulationTiming)) { | 5707 | // and will provide non-physical entity motion |
| 5349 | _physicsEngine->harvestPerformanceStats(); | 5708 | getEntities()->update(true); // update the models... |
| 5350 | } | 5709 | } |
| 5351 | // NOTE: the PhysicsEngine stats are written to stdout NOT to Qt log framework | ||
| 5352 | _physicsEngine->dumpStatsIfNecessary(); | ||
| 5353 | } | 5710 | } |
| 5354 | } | 5711 | } |
| 5355 | } else { | 5712 | } else { |
| @@ -5409,6 +5766,13 @@ void Application::update(float deltaTime) { · 53 unmodified lines | |||
| 5409 | { | 5766 | { |
| 5410 | QMutexLocker viewLocker(&_viewMutex); | 5767 | QMutexLocker viewLocker(&_viewMutex); |
| 5411 | _myCamera.loadViewFrustum(_viewFrustum); | 5768 | _myCamera.loadViewFrustum(_viewFrustum); |
| 5769 | |||
| 5770 | _conicalViews.clear(); | ||
| 5771 | _conicalViews.push_back(_viewFrustum); | ||
| 5772 | // TODO: Fix this by modeling the way the secondary camera works on how the main camera works | ||
| 5773 | // ie. Use a camera object stored in the game logic and informs the Engine on where the secondary | ||
| 5774 | // camera should be. | ||
| 5775 | updateSecondaryCameraViewFrustum(); | ||
| 5412 | } | 5776 | } |
| 5413 | 5777 | ||
| 5414 | quint64 now = usecTimestampNow(); | 5778 | quint64 now = usecTimestampNow(); |
| @@ -5418,18 +5782,31 @@ void Application::update(float deltaTime) { · 3 unmodified lines | |||
| 5418 | PROFILE_RANGE_EX(app, "QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); | 5782 | PROFILE_RANGE_EX(app, "QueryOctree", 0xffff0000, (uint64_t)getActiveDisplayPlugin()->presentCount()); |
| 5419 | PerformanceTimer perfTimer("queryOctree"); | 5783 | PerformanceTimer perfTimer("queryOctree"); |
| 5420 | QMutexLocker viewLocker(&_viewMutex); | 5784 | QMutexLocker viewLocker(&_viewMutex); |
| 5421 | quint64 sinceLastQuery = now - _lastQueriedTime; | 5785 | |
| 5422 | const quint64 TOO_LONG_SINCE_LAST_QUERY = 3 * USECS_PER_SECOND; | 5786 | bool viewIsDifferentEnough = false; |
| 5423 | bool queryIsDue = sinceLastQuery > TOO_LONG_SINCE_LAST_QUERY; | 5787 | if (_conicalViews.size() == _lastQueriedViews.size()) { |
| 5424 | bool viewIsDifferentEnough = !_lastQueriedViewFrustum.isVerySimilar(_viewFrustum); | 5788 | for (size_t i = 0; i < _conicalViews.size(); ++i) { |
| 5789 | if (!_conicalViews[i].isVerySimilar(_lastQueriedViews[i])) { | ||
| 5790 | viewIsDifferentEnough = true; | ||
| 5791 | break; | ||
| 5792 | } | ||
| 5793 | } | ||
| 5794 | } else { | ||
| 5795 | viewIsDifferentEnough = true; | ||
| 5796 | } | ||
| 5797 | |||
| 5798 | |||
| 5425 | // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it | 5799 | // if it's been a while since our last query or the view has significantly changed then send a query, otherwise suppress it |
| 5426 | if (queryIsDue || viewIsDifferentEnough) { | 5800 | static const std::chrono::seconds MIN_PERIOD_BETWEEN_QUERIES { 3 }; |
| 5427 | _lastQueriedTime = now; | 5801 | auto now = SteadyClock::now(); |
| 5802 | if (now > _queryExpiry || viewIsDifferentEnough) { | ||
| 5428 | if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) { | 5803 | if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) { |
| 5429 | queryOctree(NodeType::EntityServer, PacketType::EntityQuery); | 5804 | queryOctree(NodeType::EntityServer, PacketType::EntityQuery); |
| 5430 | } | 5805 | } |
| 5431 | sendAvatarViewFrustum(); | 5806 | queryAvatars(); |
| 5432 | _lastQueriedViewFrustum = _viewFrustum; | 5807 | |
| 5808 | _lastQueriedViews = _conicalViews; | ||
| 5809 | _queryExpiry = now + MIN_PERIOD_BETWEEN_QUERIES; | ||
| 5433 | } | 5810 | } |
| 5434 | } | 5811 | } |
| 5435 | 5812 | ||
| @@ -5469,6 +5846,28 @@ void Application::update(float deltaTime) { · 33 unmodified lines | |||
| 5469 | } | 5846 | } |
| 5470 | 5847 | ||
| 5471 | 5848 | ||
| 5849 | updateRenderArgs(deltaTime); | ||
| 5850 | |||
| 5851 | // HACK | ||
| 5852 | // load the view frustum | ||
| 5853 | // FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering. | ||
| 5854 | // Then we can move this logic into the Avatar::simulate call. | ||
| 5855 | myAvatar->preDisplaySide(&_appRenderArgs._renderArgs); | ||
| 5856 | |||
| 5857 | |||
| 5858 | { | ||
| 5859 | PerformanceTimer perfTimer("AnimDebugDraw"); | ||
| 5860 | AnimDebugDraw::getInstance().update(); | ||
| 5861 | } | ||
| 5862 | |||
| 5863 | |||
| 5864 | { // Game loop is done, mark the end of the frame for the scene transactions and the render loop to take over | ||
| 5865 | PerformanceTimer perfTimer("enqueueFrame"); | ||
| 5866 | getMain3DScene()->enqueueFrame(); | ||
| 5867 | } | ||
| 5868 | } | ||
| 5869 | |||
| 5870 | void Application::updateRenderArgs(float deltaTime) { | ||
| 5472 | editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) { | 5871 | editRenderArgs([this, deltaTime](AppRenderArgs& appRenderArgs) { |
| 5473 | PerformanceTimer perfTimer("editRenderArgs"); | 5872 | PerformanceTimer perfTimer("editRenderArgs"); |
| 5474 | appRenderArgs._headPose = getHMDSensorPose(); | 5873 | appRenderArgs._headPose = getHMDSensorPose(); |
| @@ -5492,9 +5891,9 @@ void Application::update(float deltaTime) { · 17 unmodified lines | |||
| 5492 | QMutexLocker viewLocker(&_viewMutex); | 5891 | QMutexLocker viewLocker(&_viewMutex); |
| 5493 | // adjust near clip plane to account for sensor scaling. | 5892 | // adjust near clip plane to account for sensor scaling. |
| 5494 | auto adjustedProjection = glm::perspective(glm::radians(_fieldOfView.get()), | 5893 | auto adjustedProjection = glm::perspective(glm::radians(_fieldOfView.get()), |
| 5495 | getActiveDisplayPlugin()->getRecommendedAspectRatio(), | 5894 | getActiveDisplayPlugin()->getRecommendedAspectRatio(), |
| 5496 | DEFAULT_NEAR_CLIP * sensorToWorldScale, | 5895 | DEFAULT_NEAR_CLIP * sensorToWorldScale, |
| 5497 | DEFAULT_FAR_CLIP); | 5896 | DEFAULT_FAR_CLIP); |
| 5498 | _viewFrustum.setProjection(adjustedProjection); | 5897 | _viewFrustum.setProjection(adjustedProjection); |
| 5499 | _viewFrustum.calculate(); | 5898 | _viewFrustum.calculate(); |
| 5500 | } | 5899 | } |
| @@ -5510,8 +5909,14 @@ void Application::update(float deltaTime) { · 9 unmodified lines | |||
| 5510 | } | 5909 | } |
| 5511 | { | 5910 | { |
| 5512 | PROFILE_RANGE(render, "/resizeGL"); | 5911 | PROFILE_RANGE(render, "/resizeGL"); |
| 5513 | PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings)); | 5912 | bool showWarnings = false; |
| 5514 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | 5913 | bool suppressShortTimings = false; |
| 5914 | auto menu = Menu::getInstance(); | ||
| 5915 | if (menu) { | ||
| 5916 | suppressShortTimings = menu->isOptionChecked(MenuOption::SuppressShortTimings); | ||
| 5917 | showWarnings = menu->isOptionChecked(MenuOption::PipelineWarnings); | ||
| 5918 | } | ||
| 5919 | PerformanceWarning::setSuppressShortTimings(suppressShortTimings); | ||
| 5515 | PerformanceWarning warn(showWarnings, "Application::paintGL()"); | 5920 | PerformanceWarning warn(showWarnings, "Application::paintGL()"); |
| 5516 | resizeGL(); | 5921 | resizeGL(); |
| 5517 | } | 5922 | } |
| @@ -5567,12 +5972,6 @@ void Application::update(float deltaTime) { · 49 unmodified lines | |||
| 5567 | } | 5972 | } |
| 5568 | } | 5973 | } |
| 5569 | 5974 | ||
| 5570 | // HACK | ||
| 5571 | // load the view frustum | ||
| 5572 | // FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering. | ||
| 5573 | // Then we can move this logic into the Avatar::simulate call. | ||
| 5574 | myAvatar->preDisplaySide(&appRenderArgs._renderArgs); | ||
| 5575 | |||
| 5576 | { | 5975 | { |
| 5577 | QMutexLocker viewLocker(&_viewMutex); | 5976 | QMutexLocker viewLocker(&_viewMutex); |
| 5578 | _myCamera.loadViewFrustum(_displayViewFrustum); | 5977 | _myCamera.loadViewFrustum(_displayViewFrustum); |
| @@ -5584,22 +5983,22 @@ void Application::update(float deltaTime) { · 5 unmodified lines | |||
| 5584 | appRenderArgs._renderArgs.setViewFrustum(_displayViewFrustum); | 5983 | appRenderArgs._renderArgs.setViewFrustum(_displayViewFrustum); |
| 5585 | } | 5984 | } |
| 5586 | }); | 5985 | }); |
| 5986 | } | ||
| 5587 | 5987 | ||
| 5588 | { | 5988 | void Application::queryAvatars() { |
| 5589 | PerformanceTimer perfTimer("AnimDebugDraw"); | 5989 | auto avatarPacket = NLPacket::create(PacketType::AvatarQuery); |
| 5590 | AnimDebugDraw::getInstance().update(); | 5990 | auto destinationBuffer = reinterpret_cast<unsigned char*>(avatarPacket->getPayload()); |
| 5591 | } | 5991 | unsigned char* bufferStart = destinationBuffer; |
| 5592 | 5992 | ||
| 5593 | { // Game loop is done, mark the end of the frame for the scene transactions and the render loop to take over | 5993 | uint8_t numFrustums = (uint8_t)_conicalViews.size(); |
| 5594 | PerformanceTimer perfTimer("enqueueFrame"); | 5994 | memcpy(destinationBuffer, &numFrustums, sizeof(numFrustums)); |
| 5595 | getMain3DScene()->enqueueFrame(); | 5995 | destinationBuffer += sizeof(numFrustums); |
| 5996 | |||
| 5997 | for (const auto& view : _conicalViews) { | ||
| 5998 | destinationBuffer += view.serialize(destinationBuffer); | ||
| 5596 | } | 5999 | } |
| 5597 | } | ||
| 5598 | 6000 | ||
| 5599 | void Application::sendAvatarViewFrustum() { | 6001 | avatarPacket->setPayloadSize(destinationBuffer - bufferStart); |
| 5600 | QByteArray viewFrustumByteArray = _viewFrustum.toByteArray(); | ||
| 5601 | auto avatarPacket = NLPacket::create(PacketType::ViewFrustum, viewFrustumByteArray.size()); | ||
| 5602 | avatarPacket->write(viewFrustumByteArray); | ||
| 5603 | 6002 | ||
| 5604 | DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); | 6003 | DependencyManager::get<NodeList>()->broadcastToNodes(std::move(avatarPacket), NodeSet() << NodeType::AvatarMixer); |
| 5605 | } | 6004 | } |
| @@ -5661,16 +6060,8 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType) { · 55 unmodified lines | |||
| 5661 | return; // bail early if settings are not loaded | 6060 | return; // bail early if settings are not loaded |
| 5662 | } | 6061 | } |
| 5663 | 6062 | ||
| 5664 | ViewFrustum viewFrustum; | 6063 | _octreeQuery.setConicalViews(_conicalViews); |
| 5665 | copyViewFrustum(viewFrustum); | 6064 | |
| 5666 | _octreeQuery.setCameraPosition(viewFrustum.getPosition()); | ||
| 5667 | _octreeQuery.setCameraOrientation(viewFrustum.getOrientation()); | ||
| 5668 | _octreeQuery.setCameraFov(viewFrustum.getFieldOfView()); | ||
| 5669 | _octreeQuery.setCameraAspectRatio(viewFrustum.getAspectRatio()); | ||
| 5670 | _octreeQuery.setCameraNearClip(viewFrustum.getNearClip()); | ||
| 5671 | _octreeQuery.setCameraFarClip(viewFrustum.getFarClip()); | ||
| 5672 | _octreeQuery.setCameraEyeOffsetPosition(glm::vec3()); | ||
| 5673 | _octreeQuery.setCameraCenterRadius(viewFrustum.getCenterRadius()); | ||
| 5674 | auto lodManager = DependencyManager::get<LODManager>(); | 6065 | auto lodManager = DependencyManager::get<LODManager>(); |
| 5675 | _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); | 6066 | _octreeQuery.setOctreeSizeScale(lodManager->getOctreeSizeScale()); |
| 5676 | _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); | 6067 | _octreeQuery.setBoundaryLevelAdjust(lodManager->getBoundaryLevelAdjust()); |
| @@ -5768,7 +6159,9 @@ void Application::updateWindowTitle() const { · 91 unmodified lines | |||
| 5768 | auto nodeList = DependencyManager::get<NodeList>(); | 6159 | auto nodeList = DependencyManager::get<NodeList>(); |
| 5769 | auto accountManager = DependencyManager::get<AccountManager>(); | 6160 | auto accountManager = DependencyManager::get<AccountManager>(); |
| 5770 | 6161 | ||
| 5771 | QString buildVersion = " (build " + applicationVersion() + ")"; | 6162 | QString buildVersion = " - " |
| 6163 | + (BuildInfo::BUILD_TYPE == BuildInfo::BuildType::Stable ? QString("Version") : QString("Build")) | ||
| 6164 | + " " + applicationVersion(); | ||
| 5772 | 6165 | ||
| 5773 | QString loginStatus = accountManager->isLoggedIn() ? "" : " (NOT LOGGED IN)"; | 6166 | QString loginStatus = accountManager->isLoggedIn() ? "" : " (NOT LOGGED IN)"; |
| 5774 | 6167 | ||
| @@ -5879,7 +6272,7 @@ void Application::nodeActivated(SharedNodePointer node) { · 104 unmodified lines | |||
| 5879 | // If we get a new EntityServer activated, reset lastQueried time | 6272 | // If we get a new EntityServer activated, reset lastQueried time |
| 5880 | // so we will do a proper query during update | 6273 | // so we will do a proper query during update |
| 5881 | if (node->getType() == NodeType::EntityServer) { | 6274 | if (node->getType() == NodeType::EntityServer) { |
| 5882 | _lastQueriedTime = 0; | 6275 | _queryExpiry = SteadyClock::now(); |
| 5883 | _octreeQuery.incrementConnectionID(); | 6276 | _octreeQuery.incrementConnectionID(); |
| 5884 | } | 6277 | } |
| 5885 | 6278 | ||
| @@ -5888,6 +6281,8 @@ void Application::nodeActivated(SharedNodePointer node) { · 2 unmodified lines | |||
| 5888 | } | 6281 | } |
| 5889 | 6282 | ||
| 5890 | if (node->getType() == NodeType::AvatarMixer) { | 6283 | if (node->getType() == NodeType::AvatarMixer) { |
| 6284 | _queryExpiry = SteadyClock::now(); | ||
| 6285 | |||
| 5891 | // new avatar mixer, send off our identity packet on next update loop | 6286 | // new avatar mixer, send off our identity packet on next update loop |
| 5892 | // Reset skeletonModelUrl if the last server modified our choice. | 6287 | // Reset skeletonModelUrl if the last server modified our choice. |
| 5893 | // Override the avatar url (but not model name) here too. | 6288 | // Override the avatar url (but not model name) here too. |
| @@ -5900,6 +6295,9 @@ void Application::nodeActivated(SharedNodePointer node) { · 6 unmodified lines | |||
| 5900 | } | 6295 | } |
| 5901 | getMyAvatar()->markIdentityDataChanged(); | 6296 | getMyAvatar()->markIdentityDataChanged(); |
| 5902 | getMyAvatar()->resetLastSent(); | 6297 | getMyAvatar()->resetLastSent(); |
| 6298 | |||
| 6299 | // transmit a "sendAll" packet to the AvatarMixer we just connected to. | ||
| 6300 | getMyAvatar()->sendAvatarDataPacket(true); | ||
| 5903 | } | 6301 | } |
| 5904 | } | 6302 | } |
| 5905 | 6303 | ||
| @@ -6005,9 +6403,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { · 99 unmodified lines | |||
| 6005 | bool result = true; | 6403 | bool result = true; |
| 6006 | foreach (EntityItemPointer entity, entities) { | 6404 | foreach (EntityItemPointer entity, entities) { |
| 6007 | if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) { | 6405 | if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) { |
| 6008 | static QString repeatedMessage = | 6406 | HIFI_FCDEBUG(interfaceapp(), "Physics disabled until entity loads: " << entity->getID() << entity->getName()); |
| 6009 | LogHandler::getInstance().addRepeatedMessageRegex("Physics disabled until entity loads: .*"); | ||
| 6010 | qCDebug(interfaceapp) << "Physics disabled until entity loads: " << entity->getID() << entity->getName(); | ||
| 6011 | // don't break here because we want all the relevant entities to start their downloads | 6407 | // don't break here because we want all the relevant entities to start their downloads |
| 6012 | result = false; | 6408 | result = false; |
| 6013 | } | 6409 | } |
| @@ -6191,8 +6587,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointe · 177 unmodified lines | |||
| 6191 | scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); | 6587 | scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data()); |
| 6192 | scriptEngine->registerGlobalObject("Wallet", DependencyManager::get<WalletScriptingInterface>().data()); | 6588 | scriptEngine->registerGlobalObject("Wallet", DependencyManager::get<WalletScriptingInterface>().data()); |
| 6193 | scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get<AddressManager>().data()); | 6589 | scriptEngine->registerGlobalObject("AddressManager", DependencyManager::get<AddressManager>().data()); |
| 6194 | 6590 | scriptEngine->registerGlobalObject("HifiAbout", AboutUtil::getInstance()); | |
| 6195 | scriptEngine->registerGlobalObject("App", this); | ||
| 6196 | 6591 | ||
| 6197 | qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); | 6592 | qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue); |
| 6198 | 6593 | ||
| @@ -6510,12 +6905,7 @@ void Application::showDialog(const QUrl& widgetUrl, const QUrl& tabletUrl, const · 311 unmodified lines | |||
| 6510 | if (onTablet) { | 6905 | if (onTablet) { |
| 6511 | toggleTabletUI(true); | 6906 | toggleTabletUI(true); |
| 6512 | } | 6907 | } |
| 6513 | } | 6908 | } else { |
| 6514 | |||
| 6515 | if (!onTablet) { | ||
| 6516 | DependencyManager::get<OffscreenUi>()->show(widgetUrl, name); | ||
| 6517 | } | ||
| 6518 | if (tablet->getToolbarMode()) { | ||
| 6519 | DependencyManager::get<OffscreenUi>()->show(widgetUrl, name); | 6909 | DependencyManager::get<OffscreenUi>()->show(widgetUrl, name); |
| 6520 | } | 6910 | } |
| 6521 | } | 6911 | } |
| @@ -6569,7 +6959,7 @@ void Application::addAssetToWorldFromURL(QString url) { · 47 unmodified lines | |||
| 6569 | } else { | 6959 | } else { |
| 6570 | filename.remove(".zip"); | 6960 | filename.remove(".zip"); |
| 6571 | } | 6961 | } |
| 6572 | 6962 | ||
| 6573 | } | 6963 | } |
| 6574 | 6964 | ||
| 6575 | if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) { | 6965 | if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) { |
| @@ -6743,7 +7133,7 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q · 167 unmodified lines | |||
| 6743 | addAssetToWorldError(filenameFromPath(filePath), errorInfo); | 7133 | addAssetToWorldError(filenameFromPath(filePath), errorInfo); |
| 6744 | } else { | 7134 | } else { |
| 6745 | // to prevent files that aren't models or texture files from being loaded into world automatically | 7135 | // to prevent files that aren't models or texture files from being loaded into world automatically |
| 6746 | if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION)) || | 7136 | if ((filePath.toLower().endsWith(OBJ_EXTENSION) || filePath.toLower().endsWith(FBX_EXTENSION)) || |
| 6747 | ((filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION)) && | 7137 | ((filePath.toLower().endsWith(JPG_EXTENSION) || filePath.toLower().endsWith(PNG_EXTENSION)) && |
| 6748 | ((!isBlocks) && (!isZip)))) { | 7138 | ((!isBlocks) && (!isZip)))) { |
| 6749 | addAssetToWorldAddEntity(filePath, mapping); | 7139 | addAssetToWorldAddEntity(filePath, mapping); |
| @@ -7137,7 +7527,6 @@ void Application::loadLODToolsDialog() { · 387 unmodified lines | |||
| 7137 | } | 7527 | } |
| 7138 | } | 7528 | } |
| 7139 | 7529 | ||
| 7140 | |||
| 7141 | void Application::loadEntityStatisticsDialog() { | 7530 | void Application::loadEntityStatisticsDialog() { |
| 7142 | auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); | 7531 | auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); |
| 7143 | auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet(SYSTEM_TABLET)); | 7532 | auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet(SYSTEM_TABLET)); |
| @@ -7201,11 +7590,15 @@ void Application::loadAvatarBrowser() const { · 57 unmodified lines | |||
| 7201 | void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) { | 7590 | void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) { |
| 7202 | postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] { | 7591 | postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] { |
| 7203 | // Get a screenshot and save it | 7592 | // Get a screenshot and save it |
| 7204 | QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename); | 7593 | QString path = DependencyManager::get<Snapshot>()->saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename, |
| 7594 | TestScriptingInterface::getInstance()->getTestResultsLocation()); | ||
| 7595 | |||
| 7205 | // If we're not doing an animated snapshot as well... | 7596 | // If we're not doing an animated snapshot as well... |
| 7206 | if (!includeAnimated) { | 7597 | if (!includeAnimated) { |
| 7207 | // Tell the dependency manager that the capture of the still snapshot has taken place. | 7598 | if (!path.isEmpty()) { |
| 7208 | emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(path, notify); | 7599 | // Tell the dependency manager that the capture of the still snapshot has taken place. |
| 7600 | emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(path, notify); | ||
| 7601 | } | ||
| 7209 | } else if (!SnapshotAnimated::isAlreadyTakingSnapshotAnimated()) { | 7602 | } else if (!SnapshotAnimated::isAlreadyTakingSnapshotAnimated()) { |
| 7210 | // Get an animated GIF snapshot and save it | 7603 | // Get an animated GIF snapshot and save it |
| 7211 | SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get<WindowScriptingInterface>()); | 7604 | SnapshotAnimated::saveSnapshotAnimated(path, aspectRatio, qApp, DependencyManager::get<WindowScriptingInterface>()); |
| @@ -7213,30 +7606,42 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa · 1 unmodified line | |||
| 7213 | }); | 7606 | }); |
| 7214 | } | 7607 | } |
| 7215 | 7608 | ||
| 7216 | void Application::takeSecondaryCameraSnapshot(const QString& filename) { | 7609 | void Application::takeSecondaryCameraSnapshot(const bool& notify, const QString& filename) { |
| 7217 | postLambdaEvent([filename, this] { | 7610 | postLambdaEvent([notify, filename, this] { |
| 7218 | QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename); | 7611 | QString snapshotPath = DependencyManager::get<Snapshot>()->saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename, |
| 7219 | emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, true); | 7612 | TestScriptingInterface::getInstance()->getTestResultsLocation()); |
| 7613 | |||
| 7614 | emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, notify); | ||
| 7615 | }); | ||
| 7616 | } | ||
| 7617 | |||
| 7618 | void Application::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const bool& cubemapOutputFormat, const bool& notify, const QString& filename) { | ||
| 7619 | postLambdaEvent([notify, filename, cubemapOutputFormat, cameraPosition] { | ||
| 7620 | DependencyManager::get<Snapshot>()->save360Snapshot(cameraPosition, cubemapOutputFormat, notify, filename); | ||
| 7220 | }); | 7621 | }); |
| 7221 | } | 7622 | } |
| 7222 | 7623 | ||
| 7223 | void Application::shareSnapshot(const QString& path, const QUrl& href) { | 7624 | void Application::shareSnapshot(const QString& path, const QUrl& href) { |
| 7224 | postLambdaEvent([path, href] { | 7625 | postLambdaEvent([path, href] { |
| 7225 | // not much to do here, everything is done in snapshot code... | 7626 | // not much to do here, everything is done in snapshot code... |
| 7226 | Snapshot::uploadSnapshot(path, href); | 7627 | DependencyManager::get<Snapshot>()->uploadSnapshot(path, href); |
| 7227 | }); | 7628 | }); |
| 7228 | } | 7629 | } |
| 7229 | 7630 | ||
| 7230 | float Application::getRenderResolutionScale() const { | 7631 | float Application::getRenderResolutionScale() const { |
| 7231 | if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionOne)) { | 7632 | auto menu = Menu::getInstance(); |
| 7633 | if (!menu) { | ||
| 7634 | return 1.0f; | ||
| 7635 | } | ||
| 7636 | if (menu->isOptionChecked(MenuOption::RenderResolutionOne)) { | ||
| 7232 | return 1.0f; | 7637 | return 1.0f; |
| 7233 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionTwoThird)) { | 7638 | } else if (menu->isOptionChecked(MenuOption::RenderResolutionTwoThird)) { |
| 7234 | return 0.666f; | 7639 | return 0.666f; |
| 7235 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionHalf)) { | 7640 | } else if (menu->isOptionChecked(MenuOption::RenderResolutionHalf)) { |
| 7236 | return 0.5f; | 7641 | return 0.5f; |
| 7237 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionThird)) { | 7642 | } else if (menu->isOptionChecked(MenuOption::RenderResolutionThird)) { |
| 7238 | return 0.333f; | 7643 | return 0.333f; |
| 7239 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::RenderResolutionQuarter)) { | 7644 | } else if (menu->isOptionChecked(MenuOption::RenderResolutionQuarter)) { |
| 7240 | return 0.25f; | 7645 | return 0.25f; |
| 7241 | } else { | 7646 | } else { |
| 7242 | return 1.0f; | 7647 | return 1.0f; |
| @@ -7302,7 +7707,7 @@ void Application::windowMinimizedChanged(bool minimized) { · 59 unmodified lines | |||
| 7302 | } | 7707 | } |
| 7303 | } | 7708 | } |
| 7304 | 7709 | ||
| 7305 | void Application::postLambdaEvent(std::function<void()> f) { | 7710 | void Application::postLambdaEvent(const std::function<void()>& f) { |
| 7306 | if (this->thread() == QThread::currentThread()) { | 7711 | if (this->thread() == QThread::currentThread()) { |
| 7307 | f(); | 7712 | f(); |
| 7308 | } else { | 7713 | } else { |
| @@ -7310,6 +7715,15 @@ void Application::postLambdaEvent(std::function<void()> f) { · 1 unmodified line | |||
| 7310 | } | 7715 | } |
| 7311 | } | 7716 | } |
| 7312 | 7717 | ||
| 7718 | void Application::sendLambdaEvent(const std::function<void()>& f) { | ||
| 7719 | if (this->thread() == QThread::currentThread()) { | ||
| 7720 | f(); | ||
| 7721 | } else { | ||
| 7722 | LambdaEvent event(f); | ||
| 7723 | QCoreApplication::sendEvent(this, &event); | ||
| 7724 | } | ||
| 7725 | } | ||
| 7726 | |||
| 7313 | void Application::initPlugins(const QStringList& arguments) { | 7727 | void Application::initPlugins(const QStringList& arguments) { |
| 7314 | QCommandLineOption display("display", "Preferred displays", "displays"); | 7728 | QCommandLineOption display("display", "Preferred displays", "displays"); |
| 7315 | QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays"); | 7729 | QCommandLineOption disableDisplays("disable-displays", "Displays to disable", "displays"); |
| @@ -7392,8 +7806,8 @@ bool Application::isThrottleRendering() const { · 76 unmodified lines | |||
| 7392 | bool Application::hasFocus() const { | 7806 | bool Application::hasFocus() const { |
| 7393 | bool result = (QApplication::activeWindow() != nullptr); | 7807 | bool result = (QApplication::activeWindow() != nullptr); |
| 7394 | #if defined(Q_OS_WIN) | 7808 | #if defined(Q_OS_WIN) |
| 7395 | // On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't | 7809 | // On Windows, QWidget::activateWindow() - as called in setFocus() - makes the application's taskbar icon flash but doesn't |
| 7396 | // take user focus away from their current window. So also check whether the application is the user's current foreground | 7810 | // take user focus away from their current window. So also check whether the application is the user's current foreground |
| 7397 | // window. | 7811 | // window. |
| 7398 | result = result && (HWND)QApplication::activeWindow()->winId() == GetForegroundWindow(); | 7812 | result = result && (HWND)QApplication::activeWindow()->winId() == GetForegroundWindow(); |
| 7399 | #endif | 7813 | #endif |
| @@ -7401,7 +7815,7 @@ bool Application::hasFocus() const { · 1 unmodified line | |||
| 7401 | } | 7815 | } |
| 7402 | 7816 | ||
| 7403 | void Application::setFocus() { | 7817 | void Application::setFocus() { |
| 7404 | // Note: Windows doesn't allow a user focus to be taken away from another application. Instead, it changes the color of and | 7818 | // Note: Windows doesn't allow a user focus to be taken away from another application. Instead, it changes the color of and |
| 7405 | // flashes the taskbar icon. | 7819 | // flashes the taskbar icon. |
| 7406 | auto window = qApp->getWindow(); | 7820 | auto window = qApp->getWindow(); |
| 7407 | window->activateWindow(); | 7821 | window->activateWindow(); |
| @@ -7451,7 +7865,7 @@ DisplayPluginPointer Application::getActiveDisplayPlugin() const { · 43 unmodified lines | |||
| 7451 | 7865 | ||
| 7452 | static const char* EXCLUSION_GROUP_KEY = "exclusionGroup"; | 7866 | static const char* EXCLUSION_GROUP_KEY = "exclusionGroup"; |
| 7453 | 7867 | ||
| 7454 | static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) { | 7868 | static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, int index, bool active) { |
| 7455 | auto menu = Menu::getInstance(); | 7869 | auto menu = Menu::getInstance(); |
| 7456 | QString name = displayPlugin->getName(); | 7870 | QString name = displayPlugin->getName(); |
| 7457 | auto grouping = displayPlugin->getGrouping(); | 7871 | auto grouping = displayPlugin->getGrouping(); |
| @@ -7478,7 +7892,7 @@ static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool acti · 20 unmodified lines | |||
| 7478 | } | 7892 | } |
| 7479 | auto parent = menu->getMenu(MenuOption::OutputMenu); | 7893 | auto parent = menu->getMenu(MenuOption::OutputMenu); |
| 7480 | auto action = menu->addActionToQMenuAndActionHash(parent, | 7894 | auto action = menu->addActionToQMenuAndActionHash(parent, |
| 7481 | name, 0, qApp, | 7895 | name, QKeySequence(Qt::CTRL + (Qt::Key_0 + index)), qApp, |
| 7482 | SLOT(updateDisplayMode()), | 7896 | SLOT(updateDisplayMode()), |
| 7483 | QAction::NoRole, Menu::UNSPECIFIED_POSITION, groupingMenu); | 7897 | QAction::NoRole, Menu::UNSPECIFIED_POSITION, groupingMenu); |
| 7484 | 7898 | ||
| @@ -7496,66 +7910,24 @@ void Application::updateDisplayMode() { · 11 unmodified lines | |||
| 7496 | qFatal("Attempted to switch display plugins from a non-main thread"); | 7910 | qFatal("Attempted to switch display plugins from a non-main thread"); |
| 7497 | } | 7911 | } |
| 7498 | 7912 | ||
| 7499 | auto menu = Menu::getInstance(); | 7913 | // Once time initialization code that depends on the UI being available |
| 7500 | auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); | 7914 | auto displayPlugins = getDisplayPlugins(); |
| 7501 | |||
| 7502 | static std::once_flag once; | ||
| 7503 | std::call_once(once, [&] { | ||
| 7504 | bool first = true; | ||
| 7505 | |||
| 7506 | // first sort the plugins into groupings: standard, advanced, developer | ||
| 7507 | DisplayPluginList standard; | ||
| 7508 | DisplayPluginList advanced; | ||
| 7509 | DisplayPluginList developer; | ||
| 7510 | foreach(auto displayPlugin, displayPlugins) { | ||
| 7511 | displayPlugin->setContext(_gpuContext); | ||
| 7512 | auto grouping = displayPlugin->getGrouping(); | ||
| 7513 | switch (grouping) { | ||
| 7514 | case Plugin::ADVANCED: | ||
| 7515 | advanced.push_back(displayPlugin); | ||
| 7516 | break; | ||
| 7517 | case Plugin::DEVELOPER: | ||
| 7518 | developer.push_back(displayPlugin); | ||
| 7519 | break; | ||
| 7520 | default: | ||
| 7521 | standard.push_back(displayPlugin); | ||
| 7522 | break; | ||
| 7523 | } | ||
| 7524 | } | ||
| 7525 | |||
| 7526 | // concatenate the groupings into a single list in the order: standard, advanced, developer | ||
| 7527 | standard.insert(std::end(standard), std::begin(advanced), std::end(advanced)); | ||
| 7528 | standard.insert(std::end(standard), std::begin(developer), std::end(developer)); | ||
| 7529 | |||
| 7530 | foreach(auto displayPlugin, standard) { | ||
| 7531 | addDisplayPluginToMenu(displayPlugin, first); | ||
| 7532 | auto displayPluginName = displayPlugin->getName(); | ||
| 7533 | QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) { | ||
| 7534 | resizeGL(); | ||
| 7535 | }); | ||
| 7536 | QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset); | ||
| 7537 | first = false; | ||
| 7538 | } | ||
| 7539 | |||
| 7540 | // after all plugins have been added to the menu, add a separator to the menu | ||
| 7541 | auto menu = Menu::getInstance(); | ||
| 7542 | auto parent = menu->getMenu(MenuOption::OutputMenu); | ||
| 7543 | parent->addSeparator(); | ||
| 7544 | }); | ||
| 7545 | |||
| 7546 | 7915 | ||
| 7547 | // Default to the first item on the list, in case none of the menu items match | 7916 | // Default to the first item on the list, in case none of the menu items match |
| 7548 | DisplayPluginPointer newDisplayPlugin = displayPlugins.at(0); | 7917 | DisplayPluginPointer newDisplayPlugin = displayPlugins.at(0); |
| 7549 | foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { | 7918 | auto menu = getPrimaryMenu(); |
| 7550 | QString name = displayPlugin->getName(); | 7919 | if (menu) { |
| 7551 | QAction* action = menu->getActionForOption(name); | 7920 | foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { |
| 7552 | // Menu might have been removed if the display plugin lost | 7921 | QString name = displayPlugin->getName(); |
| 7553 | if (!action) { | 7922 | QAction* action = menu->getActionForOption(name); |
| 7554 | continue; | 7923 | // Menu might have been removed if the display plugin lost |
| 7555 | } | 7924 | if (!action) { |
| 7556 | if (action->isChecked()) { | 7925 | continue; |
| 7557 | newDisplayPlugin = displayPlugin; | 7926 | } |
| 7558 | break; | 7927 | if (action->isChecked()) { |
| 7928 | newDisplayPlugin = displayPlugin; | ||
| 7929 | break; | ||
| 7930 | } | ||
| 7559 | } | 7931 | } |
| 7560 | } | 7932 | } |
| 7561 | 7933 | ||
| @@ -7563,8 +7935,21 @@ void Application::updateDisplayMode() { · 1 unmodified line | |||
| 7563 | return; | 7935 | return; |
| 7564 | } | 7936 | } |
| 7565 | 7937 | ||
| 7938 | setDisplayPlugin(newDisplayPlugin); | ||
| 7939 | } | ||
| 7940 | |||
| 7941 | void Application::setDisplayPlugin(DisplayPluginPointer newDisplayPlugin) { | ||
| 7942 | if (newDisplayPlugin == _displayPlugin) { | ||
| 7943 | return; | ||
| 7944 | } | ||
| 7945 | |||
| 7946 | // FIXME don't have the application directly set the state of the UI, | ||
| 7947 | // instead emit a signal that the display plugin is changing and let | ||
| 7948 | // the desktop lock itself. Reduces coupling between the UI and display | ||
| 7949 | // plugins | ||
| 7566 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); | 7950 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 7567 | auto desktop = offscreenUi->getDesktop(); | 7951 | auto desktop = offscreenUi->getDesktop(); |
| 7952 | auto menu = Menu::getInstance(); | ||
| 7568 | 7953 | ||
| 7569 | // Make the switch atomic from the perspective of other threads | 7954 | // Make the switch atomic from the perspective of other threads |
| 7570 | { | 7955 | { |
| @@ -7572,8 +7957,8 @@ void Application::updateDisplayMode() { · 1 unmodified line | |||
| 7572 | bool wasRepositionLocked = false; | 7957 | bool wasRepositionLocked = false; |
| 7573 | if (desktop) { | 7958 | if (desktop) { |
| 7574 | // Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below. | 7959 | // Tell the desktop to no reposition (which requires plugin info), until we have set the new plugin, below. |
| 7575 | wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool(); | 7960 | wasRepositionLocked = desktop->property("repositionLocked").toBool(); |
| 7576 | offscreenUi->getDesktop()->setProperty("repositionLocked", true); | 7961 | desktop->setProperty("repositionLocked", true); |
| 7577 | } | 7962 | } |
| 7578 | 7963 | ||
| 7579 | if (_displayPlugin) { | 7964 | if (_displayPlugin) { |
| @@ -7585,6 +7970,8 @@ void Application::updateDisplayMode() { · 5 unmodified lines | |||
| 7585 | bool active = newDisplayPlugin->activate(); | 7970 | bool active = newDisplayPlugin->activate(); |
| 7586 | 7971 | ||
| 7587 | if (!active) { | 7972 | if (!active) { |
| 7973 | auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); | ||
| 7974 | |||
| 7588 | // If the new plugin fails to activate, fallback to last display | 7975 | // If the new plugin fails to activate, fallback to last display |
| 7589 | qWarning() << "Failed to activate display: " << newDisplayPlugin->getName(); | 7976 | qWarning() << "Failed to activate display: " << newDisplayPlugin->getName(); |
| 7590 | newDisplayPlugin = oldDisplayPlugin; | 7977 | newDisplayPlugin = oldDisplayPlugin; |
| @@ -7605,13 +7992,6 @@ void Application::updateDisplayMode() { · 14 unmodified lines | |||
| 7605 | if (!active) { | 7992 | if (!active) { |
| 7606 | qFatal("Failed to activate fallback plugin"); | 7993 | qFatal("Failed to activate fallback plugin"); |
| 7607 | } | 7994 | } |
| 7608 | |||
| 7609 | // We've changed the selection - it should be reflected in the menu | ||
| 7610 | QAction* action = menu->getActionForOption(newDisplayPlugin->getName()); | ||
| 7611 | if (!action) { | ||
| 7612 | qFatal("Failed to find activated plugin"); | ||
| 7613 | } | ||
| 7614 | action->setChecked(true); | ||
| 7615 | } | 7995 | } |
| 7616 | 7996 | ||
| 7617 | offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize())); | 7997 | offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize())); |
| @@ -7638,14 +8018,21 @@ void Application::updateDisplayMode() { · 20 unmodified lines | |||
| 7638 | getMyAvatar()->reset(false); | 8018 | getMyAvatar()->reset(false); |
| 7639 | 8019 | ||
| 7640 | // switch to first person if entering hmd and setting is checked | 8020 | // switch to first person if entering hmd and setting is checked |
| 7641 | if (isHmd && menu->isOptionChecked(MenuOption::FirstPersonHMD)) { | 8021 | if (menu) { |
| 7642 | menu->setIsOptionChecked(MenuOption::FirstPerson, true); | 8022 | QAction* action = menu->getActionForOption(newDisplayPlugin->getName()); |
| 7643 | cameraMenuChanged(); | 8023 | if (action) { |
| 8024 | action->setChecked(true); | ||
| 8025 | } | ||
| 8026 | |||
| 8027 | if (isHmd && menu->isOptionChecked(MenuOption::FirstPersonHMD)) { | ||
| 8028 | menu->setIsOptionChecked(MenuOption::FirstPerson, true); | ||
| 8029 | cameraMenuChanged(); | ||
| 8030 | } | ||
| 8031 | |||
| 8032 | // Remove the mirror camera option from menu if in HMD mode | ||
| 8033 | auto mirrorAction = menu->getActionForOption(MenuOption::FullscreenMirror); | ||
| 8034 | mirrorAction->setVisible(!isHmd); | ||
| 7644 | } | 8035 | } |
| 7645 | |||
| 7646 | // Remove the mirror camera option from menu if in HMD mode | ||
| 7647 | auto mirrorAction = menu->getActionForOption(MenuOption::FullscreenMirror); | ||
| 7648 | mirrorAction->setVisible(!isHmd); | ||
| 7649 | 8036 | ||
| 7650 | Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); | 8037 | Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); |
| 7651 | } | 8038 | } |
| @@ -7666,11 +8053,30 @@ void Application::switchDisplayMode() { · 14 unmodified lines | |||
| 7666 | setActiveDisplayPlugin(DESKTOP_DISPLAY_PLUGIN_NAME); | 8053 | setActiveDisplayPlugin(DESKTOP_DISPLAY_PLUGIN_NAME); |
| 7667 | startHMDStandBySession(); | 8054 | startHMDStandBySession(); |
| 7668 | } | 8055 | } |
| 7669 | emit activeDisplayPluginChanged(); | ||
| 7670 | } | 8056 | } |
| 7671 | _previousHMDWornStatus = currentHMDWornStatus; | 8057 | _previousHMDWornStatus = currentHMDWornStatus; |
| 7672 | } | 8058 | } |
| 7673 | 8059 | ||
| 8060 | void Application::setShowBulletWireframe(bool value) { | ||
| 8061 | _physicsEngine->setShowBulletWireframe(value); | ||
| 8062 | } | ||
| 8063 | |||
| 8064 | void Application::setShowBulletAABBs(bool value) { | ||
| 8065 | _physicsEngine->setShowBulletAABBs(value); | ||
| 8066 | } | ||
| 8067 | |||
| 8068 | void Application::setShowBulletContactPoints(bool value) { | ||
| 8069 | _physicsEngine->setShowBulletContactPoints(value); | ||
| 8070 | } | ||
| 8071 | |||
| 8072 | void Application::setShowBulletConstraints(bool value) { | ||
| 8073 | _physicsEngine->setShowBulletConstraints(value); | ||
| 8074 | } | ||
| 8075 | |||
| 8076 | void Application::setShowBulletConstraintLimits(bool value) { | ||
| 8077 | _physicsEngine->setShowBulletConstraintLimits(value); | ||
| 8078 | } | ||
| 8079 | |||
| 7674 | void Application::startHMDStandBySession() { | 8080 | void Application::startHMDStandBySession() { |
| 7675 | _autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession(); | 8081 | _autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession(); |
| 7676 | } | 8082 | } |
| @@ -7721,15 +8127,18 @@ void Application::unresponsiveApplication() { · 44 unmodified lines | |||
| 7721 | } | 8127 | } |
| 7722 | 8128 | ||
| 7723 | void Application::setActiveDisplayPlugin(const QString& pluginName) { | 8129 | void Application::setActiveDisplayPlugin(const QString& pluginName) { |
| 7724 | auto menu = Menu::getInstance(); | 8130 | DisplayPluginPointer newDisplayPlugin; |
| 7725 | foreach(DisplayPluginPointer displayPlugin, PluginManager::getInstance()->getDisplayPlugins()) { | 8131 | for (DisplayPluginPointer displayPlugin : PluginManager::getInstance()->getDisplayPlugins()) { |
| 7726 | QString name = displayPlugin->getName(); | 8132 | QString name = displayPlugin->getName(); |
| 7727 | QAction* action = menu->getActionForOption(name); | ||
| 7728 | if (pluginName == name) { | 8133 | if (pluginName == name) { |
| 7729 | action->setChecked(true); | 8134 | newDisplayPlugin = displayPlugin; |
| 8135 | break; | ||
| 7730 | } | 8136 | } |
| 7731 | } | 8137 | } |
| 7732 | updateDisplayMode(); | 8138 | |
| 8139 | if (newDisplayPlugin) { | ||
| 8140 | setDisplayPlugin(newDisplayPlugin); | ||
| 8141 | } | ||
| 7733 | } | 8142 | } |
| 7734 | 8143 | ||
| 7735 | void Application::handleLocalServerConnection() const { | 8144 | void Application::handleLocalServerConnection() const { |
| @@ -7760,7 +8169,6 @@ void Application::readArgumentsFromLocalSocket() const { · 24 unmodified lines | |||
| 7760 | } | 8169 | } |
| 7761 | 8170 | ||
| 7762 | void Application::showDesktop() { | 8171 | void Application::showDesktop() { |
| 7763 | Menu::getInstance()->setIsOptionChecked(MenuOption::Overlays, true); | ||
| 7764 | } | 8172 | } |
| 7765 | 8173 | ||
| 7766 | CompositorHelper& Application::getApplicationCompositor() const { | 8174 | CompositorHelper& Application::getApplicationCompositor() const { |
| @@ -7849,4 +8257,22 @@ void Application::saveNextPhysicsStats(QString filename) { · 82 unmodified lines | |||
| 7849 | _physicsEngine->saveNextPhysicsStats(filename); | 8257 | _physicsEngine->saveNextPhysicsStats(filename); |
| 7850 | } | 8258 | } |
| 7851 | 8259 | ||
| 8260 | #if defined(Q_OS_ANDROID) | ||
| 8261 | void Application::enterBackground() { | ||
| 8262 | QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), | ||
| 8263 | "stop", Qt::BlockingQueuedConnection); | ||
| 8264 | if (getActiveDisplayPlugin()->isActive()) { | ||
| 8265 | getActiveDisplayPlugin()->deactivate(); | ||
| 8266 | } | ||
| 8267 | } | ||
| 8268 | |||
| 8269 | void Application::enterForeground() { | ||
| 8270 | QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(), | ||
| 8271 | "start", Qt::BlockingQueuedConnection); | ||
| 8272 | if (!getActiveDisplayPlugin() || getActiveDisplayPlugin()->isActive() || !getActiveDisplayPlugin()->activate()) { | ||
| 8273 | qWarning() << "Could not re-activate display plugin"; | ||
| 8274 | } | ||
| 8275 | } | ||
| 8276 | #endif | ||
| 8277 | |||
| 7852 | #include "Application.moc" | 8278 | #include "Application.moc" |