Beta Release 42 - Includes up to Developer Release 6626
Showing the changes to interface/src/Application.cpp (1 of 85 files). Show all
Unified · Split
| @@ -11,6 +11,9 @@ · 10 unmodified lines | ||
| 11 | 11 | |
| 12 | 12 | #include "Application.h" |
| 13 | 13 | |
| 14 | +#include <chrono> | |
| 15 | +#include <thread> | |
| 16 | + | |
| 14 | 17 | #include <gl/Config.h> |
| 15 | 18 | #include <glm/glm.hpp> |
| 16 | 19 | #include <glm/gtx/component_wise.hpp> |
| @@ -146,6 +149,7 @@ · 129 unmodified lines | ||
| 146 | 149 | #include "InterfaceLogging.h" |
| 147 | 150 | #include "LODManager.h" |
| 148 | 151 | #include "ModelPackager.h" |
| 152 | +#include "networking/CloseEventSender.h" | |
| 149 | 153 | #include "networking/HFWebEngineProfile.h" |
| 150 | 154 | #include "networking/HFTabletWebEngineProfile.h" |
| 151 | 155 | #include "networking/FileTypeProfile.h" |
| @@ -438,6 +442,10 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 286 unmodified lines | ||
| 438 | 442 | const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); |
| 439 | 443 | const int listenPort = portStr ? atoi(portStr) : INVALID_PORT; |
| 440 | 444 | |
| 445 | + static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; | |
| 446 | + bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET); | |
| 447 | + bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); | |
| 448 | + | |
| 441 | 449 | Setting::init(); |
| 442 | 450 | |
| 443 | 451 | if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { |
| @@ -458,10 +466,6 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 14 unmodified lines | ||
| 458 | 466 | QCoreApplication::addLibraryPath(audioDLLPath); |
| 459 | 467 | #endif |
| 460 | 468 | |
| 461 | − static const auto SUPPRESS_SETTINGS_RESET = "--suppress-settings-reset"; | |
| 462 | − bool suppressPrompt = cmdOptionExists(argc, const_cast<const char**>(argv), SUPPRESS_SETTINGS_RESET); | |
| 463 | − bool previousSessionCrashed = CrashHandler::checkForResetSettings(runningMarkerExisted, suppressPrompt); | |
| 464 | − | |
| 465 | 469 | DependencyManager::registerInheritance<LimitedNodeList, NodeList>(); |
| 466 | 470 | DependencyManager::registerInheritance<AvatarHashMap, AvatarManager>(); |
| 467 | 471 | DependencyManager::registerInheritance<EntityDynamicFactoryInterface, InterfaceDynamicFactory>(); |
| @@ -536,6 +540,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { · 68 unmodified lines | ||
| 536 | 540 | DependencyManager::set<AvatarBookmarks>(); |
| 537 | 541 | DependencyManager::set<LocationBookmarks>(); |
| 538 | 542 | DependencyManager::set<Snapshot>(); |
| 543 | + DependencyManager::set<CloseEventSender>(); | |
| 539 | 544 | |
| 540 | 545 | return previousSessionCrashed; |
| 541 | 546 | } |
| @@ -1643,6 +1648,14 @@ void Application::aboutToQuit() { · 1101 unmodified lines | ||
| 1643 | 1648 | |
| 1644 | 1649 | getActiveDisplayPlugin()->deactivate(); |
| 1645 | 1650 | |
| 1651 | + // use the CloseEventSender via a QThread to send an event that says the user asked for the app to close | |
| 1652 | + auto closeEventSender = DependencyManager::get<CloseEventSender>(); | |
| 1653 | + QThread* closureEventThread = new QThread(this); | |
| 1654 | + closeEventSender->moveToThread(closureEventThread); | |
| 1655 | + // sendQuitEventAsync will bail immediately if the UserActivityLogger is not enabled | |
| 1656 | + connect(closureEventThread, &QThread::started, closeEventSender.data(), &CloseEventSender::sendQuitEventAsync); | |
| 1657 | + closureEventThread->start(); | |
| 1658 | + | |
| 1646 | 1659 | // Hide Running Scripts dialog so that it gets destroyed in an orderly manner; prevents warnings at shutdown. |
| 1647 | 1660 | DependencyManager::get<OffscreenUi>()->hide("RunningScripts"); |
| 1648 | 1661 | |
| @@ -1697,7 +1710,6 @@ void Application::cleanupBeforeQuit() { · 48 unmodified lines | ||
| 1697 | 1710 | // Clear any queued processing (I/O, FBX/OBJ/Texture parsing) |
| 1698 | 1711 | QThreadPool::globalInstance()->clear(); |
| 1699 | 1712 | |
| 1700 | − DependencyManager::get<ScriptEngines>()->saveScripts(); | |
| 1701 | 1713 | DependencyManager::get<ScriptEngines>()->shutdownScripting(); // stop all currently running global scripts |
| 1702 | 1714 | DependencyManager::destroy<ScriptEngines>(); |
| 1703 | 1715 | |
| @@ -1808,6 +1820,15 @@ Application::~Application() { · 104 unmodified lines | ||
| 1808 | 1820 | |
| 1809 | 1821 | _window->deleteLater(); |
| 1810 | 1822 | |
| 1823 | + // make sure that the quit event has finished sending before we take the application down | |
| 1824 | + auto closeEventSender = DependencyManager::get<CloseEventSender>(); | |
| 1825 | + while (!closeEventSender->hasFinishedQuitEvent() && !closeEventSender->hasTimedOutQuitEvent()) { | |
| 1826 | + // sleep a little so we're not spinning at 100% | |
| 1827 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); | |
| 1828 | + } | |
| 1829 | + // quit the thread used by the closure event sender | |
| 1830 | + closeEventSender->thread()->quit(); | |
| 1831 | + | |
| 1811 | 1832 | // Can't log to file passed this point, FileLogger about to be deleted |
| 1812 | 1833 | qInstallMessageHandler(LogHandler::verboseMessageHandler); |
| 1813 | 1834 | } |
| @@ -2458,15 +2479,16 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { · 644 unmodified lines | ||
| 2458 | 2479 | |
| 2459 | 2480 | // Check HMD use (may be technically available without being in use) |
| 2460 | 2481 | bool hasHMD = PluginUtils::isHMDAvailable(); |
| 2461 | − bool isUsingHMD = hasHMD && hasHandControllers && _displayPlugin->isHmd(); | |
| 2482 | + bool isUsingHMD = _displayPlugin->isHmd(); | |
| 2483 | + bool isUsingHMDAndHandControllers = hasHMD && hasHandControllers && isUsingHMD; | |
| 2462 | 2484 | |
| 2463 | 2485 | Setting::Handle<bool> tutorialComplete{ "tutorialComplete", false }; |
| 2464 | 2486 | Setting::Handle<bool> firstRun{ Settings::firstRun, true }; |
| 2465 | 2487 | |
| 2466 | 2488 | bool isTutorialComplete = tutorialComplete.get(); |
| 2467 | − bool shouldGoToTutorial = isUsingHMD && hasTutorialContent && !isTutorialComplete; | |
| 2489 | + bool shouldGoToTutorial = isUsingHMDAndHandControllers && hasTutorialContent && !isTutorialComplete; | |
| 2468 | 2490 | |
| 2469 | − qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMD; | |
| 2491 | + qCDebug(interfaceapp) << "HMD:" << hasHMD << ", Hand Controllers: " << hasHandControllers << ", Using HMD: " << isUsingHMDAndHandControllers; | |
| 2470 | 2492 | qCDebug(interfaceapp) << "Tutorial version:" << contentVersion << ", sufficient:" << hasTutorialContent << |
| 2471 | 2493 | ", complete:" << isTutorialComplete << ", should go:" << shouldGoToTutorial; |
| 2472 | 2494 | |
| @@ -2480,10 +2502,18 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { · 7 unmodified lines | ||
| 2480 | 2502 | |
| 2481 | 2503 | const QString TUTORIAL_PATH = "/tutorial_begin"; |
| 2482 | 2504 | |
| 2505 | + static const QString SENT_TO_TUTORIAL = "tutorial"; | |
| 2506 | + static const QString SENT_TO_PREVIOUS_LOCATION = "previous_location"; | |
| 2507 | + static const QString SENT_TO_ENTRY = "entry"; | |
| 2508 | + static const QString SENT_TO_SANDBOX = "sandbox"; | |
| 2509 | + | |
| 2510 | + QString sentTo; | |
| 2511 | + | |
| 2483 | 2512 | if (shouldGoToTutorial) { |
| 2484 | 2513 | if (sandboxIsRunning) { |
| 2485 | 2514 | qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home."; |
| 2486 | 2515 | DependencyManager::get<AddressManager>()->goToLocalSandbox(TUTORIAL_PATH); |
| 2516 | + sentTo = SENT_TO_TUTORIAL; | |
| 2487 | 2517 | } else { |
| 2488 | 2518 | qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry."; |
| 2489 | 2519 | if (firstRun.get()) { |
| @@ -2491,8 +2521,10 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { · 1 unmodified line | ||
| 2491 | 2521 | } |
| 2492 | 2522 | if (addressLookupString.isEmpty()) { |
| 2493 | 2523 | DependencyManager::get<AddressManager>()->goToEntry(); |
| 2524 | + sentTo = SENT_TO_ENTRY; | |
| 2494 | 2525 | } else { |
| 2495 | 2526 | DependencyManager::get<AddressManager>()->loadSettings(addressLookupString); |
| 2527 | + sentTo = SENT_TO_PREVIOUS_LOCATION; | |
| 2496 | 2528 | } |
| 2497 | 2529 | } |
| 2498 | 2530 | } else { |
| @@ -2505,23 +2537,40 @@ void Application::handleSandboxStatus(QNetworkReply* reply) { · 6 unmodified lines | ||
| 2505 | 2537 | |
| 2506 | 2538 | // If this is a first run we short-circuit the address passed in |
| 2507 | 2539 | if (isFirstRun) { |
| 2508 | − if (isUsingHMD) { | |
| 2540 | + if (isUsingHMDAndHandControllers) { | |
| 2509 | 2541 | if (sandboxIsRunning) { |
| 2510 | 2542 | qCDebug(interfaceapp) << "Home sandbox appears to be running, going to Home."; |
| 2511 | 2543 | DependencyManager::get<AddressManager>()->goToLocalSandbox(); |
| 2544 | + sentTo = SENT_TO_SANDBOX; | |
| 2512 | 2545 | } else { |
| 2513 | 2546 | qCDebug(interfaceapp) << "Home sandbox does not appear to be running, going to Entry."; |
| 2514 | 2547 | DependencyManager::get<AddressManager>()->goToEntry(); |
| 2548 | + sentTo = SENT_TO_ENTRY; | |
| 2515 | 2549 | } |
| 2516 | 2550 | } else { |
| 2517 | 2551 | DependencyManager::get<AddressManager>()->goToEntry(); |
| 2552 | + sentTo = SENT_TO_ENTRY; | |
| 2518 | 2553 | } |
| 2519 | 2554 | } else { |
| 2520 | 2555 | qCDebug(interfaceapp) << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString); |
| 2521 | 2556 | DependencyManager::get<AddressManager>()->loadSettings(addressLookupString); |
| 2557 | + sentTo = SENT_TO_PREVIOUS_LOCATION; | |
| 2522 | 2558 | } |
| 2523 | 2559 | } |
| 2524 | 2560 | |
| 2561 | + UserActivityLogger::getInstance().logAction("startup_sent_to", { | |
| 2562 | + { "sent_to", sentTo }, | |
| 2563 | + { "sandbox_is_running", sandboxIsRunning }, | |
| 2564 | + { "has_hmd", hasHMD }, | |
| 2565 | + { "has_hand_controllers", hasHandControllers }, | |
| 2566 | + { "is_using_hmd", isUsingHMD }, | |
| 2567 | + { "is_using_hmd_and_hand_controllers", isUsingHMDAndHandControllers }, | |
| 2568 | + { "content_version", contentVersion }, | |
| 2569 | + { "is_tutorial_complete", isTutorialComplete }, | |
| 2570 | + { "has_tutorial_content", hasTutorialContent }, | |
| 2571 | + { "should_go_to_tutorial", shouldGoToTutorial } | |
| 2572 | + }); | |
| 2573 | + | |
| 2525 | 2574 | _connectionMonitor.init(); |
| 2526 | 2575 | |
| 2527 | 2576 | // After all of the constructor is completed, then set firstRun to false. |
| @@ -4439,7 +4488,11 @@ void Application::update(float deltaTime) { · 1911 unmodified lines | ||
| 4439 | 4488 | myAvatar->getSpine2CalibrationMat(), |
| 4440 | 4489 | myAvatar->getHipsCalibrationMat(), |
| 4441 | 4490 | myAvatar->getLeftFootCalibrationMat(), |
| 4442 | − myAvatar->getRightFootCalibrationMat() | |
| 4491 | + myAvatar->getRightFootCalibrationMat(), | |
| 4492 | + myAvatar->getRightArmCalibrationMat(), | |
| 4493 | + myAvatar->getLeftArmCalibrationMat(), | |
| 4494 | + myAvatar->getRightHandCalibrationMat(), | |
| 4495 | + myAvatar->getLeftHandCalibrationMat() | |
| 4443 | 4496 | }; |
| 4444 | 4497 | |
| 4445 | 4498 | InputPluginPointer keyboardMousePlugin; |
| @@ -4495,6 +4548,10 @@ void Application::update(float deltaTime) { · 49 unmodified lines | ||
| 4495 | 4548 | controller::Pose headPose = userInputMapper->getPoseState(controller::Action::HEAD); |
| 4496 | 4549 | myAvatar->setHeadControllerPoseInSensorFrame(headPose.transform(avatarToSensorMatrix)); |
| 4497 | 4550 | |
| 4551 | + controller::Pose leftArmPose = userInputMapper->getPoseState(controller::Action::LEFT_ARM); | |
| 4552 | + controller::Pose rightArmPose = userInputMapper->getPoseState(controller::Action::RIGHT_ARM); | |
| 4553 | + myAvatar->setArmControllerPosesInSensorFrame(leftArmPose.transform(avatarToSensorMatrix), rightArmPose.transform(avatarToSensorMatrix)); | |
| 4554 | + | |
| 4498 | 4555 | updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... |
| 4499 | 4556 | updateDialogs(deltaTime); // update various stats dialogs if present |
| 4500 | 4557 | |
| @@ -4949,12 +5006,6 @@ QRect Application::getDesirableApplicationGeometry() const { · 448 unmodified lines | ||
| 4949 | 5006 | return applicationGeometry; |
| 4950 | 5007 | } |
| 4951 | 5008 | |
| 4952 | −glm::vec3 Application::getSunDirection() const { | |
| 4953 | − // Sun direction is in fact just the location of the sun relative to the origin | |
| 4954 | − auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage(); | |
| 4955 | − return skyStage->getSunLight()->getDirection(); | |
| 4956 | −} | |
| 4957 | − | |
| 4958 | 5009 | // FIXME, preprocessor guard this check to occur only in DEBUG builds |
| 4959 | 5010 | static QThread * activeRenderingThread = nullptr; |
| 4960 | 5011 | |
| @@ -5021,90 +5072,6 @@ namespace render { · 60 unmodified lines | ||
| 5021 | 5072 | } |
| 5022 | 5073 | } |
| 5023 | 5074 | |
| 5024 | −// Background Render Data & rendering functions | |
| 5025 | −class BackgroundRenderData { | |
| 5026 | −public: | |
| 5027 | − typedef render::Payload<BackgroundRenderData> Payload; | |
| 5028 | − typedef Payload::DataPointer Pointer; | |
| 5029 | − | |
| 5030 | − static render::ItemID _item; // unique WorldBoxRenderData | |
| 5031 | −}; | |
| 5032 | − | |
| 5033 | −render::ItemID BackgroundRenderData::_item = 0; | |
| 5034 | − | |
| 5035 | −namespace render { | |
| 5036 | − template <> const ItemKey payloadGetKey(const BackgroundRenderData::Pointer& stuff) { | |
| 5037 | − return ItemKey::Builder::background(); | |
| 5038 | − } | |
| 5039 | − | |
| 5040 | − template <> const Item::Bound payloadGetBound(const BackgroundRenderData::Pointer& stuff) { | |
| 5041 | − return Item::Bound(); | |
| 5042 | − } | |
| 5043 | − | |
| 5044 | − template <> void payloadRender(const BackgroundRenderData::Pointer& background, RenderArgs* args) { | |
| 5045 | − Q_ASSERT(args->_batch); | |
| 5046 | − gpu::Batch& batch = *args->_batch; | |
| 5047 | − | |
| 5048 | − // Background rendering decision | |
| 5049 | − auto skyStage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage(); | |
| 5050 | − auto backgroundMode = skyStage->getBackgroundMode(); | |
| 5051 | − | |
| 5052 | − switch (backgroundMode) { | |
| 5053 | − case model::SunSkyStage::SKY_DEFAULT: { | |
| 5054 | − auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage(); | |
| 5055 | − auto sceneKeyLight = scene->getKeyLight(); | |
| 5056 | − | |
| 5057 | − scene->setSunModelEnable(false); | |
| 5058 | − sceneKeyLight->setColor(ColorUtils::toVec3(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_COLOR)); | |
| 5059 | − sceneKeyLight->setIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_INTENSITY); | |
| 5060 | − sceneKeyLight->setAmbientIntensity(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY); | |
| 5061 | − sceneKeyLight->setDirection(KeyLightPropertyGroup::DEFAULT_KEYLIGHT_DIRECTION); | |
| 5062 | − // fall through: render a skybox (if available), or the defaults (if requested) | |
| 5063 | − } | |
| 5064 | − | |
| 5065 | − case model::SunSkyStage::SKY_BOX: { | |
| 5066 | − auto skybox = skyStage->getSkybox(); | |
| 5067 | − if (!skybox->empty()) { | |
| 5068 | − PerformanceTimer perfTimer("skybox"); | |
| 5069 | − skybox->render(batch, args->getViewFrustum()); | |
| 5070 | − break; | |
| 5071 | − } | |
| 5072 | − // fall through: render defaults (if requested) | |
| 5073 | − } | |
| 5074 | − | |
| 5075 | − case model::SunSkyStage::SKY_DEFAULT_AMBIENT_TEXTURE: { | |
| 5076 | − if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) { | |
| 5077 | − auto scene = DependencyManager::get<SceneScriptingInterface>()->getStage(); | |
| 5078 | − auto sceneKeyLight = scene->getKeyLight(); | |
| 5079 | − auto defaultSkyboxAmbientTexture = qApp->getDefaultSkyboxAmbientTexture(); | |
| 5080 | − if (defaultSkyboxAmbientTexture) { | |
| 5081 | − sceneKeyLight->setAmbientSphere(defaultSkyboxAmbientTexture->getIrradiance()); | |
| 5082 | − sceneKeyLight->setAmbientMap(defaultSkyboxAmbientTexture); | |
| 5083 | − } else { | |
| 5084 | − static QString repeatedMessage = LogHandler::getInstance().addRepeatedMessageRegex( | |
| 5085 | − "Failed to get a valid Default Skybox Ambient Texture ? probably because it couldn't be find during initialization step"); | |
| 5086 | − } | |
| 5087 | − // fall through: render defaults skybox | |
| 5088 | − } else { | |
| 5089 | − break; | |
| 5090 | − } | |
| 5091 | − } | |
| 5092 | − | |
| 5093 | − case model::SunSkyStage::SKY_DEFAULT_TEXTURE: | |
| 5094 | − if (Menu::getInstance()->isOptionChecked(MenuOption::DefaultSkybox)) { | |
| 5095 | − qApp->getDefaultSkybox()->render(batch, args->getViewFrustum()); | |
| 5096 | − } | |
| 5097 | − break; | |
| 5098 | − | |
| 5099 | − // Any other cases require no extra rendering | |
| 5100 | − case model::SunSkyStage::NO_BACKGROUND: | |
| 5101 | − default: | |
| 5102 | − break; | |
| 5103 | − } | |
| 5104 | − } | |
| 5105 | −} | |
| 5106 | − | |
| 5107 | − | |
| 5108 | 5075 | void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) { |
| 5109 | 5076 | |
| 5110 | 5077 | // FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering. |
| @@ -5128,15 +5095,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 17 unmodified lines | ||
| 5128 | 5095 | // The pending changes collecting the changes here |
| 5129 | 5096 | render::Transaction transaction; |
| 5130 | 5097 | |
| 5131 | − // FIXME: Move this out of here!, Background / skybox should be driven by the enityt content just like the other entities | |
| 5132 | − // Background rendering decision | |
| 5133 | − if (!render::Item::isValidID(BackgroundRenderData::_item)) { | |
| 5134 | − auto backgroundRenderData = make_shared<BackgroundRenderData>(); | |
| 5135 | − auto backgroundRenderPayload = make_shared<BackgroundRenderData::Payload>(backgroundRenderData); | |
| 5136 | − BackgroundRenderData::_item = _main3DScene->allocateID(); | |
| 5137 | − transaction.resetItem(BackgroundRenderData::_item, backgroundRenderPayload); | |
| 5138 | − } | |
| 5139 | − | |
| 5140 | 5098 | // Assuming nothing gets rendered through that |
| 5141 | 5099 | if (!selfAvatarOnly) { |
| 5142 | 5100 | if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) { |
| @@ -5172,12 +5130,6 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 29 unmodified lines | ||
| 5172 | 5130 | }); |
| 5173 | 5131 | } |
| 5174 | 5132 | |
| 5175 | − // Setup the current Zone Entity lighting | |
| 5176 | − { | |
| 5177 | − auto stage = DependencyManager::get<SceneScriptingInterface>()->getSkyStage(); | |
| 5178 | − DependencyManager::get<DeferredLightingEffect>()->setGlobalLight(stage->getSunLight()); | |
| 5179 | − } | |
| 5180 | − | |
| 5181 | 5133 | { |
| 5182 | 5134 | PerformanceTimer perfTimer("SceneProcessTransaction"); |
| 5183 | 5135 | _main3DScene->enqueueTransaction(transaction); |