History

Merge branch 'master' of github.com:highfidelity/hifi into merge/triplelexx-21883

# Conflicts: # interface/src/Application.cpp # interface/src/scripting/LimitlessVoiceRecognitionScriptingInterface.cpp

Thijs Wenker committed 8 years ago

Commit 05bc32b2 parents 883cd7b 74e5c4b1575 files · +55139 −32393Browse files

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

Unified · Split

interface/src/Application.cpp+897−471
@@ -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_QUEUE227#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/QtCore230// 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.1231// E:/Qt/5.10.1/Src/qtbase/include/QtCore/5.10.1
229#define QT_BOOTSTRAPPED232#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#endif248#endif
245 249
246enum ApplicationEvent {250enum ApplicationEvent {
@@ -329,7 +333,11 @@ static const QString RENDER_FORWARD{ "HIFI_RENDER_FORWARD" }; · 82 unmodified lines
329static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);333static bool DISABLE_DEFERRED = QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD);
330#endif334#endif
331 335
336#if !defined(Q_OS_ANDROID)
332static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;337static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16;
338#else
339static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 4;
340#endif
333 341
334// For processing on QThreadPool, we target a number of threads after reserving some342// 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
373static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";381static const QString MARKETPLACE_CDN_HOSTNAME = "mpassets.highfidelity.com";
374static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds382static const int INTERVAL_TO_CHECK_HMD_WORN_STATUS = 500; // milliseconds
375static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop";383static const QString DESKTOP_DISPLAY_PLUGIN_NAME = "Desktop";
376 384static const QString ACTIVE_DISPLAY_PLUGIN_SETTING_NAME = "activeDisplayPlugin";
377static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";385static const QString SYSTEM_TABLET = "com.highfidelity.interface.tablet.system";
378 386
379const std::vector<std::pair<QString, Application::AcceptURLMethod>> Application::_acceptedExtensions {387const 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 from497 // Don't actually crash in debug builds, in case this apparent deadlock is simply from
490 // the developer actively debugging code498 // the developer actively debugging code
491 #ifdef NDEBUG499 #ifdef NDEBUG
492 deadlockDetectionCrash();500 deadlockDetectionCrash();
493 #endif501 #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
690static const QString STATE_IN_HMD = "InHMD";726static const QString STATE_IN_HMD = "InHMD";
691static const QString STATE_CAMERA_FULL_SCREEN_MIRROR = "CameraFSM";727static const QString STATE_CAMERA_FULL_SCREEN_MIRROR = "CameraFSM";
692static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson";728static const QString STATE_CAMERA_FIRST_PERSON = "CameraFirstPerson";
@@ -703,6 +739,11 @@ extern DisplayPluginList getDisplayPlugins(); · 10 unmodified lines
703extern InputPluginList getInputPlugins();739extern InputPluginList getInputPlugins();
704extern void saveInputPluginSettings(const InputPluginList& plugins);740extern void saveInputPluginSettings(const InputPluginList& plugins);
705 741
742// Parameters used for running tests from teh command line
743const QString TEST_SCRIPT_COMMAND{ "--testScript" };
744const QString TEST_QUIT_WHEN_FINISHED_OPTION{ "quitWhenFinished" };
745const QString TEST_RESULTS_LOCATION_COMMAND{ "--testResultsLocation" };
746
706bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {747bool 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 cache797 // 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 plugins814 // 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 deadlocks1086 // 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_SERVICES1110#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 token1248 // 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 registering1280 // 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 events1357 // 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 startup1391 // 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 event1436 // 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 UserActivityLogger1439 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 event1491 // 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 import1501 // 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 plugin1712 // 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 be1713 // we can unlock the desktop repositioning code, since all the positions will be
1596 // relative to the desktop size for this plugin1714 // 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 updates1773 // 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
2264void 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
2119void Application::domainConnectionRefused(const QString& reasonMessage, int reasonCodeInt, const QString& extraInfo) {2280void 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 (_autoSwitchDisplayModeSupportedHMDPlugin2395 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_DDE2486#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 processes2601 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 capturing2606 // 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#endif2634#endif
2454 2635
2455 // Build a shared canvas / context for the QML rendering2636 // 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
2690static const QString SPLASH_SKYBOX{ "{\"ProceduralEntity\":{ \"version\":2, \"shaderUrl\":\"qrc:///shaders/splashSkybox.frag\" } }" };
2691
2692void 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();2764void 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
2538extern void setupPreferences();2784extern void setupPreferences();
2785static void addDisplayPluginToMenu(const DisplayPluginPointer& displayPlugin, int index, bool active = false);
2539 2786
2540void Application::initializeUi() {2787void 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 UI2865 // 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
2752void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) {3026void 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 FBOs3249 // 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
2996void Application::handleSandboxStatus(QNetworkReply* reply) {3272void 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 in3325 // 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 scripts3651 _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 it3652 // 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
3618void Application::keyReleaseEvent(QKeyEvent* event) {3859void 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 scripts3868 _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 it3870 // 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
3952static uint32_t _renderedFrameIndex { INVALID_FRAME };4199static uint32_t _renderedFrameIndex { INVALID_FRAME };
3953 4200
3954bool Application::shouldPaint() const {4201bool 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 IN4759 // 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
4612void Application::initDisplay() {
4613}
4614
4615void Application::init() {4856void Application::init() {
4616 4857 _offscreenContext->makeCurrent();
4617 // Make sure Login state is up to date4858 // 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
4932void 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
4946void 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
4691void Application::updateLOD(float deltaTime) const {4957void 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 mode4959 // 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
4706void Application::pushPostUpdateLambda(void* key, std::function<void()> func) {4972void 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
4820void Application::toggleOverlays() {5086void 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
4825void Application::setOverlaysVisible(bool visible) {5091void 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
4830void Application::centerUI() {5096void Application::centerUI() {
@@ -4878,6 +5144,21 @@ void Application::cameraModeChanged() { · 47 unmodified lines
4878 cameraMenuChanged();5144 cameraMenuChanged();
4879}5145}
4880 5146
5147void 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
4882void Application::cameraMenuChanged() {5163void 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 view5209 // 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
5344void 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
5063static bool domainLoadingInProgress = false;5416static bool domainLoadingInProgress = false;
5064 5417
5065void Application::update(float deltaTime) {5418void 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 that5438 // 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 > 05471 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 point5661 {
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 lock5696 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 it5799 // 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
5870void 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 {5988void 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 over5993 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
5599void 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 loaded6060 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 time6272 // If we get a new EntityServer activated, reset lastQueried time
5880 // so we will do a proper query during update6273 // 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 loop6286 // 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 downloads6407 // 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 automatically7135 // 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
7141void Application::loadEntityStatisticsDialog() {7530void 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
7201void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) {7590void 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 it7592 // 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 it7603 // 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
7216void Application::takeSecondaryCameraSnapshot(const QString& filename) {7609void 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
7618void 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
7223void Application::shareSnapshot(const QString& path, const QUrl& href) {7624void 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
7230float Application::getRenderResolutionScale() const {7631float 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
7305void Application::postLambdaEvent(std::function<void()> f) {7710void 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
7718void 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
7313void Application::initPlugins(const QStringList& arguments) {7727void 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
7392bool Application::hasFocus() const {7806bool 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#endif7813#endif
@@ -7401,7 +7815,7 @@ bool Application::hasFocus() const { · 1 unmodified line
7401}7815}
7402 7816
7403void Application::setFocus() {7817void 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
7452static const char* EXCLUSION_GROUP_KEY = "exclusionGroup";7866static const char* EXCLUSION_GROUP_KEY = "exclusionGroup";
7453 7867
7454static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) {7868static 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 match7916 // 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 lost7921 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
7941void 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 threads7954 // 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 display7975 // 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 checked8020 // 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
8060void Application::setShowBulletWireframe(bool value) {
8061 _physicsEngine->setShowBulletWireframe(value);
8062}
8063
8064void Application::setShowBulletAABBs(bool value) {
8065 _physicsEngine->setShowBulletAABBs(value);
8066}
8067
8068void Application::setShowBulletContactPoints(bool value) {
8069 _physicsEngine->setShowBulletContactPoints(value);
8070}
8071
8072void Application::setShowBulletConstraints(bool value) {
8073 _physicsEngine->setShowBulletConstraints(value);
8074}
8075
8076void Application::setShowBulletConstraintLimits(bool value) {
8077 _physicsEngine->setShowBulletConstraintLimits(value);
8078}
8079
7674void Application::startHMDStandBySession() {8080void Application::startHMDStandBySession() {
7675 _autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession();8081 _autoSwitchDisplayModeSupportedHMDPlugin->startStandBySession();
7676}8082}
@@ -7721,15 +8127,18 @@ void Application::unresponsiveApplication() { · 44 unmodified lines
7721}8127}
7722 8128
7723void Application::setActiveDisplayPlugin(const QString& pluginName) {8129void 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
7735void Application::handleLocalServerConnection() const {8144void Application::handleLocalServerConnection() const {
@@ -7760,7 +8169,6 @@ void Application::readArgumentsFromLocalSocket() const { · 24 unmodified lines
7760}8169}
7761 8170
7762void Application::showDesktop() {8171void Application::showDesktop() {
7763 Menu::getInstance()->setIsOptionChecked(MenuOption::Overlays, true);
7764}8172}
7765 8173
7766CompositorHelper& Application::getApplicationCompositor() const {8174CompositorHelper& 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)
8261void Application::enterBackground() {
8262 QMetaObject::invokeMethod(DependencyManager::get<AudioClient>().data(),
8263 "stop", Qt::BlockingQueuedConnection);
8264 if (getActiveDisplayPlugin()->isActive()) {
8265 getActiveDisplayPlugin()->deactivate();
8266 }
8267}
8268
8269void 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"