//// main.cpp// interface/src//// Copyright 2013 High Fidelity, Inc.// Copyright 2022 Overte e.V.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include <QCommandLineParser>#include <QtCore/QProcess>#include <QDebug>#include <QDir>#include <QFileInfo>#include <QLocalSocket>#include <QLocalServer>#include <QSharedMemory>#include <QTranslator>#include <QStandardPaths> #include <BuildInfo.h>#include <SandboxUtils.h>#include <SharedUtil.h>#include <NetworkAccessManager.h>#include <gl/GLHelpers.h>#include <iostream>#include <plugins/InputPlugin.h>#include <plugins/PluginManager.h>#include <plugins/DisplayPlugin.h>#include <plugins/CodecPlugin.h>#include <shared/GlobalAppProperties.h> #include "AddressManager.h"#include "Application.h"#include "crash-handler/CrashHandler.h"#include "InterfaceLogging.h"#include "UserActivityLogger.h"#include "MainWindow.h"#include "Profile.h"#include "LogHandler.h"#include "RunningMarker.h" #ifdef Q_OS_WIN#include <Windows.h>extern "C" { typedef int(__stdcall* CHECKMINSPECPROC)();}#endif int main(int argc, const char* argv[]) {#ifdef Q_OS_MAC auto format = getDefaultOpenGLSurfaceFormat(); // Deal with some weirdness in the chromium context sharing on Mac. // The primary share context needs to be 3.2, so that the Chromium will // succeed in it's creation of it's command stub contexts. format.setVersion(3, 2); // This appears to resolve the issues with corrupted fonts on OSX. No // idea why. qputenv("QT_ENABLE_GLYPH_CACHE_WORKAROUND", "true"); // https://i.kym-cdn.com/entries/icons/original/000/008/342/ihave.jpg QSurfaceFormat::setDefaultFormat(format);#endif // You can force a specific graphics API with the --graphicsAPI option. By default we will pick the best available based on the platform. // Some systems may fallback to a lower API than requested based on what is supported. std::string apiString; for (int i = 1; i < argc; ++i) { if (std::string(argv[i]) == "--graphicsAPI" && i + 1 < argc) { apiString = argv[i + 1]; break; } } if (!apiString.empty()) { if (apiString == "gl45") { hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45); } else if (apiString == "gl41") { hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL41); } else if (apiString == "gles32") { hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GLES32); } else { qWarning() << "Unknown graphics API specified, defaulting to GL4.5:" << QString::fromStdString(apiString); hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45); } } else {#ifdef Q_OS_MAC hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL41);#elif defined(Q_OS_ANDROID) || (defined(Q_OS_LINUX) && defined(__aarch64__)) // Use GLES on Android and aarch64 Linux hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GLES32);#else hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45);#endif } #ifdef Q_OS_WIN // Check the minimum GL version as early as possible { uint16_t available = gl::getAvailableVersion(); uint16_t required = gl::getRequiredVersion(); if (gl::getAvailableVersion() < gl::getRequiredVersion()) { int availMajor = GL_GET_MAJOR_VERSION(available); int availMinor = GL_GET_MINOR_VERSION(available); int reqMajor = GL_GET_MAJOR_VERSION(required); int reqMinor = GL_GET_MINOR_VERSION(required); std::string message = "Interface requires OpenGL " + std::to_string(reqMajor) + "." + std::to_string(reqMinor) + " or higher. Available: " + std::to_string(availMajor) + "." + std::to_string(availMinor); MessageBoxA(nullptr, message.c_str(), "Unsupported", MB_OK); // GL version logging is currently disabled. Version checking needs to happen before Application creation, but then the AccountManager + UserActivityLogger aren't set up yet. #if 0 auto accountManager = DependencyManager::get<AccountManager>(); if (accountManager->isLoggedIn()) { UserActivityLogger::getInstance().insufficientGLVersion(glData); } else { QObject::connect(accountManager.data(), &AccountManager::loginComplete, [glData](){ static bool loggedInsufficientGL = false; if (!loggedInsufficientGL) { UserActivityLogger::getInstance().insufficientGLVersion(glData); loggedInsufficientGL = true; } }); } #endif return -1; } }#endif // Force-disable subpixel antialiasing on QML distance-field text. // An existing override for QSG_DISTANCEFIELD_ANTIALIASING will be respected, and this // variable will change nothing if QML_DISABLE_DISTANCEFIELD is set. // Qt doesn't seem to have any public API for changing this besides the environment variable. // See qtdeclarative/src/quick/scenegraph/qsgdefaultcontext.cpp if ( auto aa = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING"); aa.isNull() || aa.isEmpty() ) { qputenv("QSG_DISTANCEFIELD_ANTIALIASING", "gray"); } // Setup QCoreApplication settings, install log message handler setupHifiApplication(BuildInfo::INTERFACE_NAME); // Journald by default in user applications is probably a bit too modern still. LogHandler::getInstance().setShouldUseJournald(false); std::vector<const char*> argvExtended(&argv[0], &argv[argc]);#ifdef Q_OS_ANDROID argvExtended.push_back("--suppress-settings-reset");#endif int argcExtended = (int)argvExtended.size(); QElapsedTimer startupTime; startupTime.start(); QCommandLineParser parser; parser.setApplicationDescription("Overte -- A free/libre and open-source virtual worlds client"); QCommandLineOption helpOption = parser.addHelpOption(); QCommandLineOption versionOption = parser.addVersionOption(); QCommandLineOption urlOption( "url", "Start at specified URL location.", "string" ); QCommandLineOption protocolVersionOption( "protocolVersion", "Writes the protocol version base64 signature to a file", "path" ); QCommandLineOption noUpdaterOption( "no-updater", "Do not show auto-updater." ); QCommandLineOption checkMinSpecOption( "checkMinSpec", "Check if machine meets minimum specifications. The program will run if check passes." ); QCommandLineOption runServerOption( "runServer", "Run the server." ); QCommandLineOption listenPortOption( "listenPort", "Port to listen on.", "port_number" ); QCommandLineOption serverContentPathOption( "serverContentPath", "Path to find server content.", // What content?? "path" ); QCommandLineOption overrideAppLocalDataPathOption( "cache", "Set test cache.", "dir" ); QCommandLineOption scriptsOption( "scripts", "Set path for defaultScripts. These are probably scripts that run automatically. This parameter does not seem to work.", "dir" ); QCommandLineOption allowMultipleInstancesOption( "allowMultipleInstances", "Allow multiple instances to run." ); QCommandLineOption displaysOption( "display", "Preferred display plugin. Valid options include \"Desktop\", \"OpenXR\", and \"OpenVR (Vive)\". If \"Desktop\" is specified, all VR plugins are disabled.", "displays" ); QCommandLineOption disableDisplaysOption( "disableDisplayPlugins", "Display plugins to disable, separated by commas. Valid options include \"OpenXR\" and \"OpenVR (Vive)\".", "string" ); QCommandLineOption disableInputsOption( "disableInputPlugins", "Input plugins to disable, separated by commas. Valid options include \"SDL2\" (used only for gamepads), \"OpenXR\", and \"OpenVR (Vive)\".", "string" ); QCommandLineOption suppressSettingsResetOption( "suppress-settings-reset", "Suppress the prompt to reset interface settings." ); QCommandLineOption oculusStoreOption( "oculus-store", "Let the Oculus plugin know if interface was run from the Oculus Store." ); QCommandLineOption standaloneOption( "standalone", "Emulate a standalone device." ); QCommandLineOption disableWatchdogOption( "disableWatchdog", "Disable the watchdog thread. The interface will crash on deadlocks." ); QCommandLineOption systemCursorOption( "system-cursor", "Use the default system cursor." ); QCommandLineOption concurrentDownloadsOption( "concurrent-downloads", "Maximum concurrent resource downloads. Default is 16, except for Android where it is 4.", "integer" ); QCommandLineOption avatarURLOption( "avatarURL", "Override the avatar U.R.L.", "url" ); QCommandLineOption replaceAvatarURLOption( "replaceAvatarURL", "Replaces the avatar U.R.L. When used with --avatarURL, this takes precedence.", "url" ); QCommandLineOption setBookmarkOption( "setBookmark", "Set bookmark as key=value pair. Including the '=' symbol in either string is unsupported.", "string" ); QCommandLineOption forceCrashReportingOption( "forceCrashReporting", "Force crash reporting to initialize." ); // The documented "--disable-lod" does not seem to exist. // Below are undocumented. QCommandLineOption noLauncherOption( "no-launcher", "Supposedly does something for the server, unrelated to the application launcher. The feature may never have been implemented." ); QCommandLineOption overrideScriptsPathOption( "overrideScriptsPath", "Specifies path to default directory where the application will look for scripts to load.", "string" ); QCommandLineOption defaultScriptsOverrideOption( "defaultScriptsOverride", "Override default script to run automatically on start. Default is \"defaultsScripts.js\".", "string" ); QCommandLineOption responseTokensOption( "tokens", "Set response tokens <json>.", "json" ); QCommandLineOption displayNameOption( "displayName", "Set user display name <string>.", "string" ); QCommandLineOption noLoginOption( "no-login-suggestion", "Do not show log-in dialogue." ); QCommandLineOption traceFileOption( "traceFile", "Writes a trace to a file in the documents folder. Only works if \"--traceDuration\" is specified.", "path" ); QCommandLineOption traceDurationOption( "traceDuration", "Automatically quit interface after duration. Only works if \"--traceFile\" is specified.", "seconds" ); QCommandLineOption clockSkewOption( "clockSkew", "Forces client instance's clock to skew for demonstration purposes.", "integer" ); // This should probably be removed. QCommandLineOption testScriptOption( "testScript", "Undocumented. Accepts parameter as U.R.L.", "string" ); QCommandLineOption testResultsLocationOption( "testResultsLocation", "Undocumented", "path" ); QCommandLineOption quitWhenFinishedOption( "quitWhenFinished", "Only works if \"--testScript\" is provided." ); // Should probably also be made to work on testResultsLocationOption. QCommandLineOption fastHeartbeatOption( "fast-heartbeat", "Change stats polling interval from 10000ms to 1000ms." ); QCommandLineOption logOption( "logOptions", "Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald", "options" ); QCommandLineOption getPluginsOption( "getPlugins", "Print out a list of plugins in JSON" ); QCommandLineOption abortAfterStartupOption( "abortAfterStartup", "Debug option. Aborts right after startup." ); QCommandLineOption abortAfterInitOption( "abortAfterInit", "Debug option. Aborts after initialization, right before the program starts running the event loop." ); QCommandLineOption getProtocolVersionHashOption( "getProtocolVersionHash", "Debug option. Returns the network protocol version MD5 hash." ); QCommandLineOption getProtocolVersionDataOption( "getProtocolVersionData", "Debug option. Returns the network protocol detailed data in JSON." ); QCommandLineOption useExperimentalXROption( "useExperimentalXR", "Legacy alias of \"--display=OpenXR\"." ); QCommandLineOption xrNoHandTrackingOption( "xrNoHandTracking", "Debug option. Disables OpenXR hand tracking, even if it's supported." ); QCommandLineOption xrNoBodyTrackingOption( "xrNoBodyTracking", "Debug option. Disables OpenXR body tracking, even if it's supported." ); QCommandLineOption xrNoPalmPoseOption( "xrNoPalmPose", "Debug option. Disables use of the OpenXR palm pose, even if it's supported. Falls back to the controller's grip pose." ); QCommandLineOption graphicsAPIOption( "graphicsAPI", "Which graphics API to target. Supports gl45, gl41, and gles32. Final API may vary based on system support.", "string" ); parser.addOption(urlOption); parser.addOption(protocolVersionOption); parser.addOption(noUpdaterOption); parser.addOption(checkMinSpecOption); parser.addOption(runServerOption); parser.addOption(listenPortOption); parser.addOption(serverContentPathOption); parser.addOption(overrideAppLocalDataPathOption); parser.addOption(scriptsOption); parser.addOption(allowMultipleInstancesOption); parser.addOption(displaysOption); parser.addOption(disableDisplaysOption); parser.addOption(disableInputsOption); parser.addOption(suppressSettingsResetOption); parser.addOption(oculusStoreOption); parser.addOption(standaloneOption); parser.addOption(disableWatchdogOption); parser.addOption(systemCursorOption); parser.addOption(concurrentDownloadsOption); parser.addOption(avatarURLOption); parser.addOption(replaceAvatarURLOption); parser.addOption(setBookmarkOption); parser.addOption(forceCrashReportingOption); parser.addOption(noLauncherOption); parser.addOption(responseTokensOption); parser.addOption(displayNameOption); parser.addOption(noLoginOption); parser.addOption(overrideScriptsPathOption); parser.addOption(defaultScriptsOverrideOption); parser.addOption(traceFileOption); parser.addOption(traceDurationOption); parser.addOption(clockSkewOption); parser.addOption(testScriptOption); parser.addOption(testResultsLocationOption); parser.addOption(quitWhenFinishedOption); parser.addOption(fastHeartbeatOption); parser.addOption(logOption); parser.addOption(abortAfterStartupOption); parser.addOption(abortAfterInitOption); parser.addOption(getPluginsOption); parser.addOption(getProtocolVersionHashOption); parser.addOption(getProtocolVersionDataOption); parser.addOption(useExperimentalXROption); parser.addOption(xrNoHandTrackingOption); parser.addOption(xrNoPalmPoseOption); parser.addOption(graphicsAPIOption); QString applicationPath; // A temporary application instance is needed to get the location of the running executable // Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV) // If we wanted to avoid the QCoreApplication, we would need to write our own // cross-platform implementation. { QCoreApplication tempApp(argc, const_cast<char**>(argv)); parser.process(QCoreApplication::arguments()); // Must be run after QCoreApplication is initalised. #ifdef Q_OS_OSX if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/../../../config.json")) { applicationPath = QCoreApplication::applicationDirPath() + "/../../../"; } else { applicationPath = QCoreApplication::applicationDirPath(); }#else applicationPath = QCoreApplication::applicationDirPath();#endif } // TODO: We need settings for Application, but Settings needs an Application // to handle events. Needs splitting into two parts: enough initialization // for Application to work, and then thread start afterwards. Setting::init();#ifdef NDEBUG // Fail if asserts are enabled on release build. Q_ASSERT_X(false, "Interface", "This is not a debug build, but somehow Q_ASSERTs are enabled. \ This is known to happen on Windows if QT_NO_DEBUG isn't set by us.");#endif Application app(argcExtended, const_cast<char**>(argvExtended.data()), startupTime); if (parser.isSet("abortAfterStartup")) { return 99; } // We want to configure the logging system as early as possible auto& logHandler = LogHandler::getInstance(); if (parser.isSet(logOption)) { if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) { QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp() parser.showHelp(); Q_UNREACHABLE(); } } app.initializePluginManager(parser); if (parser.isSet(getPluginsOption)) { auto pluginManager = PluginManager::getInstance(); QJsonObject pluginsJson; for (const auto &plugin : pluginManager->getPluginInfo()) { QJsonObject data; data["data"] = plugin.metaData; data["loaded"] = plugin.loaded; data["disabled"] = plugin.disabled; data["filteredOut"] = plugin.filteredOut; data["wrongVersion"] = plugin.wrongVersion; pluginsJson[plugin.name] = data; } QJsonObject inputJson; for (const auto &plugin : pluginManager->getInputPlugins()) { QJsonObject data; data["subdeviceNames"] = QJsonArray::fromStringList(plugin->getSubdeviceNames()); data["deviceName"] = plugin->getDeviceName(); data["configurable"] = plugin->configurable(); data["isHandController"] = plugin->isHandController(); data["isHeadController"] = plugin->isHeadController(); data["isActive"] = plugin->isActive(); data["isSupported"] = plugin->isSupported(); inputJson[plugin->getName()] = data; } QJsonObject displayJson;Lines 1–500 of 878. Load more
// // main.cpp // interface/src // // Copyright 2013 High Fidelity, Inc. // Copyright 2022 Overte e.V. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include <QCommandLineParser> #include <QtCore/QProcess> #include <QDebug> #include <QDir> #include <QFileInfo> #include <QLocalSocket> #include <QLocalServer> #include <QSharedMemory> #include <QTranslator> #include <QStandardPaths> #include <BuildInfo.h> #include <SandboxUtils.h> #include <SharedUtil.h> #include <NetworkAccessManager.h> #include <gl/GLHelpers.h> #include <iostream> #include <plugins/InputPlugin.h> #include <plugins/PluginManager.h> #include <plugins/DisplayPlugin.h> #include <plugins/CodecPlugin.h> #include <shared/GlobalAppProperties.h> #include "AddressManager.h" #include "Application.h" #include "crash-handler/CrashHandler.h" #include "InterfaceLogging.h" #include "UserActivityLogger.h" #include "MainWindow.h" #include "Profile.h" #include "LogHandler.h" #include "RunningMarker.h" #ifdef Q_OS_WIN #include <Windows.h> extern "C" { typedef int(__stdcall* CHECKMINSPECPROC)(); } #endif int main(int argc, const char* argv[]) { #ifdef Q_OS_MAC auto format = getDefaultOpenGLSurfaceFormat(); // Deal with some weirdness in the chromium context sharing on Mac. // The primary share context needs to be 3.2, so that the Chromium will // succeed in it's creation of it's command stub contexts. format.setVersion(3, 2); // This appears to resolve the issues with corrupted fonts on OSX. No // idea why. qputenv("QT_ENABLE_GLYPH_CACHE_WORKAROUND", "true"); // https://i.kym-cdn.com/entries/icons/original/000/008/342/ihave.jpg QSurfaceFormat::setDefaultFormat(format); #endif // You can force a specific graphics API with the --graphicsAPI option. By default we will pick the best available based on the platform. // Some systems may fallback to a lower API than requested based on what is supported. std::string apiString; for (int i = 1; i < argc; ++i) { if (std::string(argv[i]) == "--graphicsAPI" && i + 1 < argc) { apiString = argv[i + 1]; break; } } if (!apiString.empty()) { if (apiString == "gl45") { hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45); } else if (apiString == "gl41") { hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL41); } else if (apiString == "gles32") { hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GLES32); } else { qWarning() << "Unknown graphics API specified, defaulting to GL4.5:" << QString::fromStdString(apiString); hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45); } } else { #ifdef Q_OS_MAC hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL41); #elif defined(Q_OS_ANDROID) || (defined(Q_OS_LINUX) && defined(__aarch64__)) // Use GLES on Android and aarch64 Linux hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GLES32); #else hifi::properties::setGraphicsAPI(hifi::properties::GraphicsAPI::GL45); #endif } #ifdef Q_OS_WIN // Check the minimum GL version as early as possible { uint16_t available = gl::getAvailableVersion(); uint16_t required = gl::getRequiredVersion(); if (gl::getAvailableVersion() < gl::getRequiredVersion()) { int availMajor = GL_GET_MAJOR_VERSION(available); int availMinor = GL_GET_MINOR_VERSION(available); int reqMajor = GL_GET_MAJOR_VERSION(required); int reqMinor = GL_GET_MINOR_VERSION(required); std::string message = "Interface requires OpenGL " + std::to_string(reqMajor) + "." + std::to_string(reqMinor) + " or higher. Available: " + std::to_string(availMajor) + "." + std::to_string(availMinor); MessageBoxA(nullptr, message.c_str(), "Unsupported", MB_OK); // GL version logging is currently disabled. Version checking needs to happen before Application creation, but then the AccountManager + UserActivityLogger aren't set up yet. #if 0 auto accountManager = DependencyManager::get<AccountManager>(); if (accountManager->isLoggedIn()) { UserActivityLogger::getInstance().insufficientGLVersion(glData); } else { QObject::connect(accountManager.data(), &AccountManager::loginComplete, [glData](){ static bool loggedInsufficientGL = false; if (!loggedInsufficientGL) { UserActivityLogger::getInstance().insufficientGLVersion(glData); loggedInsufficientGL = true; } }); } #endif return -1; } } #endif // Force-disable subpixel antialiasing on QML distance-field text. // An existing override for QSG_DISTANCEFIELD_ANTIALIASING will be respected, and this // variable will change nothing if QML_DISABLE_DISTANCEFIELD is set. // Qt doesn't seem to have any public API for changing this besides the environment variable. // See qtdeclarative/src/quick/scenegraph/qsgdefaultcontext.cpp if ( auto aa = qgetenv("QSG_DISTANCEFIELD_ANTIALIASING"); aa.isNull() || aa.isEmpty() ) { qputenv("QSG_DISTANCEFIELD_ANTIALIASING", "gray"); } // Setup QCoreApplication settings, install log message handler setupHifiApplication(BuildInfo::INTERFACE_NAME); // Journald by default in user applications is probably a bit too modern still. LogHandler::getInstance().setShouldUseJournald(false); std::vector<const char*> argvExtended(&argv[0], &argv[argc]); #ifdef Q_OS_ANDROID argvExtended.push_back("--suppress-settings-reset"); #endif int argcExtended = (int)argvExtended.size(); QElapsedTimer startupTime; startupTime.start(); QCommandLineParser parser; parser.setApplicationDescription("Overte -- A free/libre and open-source virtual worlds client"); QCommandLineOption helpOption = parser.addHelpOption(); QCommandLineOption versionOption = parser.addVersionOption(); QCommandLineOption urlOption( "url", "Start at specified URL location.", "string" ); QCommandLineOption protocolVersionOption( "protocolVersion", "Writes the protocol version base64 signature to a file", "path" ); QCommandLineOption noUpdaterOption( "no-updater", "Do not show auto-updater." ); QCommandLineOption checkMinSpecOption( "checkMinSpec", "Check if machine meets minimum specifications. The program will run if check passes." ); QCommandLineOption runServerOption( "runServer", "Run the server." ); QCommandLineOption listenPortOption( "listenPort", "Port to listen on.", "port_number" ); QCommandLineOption serverContentPathOption( "serverContentPath", "Path to find server content.", // What content?? "path" ); QCommandLineOption overrideAppLocalDataPathOption( "cache", "Set test cache.", "dir" ); QCommandLineOption scriptsOption( "scripts", "Set path for defaultScripts. These are probably scripts that run automatically. This parameter does not seem to work.", "dir" ); QCommandLineOption allowMultipleInstancesOption( "allowMultipleInstances", "Allow multiple instances to run." ); QCommandLineOption displaysOption( "display", "Preferred display plugin. Valid options include \"Desktop\", \"OpenXR\", and \"OpenVR (Vive)\". If \"Desktop\" is specified, all VR plugins are disabled.", "displays" ); QCommandLineOption disableDisplaysOption( "disableDisplayPlugins", "Display plugins to disable, separated by commas. Valid options include \"OpenXR\" and \"OpenVR (Vive)\".", "string" ); QCommandLineOption disableInputsOption( "disableInputPlugins", "Input plugins to disable, separated by commas. Valid options include \"SDL2\" (used only for gamepads), \"OpenXR\", and \"OpenVR (Vive)\".", "string" ); QCommandLineOption suppressSettingsResetOption( "suppress-settings-reset", "Suppress the prompt to reset interface settings." ); QCommandLineOption oculusStoreOption( "oculus-store", "Let the Oculus plugin know if interface was run from the Oculus Store." ); QCommandLineOption standaloneOption( "standalone", "Emulate a standalone device." ); QCommandLineOption disableWatchdogOption( "disableWatchdog", "Disable the watchdog thread. The interface will crash on deadlocks." ); QCommandLineOption systemCursorOption( "system-cursor", "Use the default system cursor." ); QCommandLineOption concurrentDownloadsOption( "concurrent-downloads", "Maximum concurrent resource downloads. Default is 16, except for Android where it is 4.", "integer" ); QCommandLineOption avatarURLOption( "avatarURL", "Override the avatar U.R.L.", "url" ); QCommandLineOption replaceAvatarURLOption( "replaceAvatarURL", "Replaces the avatar U.R.L. When used with --avatarURL, this takes precedence.", "url" ); QCommandLineOption setBookmarkOption( "setBookmark", "Set bookmark as key=value pair. Including the '=' symbol in either string is unsupported.", "string" ); QCommandLineOption forceCrashReportingOption( "forceCrashReporting", "Force crash reporting to initialize." ); // The documented "--disable-lod" does not seem to exist. // Below are undocumented. QCommandLineOption noLauncherOption( "no-launcher", "Supposedly does something for the server, unrelated to the application launcher. The feature may never have been implemented." ); QCommandLineOption overrideScriptsPathOption( "overrideScriptsPath", "Specifies path to default directory where the application will look for scripts to load.", "string" ); QCommandLineOption defaultScriptsOverrideOption( "defaultScriptsOverride", "Override default script to run automatically on start. Default is \"defaultsScripts.js\".", "string" ); QCommandLineOption responseTokensOption( "tokens", "Set response tokens <json>.", "json" ); QCommandLineOption displayNameOption( "displayName", "Set user display name <string>.", "string" ); QCommandLineOption noLoginOption( "no-login-suggestion", "Do not show log-in dialogue." ); QCommandLineOption traceFileOption( "traceFile", "Writes a trace to a file in the documents folder. Only works if \"--traceDuration\" is specified.", "path" ); QCommandLineOption traceDurationOption( "traceDuration", "Automatically quit interface after duration. Only works if \"--traceFile\" is specified.", "seconds" ); QCommandLineOption clockSkewOption( "clockSkew", "Forces client instance's clock to skew for demonstration purposes.", "integer" ); // This should probably be removed. QCommandLineOption testScriptOption( "testScript", "Undocumented. Accepts parameter as U.R.L.", "string" ); QCommandLineOption testResultsLocationOption( "testResultsLocation", "Undocumented", "path" ); QCommandLineOption quitWhenFinishedOption( "quitWhenFinished", "Only works if \"--testScript\" is provided." ); // Should probably also be made to work on testResultsLocationOption. QCommandLineOption fastHeartbeatOption( "fast-heartbeat", "Change stats polling interval from 10000ms to 1000ms." ); QCommandLineOption logOption( "logOptions", "Logging options, comma separated: color,nocolor,process_id,thread_id,milliseconds,keep_repeats,journald,nojournald", "options" ); QCommandLineOption getPluginsOption( "getPlugins", "Print out a list of plugins in JSON" ); QCommandLineOption abortAfterStartupOption( "abortAfterStartup", "Debug option. Aborts right after startup." ); QCommandLineOption abortAfterInitOption( "abortAfterInit", "Debug option. Aborts after initialization, right before the program starts running the event loop." ); QCommandLineOption getProtocolVersionHashOption( "getProtocolVersionHash", "Debug option. Returns the network protocol version MD5 hash." ); QCommandLineOption getProtocolVersionDataOption( "getProtocolVersionData", "Debug option. Returns the network protocol detailed data in JSON." ); QCommandLineOption useExperimentalXROption( "useExperimentalXR", "Legacy alias of \"--display=OpenXR\"." ); QCommandLineOption xrNoHandTrackingOption( "xrNoHandTracking", "Debug option. Disables OpenXR hand tracking, even if it's supported." ); QCommandLineOption xrNoBodyTrackingOption( "xrNoBodyTracking", "Debug option. Disables OpenXR body tracking, even if it's supported." ); QCommandLineOption xrNoPalmPoseOption( "xrNoPalmPose", "Debug option. Disables use of the OpenXR palm pose, even if it's supported. Falls back to the controller's grip pose." ); QCommandLineOption graphicsAPIOption( "graphicsAPI", "Which graphics API to target. Supports gl45, gl41, and gles32. Final API may vary based on system support.", "string" ); parser.addOption(urlOption); parser.addOption(protocolVersionOption); parser.addOption(noUpdaterOption); parser.addOption(checkMinSpecOption); parser.addOption(runServerOption); parser.addOption(listenPortOption); parser.addOption(serverContentPathOption); parser.addOption(overrideAppLocalDataPathOption); parser.addOption(scriptsOption); parser.addOption(allowMultipleInstancesOption); parser.addOption(displaysOption); parser.addOption(disableDisplaysOption); parser.addOption(disableInputsOption); parser.addOption(suppressSettingsResetOption); parser.addOption(oculusStoreOption); parser.addOption(standaloneOption); parser.addOption(disableWatchdogOption); parser.addOption(systemCursorOption); parser.addOption(concurrentDownloadsOption); parser.addOption(avatarURLOption); parser.addOption(replaceAvatarURLOption); parser.addOption(setBookmarkOption); parser.addOption(forceCrashReportingOption); parser.addOption(noLauncherOption); parser.addOption(responseTokensOption); parser.addOption(displayNameOption); parser.addOption(noLoginOption); parser.addOption(overrideScriptsPathOption); parser.addOption(defaultScriptsOverrideOption); parser.addOption(traceFileOption); parser.addOption(traceDurationOption); parser.addOption(clockSkewOption); parser.addOption(testScriptOption); parser.addOption(testResultsLocationOption); parser.addOption(quitWhenFinishedOption); parser.addOption(fastHeartbeatOption); parser.addOption(logOption); parser.addOption(abortAfterStartupOption); parser.addOption(abortAfterInitOption); parser.addOption(getPluginsOption); parser.addOption(getProtocolVersionHashOption); parser.addOption(getProtocolVersionDataOption); parser.addOption(useExperimentalXROption); parser.addOption(xrNoHandTrackingOption); parser.addOption(xrNoPalmPoseOption); parser.addOption(graphicsAPIOption); QString applicationPath; // A temporary application instance is needed to get the location of the running executable // Tests using high_resolution_clock show that this takes about 30-50 microseconds (on my machine, YMMV) // If we wanted to avoid the QCoreApplication, we would need to write our own // cross-platform implementation. { QCoreApplication tempApp(argc, const_cast<char**>(argv)); parser.process(QCoreApplication::arguments()); // Must be run after QCoreApplication is initalised. #ifdef Q_OS_OSX if (QFileInfo::exists(QCoreApplication::applicationDirPath() + "/../../../config.json")) { applicationPath = QCoreApplication::applicationDirPath() + "/../../../"; } else { applicationPath = QCoreApplication::applicationDirPath(); } #else applicationPath = QCoreApplication::applicationDirPath(); #endif } // TODO: We need settings for Application, but Settings needs an Application // to handle events. Needs splitting into two parts: enough initialization // for Application to work, and then thread start afterwards. Setting::init(); #ifdef NDEBUG // Fail if asserts are enabled on release build. Q_ASSERT_X(false, "Interface", "This is not a debug build, but somehow Q_ASSERTs are enabled. \ This is known to happen on Windows if QT_NO_DEBUG isn't set by us."); #endif Application app(argcExtended, const_cast<char**>(argvExtended.data()), startupTime); if (parser.isSet("abortAfterStartup")) { return 99; } // We want to configure the logging system as early as possible auto& logHandler = LogHandler::getInstance(); if (parser.isSet(logOption)) { if (!logHandler.parseOptions(parser.value(logOption).toUtf8(), logOption.names().first())) { QCoreApplication mockApp(argc, const_cast<char**>(argv)); // required for call to showHelp() parser.showHelp(); Q_UNREACHABLE(); } } app.initializePluginManager(parser); if (parser.isSet(getPluginsOption)) { auto pluginManager = PluginManager::getInstance(); QJsonObject pluginsJson; for (const auto &plugin : pluginManager->getPluginInfo()) { QJsonObject data; data["data"] = plugin.metaData; data["loaded"] = plugin.loaded; data["disabled"] = plugin.disabled; data["filteredOut"] = plugin.filteredOut; data["wrongVersion"] = plugin.wrongVersion; pluginsJson[plugin.name] = data; } QJsonObject inputJson; for (const auto &plugin : pluginManager->getInputPlugins()) { QJsonObject data; data["subdeviceNames"] = QJsonArray::fromStringList(plugin->getSubdeviceNames()); data["deviceName"] = plugin->getDeviceName(); data["configurable"] = plugin->configurable(); data["isHandController"] = plugin->isHandController(); data["isHeadController"] = plugin->isHeadController(); data["isActive"] = plugin->isActive(); data["isSupported"] = plugin->isSupported(); inputJson[plugin->getName()] = data; } QJsonObject displayJson;