Showing the changes to interface/src/Application.cpp (1 of 498 files). Show all
Unified · Split
| @@ -319,7 +319,7 @@ static QTimer pingTimer; · 318 unmodified lines | ||
| 319 | 319 | static bool DISABLE_WATCHDOG = true; |
| 320 | 320 | #else |
| 321 | 321 | static const QString DISABLE_WATCHDOG_FLAG{ "HIFI_DISABLE_WATCHDOG" }; |
| 322 | −static bool DISABLE_WATCHDOG = QProcessEnvironment::systemEnvironment().contains(DISABLE_WATCHDOG_FLAG); | |
| 322 | +static bool DISABLE_WATCHDOG = nsightActive() || QProcessEnvironment::systemEnvironment().contains(DISABLE_WATCHDOG_FLAG); | |
| 323 | 323 | #endif |
| 324 | 324 | |
| 325 | 325 | #if defined(USE_GLES) |
| @@ -336,15 +336,17 @@ static const int MAX_CONCURRENT_RESOURCE_DOWNLOADS = 16; · 10 unmodified lines | ||
| 336 | 336 | // we will never drop below the 'min' value |
| 337 | 337 | static const int MIN_PROCESSING_THREAD_POOL_SIZE = 1; |
| 338 | 338 | |
| 339 | −static const QString SNAPSHOT_EXTENSION = ".jpg"; | |
| 340 | −static const QString SVO_EXTENSION = ".svo"; | |
| 339 | +static const QString SNAPSHOT_EXTENSION = ".jpg"; | |
| 340 | +static const QString JPG_EXTENSION = ".jpg"; | |
| 341 | +static const QString PNG_EXTENSION = ".png"; | |
| 342 | +static const QString SVO_EXTENSION = ".svo"; | |
| 341 | 343 | static const QString SVO_JSON_EXTENSION = ".svo.json"; |
| 342 | 344 | static const QString JSON_GZ_EXTENSION = ".json.gz"; |
| 343 | 345 | static const QString JSON_EXTENSION = ".json"; |
| 344 | −static const QString JS_EXTENSION = ".js"; | |
| 345 | −static const QString FST_EXTENSION = ".fst"; | |
| 346 | −static const QString FBX_EXTENSION = ".fbx"; | |
| 347 | −static const QString OBJ_EXTENSION = ".obj"; | |
| 346 | +static const QString JS_EXTENSION = ".js"; | |
| 347 | +static const QString FST_EXTENSION = ".fst"; | |
| 348 | +static const QString FBX_EXTENSION = ".fbx"; | |
| 349 | +static const QString OBJ_EXTENSION = ".obj"; | |
| 348 | 350 | static const QString AVA_JSON_EXTENSION = ".ava.json"; |
| 349 | 351 | static const QString WEB_VIEW_TAG = "noDownload=true"; |
| 350 | 352 | static const QString ZIP_EXTENSION = ".zip"; |
| @@ -383,7 +385,9 @@ const QHash<QString, Application::AcceptURLMethod> Application::_acceptedExtensi · 32 unmodified lines | ||
| 383 | 385 | { JS_EXTENSION, &Application::askToLoadScript }, |
| 384 | 386 | { FST_EXTENSION, &Application::askToSetAvatarUrl }, |
| 385 | 387 | { JSON_GZ_EXTENSION, &Application::askToReplaceDomainContent }, |
| 386 | − { ZIP_EXTENSION, &Application::importFromZIP } | |
| 388 | + { ZIP_EXTENSION, &Application::importFromZIP }, | |
| 389 | + { JPG_EXTENSION, &Application::importImage }, | |
| 390 | + { PNG_EXTENSION, &Application::importImage } | |
| 387 | 391 | }; |
| 388 | 392 | |
| 389 | 393 | class DeadlockWatchdogThread : public QThread { |
| @@ -416,20 +420,26 @@ public: · 26 unmodified lines | ||
| 416 | 420 | *crashTrigger = 0xDEAD10CC; |
| 417 | 421 | } |
| 418 | 422 | |
| 423 | + static void withPause(const std::function<void()>& lambda) { | |
| 424 | + pause(); | |
| 425 | + lambda(); | |
| 426 | + resume(); | |
| 427 | + } | |
| 419 | 428 | static void pause() { |
| 420 | 429 | _paused = true; |
| 421 | 430 | } |
| 422 | 431 | |
| 423 | 432 | static void resume() { |
| 424 | − _paused = false; | |
| 433 | + // Update the heartbeat BEFORE resuming the checks | |
| 425 | 434 | updateHeartbeat(); |
| 435 | + _paused = false; | |
| 426 | 436 | } |
| 427 | 437 | |
| 428 | 438 | void run() override { |
| 429 | 439 | while (!_quit) { |
| 430 | 440 | QThread::sleep(HEARTBEAT_UPDATE_INTERVAL_SECS); |
| 431 | 441 | // Don't do heartbeat detection under nsight |
| 432 | − if (nsightActive() || _paused) { | |
| 442 | + if (_paused) { | |
| 433 | 443 | continue; |
| 434 | 444 | } |
| 435 | 445 | uint64_t lastHeartbeat = _heartbeat; // sample atomic _heartbeat, because we could context switch away and have it updated on us |
| @@ -863,6 +873,8 @@ std::shared_ptr<Cube3DOverlay> _keyboardFocusHighlight{ nullptr }; · 427 unmodified lines | ||
| 863 | 873 | OverlayID _keyboardFocusHighlightID{ UNKNOWN_OVERLAY_ID }; |
| 864 | 874 | |
| 865 | 875 | |
| 876 | +OffscreenGLCanvas* _qmlShareContext { nullptr }; | |
| 877 | + | |
| 866 | 878 | // FIXME hack access to the internal share context for the Chromium helper |
| 867 | 879 | // Normally we'd want to use QWebEngine::initialize(), but we can't because |
| 868 | 880 | // our primary context is a QGLWidget, which can't easily be initialized to share |
| @@ -1112,7 +1124,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 243 unmodified lines | ||
| 1112 | 1124 | connect(nodeList.data(), &NodeList::packetVersionMismatch, this, &Application::notifyPacketVersionMismatch); |
| 1113 | 1125 | |
| 1114 | 1126 | // you might think we could just do this in NodeList but we only want this connection for Interface |
| 1115 | − connect(nodeList.data(), &NodeList::limitOfSilentDomainCheckInsReached, nodeList.data(), &NodeList::reset); | |
| 1127 | + connect(&nodeList->getDomainHandler(), SIGNAL(limitOfSilentDomainCheckInsReached()), | |
| 1128 | + nodeList.data(), SLOT(reset())); | |
| 1116 | 1129 | |
| 1117 | 1130 | auto dialogsManager = DependencyManager::get<DialogsManager>(); |
| 1118 | 1131 | connect(accountManager.data(), &AccountManager::authRequired, dialogsManager.data(), &DialogsManager::showLoginDialog); |
| @@ -1646,6 +1659,73 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 527 unmodified lines | ||
| 1646 | 1659 | } |
| 1647 | 1660 | }); |
| 1648 | 1661 | |
| 1662 | + EntityTree::setAddMaterialToEntityOperator([&](const QUuid& entityID, graphics::MaterialLayer material, const std::string& parentMaterialName) { | |
| 1663 | + // try to find the renderable | |
| 1664 | + auto renderable = getEntities()->renderableForEntityId(entityID); | |
| 1665 | + if (renderable) { | |
| 1666 | + renderable->addMaterial(material, parentMaterialName); | |
| 1667 | + } | |
| 1668 | + | |
| 1669 | + // even if we don't find it, try to find the entity | |
| 1670 | + auto entity = getEntities()->getEntity(entityID); | |
| 1671 | + if (entity) { | |
| 1672 | + entity->addMaterial(material, parentMaterialName); | |
| 1673 | + return true; | |
| 1674 | + } | |
| 1675 | + return false; | |
| 1676 | + }); | |
| 1677 | + EntityTree::setRemoveMaterialFromEntityOperator([&](const QUuid& entityID, graphics::MaterialPointer material, const std::string& parentMaterialName) { | |
| 1678 | + // try to find the renderable | |
| 1679 | + auto renderable = getEntities()->renderableForEntityId(entityID); | |
| 1680 | + if (renderable) { | |
| 1681 | + renderable->removeMaterial(material, parentMaterialName); | |
| 1682 | + } | |
| 1683 | + | |
| 1684 | + // even if we don't find it, try to find the entity | |
| 1685 | + auto entity = getEntities()->getEntity(entityID); | |
| 1686 | + if (entity) { | |
| 1687 | + entity->removeMaterial(material, parentMaterialName); | |
| 1688 | + return true; | |
| 1689 | + } | |
| 1690 | + return false; | |
| 1691 | + }); | |
| 1692 | + | |
| 1693 | + EntityTree::setAddMaterialToAvatarOperator([](const QUuid& avatarID, graphics::MaterialLayer material, const std::string& parentMaterialName) { | |
| 1694 | + auto avatarManager = DependencyManager::get<AvatarManager>(); | |
| 1695 | + auto avatar = avatarManager->getAvatarBySessionID(avatarID); | |
| 1696 | + if (avatar) { | |
| 1697 | + avatar->addMaterial(material, parentMaterialName); | |
| 1698 | + return true; | |
| 1699 | + } | |
| 1700 | + return false; | |
| 1701 | + }); | |
| 1702 | + EntityTree::setRemoveMaterialFromAvatarOperator([](const QUuid& avatarID, graphics::MaterialPointer material, const std::string& parentMaterialName) { | |
| 1703 | + auto avatarManager = DependencyManager::get<AvatarManager>(); | |
| 1704 | + auto avatar = avatarManager->getAvatarBySessionID(avatarID); | |
| 1705 | + if (avatar) { | |
| 1706 | + avatar->removeMaterial(material, parentMaterialName); | |
| 1707 | + return true; | |
| 1708 | + } | |
| 1709 | + return false; | |
| 1710 | + }); | |
| 1711 | + | |
| 1712 | + EntityTree::setAddMaterialToOverlayOperator([&](const QUuid& overlayID, graphics::MaterialLayer material, const std::string& parentMaterialName) { | |
| 1713 | + auto overlay = _overlays.getOverlay(overlayID); | |
| 1714 | + if (overlay) { | |
| 1715 | + overlay->addMaterial(material, parentMaterialName); | |
| 1716 | + return true; | |
| 1717 | + } | |
| 1718 | + return false; | |
| 1719 | + }); | |
| 1720 | + EntityTree::setRemoveMaterialFromOverlayOperator([&](const QUuid& overlayID, graphics::MaterialPointer material, const std::string& parentMaterialName) { | |
| 1721 | + auto overlay = _overlays.getOverlay(overlayID); | |
| 1722 | + if (overlay) { | |
| 1723 | + overlay->removeMaterial(material, parentMaterialName); | |
| 1724 | + return true; | |
| 1725 | + } | |
| 1726 | + return false; | |
| 1727 | + }); | |
| 1728 | + | |
| 1649 | 1729 | // Keyboard focus handling for Web overlays. |
| 1650 | 1730 | auto overlays = &(qApp->getOverlays()); |
| 1651 | 1731 | connect(overlays, &Overlays::overlayDeleted, [=](const OverlayID& overlayID) { |
| @@ -2324,18 +2404,37 @@ void Application::initializeGL() { · 672 unmodified lines | ||
| 2324 | 2404 | _isGLInitialized = true; |
| 2325 | 2405 | } |
| 2326 | 2406 | |
| 2407 | + // Build a shared canvas / context for the Chromium processes | |
| 2327 | 2408 | _glWidget->makeCurrent(); |
| 2328 | 2409 | |
| 2329 | 2410 | #if !defined(DISABLE_QML) |
| 2411 | + // Chromium rendering uses some GL functions that prevent nSight from capturing | |
| 2412 | + // frames, so we only create the shared context if nsight is NOT active. | |
| 2330 | 2413 | if (!nsightActive()) { |
| 2331 | 2414 | _chromiumShareContext = new OffscreenGLCanvas(); |
| 2332 | 2415 | _chromiumShareContext->setObjectName("ChromiumShareContext"); |
| 2333 | 2416 | _chromiumShareContext->create(_glWidget->qglContext()); |
| 2334 | 2417 | _chromiumShareContext->makeCurrent(); |
| 2418 | + if (!_chromiumShareContext->makeCurrent()) { | |
| 2419 | + qCWarning(interfaceapp, "Unable to make chromium shared context current"); | |
| 2420 | + } | |
| 2335 | 2421 | qt_gl_set_global_share_context(_chromiumShareContext->getContext()); |
| 2422 | + } else { | |
| 2423 | + qCWarning(interfaceapp) << "nSIGHT detected, disabling chrome rendering"; | |
| 2336 | 2424 | } |
| 2337 | 2425 | #endif |
| 2338 | 2426 | |
| 2427 | + // Build a shared canvas / context for the QML rendering | |
| 2428 | + _glWidget->makeCurrent(); | |
| 2429 | + _qmlShareContext = new OffscreenGLCanvas(); | |
| 2430 | + _qmlShareContext->setObjectName("QmlShareContext"); | |
| 2431 | + _qmlShareContext->create(_glWidget->qglContext()); | |
| 2432 | + if (!_qmlShareContext->makeCurrent()) { | |
| 2433 | + qCWarning(interfaceapp, "Unable to make QML shared context current"); | |
| 2434 | + } | |
| 2435 | + OffscreenQmlSurface::setSharedContext(_qmlShareContext->getContext()); | |
| 2436 | + _qmlShareContext->doneCurrent(); | |
| 2437 | + | |
| 2339 | 2438 | _glWidget->makeCurrent(); |
| 2340 | 2439 | gpu::Context::init<gpu::gl::GLBackend>(); |
| 2341 | 2440 | qApp->setProperty(hifi::properties::gl::MAKE_PROGRAM_CALLBACK, |
| @@ -2348,29 +2447,22 @@ void Application::initializeGL() { · 6 unmodified lines | ||
| 2348 | 2447 | initDisplay(); |
| 2349 | 2448 | qCDebug(interfaceapp, "Initialized Display."); |
| 2350 | 2449 | |
| 2351 | −#ifdef Q_OS_OSX | |
| 2352 | − // FIXME: on mac os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread. | |
| 2353 | − DeadlockWatchdogThread::pause(); | |
| 2354 | −#endif | |
| 2355 | − | |
| 2356 | − // Set up the render engine | |
| 2357 | − render::CullFunctor cullFunctor = LODManager::shouldRender; | |
| 2358 | − static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD"; | |
| 2359 | − _renderEngine->addJob<UpdateSceneTask>("UpdateScene"); | |
| 2450 | + // FIXME: on low end systems os the shaders take up to 1 minute to compile, so we pause the deadlock watchdog thread. | |
| 2451 | + DeadlockWatchdogThread::withPause([&] { | |
| 2452 | + // Set up the render engine | |
| 2453 | + render::CullFunctor cullFunctor = LODManager::shouldRender; | |
| 2454 | + static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD"; | |
| 2455 | + _renderEngine->addJob<UpdateSceneTask>("UpdateScene"); | |
| 2360 | 2456 | #ifndef Q_OS_ANDROID |
| 2361 | − _renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED); | |
| 2457 | + _renderEngine->addJob<SecondaryCameraRenderTask>("SecondaryCameraJob", cullFunctor, !DISABLE_DEFERRED); | |
| 2362 | 2458 | #endif |
| 2363 | − _renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED); | |
| 2459 | + _renderEngine->addJob<RenderViewTask>("RenderMainView", cullFunctor, !DISABLE_DEFERRED, render::ItemKey::TAG_BITS_0, render::ItemKey::TAG_BITS_0); | |
| 2460 | + _renderEngine->load(); | |
| 2461 | + _renderEngine->registerScene(_main3DScene); | |
| 2364 | 2462 | |
| 2365 | −#ifdef Q_OS_OSX | |
| 2366 | − DeadlockWatchdogThread::resume(); | |
| 2367 | −#endif | |
| 2368 | − | |
| 2369 | − _renderEngine->load(); | |
| 2370 | − _renderEngine->registerScene(_main3DScene); | |
| 2371 | − | |
| 2372 | − // Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success. | |
| 2373 | − DependencyManager::get<GeometryCache>()->initializeShapePipelines(); | |
| 2463 | + // Now that OpenGL is initialized, we are sure we have a valid context and can create the various pipeline shaders with success. | |
| 2464 | + DependencyManager::get<GeometryCache>()->initializeShapePipelines(); | |
| 2465 | + }); | |
| 2374 | 2466 | |
| 2375 | 2467 | _offscreenContext = new OffscreenGLCanvas(); |
| 2376 | 2468 | _offscreenContext->setObjectName("MainThreadContext"); |
| @@ -2378,20 +2470,24 @@ void Application::initializeGL() { · 1 unmodified line | ||
| 2378 | 2470 | if (!_offscreenContext->makeCurrent()) { |
| 2379 | 2471 | qFatal("Unable to make offscreen context current"); |
| 2380 | 2472 | } |
| 2473 | + _offscreenContext->doneCurrent(); | |
| 2474 | + _offscreenContext->setThreadContext(); | |
| 2475 | + _renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); | |
| 2381 | 2476 | |
| 2382 | 2477 | // The UI can't be created until the primary OpenGL |
| 2383 | 2478 | // context is created, because it needs to share |
| 2384 | 2479 | // texture resources |
| 2385 | 2480 | // Needs to happen AFTER the render engine initialization to access its configuration |
| 2481 | + if (!_offscreenContext->makeCurrent()) { | |
| 2482 | + qFatal("Unable to make offscreen context current"); | |
| 2483 | + } | |
| 2484 | + | |
| 2386 | 2485 | initializeUi(); |
| 2387 | 2486 | qCDebug(interfaceapp, "Initialized Offscreen UI."); |
| 2388 | − _glWidget->makeCurrent(); | |
| 2389 | − | |
| 2390 | − | |
| 2391 | − // call Menu getInstance static method to set up the menu | |
| 2392 | − // Needs to happen AFTER the QML UI initialization | |
| 2393 | − _window->setMenuBar(Menu::getInstance()); | |
| 2394 | 2487 | |
| 2488 | + if (!_offscreenContext->makeCurrent()) { | |
| 2489 | + qFatal("Unable to make offscreen context current"); | |
| 2490 | + } | |
| 2395 | 2491 | init(); |
| 2396 | 2492 | qCDebug(interfaceapp, "init() complete."); |
| 2397 | 2493 | |
| @@ -2402,7 +2498,6 @@ void Application::initializeGL() { · 4 unmodified lines | ||
| 2402 | 2498 | |
| 2403 | 2499 | _idleLoopStdev.reset(); |
| 2404 | 2500 | |
| 2405 | − _renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); | |
| 2406 | 2501 | |
| 2407 | 2502 | // Restore the primary GL content for the main thread |
| 2408 | 2503 | if (!_offscreenContext->makeCurrent()) { |
| @@ -2468,27 +2563,70 @@ void Application::initializeUi() { · 59 unmodified lines | ||
| 2468 | 2563 | auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); |
| 2469 | 2564 | tabletScriptingInterface->getTablet(SYSTEM_TABLET); |
| 2470 | 2565 | } |
| 2471 | − auto offscreenUi = DependencyManager::get<OffscreenUi>(); | |
| 2472 | − offscreenUi->create(); | |
| 2473 | 2566 | |
| 2474 | − auto surfaceContext = offscreenUi->getSurfaceContext(); | |
| 2567 | + auto offscreenUi = DependencyManager::get<OffscreenUi>(); | |
| 2568 | + connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootContextCreated, | |
| 2569 | + this, &Application::onDesktopRootContextCreated); | |
| 2570 | + connect(offscreenUi.data(), &hifi::qml::OffscreenSurface::rootItemCreated, | |
| 2571 | + this, &Application::onDesktopRootItemCreated); | |
| 2475 | 2572 | |
| 2476 | 2573 | offscreenUi->setProxyWindow(_window->windowHandle()); |
| 2477 | 2574 | // OffscreenUi is a subclass of OffscreenQmlSurface specifically designed to |
| 2478 | 2575 | // support the window management and scripting proxies for VR use |
| 2479 | − offscreenUi->createDesktop(PathUtils::qmlUrl("hifi/Desktop.qml")); | |
| 2576 | + DeadlockWatchdogThread::withPause([&] { | |
| 2577 | + offscreenUi->createDesktop(PathUtils::qmlUrl("hifi/Desktop.qml")); | |
| 2578 | + }); | |
| 2480 | 2579 | // FIXME either expose so that dialogs can set this themselves or |
| 2481 | 2580 | // do better detection in the offscreen UI of what has focus |
| 2482 | 2581 | offscreenUi->setNavigationFocused(false); |
| 2483 | 2582 | |
| 2484 | − auto engine = surfaceContext->engine(); | |
| 2485 | − connect(engine, &QQmlEngine::quit, [] { | |
| 2486 | − qApp->quit(); | |
| 2583 | + setupPreferences(); | |
| 2584 | + | |
| 2585 | + _glWidget->installEventFilter(offscreenUi.data()); | |
| 2586 | + offscreenUi->setMouseTranslator([=](const QPointF& pt) { | |
| 2587 | + QPointF result = pt; | |
| 2588 | + auto displayPlugin = getActiveDisplayPlugin(); | |
| 2589 | + if (displayPlugin->isHmd()) { | |
| 2590 | + getApplicationCompositor().handleRealMouseMoveEvent(false); | |
| 2591 | + auto resultVec = getApplicationCompositor().getReticlePosition(); | |
| 2592 | + result = QPointF(resultVec.x, resultVec.y); | |
| 2593 | + } | |
| 2594 | + return result.toPoint(); | |
| 2595 | + }); | |
| 2596 | + offscreenUi->resume(); | |
| 2597 | + connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ | |
| 2598 | + resizeGL(); | |
| 2487 | 2599 | }); |
| 2488 | 2600 | |
| 2601 | + // This will set up the input plugins UI | |
| 2602 | + _activeInputPlugins.clear(); | |
| 2603 | + foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { | |
| 2604 | + if (KeyboardMouseDevice::NAME == inputPlugin->getName()) { | |
| 2605 | + _keyboardMouseDevice = std::dynamic_pointer_cast<KeyboardMouseDevice>(inputPlugin); | |
| 2606 | + } | |
| 2607 | + if (TouchscreenDevice::NAME == inputPlugin->getName()) { | |
| 2608 | + _touchscreenDevice = std::dynamic_pointer_cast<TouchscreenDevice>(inputPlugin); | |
| 2609 | + } | |
| 2610 | + } | |
| 2611 | + | |
| 2612 | + auto compositorHelper = DependencyManager::get<CompositorHelper>(); | |
| 2613 | + connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] { | |
| 2614 | + if (isHMDMode()) { | |
| 2615 | + showCursor(compositorHelper->getAllowMouseCapture() ? | |
| 2616 | + Cursor::Manager::lookupIcon(_preferredCursor.get()) : | |
| 2617 | + Cursor::Icon::SYSTEM); | |
| 2618 | + } | |
| 2619 | + }); | |
| 2620 | + | |
| 2621 | + // Pre-create a couple of Web3D overlays to speed up tablet UI | |
| 2622 | + auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>(); | |
| 2623 | + offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1); | |
| 2624 | + offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2); | |
| 2625 | +} | |
| 2489 | 2626 | |
| 2490 | − setupPreferences(); | |
| 2491 | 2627 | |
| 2628 | +void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) { | |
| 2629 | + auto engine = surfaceContext->engine(); | |
| 2492 | 2630 | // in Qt 5.10.0 there is already an "Audio" object in the QML context |
| 2493 | 2631 | // though I failed to find it (from QtMultimedia??). So.. let it be "AudioScriptingInterface" |
| 2494 | 2632 | surfaceContext->setContextProperty("AudioScriptingInterface", DependencyManager::get<AudioScriptingInterface>().data()); |
| @@ -2570,48 +2708,12 @@ void Application::initializeUi() { · 75 unmodified lines | ||
| 2570 | 2708 | surfaceContext->setContextProperty("Steam", new SteamScriptingInterface(engine, steamClient.get())); |
| 2571 | 2709 | } |
| 2572 | 2710 | |
| 2573 | − | |
| 2574 | − _glWidget->installEventFilter(offscreenUi.data()); | |
| 2575 | − offscreenUi->setMouseTranslator([=](const QPointF& pt) { | |
| 2576 | − QPointF result = pt; | |
| 2577 | − auto displayPlugin = getActiveDisplayPlugin(); | |
| 2578 | − if (displayPlugin->isHmd()) { | |
| 2579 | − getApplicationCompositor().handleRealMouseMoveEvent(false); | |
| 2580 | − auto resultVec = getApplicationCompositor().getReticlePosition(); | |
| 2581 | − result = QPointF(resultVec.x, resultVec.y); | |
| 2582 | − } | |
| 2583 | − return result.toPoint(); | |
| 2584 | − }); | |
| 2585 | − offscreenUi->resume(); | |
| 2586 | − connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect& r){ | |
| 2587 | − resizeGL(); | |
| 2588 | − }); | |
| 2589 | − | |
| 2590 | − // This will set up the input plugins UI | |
| 2591 | − _activeInputPlugins.clear(); | |
| 2592 | − foreach(auto inputPlugin, PluginManager::getInstance()->getInputPlugins()) { | |
| 2593 | − if (KeyboardMouseDevice::NAME == inputPlugin->getName()) { | |
| 2594 | − _keyboardMouseDevice = std::dynamic_pointer_cast<KeyboardMouseDevice>(inputPlugin); | |
| 2595 | − } | |
| 2596 | − if (TouchscreenDevice::NAME == inputPlugin->getName()) { | |
| 2597 | − _touchscreenDevice = std::dynamic_pointer_cast<TouchscreenDevice>(inputPlugin); | |
| 2598 | − } | |
| 2599 | − } | |
| 2600 | 2711 | _window->setMenuBar(new Menu()); |
| 2712 | +} | |
| 2601 | 2713 | |
| 2602 | − auto compositorHelper = DependencyManager::get<CompositorHelper>(); | |
| 2603 | − connect(compositorHelper.data(), &CompositorHelper::allowMouseCaptureChanged, this, [=] { | |
| 2604 | − if (isHMDMode()) { | |
| 2605 | − showCursor(compositorHelper->getAllowMouseCapture() ? | |
| 2606 | − Cursor::Manager::lookupIcon(_preferredCursor.get()) : | |
| 2607 | − Cursor::Icon::SYSTEM); | |
| 2608 | − } | |
| 2609 | − }); | |
| 2610 | − | |
| 2611 | − // Pre-create a couple of Web3D overlays to speed up tablet UI | |
| 2612 | − auto offscreenSurfaceCache = DependencyManager::get<OffscreenQmlSurfaceCache>(); | |
| 2613 | − offscreenSurfaceCache->reserve(TabletScriptingInterface::QML, 1); | |
| 2614 | − offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2); | |
| 2714 | +void Application::onDesktopRootItemCreated(QQuickItem* rootItem) { | |
| 2715 | + Stats::show(); | |
| 2716 | + AvatarInputs::show(); | |
| 2615 | 2717 | } |
| 2616 | 2718 | |
| 2617 | 2719 | void Application::updateCamera(RenderArgs& renderArgs, float deltaTime) { |
| @@ -2850,6 +2952,8 @@ void Application::resizeGL() { · 232 unmodified lines | ||
| 2850 | 2952 | QMutexLocker viewLocker(&_viewMutex); |
| 2851 | 2953 | _myCamera.loadViewFrustum(_viewFrustum); |
| 2852 | 2954 | } |
| 2955 | + | |
| 2956 | + DependencyManager::get<OffscreenUi>()->resize(fromGlm(displayPlugin->getRecommendedUiSize())); | |
| 2853 | 2957 | } |
| 2854 | 2958 | |
| 2855 | 2959 | void Application::handleSandboxStatus(QNetworkReply* reply) { |
| @@ -2965,6 +3069,14 @@ bool Application::importFromZIP(const QString& filePath) { · 109 unmodified lines | ||
| 2965 | 3069 | return true; |
| 2966 | 3070 | } |
| 2967 | 3071 | |
| 3072 | +bool Application::importImage(const QString& urlString) { | |
| 3073 | + qCDebug(interfaceapp) << "An image file has been dropped in"; | |
| 3074 | + QString filepath(urlString); | |
| 3075 | + filepath.remove("file:///"); | |
| 3076 | + addAssetToWorld(filepath, "", false, false); | |
| 3077 | + return true; | |
| 3078 | +} | |
| 3079 | + | |
| 2968 | 3080 | // thread-safe |
| 2969 | 3081 | void Application::onPresent(quint32 frameCount) { |
| 2970 | 3082 | bool expected = false; |
| @@ -4058,7 +4170,7 @@ void Application::idle() { · 1087 unmodified lines | ||
| 4058 | 4170 | // Bit of a hack since there's no device pixel ratio change event I can find. |
| 4059 | 4171 | if (offscreenUi->size() != fromGlm(uiSize)) { |
| 4060 | 4172 | qCDebug(interfaceapp) << "Device pixel ratio changed, triggering resize to " << uiSize; |
| 4061 | − offscreenUi->resize(fromGlm(uiSize), true); | |
| 4173 | + offscreenUi->resize(fromGlm(uiSize)); | |
| 4062 | 4174 | _offscreenContext->makeCurrent(); |
| 4063 | 4175 | } |
| 4064 | 4176 | } |
| @@ -6560,7 +6672,8 @@ void Application::addAssetToWorldSetMapping(QString filePath, QString mapping, Q · 2495 unmodified lines | ||
| 6560 | 6672 | addAssetToWorldError(filenameFromPath(filePath), errorInfo); |
| 6561 | 6673 | } else { |
| 6562 | 6674 | // to prevent files that aren't models from being loaded into world automatically |
| 6563 | − if (filePath.endsWith(".obj") || filePath.endsWith(".fbx")) { | |
| 6675 | + if (filePath.endsWith(OBJ_EXTENSION) || filePath.endsWith(FBX_EXTENSION) || | |
| 6676 | + filePath.endsWith(JPG_EXTENSION) || filePath.endsWith(PNG_EXTENSION)) { | |
| 6564 | 6677 | addAssetToWorldAddEntity(filePath, mapping); |
| 6565 | 6678 | } else { |
| 6566 | 6679 | qCDebug(interfaceapp) << "Zipped contents are not supported entity files"; |
| @@ -6577,8 +6690,17 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) { · 10 unmodified lines | ||
| 6577 | 6690 | EntityItemProperties properties; |
| 6578 | 6691 | properties.setType(EntityTypes::Model); |
| 6579 | 6692 | properties.setName(mapping.right(mapping.length() - 1)); |
| 6580 | − properties.setModelURL("atp:" + mapping); | |
| 6581 | − properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); | |
| 6693 | + if (filePath.endsWith(PNG_EXTENSION) || filePath.endsWith(JPG_EXTENSION)) { | |
| 6694 | + QJsonObject textures { | |
| 6695 | + {"tex.picture", QString("atp:" + mapping) } | |
| 6696 | + }; | |
| 6697 | + properties.setModelURL("https://hifi-content.s3.amazonaws.com/DomainContent/production/default-image-model.fbx"); | |
| 6698 | + properties.setTextures(QJsonDocument(textures).toJson(QJsonDocument::Compact)); | |
| 6699 | + properties.setShapeType(SHAPE_TYPE_BOX); | |
| 6700 | + } else { | |
| 6701 | + properties.setModelURL("atp:" + mapping); | |
| 6702 | + properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND); | |
| 6703 | + } | |
| 6582 | 6704 | properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar. |
| 6583 | 6705 | properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions. |
| 6584 | 6706 | glm::vec3 positionOffset = getMyAvatar()->getWorldOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f)); |
| @@ -7002,10 +7124,10 @@ void Application::loadAvatarBrowser() const { · 417 unmodified lines | ||
| 7002 | 7124 | DependencyManager::get<HMDScriptingInterface>()->openTablet(); |
| 7003 | 7125 | } |
| 7004 | 7126 | |
| 7005 | −void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio) { | |
| 7006 | − postLambdaEvent([notify, includeAnimated, aspectRatio, this] { | |
| 7127 | +void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRatio, const QString& filename) { | |
| 7128 | + postLambdaEvent([notify, includeAnimated, aspectRatio, filename, this] { | |
| 7007 | 7129 | // Get a screenshot and save it |
| 7008 | − QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio)); | |
| 7130 | + QString path = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getScreenshot(aspectRatio), filename); | |
| 7009 | 7131 | // If we're not doing an animated snapshot as well... |
| 7010 | 7132 | if (!includeAnimated) { |
| 7011 | 7133 | // Tell the dependency manager that the capture of the still snapshot has taken place. |
| @@ -7017,9 +7139,9 @@ void Application::takeSnapshot(bool notify, bool includeAnimated, float aspectRa · 5 unmodified lines | ||
| 7017 | 7139 | }); |
| 7018 | 7140 | } |
| 7019 | 7141 | |
| 7020 | −void Application::takeSecondaryCameraSnapshot() { | |
| 7021 | − postLambdaEvent([this] { | |
| 7022 | − QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot()); | |
| 7142 | +void Application::takeSecondaryCameraSnapshot(const QString& filename) { | |
| 7143 | + postLambdaEvent([filename, this] { | |
| 7144 | + QString snapshotPath = Snapshot::saveSnapshot(getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), filename); | |
| 7023 | 7145 | emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, true); |
| 7024 | 7146 | }); |
| 7025 | 7147 | } |
| @@ -7393,9 +7515,7 @@ void Application::updateDisplayMode() { · 367 unmodified lines | ||
| 7393 | 7515 | action->setChecked(true); |
| 7394 | 7516 | } |
| 7395 | 7517 | |
| 7396 | − _offscreenContext->makeCurrent(); | |
| 7397 | 7518 | offscreenUi->resize(fromGlm(newDisplayPlugin->getRecommendedUiSize())); |
| 7398 | − _offscreenContext->makeCurrent(); | |
| 7399 | 7519 | getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); |
| 7400 | 7520 | _displayPlugin = newDisplayPlugin; |
| 7401 | 7521 | connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection); |