Showing the changes to interface/src/Application.cpp (1 of 136 files). Show all
Unified · Split
| @@ -20,6 +20,8 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <glm/gtc/type_ptr.hpp> |
| 21 | 21 | |
| 22 | 22 | #include <QtCore/QDebug> |
| 23 | +#include <QtCore/QJsonDocument> | |
| 24 | +#include <QtCore/QJsonObject> | |
| 23 | 25 | #include <QtCore/QObject> |
| 24 | 26 | #include <QtCore/QUrl> |
| 25 | 27 | #include <QtCore/QTimer> |
| @@ -89,6 +91,7 @@ · 63 unmodified lines | ||
| 89 | 91 | #include <ObjectMotionState.h> |
| 90 | 92 | #include <OctalCode.h> |
| 91 | 93 | #include <OctreeSceneStats.h> |
| 94 | +#include <OffscreenUi.h> | |
| 92 | 95 | #include <gl/OffscreenGLCanvas.h> |
| 93 | 96 | #include <PathUtils.h> |
| 94 | 97 | #include <PerfStat.h> |
| @@ -187,6 +190,7 @@ static const QString JS_EXTENSION = ".js"; · 92 unmodified lines | ||
| 187 | 190 | static const QString FST_EXTENSION = ".fst"; |
| 188 | 191 | static const QString FBX_EXTENSION = ".fbx"; |
| 189 | 192 | static const QString OBJ_EXTENSION = ".obj"; |
| 193 | +static const QString AVA_JSON_EXTENSION = ".ava.json"; | |
| 190 | 194 | |
| 191 | 195 | static const int MIRROR_VIEW_TOP_PADDING = 5; |
| 192 | 196 | static const int MIRROR_VIEW_LEFT_PADDING = 10; |
| @@ -222,7 +226,8 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi · 29 unmodified lines | ||
| 222 | 226 | { SVO_EXTENSION, &Application::importSVOFromURL }, |
| 223 | 227 | { SVO_JSON_EXTENSION, &Application::importSVOFromURL }, |
| 224 | 228 | { JS_EXTENSION, &Application::askToLoadScript }, |
| 225 | − { FST_EXTENSION, &Application::askToSetAvatarUrl } | |
| 229 | + { FST_EXTENSION, &Application::askToSetAvatarUrl }, | |
| 230 | + { AVA_JSON_EXTENSION, &Application::askToWearAvatarAttachmentUrl } | |
| 226 | 231 | }; |
| 227 | 232 | |
| 228 | 233 | #ifdef Q_OS_WIN |
| @@ -347,7 +352,7 @@ bool setupEssentials(int& argc, char** argv) { · 118 unmodified lines | ||
| 347 | 352 | DependencyManager::set<WindowScriptingInterface>(); |
| 348 | 353 | DependencyManager::set<HMDScriptingInterface>(); |
| 349 | 354 | DependencyManager::set<ResourceScriptingInterface>(); |
| 350 | − | |
| 355 | + | |
| 351 | 356 | |
| 352 | 357 | #if defined(Q_OS_MAC) || defined(Q_OS_WIN) |
| 353 | 358 | DependencyManager::set<SpeechRecognizer>(); |
| @@ -378,7 +383,7 @@ PluginContainer* _pluginContainer; · 24 unmodified lines | ||
| 378 | 383 | |
| 379 | 384 | |
| 380 | 385 | // FIXME hack access to the internal share context for the Chromium helper |
| 381 | −// Normally we'd want to use QWebEngine::initialize(), but we can't because | |
| 386 | +// Normally we'd want to use QWebEngine::initialize(), but we can't because | |
| 382 | 387 | // our primary context is a QGLWidget, which can't easily be initialized to share |
| 383 | 388 | // from a QOpenGLContext. |
| 384 | 389 | // |
| @@ -694,7 +699,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 309 unmodified lines | ||
| 694 | 699 | auto userInputMapper = DependencyManager::get<UserInputMapper>(); |
| 695 | 700 | connect(userInputMapper.data(), &UserInputMapper::actionEvent, [this](int action, float state) { |
| 696 | 701 | using namespace controller; |
| 697 | − static auto offscreenUi = DependencyManager::get<OffscreenUi>(); | |
| 702 | + auto offscreenUi = DependencyManager::get<OffscreenUi>(); | |
| 698 | 703 | if (offscreenUi->navigationFocused()) { |
| 699 | 704 | auto actionEnum = static_cast<Action>(action); |
| 700 | 705 | int key = Qt::Key_unknown; |
| @@ -735,6 +740,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 34 unmodified lines | ||
| 735 | 740 | case Action::UI_NAV_SELECT: |
| 736 | 741 | key = Qt::Key_Return; |
| 737 | 742 | break; |
| 743 | + default: | |
| 744 | + break; | |
| 738 | 745 | } |
| 739 | 746 | |
| 740 | 747 | if (navAxis) { |
| @@ -832,7 +839,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : · 91 unmodified lines | ||
| 832 | 839 | return (float)qApp->getMyAvatar()->getCharacterController()->onGround(); |
| 833 | 840 | })); |
| 834 | 841 | _applicationStateDevice->addInputVariant(QString("NavigationFocused"), controller::StateController::ReadLambda([]() -> float { |
| 835 | − static auto offscreenUi = DependencyManager::get<OffscreenUi>(); | |
| 842 | + auto offscreenUi = DependencyManager::get<OffscreenUi>(); | |
| 836 | 843 | return offscreenUi->navigationFocused() ? 1.0 : 0.0; |
| 837 | 844 | })); |
| 838 | 845 | |
| @@ -1035,7 +1042,7 @@ void Application::cleanupBeforeQuit() { · 196 unmodified lines | ||
| 1035 | 1042 | |
| 1036 | 1043 | // destroy the AudioClient so it and its thread have a chance to go down safely |
| 1037 | 1044 | DependencyManager::destroy<AudioClient>(); |
| 1038 | − | |
| 1045 | + | |
| 1039 | 1046 | // destroy the AudioInjectorManager so it and its thread have a chance to go down safely |
| 1040 | 1047 | // this will also stop any ongoing network injectors |
| 1041 | 1048 | DependencyManager::destroy<AudioInjectorManager>(); |
| @@ -1047,6 +1054,8 @@ void Application::cleanupBeforeQuit() { · 5 unmodified lines | ||
| 1047 | 1054 | #ifdef HAVE_IVIEWHMD |
| 1048 | 1055 | DependencyManager::destroy<EyeTracker>(); |
| 1049 | 1056 | #endif |
| 1057 | + | |
| 1058 | + DependencyManager::destroy<OffscreenUi>(); | |
| 1050 | 1059 | } |
| 1051 | 1060 | |
| 1052 | 1061 | void Application::emptyLocalCache() { |
| @@ -1080,8 +1089,8 @@ Application::~Application() { · 27 unmodified lines | ||
| 1080 | 1089 | // remove avatars from physics engine |
| 1081 | 1090 | DependencyManager::get<AvatarManager>()->clearOtherAvatars(); |
| 1082 | 1091 | VectorOfMotionStates motionStates; |
| 1083 | − DependencyManager::get<AvatarManager>()->getObjectsToDelete(motionStates); | |
| 1084 | − _physicsEngine->deleteObjects(motionStates); | |
| 1092 | + DependencyManager::get<AvatarManager>()->getObjectsToRemoveFromPhysics(motionStates); | |
| 1093 | + _physicsEngine->removeObjects(motionStates); | |
| 1085 | 1094 | |
| 1086 | 1095 | DependencyManager::destroy<OffscreenUi>(); |
| 1087 | 1096 | DependencyManager::destroy<AvatarManager>(); |
| @@ -1176,7 +1185,6 @@ void Application::initializeUi() { · 88 unmodified lines | ||
| 1176 | 1185 | offscreenUi->setProxyWindow(_window->windowHandle()); |
| 1177 | 1186 | offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/")); |
| 1178 | 1187 | offscreenUi->load("Root.qml"); |
| 1179 | − offscreenUi->load("RootMenu.qml"); | |
| 1180 | 1188 | // FIXME either expose so that dialogs can set this themselves or |
| 1181 | 1189 | // do better detection in the offscreen UI of what has focus |
| 1182 | 1190 | offscreenUi->setNavigationFocused(false); |
| @@ -1265,7 +1273,7 @@ void Application::initializeUi() { · 82 unmodified lines | ||
| 1265 | 1273 | } |
| 1266 | 1274 | |
| 1267 | 1275 | void Application::paintGL() { |
| 1268 | − // paintGL uses a queued connection, so we can get messages from the queue even after we've quit | |
| 1276 | + // paintGL uses a queued connection, so we can get messages from the queue even after we've quit | |
| 1269 | 1277 | // and the plugins have shutdown |
| 1270 | 1278 | if (_aboutToQuit) { |
| 1271 | 1279 | return; |
| @@ -1335,7 +1343,7 @@ void Application::paintGL() { · 63 unmodified lines | ||
| 1335 | 1343 | renderArgs._context->syncCache(); |
| 1336 | 1344 | } |
| 1337 | 1345 | |
| 1338 | − if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { | |
| 1346 | + if (Menu::getInstance()->isOptionChecked(MenuOption::MiniMirror)) { | |
| 1339 | 1347 | PerformanceTimer perfTimer("Mirror"); |
| 1340 | 1348 | auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer(); |
| 1341 | 1349 | |
| @@ -1624,7 +1632,7 @@ void Application::aboutApp() { · 282 unmodified lines | ||
| 1624 | 1632 | InfoView::show(INFO_HELP_PATH); |
| 1625 | 1633 | } |
| 1626 | 1634 | |
| 1627 | −void Application::showEditEntitiesHelp() { | |
| 1635 | +void Application::showHelp() { | |
| 1628 | 1636 | InfoView::show(INFO_EDIT_ENTITIES_PATH); |
| 1629 | 1637 | } |
| 1630 | 1638 | |
| @@ -1982,7 +1990,7 @@ void Application::keyPressEvent(QKeyEvent* event) { · 351 unmodified lines | ||
| 1982 | 1990 | |
| 1983 | 1991 | case Qt::Key_H: |
| 1984 | 1992 | if (isShifted) { |
| 1985 | − Menu::getInstance()->triggerOption(MenuOption::Mirror); | |
| 1993 | + Menu::getInstance()->triggerOption(MenuOption::MiniMirror); | |
| 1986 | 1994 | } else { |
| 1987 | 1995 | Menu::getInstance()->setIsOptionChecked(MenuOption::FullscreenMirror, !Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)); |
| 1988 | 1996 | if (!Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { |
| @@ -3082,11 +3090,11 @@ void Application::update(float deltaTime) { · 1093 unmodified lines | ||
| 3082 | 3090 | PerformanceTimer perfTimer("physics"); |
| 3083 | 3091 | |
| 3084 | 3092 | static VectorOfMotionStates motionStates; |
| 3085 | − _entitySimulation.getObjectsToDelete(motionStates); | |
| 3086 | − _physicsEngine->deleteObjects(motionStates); | |
| 3093 | + _entitySimulation.getObjectsToRemoveFromPhysics(motionStates); | |
| 3094 | + _physicsEngine->removeObjects(motionStates); | |
| 3087 | 3095 | |
| 3088 | 3096 | getEntities()->getTree()->withWriteLock([&] { |
| 3089 | − _entitySimulation.getObjectsToAdd(motionStates); | |
| 3097 | + _entitySimulation.getObjectsToAddToPhysics(motionStates); | |
| 3090 | 3098 | _physicsEngine->addObjects(motionStates); |
| 3091 | 3099 | |
| 3092 | 3100 | }); |
| @@ -3099,9 +3107,9 @@ void Application::update(float deltaTime) { · 6 unmodified lines | ||
| 3099 | 3107 | _entitySimulation.applyActionChanges(); |
| 3100 | 3108 | |
| 3101 | 3109 | AvatarManager* avatarManager = DependencyManager::get<AvatarManager>().data(); |
| 3102 | − avatarManager->getObjectsToDelete(motionStates); | |
| 3103 | − _physicsEngine->deleteObjects(motionStates); | |
| 3104 | − avatarManager->getObjectsToAdd(motionStates); | |
| 3110 | + avatarManager->getObjectsToRemoveFromPhysics(motionStates); | |
| 3111 | + _physicsEngine->removeObjects(motionStates); | |
| 3112 | + avatarManager->getObjectsToAddToPhysics(motionStates); | |
| 3105 | 3113 | _physicsEngine->addObjects(motionStates); |
| 3106 | 3114 | avatarManager->getObjectsToChange(motionStates); |
| 3107 | 3115 | _physicsEngine->changeObjects(motionStates); |
| @@ -3738,7 +3746,7 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se · 630 unmodified lines | ||
| 3738 | 3746 | auto backgroundRenderData = make_shared<BackgroundRenderData>(&_environment); |
| 3739 | 3747 | auto backgroundRenderPayload = make_shared<BackgroundRenderData::Payload>(backgroundRenderData); |
| 3740 | 3748 | BackgroundRenderData::_item = _main3DScene->allocateID(); |
| 3741 | − pendingChanges.resetItem(WorldBoxRenderData::_item, backgroundRenderPayload); | |
| 3749 | + pendingChanges.resetItem(BackgroundRenderData::_item, backgroundRenderPayload); | |
| 3742 | 3750 | } else { |
| 3743 | 3751 | |
| 3744 | 3752 | } |
| @@ -4080,7 +4088,7 @@ bool Application::nearbyEntitiesAreReadyForPhysics() { · 335 unmodified lines | ||
| 4080 | 4088 | }); |
| 4081 | 4089 | |
| 4082 | 4090 | foreach (EntityItemPointer entity, entities) { |
| 4083 | − if (!entity->isReadyToComputeShape()) { | |
| 4091 | + if (entity->shouldBePhysical() && !entity->isReadyToComputeShape()) { | |
| 4084 | 4092 | static QString repeatedMessage = |
| 4085 | 4093 | LogHandler::getInstance().addRepeatedMessageRegex("Physics disabled until entity loads: .*"); |
| 4086 | 4094 | qCDebug(interfaceapp) << "Physics disabled until entity loads: " << entity->getID() << entity->getName(); |
| @@ -4380,7 +4388,7 @@ bool Application::askToSetAvatarUrl(const QString& url) { · 293 unmodified lines | ||
| 4380 | 4388 | bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { |
| 4381 | 4389 | QMessageBox::StandardButton reply; |
| 4382 | 4390 | QString message = "Would you like to run this script:\n" + scriptFilenameOrURL; |
| 4383 | − reply = QMessageBox::question(getWindow(), "Run Script", message, QMessageBox::Yes|QMessageBox::No); | |
| 4391 | + reply = OffscreenUi::question(getWindow(), "Run Script", message, QMessageBox::Yes | QMessageBox::No); | |
| 4384 | 4392 | |
| 4385 | 4393 | if (reply == QMessageBox::Yes) { |
| 4386 | 4394 | qCDebug(interfaceapp) << "Chose to run the script: " << scriptFilenameOrURL; |
| @@ -4393,7 +4401,7 @@ bool Application::askToLoadScript(const QString& scriptFilenameOrURL) { · 6 unmodified lines | ||
| 4393 | 4401 | |
| 4394 | 4402 | bool Application::askToUploadAsset(const QString& filename) { |
| 4395 | 4403 | if (!DependencyManager::get<NodeList>()->getThisNodeCanRez()) { |
| 4396 | − QMessageBox::warning(_window, "Failed Upload", | |
| 4404 | + OffscreenUi::warning(_window, "Failed Upload", | |
| 4397 | 4405 | QString("You don't have upload rights on that domain.\n\n")); |
| 4398 | 4406 | return false; |
| 4399 | 4407 | } |
| @@ -4437,7 +4445,7 @@ bool Application::askToUploadAsset(const QString& filename) { · 37 unmodified lines | ||
| 4437 | 4445 | } |
| 4438 | 4446 | |
| 4439 | 4447 | // display a message box with the error |
| 4440 | − QMessageBox::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename)); | |
| 4448 | + OffscreenUi::warning(_window, "Failed Upload", QString("Failed to upload %1.\n\n").arg(filename)); | |
| 4441 | 4449 | return false; |
| 4442 | 4450 | } |
| 4443 | 4451 | |
| @@ -4464,6 +4472,99 @@ void Application::modelUploadFinished(AssetUpload* upload, const QString& hash) · 20 unmodified lines | ||
| 4464 | 4472 | } |
| 4465 | 4473 | } |
| 4466 | 4474 | |
| 4475 | +bool Application::askToWearAvatarAttachmentUrl(const QString& url) { | |
| 4476 | + | |
| 4477 | + QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); | |
| 4478 | + QNetworkRequest networkRequest = QNetworkRequest(url); | |
| 4479 | + networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); | |
| 4480 | + QNetworkReply* reply = networkAccessManager.get(networkRequest); | |
| 4481 | + int requestNumber = ++_avatarAttachmentRequest; | |
| 4482 | + connect(reply, &QNetworkReply::finished, [this, reply, url, requestNumber]() { | |
| 4483 | + | |
| 4484 | + if (requestNumber != _avatarAttachmentRequest) { | |
| 4485 | + // this request has been superseded by another more recent request | |
| 4486 | + reply->deleteLater(); | |
| 4487 | + return; | |
| 4488 | + } | |
| 4489 | + | |
| 4490 | + QNetworkReply::NetworkError networkError = reply->error(); | |
| 4491 | + if (networkError == QNetworkReply::NoError) { | |
| 4492 | + // download success | |
| 4493 | + QByteArray contents = reply->readAll(); | |
| 4494 | + | |
| 4495 | + QJsonParseError jsonError; | |
| 4496 | + auto doc = QJsonDocument::fromJson(contents, &jsonError); | |
| 4497 | + if (jsonError.error == QJsonParseError::NoError) { | |
| 4498 | + | |
| 4499 | + auto jsonObject = doc.object(); | |
| 4500 | + | |
| 4501 | + // retrieve optional name field from JSON | |
| 4502 | + QString name = tr("Unnamed Attachment"); | |
| 4503 | + auto nameValue = jsonObject.value("name"); | |
| 4504 | + if (nameValue.isString()) { | |
| 4505 | + name = nameValue.toString(); | |
| 4506 | + } | |
| 4507 | + | |
| 4508 | + // display confirmation dialog | |
| 4509 | + if (displayAvatarAttachmentConfirmationDialog(name)) { | |
| 4510 | + | |
| 4511 | + // add attachment to avatar | |
| 4512 | + auto myAvatar = getMyAvatar(); | |
| 4513 | + assert(myAvatar); | |
| 4514 | + auto attachmentDataVec = myAvatar->getAttachmentData(); | |
| 4515 | + AttachmentData attachmentData; | |
| 4516 | + attachmentData.fromJson(jsonObject); | |
| 4517 | + attachmentDataVec.push_back(attachmentData); | |
| 4518 | + myAvatar->setAttachmentData(attachmentDataVec); | |
| 4519 | + | |
| 4520 | + } else { | |
| 4521 | + qCDebug(interfaceapp) << "User declined to wear the avatar attachment: " << url; | |
| 4522 | + } | |
| 4523 | + | |
| 4524 | + } else { | |
| 4525 | + // json parse error | |
| 4526 | + auto avatarAttachmentParseErrorString = tr("Error parsing attachment JSON from url: \"%1\""); | |
| 4527 | + displayAvatarAttachmentWarning(avatarAttachmentParseErrorString.arg(url)); | |
| 4528 | + } | |
| 4529 | + } else { | |
| 4530 | + // download failure | |
| 4531 | + auto avatarAttachmentDownloadErrorString = tr("Error downloading attachment JSON from url: \"%1\""); | |
| 4532 | + displayAvatarAttachmentWarning(avatarAttachmentDownloadErrorString.arg(url)); | |
| 4533 | + } | |
| 4534 | + reply->deleteLater(); | |
| 4535 | + }); | |
| 4536 | + return true; | |
| 4537 | +} | |
| 4538 | + | |
| 4539 | +void Application::displayAvatarAttachmentWarning(const QString& message) const { | |
| 4540 | + auto avatarAttachmentWarningTitle = tr("Avatar Attachment Failure"); | |
| 4541 | + QMessageBox msgBox; | |
| 4542 | + msgBox.setIcon(QMessageBox::Warning); | |
| 4543 | + msgBox.setWindowTitle(avatarAttachmentWarningTitle); | |
| 4544 | + msgBox.setText(message); | |
| 4545 | + msgBox.exec(); | |
| 4546 | + msgBox.addButton(QMessageBox::Ok); | |
| 4547 | + msgBox.exec(); | |
| 4548 | +} | |
| 4549 | + | |
| 4550 | +bool Application::displayAvatarAttachmentConfirmationDialog(const QString& name) const { | |
| 4551 | + auto avatarAttachmentConfirmationTitle = tr("Avatar Attachment Confirmation"); | |
| 4552 | + auto avatarAttachmentConfirmationMessage = tr("Would you like to wear '%1' on your avatar?"); | |
| 4553 | + QMessageBox msgBox; | |
| 4554 | + msgBox.setIcon(QMessageBox::Question); | |
| 4555 | + msgBox.setWindowTitle(avatarAttachmentConfirmationTitle); | |
| 4556 | + QPushButton* button = msgBox.addButton(tr("Yes"), QMessageBox::ActionRole); | |
| 4557 | + QString message = avatarAttachmentConfirmationMessage.arg(name); | |
| 4558 | + msgBox.setText(message); | |
| 4559 | + msgBox.addButton(QMessageBox::Cancel); | |
| 4560 | + msgBox.exec(); | |
| 4561 | + if (msgBox.clickedButton() == button) { | |
| 4562 | + return true; | |
| 4563 | + } else { | |
| 4564 | + return false; | |
| 4565 | + } | |
| 4566 | +} | |
| 4567 | + | |
| 4467 | 4568 | ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUserLoaded, |
| 4468 | 4569 | bool loadScriptFromEditor, bool activateMainWindow, bool reload) { |
| 4469 | 4570 | |
| @@ -4535,7 +4636,7 @@ void Application::handleScriptEngineLoaded(const QString& scriptFilename) { · 65 unmodified lines | ||
| 4535 | 4636 | // FIXME - change to new version of ScriptCache loading notification |
| 4536 | 4637 | void Application::handleScriptLoadError(const QString& scriptFilename) { |
| 4537 | 4638 | qCDebug(interfaceapp) << "Application::loadScript(), script failed to load..."; |
| 4538 | − QMessageBox::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load."); | |
| 4639 | + OffscreenUi::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load."); | |
| 4539 | 4640 | } |
| 4540 | 4641 | |
| 4541 | 4642 | QStringList Application::getRunningScripts() { |
| @@ -4991,7 +5092,7 @@ void Application::updateDisplayMode() { · 449 unmodified lines | ||
| 4991 | 5092 | foreach(auto displayPlugin, displayPlugins) { |
| 4992 | 5093 | addDisplayPluginToMenu(displayPlugin, first); |
| 4993 | 5094 | // This must be a queued connection to avoid a deadlock |
| 4994 | − QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, | |
| 5095 | + QObject::connect(displayPlugin.get(), &DisplayPlugin::requestRender, | |
| 4995 | 5096 | this, &Application::paintGL, Qt::QueuedConnection); |
| 4996 | 5097 | |
| 4997 | 5098 | QObject::connect(displayPlugin.get(), &DisplayPlugin::recommendedFramebufferSizeChanged, [this](const QSize & size) { |