Showing the changes to interface/src/Application.cpp (1 of 164 files). Show all
Unified · Split
| @@ -113,7 +113,6 @@ · 112 unmodified lines | ||
| 113 | 113 | #include <plugins/SteamClientPlugin.h> |
| 114 | 114 | #include <plugins/InputConfiguration.h> |
| 115 | 115 | #include <RecordingScriptingInterface.h> |
| 116 | −#include <RenderableWebEntityItem.h> | |
| 117 | 116 | #include <UpdateSceneTask.h> |
| 118 | 117 | #include <RenderViewTask.h> |
| 119 | 118 | #include <SecondaryCamera.h> |
| @@ -139,6 +138,7 @@ · 19 unmodified lines | ||
| 139 | 138 | #include <display-plugins/CompositorHelper.h> |
| 140 | 139 | #include <trackers/EyeTracker.h> |
| 141 | 140 | #include <avatars-renderer/ScriptAvatar.h> |
| 141 | +#include <RenderableEntityItem.h> | |
| 142 | 142 | |
| 143 | 143 | #include "AudioClient.h" |
| 144 | 144 | #include "audio/AudioScope.h" |
| @@ -184,6 +184,7 @@ · 39 unmodified lines | ||
| 184 | 184 | #include "ui/UpdateDialog.h" |
| 185 | 185 | #include "ui/overlays/Overlays.h" |
| 186 | 186 | #include "ui/DomainConnectionModel.h" |
| 187 | +#include "ui/ImageProvider.h" | |
| 187 | 188 | #include "Util.h" |
| 188 | 189 | #include "InterfaceParentFinder.h" |
| 189 | 190 | #include "ui/OctreeStatsProvider.h" |
| @@ -212,6 +213,73 @@ extern "C" { · 22 unmodified lines | ||
| 212 | 213 | } |
| 213 | 214 | #endif |
| 214 | 215 | |
| 216 | +enum ApplicationEvent { | |
| 217 | + // Execute a lambda function | |
| 218 | + Lambda = QEvent::User + 1, | |
| 219 | + // Trigger the next render | |
| 220 | + Render, | |
| 221 | + // Trigger the next idle | |
| 222 | + Idle, | |
| 223 | +}; | |
| 224 | + | |
| 225 | + | |
| 226 | +class RenderEventHandler : public QObject { | |
| 227 | + using Parent = QObject; | |
| 228 | + Q_OBJECT | |
| 229 | +public: | |
| 230 | + RenderEventHandler(QOpenGLContext* context) { | |
| 231 | + _renderContext = new OffscreenGLCanvas(); | |
| 232 | + _renderContext->setObjectName("RenderContext"); | |
| 233 | + _renderContext->create(context); | |
| 234 | + if (!_renderContext->makeCurrent()) { | |
| 235 | + qFatal("Unable to make rendering context current"); | |
| 236 | + } | |
| 237 | + _renderContext->doneCurrent(); | |
| 238 | + | |
| 239 | + // Deleting the object with automatically shutdown the thread | |
| 240 | + connect(qApp, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); | |
| 241 | + | |
| 242 | + // Transfer to a new thread | |
| 243 | + moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) { | |
| 244 | + hifi::qt::addBlockingForbiddenThread("Render", renderThread); | |
| 245 | + _renderContext->moveToThreadWithContext(renderThread); | |
| 246 | + qApp->_lastTimeRendered.start(); | |
| 247 | + }, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority); | |
| 248 | + } | |
| 249 | + | |
| 250 | +private: | |
| 251 | + void initialize() { | |
| 252 | + PROFILE_SET_THREAD_NAME("Render"); | |
| 253 | + if (!_renderContext->makeCurrent()) { | |
| 254 | + qFatal("Unable to make rendering context current on render thread"); | |
| 255 | + } | |
| 256 | + } | |
| 257 | + | |
| 258 | + void render() { | |
| 259 | + if (qApp->shouldPaint()) { | |
| 260 | + qApp->paintGL(); | |
| 261 | + } | |
| 262 | + } | |
| 263 | + | |
| 264 | + bool event(QEvent* event) override { | |
| 265 | + switch ((int)event->type()) { | |
| 266 | + case ApplicationEvent::Render: | |
| 267 | + render(); | |
| 268 | + // Ensure we never back up the render events. Each render should be triggered only in response | |
| 269 | + // to the NEXT render event after the last render occured | |
| 270 | + QCoreApplication::removePostedEvents(this, ApplicationEvent::Render); | |
| 271 | + return true; | |
| 272 | + | |
| 273 | + default: | |
| 274 | + break; | |
| 275 | + } | |
| 276 | + return Parent::event(event); | |
| 277 | + } | |
| 278 | + | |
| 279 | + OffscreenGLCanvas* _renderContext { nullptr }; | |
| 280 | +}; | |
| 281 | + | |
| 282 | + | |
| 215 | 283 | Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") |
| 216 | 284 | |
| 217 | 285 | using namespace std; |
| @@ -427,10 +495,10 @@ class LambdaEvent : public QEvent { · 209 unmodified lines | ||
| 427 | 495 | std::function<void()> _fun; |
| 428 | 496 | public: |
| 429 | 497 | LambdaEvent(const std::function<void()> & fun) : |
| 430 | − QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) { | |
| 498 | + QEvent(static_cast<QEvent::Type>(ApplicationEvent::Lambda)), _fun(fun) { | |
| 431 | 499 | } |
| 432 | 500 | LambdaEvent(std::function<void()> && fun) : |
| 433 | − QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) { | |
| 501 | + QEvent(static_cast<QEvent::Type>(ApplicationEvent::Lambda)), _fun(fun) { | |
| 434 | 502 | } |
| 435 | 503 | void call() const { _fun(); } |
| 436 | 504 | }; |
| @@ -1368,8 +1436,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 931 unmodified lines | ||
| 1368 | 1436 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 1369 | 1437 | connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, |
| 1370 | 1438 | [this](const EntityItemID& entityItemID, const PointerEvent& event) { |
| 1371 | − auto entity = getEntities()->getTree()->findEntityByID(entityItemID); | |
| 1372 | − if (entity && entity->wantsKeyboardFocus()) { | |
| 1439 | + if (getEntities()->wantsKeyboardFocus(entityItemID)) { | |
| 1373 | 1440 | setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); |
| 1374 | 1441 | setKeyboardFocusEntity(entityItemID); |
| 1375 | 1442 | } else { |
| @@ -1693,7 +1760,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 317 unmodified lines | ||
| 1693 | 1760 | _defaultSkybox->setCubemap(_defaultSkyboxTexture); |
| 1694 | 1761 | } |
| 1695 | 1762 | |
| 1696 | − EntityItem::setEntitiesShouldFadeFunction([this]() { | |
| 1763 | + EntityTreeRenderer::setEntitiesShouldFadeFunction([this]() { | |
| 1697 | 1764 | SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer); |
| 1698 | 1765 | return entityServerNode && !isPhysicsEnabled(); |
| 1699 | 1766 | }); |
| @@ -1737,6 +1804,27 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 37 unmodified lines | ||
| 1737 | 1804 | |
| 1738 | 1805 | connect(&_myCamera, &Camera::modeUpdated, this, &Application::cameraModeChanged); |
| 1739 | 1806 | |
| 1807 | + // Setup the mouse ray pick and related operators | |
| 1808 | + DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickID(_rayPickManager.createRayPick( | |
| 1809 | + RayPickFilter(DependencyManager::get<RayPickScriptingInterface>()->PICK_ENTITIES() | DependencyManager::get<RayPickScriptingInterface>()->PICK_INCLUDE_NONCOLLIDABLE()), | |
| 1810 | + 0.0f, true)); | |
| 1811 | + DependencyManager::get<EntityTreeRenderer>()->setMouseRayPickResultOperator([&](QUuid rayPickID) { | |
| 1812 | + RayToEntityIntersectionResult entityResult; | |
| 1813 | + RayPickResult result = _rayPickManager.getPrevRayPickResult(rayPickID); | |
| 1814 | + entityResult.intersects = result.type != DependencyManager::get<RayPickScriptingInterface>()->INTERSECTED_NONE(); | |
| 1815 | + if (entityResult.intersects) { | |
| 1816 | + entityResult.intersection = result.intersection; | |
| 1817 | + entityResult.distance = result.distance; | |
| 1818 | + entityResult.surfaceNormal = result.surfaceNormal; | |
| 1819 | + entityResult.entityID = result.objectID; | |
| 1820 | + entityResult.entity = DependencyManager::get<EntityTreeRenderer>()->getTree()->findEntityByID(entityResult.entityID); | |
| 1821 | + } | |
| 1822 | + return entityResult; | |
| 1823 | + }); | |
| 1824 | + DependencyManager::get<EntityTreeRenderer>()->setSetPrecisionPickingOperator([&](QUuid rayPickID, bool value) { | |
| 1825 | + _rayPickManager.setPrecisionPicking(rayPickID, value); | |
| 1826 | + }); | |
| 1827 | + | |
| 1740 | 1828 | qCDebug(interfaceapp) << "Metaverse session ID is" << uuidStringWithoutCurlyBraces(accountManager->getSessionID()); |
| 1741 | 1829 | } |
| 1742 | 1830 | |
| @@ -2079,6 +2167,13 @@ void Application::initializeGL() { · 336 unmodified lines | ||
| 2079 | 2167 | _renderEngine->load(); |
| 2080 | 2168 | _renderEngine->registerScene(_main3DScene); |
| 2081 | 2169 | |
| 2170 | + _offscreenContext = new OffscreenGLCanvas(); | |
| 2171 | + _offscreenContext->setObjectName("MainThreadContext"); | |
| 2172 | + _offscreenContext->create(_glWidget->qglContext()); | |
| 2173 | + if (!_offscreenContext->makeCurrent()) { | |
| 2174 | + qFatal("Unable to make offscreen context current"); | |
| 2175 | + } | |
| 2176 | + | |
| 2082 | 2177 | // The UI can't be created until the primary OpenGL |
| 2083 | 2178 | // context is created, because it needs to share |
| 2084 | 2179 | // texture resources |
| @@ -2102,14 +2197,15 @@ void Application::initializeGL() { · 17 unmodified lines | ||
| 2102 | 2197 | |
| 2103 | 2198 | _idleLoopStdev.reset(); |
| 2104 | 2199 | |
| 2105 | − _offscreenContext = new OffscreenGLCanvas(); | |
| 2106 | − _offscreenContext->setObjectName("MainThreadContext"); | |
| 2107 | − _offscreenContext->create(_glWidget->qglContext()); | |
| 2108 | − _offscreenContext->makeCurrent(); | |
| 2200 | + _renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); | |
| 2201 | + | |
| 2202 | + // Restore the primary GL content for the main thread | |
| 2203 | + if (!_offscreenContext->makeCurrent()) { | |
| 2204 | + qFatal("Unable to make offscreen context current"); | |
| 2205 | + } | |
| 2109 | 2206 | |
| 2110 | 2207 | // update before the first render |
| 2111 | 2208 | update(0); |
| 2112 | − | |
| 2113 | 2209 | } |
| 2114 | 2210 | |
| 2115 | 2211 | FrameTimingsScriptingInterface _frameTimingsScriptingInterface; |
| @@ -2117,6 +2213,9 @@ FrameTimingsScriptingInterface _frameTimingsScriptingInterface; · 1 unmodified line | ||
| 2117 | 2213 | extern void setupPreferences(); |
| 2118 | 2214 | |
| 2119 | 2215 | void Application::initializeUi() { |
| 2216 | + // Make sure all QML surfaces share the main thread GL context | |
| 2217 | + OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext()); | |
| 2218 | + | |
| 2120 | 2219 | AddressBarDialog::registerType(); |
| 2121 | 2220 | ErrorDialog::registerType(); |
| 2122 | 2221 | LoginDialog::registerType(); |
| @@ -2127,7 +2226,7 @@ void Application::initializeUi() { · 4 unmodified lines | ||
| 2127 | 2226 | qmlRegisterType<Preference>("Hifi", 1, 0, "Preference"); |
| 2128 | 2227 | |
| 2129 | 2228 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 2130 | − offscreenUi->create(_glWidget->qglContext()); | |
| 2229 | + offscreenUi->create(); | |
| 2131 | 2230 | |
| 2132 | 2231 | auto surfaceContext = offscreenUi->getSurfaceContext(); |
| 2133 | 2232 | |
| @@ -2146,6 +2245,9 @@ void Application::initializeUi() { · 12 unmodified lines | ||
| 2146 | 2245 | qApp->quit(); |
| 2147 | 2246 | }); |
| 2148 | 2247 | |
| 2248 | + // register the pixmap image provider (used only for security image, for now) | |
| 2249 | + engine->addImageProvider(ImageProvider::PROVIDER_NAME, new ImageProvider()); | |
| 2250 | + | |
| 2149 | 2251 | setupPreferences(); |
| 2150 | 2252 | |
| 2151 | 2253 | // For some reason there is already an "Application" object in the QML context, |
| @@ -2270,14 +2372,12 @@ void Application::initializeUi() { · 118 unmodified lines | ||
| 2270 | 2372 | |
| 2271 | 2373 | void Application::paintGL() { |
| 2272 | 2374 | // Some plugins process message events, allowing paintGL to be called reentrantly. |
| 2273 | − if (_inPaint || _aboutToQuit || _window->isMinimized()) { | |
| 2375 | + if (_aboutToQuit || _window->isMinimized()) { | |
| 2274 | 2376 | return; |
| 2275 | 2377 | } |
| 2276 | 2378 | |
| 2277 | − _inPaint = true; | |
| 2278 | − Finally clearFlag([this] { _inPaint = false; }); | |
| 2279 | − | |
| 2280 | 2379 | _frameCount++; |
| 2380 | + _lastTimeRendered.start(); | |
| 2281 | 2381 | |
| 2282 | 2382 | auto lastPaintBegin = usecTimestampNow(); |
| 2283 | 2383 | PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_frameCount); |
| @@ -2293,18 +2393,11 @@ void Application::paintGL() { · 9 unmodified lines | ||
| 2293 | 2393 | displayPlugin = getActiveDisplayPlugin(); |
| 2294 | 2394 | } |
| 2295 | 2395 | |
| 2296 | − { | |
| 2297 | − PROFILE_RANGE(render, "/offscreenMakeCurrent"); | |
| 2298 | − // FIXME not needed anymore? | |
| 2299 | − _offscreenContext->makeCurrent(); | |
| 2300 | − } | |
| 2301 | − | |
| 2302 | 2396 | { |
| 2303 | 2397 | PROFILE_RANGE(render, "/pluginBeginFrameRender"); |
| 2304 | 2398 | // If a display plugin loses it's underlying support, it |
| 2305 | 2399 | // needs to be able to signal us to not use it |
| 2306 | 2400 | if (!displayPlugin->beginFrameRender(_frameCount)) { |
| 2307 | − _inPaint = false; | |
| 2308 | 2401 | updateDisplayMode(); |
| 2309 | 2402 | return; |
| 2310 | 2403 | } |
| @@ -2372,12 +2465,6 @@ void Application::paintGL() { · 61 unmodified lines | ||
| 2372 | 2465 | auto myAvatar = getMyAvatar(); |
| 2373 | 2466 | boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD; |
| 2374 | 2467 | |
| 2375 | − if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { | |
| 2376 | − Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); | |
| 2377 | − Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); | |
| 2378 | − cameraMenuChanged(); | |
| 2379 | − } | |
| 2380 | − | |
| 2381 | 2468 | // The render mode is default or mirror if the camera is in mirror mode, assigned further below |
| 2382 | 2469 | renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; |
| 2383 | 2470 | |
| @@ -2685,15 +2772,6 @@ void Application::resizeGL() { · 301 unmodified lines | ||
| 2685 | 2772 | QMutexLocker viewLocker(&_viewMutex); |
| 2686 | 2773 | _myCamera.loadViewFrustum(_viewFrustum); |
| 2687 | 2774 | } |
| 2688 | − | |
| 2689 | − auto offscreenUi = DependencyManager::get<OffscreenUi>(); | |
| 2690 | − auto uiSize = displayPlugin->getRecommendedUiSize(); | |
| 2691 | − // Bit of a hack since there's no device pixel ratio change event I can find. | |
| 2692 | − if (offscreenUi->size() != fromGlm(uiSize)) { | |
| 2693 | − qCDebug(interfaceapp) << "Device pixel ratio changed, triggering resize to " << uiSize; | |
| 2694 | − offscreenUi->resize(fromGlm(uiSize), true); | |
| 2695 | − _offscreenContext->makeCurrent(); | |
| 2696 | − } | |
| 2697 | 2775 | } |
| 2698 | 2776 | |
| 2699 | 2777 | void Application::handleSandboxStatus(QNetworkReply* reply) { |
| @@ -2867,56 +2945,26 @@ bool Application::importFromZIP(const QString& filePath) { · 167 unmodified lines | ||
| 2867 | 2945 | } |
| 2868 | 2946 | |
| 2869 | 2947 | void Application::onPresent(quint32 frameCount) { |
| 2870 | − if (shouldPaint()) { | |
| 2871 | − postEvent(this, new QEvent(static_cast<QEvent::Type>(Idle)), Qt::HighEventPriority); | |
| 2872 | − postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority); | |
| 2948 | + postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); | |
| 2949 | + if (_renderEventHandler && !isAboutToQuit()) { | |
| 2950 | + postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render)); | |
| 2873 | 2951 | } |
| 2874 | 2952 | } |
| 2875 | 2953 | |
| 2876 | −bool _renderRequested { false }; | |
| 2877 | − | |
| 2878 | −bool Application::event(QEvent* event) { | |
| 2879 | − if (!Menu::getInstance()) { | |
| 2880 | − return false; | |
| 2881 | − } | |
| 2882 | − | |
| 2883 | − int type = event->type(); | |
| 2884 | − switch (type) { | |
| 2885 | − case Event::Lambda: | |
| 2886 | − static_cast<LambdaEvent*>(event)->call(); | |
| 2887 | − return true; | |
| 2888 | − | |
| 2889 | − // Explicit idle keeps the idle running at a lower interval, but without any rendering | |
| 2890 | − // see (windowMinimizedChanged) | |
| 2891 | − case Event::Idle: | |
| 2892 | − idle(); | |
| 2893 | − // Clear the event queue of pending idle calls | |
| 2894 | − removePostedEvents(this, Idle); | |
| 2895 | − return true; | |
| 2896 | − | |
| 2897 | − case Event::Paint: | |
| 2898 | − // NOTE: This must be updated as close to painting as possible, | |
| 2899 | − // or AvatarInputs will mysteriously move to the bottom-right | |
| 2900 | − AvatarInputs::getInstance()->update(); | |
| 2901 | − paintGL(); | |
| 2902 | − // Clear the event queue of pending paint calls | |
| 2903 | − removePostedEvents(this, Paint); | |
| 2904 | − return true; | |
| 2905 | − | |
| 2906 | − default: | |
| 2907 | − break; | |
| 2908 | − } | |
| 2954 | +static inline bool isKeyEvent(QEvent::Type type) { | |
| 2955 | + return type == QEvent::KeyPress || type == QEvent::KeyRelease; | |
| 2956 | +} | |
| 2909 | 2957 | |
| 2910 | − { | |
| 2911 | − if (!_keyboardFocusedEntity.get().isInvalidID()) { | |
| 2912 | − switch (event->type()) { | |
| 2913 | − case QEvent::KeyPress: | |
| 2914 | − case QEvent::KeyRelease: { | |
| 2915 | − //auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | |
| 2916 | − auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get()); | |
| 2917 | − if (entity && entity->getEventHandler()) { | |
| 2958 | +bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { | |
| 2959 | + if (!_keyboardFocusedEntity.get().isInvalidID()) { | |
| 2960 | + switch (event->type()) { | |
| 2961 | + case QEvent::KeyPress: | |
| 2962 | + case QEvent::KeyRelease: | |
| 2963 | + { | |
| 2964 | + auto eventHandler = getEntities()->getEventHandler(_keyboardFocusedEntity.get()); | |
| 2965 | + if (eventHandler) { | |
| 2918 | 2966 | event->setAccepted(false); |
| 2919 | − QCoreApplication::sendEvent(entity->getEventHandler(), event); | |
| 2967 | + QCoreApplication::sendEvent(eventHandler, event); | |
| 2920 | 2968 | if (event->isAccepted()) { |
| 2921 | 2969 | _lastAcceptedKeyPress = usecTimestampNow(); |
| 2922 | 2970 | return true; |
| @@ -2924,20 +2972,17 @@ bool Application::event(QEvent* event) { · 1 unmodified line | ||
| 2924 | 2972 | } |
| 2925 | 2973 | break; |
| 2926 | 2974 | } |
| 2927 | − default: | |
| 2928 | − break; | |
| 2929 | − } | |
| 2975 | + default: | |
| 2976 | + break; | |
| 2930 | 2977 | } |
| 2931 | 2978 | } |
| 2932 | 2979 | |
| 2933 | − { | |
| 2934 | − if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) { | |
| 2935 | − switch (event->type()) { | |
| 2936 | − case QEvent::KeyPress: | |
| 2937 | − case QEvent::KeyRelease: { | |
| 2980 | + if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) { | |
| 2981 | + switch (event->type()) { | |
| 2982 | + case QEvent::KeyPress: | |
| 2983 | + case QEvent::KeyRelease: { | |
| 2938 | 2984 | // Only Web overlays can have focus. |
| 2939 | − auto overlay = | |
| 2940 | − std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); | |
| 2985 | + auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); | |
| 2941 | 2986 | if (overlay && overlay->getEventHandler()) { |
| 2942 | 2987 | event->setAccepted(false); |
| 2943 | 2988 | QCoreApplication::sendEvent(overlay->getEventHandler(), event); |
| @@ -2946,15 +2991,52 @@ bool Application::event(QEvent* event) { · 2 unmodified lines | ||
| 2946 | 2991 | return true; |
| 2947 | 2992 | } |
| 2948 | 2993 | } |
| 2949 | − break; | |
| 2950 | − } | |
| 2951 | − default: | |
| 2952 | − break; | |
| 2953 | 2994 | } |
| 2995 | + break; | |
| 2996 | + | |
| 2997 | + default: | |
| 2998 | + break; | |
| 2954 | 2999 | } |
| 2955 | 3000 | } |
| 2956 | 3001 | |
| 2957 | − switch (event->type()) { | |
| 3002 | + return false; | |
| 3003 | +} | |
| 3004 | + | |
| 3005 | +bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) { | |
| 3006 | + QUrl url = fileEvent->url(); | |
| 3007 | + if (!url.isEmpty()) { | |
| 3008 | + QString urlString = url.toString(); | |
| 3009 | + if (canAcceptURL(urlString)) { | |
| 3010 | + return acceptURL(urlString); | |
| 3011 | + } | |
| 3012 | + } | |
| 3013 | + return false; | |
| 3014 | +} | |
| 3015 | + | |
| 3016 | +bool Application::event(QEvent* event) { | |
| 3017 | + if (!Menu::getInstance()) { | |
| 3018 | + return false; | |
| 3019 | + } | |
| 3020 | + | |
| 3021 | + // Allow focused Entities and Overlays to handle keyboard input | |
| 3022 | + if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntityOrOverlay(event)) { | |
| 3023 | + return true; | |
| 3024 | + } | |
| 3025 | + | |
| 3026 | + int type = event->type(); | |
| 3027 | + switch (type) { | |
| 3028 | + case ApplicationEvent::Lambda: | |
| 3029 | + static_cast<LambdaEvent*>(event)->call(); | |
| 3030 | + return true; | |
| 3031 | + | |
| 3032 | + // Explicit idle keeps the idle running at a lower interval, but without any rendering | |
| 3033 | + // see (windowMinimizedChanged) | |
| 3034 | + case ApplicationEvent::Idle: | |
| 3035 | + idle(); | |
| 3036 | + // Don't process extra idle events that arrived in the event queue while we were doing this idle | |
| 3037 | + QCoreApplication::removePostedEvents(this, ApplicationEvent::Idle); | |
| 3038 | + return true; | |
| 3039 | + | |
| 2958 | 3040 | case QEvent::MouseMove: |
| 2959 | 3041 | mouseMoveEvent(static_cast<QMouseEvent*>(event)); |
| 2960 | 3042 | return true; |
| @@ -2995,26 +3077,15 @@ bool Application::event(QEvent* event) { · 34 unmodified lines | ||
| 2995 | 3077 | case QEvent::Drop: |
| 2996 | 3078 | dropEvent(static_cast<QDropEvent*>(event)); |
| 2997 | 3079 | return true; |
| 2998 | − default: | |
| 2999 | − break; | |
| 3000 | − } | |
| 3001 | 3080 | |
| 3002 | − // handle custom URL | |
| 3003 | − if (event->type() == QEvent::FileOpen) { | |
| 3004 | − | |
| 3005 | − QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event); | |
| 3006 | − | |
| 3007 | − QUrl url = fileEvent->url(); | |
| 3008 | − | |
| 3009 | − if (!url.isEmpty()) { | |
| 3010 | − QString urlString = url.toString(); | |
| 3011 | − | |
| 3012 | − if (canAcceptURL(urlString)) { | |
| 3013 | − | |
| 3014 | − return acceptURL(urlString); | |
| 3081 | + case QEvent::FileOpen: | |
| 3082 | + if (handleFileOpenEvent(static_cast<QFileOpenEvent*>(event))) { | |
| 3083 | + return true; | |
| 3015 | 3084 | } |
| 3016 | − } | |
| 3017 | − return false; | |
| 3085 | + break; | |
| 3086 | + | |
| 3087 | + default: | |
| 3088 | + break; | |
| 3018 | 3089 | } |
| 3019 | 3090 | |
| 3020 | 3091 | if (HFActionEvent::types().contains(event->type())) { |
| @@ -3719,11 +3790,12 @@ bool Application::acceptSnapshot(const QString& urlString) { · 698 unmodified lines | ||
| 3719 | 3790 | |
| 3720 | 3791 | static uint32_t _renderedFrameIndex { INVALID_FRAME }; |
| 3721 | 3792 | |
| 3722 | −bool Application::shouldPaint() { | |
| 3793 | +bool Application::shouldPaint() const { | |
| 3723 | 3794 | if (_aboutToQuit) { |
| 3724 | 3795 | return false; |
| 3725 | 3796 | } |
| 3726 | 3797 | |
| 3798 | + | |
| 3727 | 3799 | auto displayPlugin = getActiveDisplayPlugin(); |
| 3728 | 3800 | |
| 3729 | 3801 | #ifdef DEBUG_PAINT_DELAY |
| @@ -3739,15 +3811,14 @@ bool Application::shouldPaint() { · 9 unmodified lines | ||
| 3739 | 3811 | (float)paintDelaySamples / paintDelayUsecs << "us"; |
| 3740 | 3812 | } |
| 3741 | 3813 | #endif |
| 3742 | − | |
| 3814 | + | |
| 3743 | 3815 | // Throttle if requested |
| 3744 | − if (displayPlugin->isThrottled() && (_lastTimeUpdated.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) { | |
| 3816 | + if (displayPlugin->isThrottled() && (_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) { | |
| 3745 | 3817 | return false; |
| 3746 | 3818 | } |
| 3747 | 3819 | |
| 3748 | 3820 | // Sync up the _renderedFrameIndex |
| 3749 | 3821 | _renderedFrameIndex = displayPlugin->presentCount(); |
| 3750 | − | |
| 3751 | 3822 | return true; |
| 3752 | 3823 | } |
| 3753 | 3824 | |
| @@ -3957,7 +4028,6 @@ void setupCpuMonitorThread() { · 203 unmodified lines | ||
| 3957 | 4028 | |
| 3958 | 4029 | #endif |
| 3959 | 4030 | |
| 3960 | − | |
| 3961 | 4031 | void Application::idle() { |
| 3962 | 4032 | PerformanceTimer perfTimer("idle"); |
| 3963 | 4033 | |
| @@ -3988,9 +4058,17 @@ void Application::idle() { · 24 unmodified lines | ||
| 3988 | 4058 | }); |
| 3989 | 4059 | #endif |
| 3990 | 4060 | |
| 3991 | − | |
| 3992 | − | |
| 3993 | 4061 | auto displayPlugin = getActiveDisplayPlugin(); |
| 4062 | + if (displayPlugin) { | |
| 4063 | + auto uiSize = displayPlugin->getRecommendedUiSize(); | |
| 4064 | + // Bit of a hack since there's no device pixel ratio change event I can find. | |
| 4065 | + if (offscreenUi->size() != fromGlm(uiSize)) { | |
| 4066 | + qCDebug(interfaceapp) << "Device pixel ratio changed, triggering resize to " << uiSize; | |
| 4067 | + offscreenUi->resize(fromGlm(uiSize), true); | |
| 4068 | + _offscreenContext->makeCurrent(); | |
| 4069 | + } | |
| 4070 | + } | |
| 4071 | + | |
| 3994 | 4072 | if (displayPlugin) { |
| 3995 | 4073 | PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate()); |
| 3996 | 4074 | } |
| @@ -4038,6 +4116,10 @@ void Application::idle() { · 41 unmodified lines | ||
| 4038 | 4116 | bool showWarnings = getLogger()->extraDebugging(); |
| 4039 | 4117 | PerformanceWarning warn(showWarnings, "idle()"); |
| 4040 | 4118 | |
| 4119 | + if (!_offscreenContext->makeCurrent()) { | |
| 4120 | + qFatal("Unable to make main thread context current"); | |
| 4121 | + } | |
| 4122 | + | |
| 4041 | 4123 | { |
| 4042 | 4124 | PerformanceTimer perfTimer("update"); |
| 4043 | 4125 | PerformanceWarning warn(showWarnings, "Application::idle()... update()"); |
| @@ -4100,6 +4182,13 @@ void Application::idle() { · 56 unmodified lines | ||
| 4100 | 4182 | } |
| 4101 | 4183 | |
| 4102 | 4184 | _overlayConductor.update(secondsSinceLastUpdate); |
| 4185 | + | |
| 4186 | + auto myAvatar = getMyAvatar(); | |
| 4187 | + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { | |
| 4188 | + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); | |
| 4189 | + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); | |
| 4190 | + cameraMenuChanged(); | |
| 4191 | + } | |
| 4103 | 4192 | } |
| 4104 | 4193 | |
| 4105 | 4194 | ivec2 Application::getMouse() const { |
| @@ -4354,7 +4443,6 @@ void Application::init() { · 248 unmodified lines | ||
| 4354 | 4443 | _timerStart.start(); |
| 4355 | 4444 | _lastTimeUpdated.start(); |
| 4356 | 4445 | |
| 4357 | − | |
| 4358 | 4446 | if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { |
| 4359 | 4447 | // when +connect_lobby in command line, join steam lobby |
| 4360 | 4448 | const QString STEAM_LOBBY_COMMAND_LINE_KEY = "+connect_lobby"; |
| @@ -4403,14 +4491,7 @@ void Application::init() { · 42 unmodified lines | ||
| 4403 | 4491 | |
| 4404 | 4492 | // Make sure any new sounds are loaded as soon as know about them. |
| 4405 | 4493 | connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) { |
| 4406 | − EntityTreePointer tree = getEntities()->getTree(); | |
| 4407 | − if (auto entity = tree->findEntityByEntityItemID(id)) { | |
| 4408 | − auto sound = DependencyManager::get<SoundCache>()->getSound(newURL); | |
| 4409 | − auto renderable = entity->getRenderableInterface(); | |
| 4410 | − if (renderable) { | |
| 4411 | − renderable->setCollisionSound(sound); | |
| 4412 | − } | |
| 4413 | − } | |
| 4494 | + getEntities()->setCollisionSound(id, DependencyManager::get<SoundCache>()->getSound(newURL)); | |
| 4414 | 4495 | }, Qt::QueuedConnection); |
| 4415 | 4496 | connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) { |
| 4416 | 4497 | if (auto avatar = getMyAvatar()) { |
| @@ -4721,9 +4802,12 @@ void Application::setKeyboardFocusEntity(EntityItemID entityItemID) { · 304 unmodified lines | ||
| 4721 | 4802 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 4722 | 4803 | auto properties = entityScriptingInterface->getEntityProperties(entityItemID); |
| 4723 | 4804 | if (!properties.getLocked() && properties.getVisible()) { |
| 4724 | − auto entity = getEntities()->getTree()->findEntityByID(entityItemID); | |
| 4725 | − if (entity && entity->wantsKeyboardFocus()) { | |
| 4726 | − entity->setProxyWindow(_window->windowHandle()); | |
| 4805 | + | |
| 4806 | + auto entities = getEntities(); | |
| 4807 | + auto entityId = _keyboardFocusedEntity.get(); | |
| 4808 | + if (entities->wantsKeyboardFocus(entityId)) { | |
| 4809 | + entities->setProxyWindow(entityId, _window->windowHandle()); | |
| 4810 | + auto entity = getEntities()->getEntity(entityId); | |
| 4727 | 4811 | if (_keyboardMouseDevice->isActive()) { |
| 4728 | 4812 | _keyboardMouseDevice->pluginFocusOutEvent(); |
| 4729 | 4813 | } |
| @@ -4999,7 +5083,7 @@ void Application::update(float deltaTime) { · 269 unmodified lines | ||
| 4999 | 5083 | PerformanceTimer perfTimer("physics"); |
| 5000 | 5084 | |
| 5001 | 5085 | { |
| 5002 | − PROFILE_RANGE_EX(simulation_physics, "UpdateStats", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount()); | |
| 5086 | + PROFILE_RANGE_EX(simulation_physics, "UpdateStates", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount()); | |
| 5003 | 5087 | |
| 5004 | 5088 | PerformanceTimer perfTimer("updateStates)"); |
| 5005 | 5089 | static VectorOfMotionStates motionStates; |
| @@ -5068,7 +5152,7 @@ void Application::update(float deltaTime) { · 62 unmodified lines | ||
| 5068 | 5152 | |
| 5069 | 5153 | // NOTE: the getEntities()->update() call below will wait for lock |
| 5070 | 5154 | // and will simulate entity motion (the EntityTree has been given an EntitySimulation). |
| 5071 | − getEntities()->update(); // update the models... | |
| 5155 | + getEntities()->update(true); // update the models... | |
| 5072 | 5156 | } |
| 5073 | 5157 | |
| 5074 | 5158 | myAvatar->harvestResultsFromPhysicsSimulation(deltaTime); |
| @@ -5081,6 +5165,9 @@ void Application::update(float deltaTime) { · 6 unmodified lines | ||
| 5081 | 5165 | _physicsEngine->dumpStatsIfNecessary(); |
| 5082 | 5166 | } |
| 5083 | 5167 | } |
| 5168 | + } else { | |
| 5169 | + // update the rendering without any simulation | |
| 5170 | + getEntities()->update(false); | |
| 5084 | 5171 | } |
| 5085 | 5172 | |
| 5086 | 5173 | // AvatarManager update |
| @@ -6256,7 +6343,11 @@ bool Application::askToReplaceDomainContent(const QString& url) { · 1169 unmodified lines | ||
| 6256 | 6343 | octreeFilePacket->write(urlData); |
| 6257 | 6344 | limitedNodeList->sendPacket(std::move(octreeFilePacket), *octreeNode); |
| 6258 | 6345 | }); |
| 6259 | − DependencyManager::get<AddressManager>()->handleLookupString(DOMAIN_SPAWNING_POINT); | |
| 6346 | + auto addressManager = DependencyManager::get<AddressManager>(); | |
| 6347 | + addressManager->handleLookupString(DOMAIN_SPAWNING_POINT); | |
| 6348 | + QString newHomeAddress = addressManager->getHost() + DOMAIN_SPAWNING_POINT; | |
| 6349 | + qCDebug(interfaceapp) << "Setting new home bookmark to: " << newHomeAddress; | |
| 6350 | + DependencyManager::get<LocationBookmarks>()->setHomeLocationToAddress(newHomeAddress); | |
| 6260 | 6351 | methodDetails = "SuccessfulRequestToReplaceContent"; |
| 6261 | 6352 | } else { |
| 6262 | 6353 | methodDetails = "UserDeclinedToReplaceContent"; |
| @@ -6269,7 +6360,7 @@ bool Application::askToReplaceDomainContent(const QString& url) { · 6 unmodified lines | ||
| 6269 | 6360 | OffscreenUi::warning("Unable to replace content", "You do not have permissions to replace domain content", |
| 6270 | 6361 | QMessageBox::Ok, QMessageBox::Ok); |
| 6271 | 6362 | } |
| 6272 | − QJsonObject messageProperties = { | |
| 6363 | + QJsonObject messageProperties = { | |
| 6273 | 6364 | { "status", methodDetails }, |
| 6274 | 6365 | { "content_set_url", url } |
| 6275 | 6366 | }; |
| @@ -6352,14 +6443,14 @@ void Application::showAssetServerWidget(QString filePath) { · 76 unmodified lines | ||
| 6352 | 6443 | |
| 6353 | 6444 | void Application::addAssetToWorldFromURL(QString url) { |
| 6354 | 6445 | qInfo(interfaceapp) << "Download model and add to world from" << url; |
| 6355 | − | |
| 6446 | + | |
| 6356 | 6447 | QString filename; |
| 6357 | 6448 | if (url.contains("filename")) { |
| 6358 | 6449 | filename = url.section("filename=", 1, 1); // Filename is in "?filename=" parameter at end of URL. |
| 6359 | 6450 | } |
| 6360 | 6451 | if (url.contains("vr.google.com/downloads")) { |
| 6361 | 6452 | filename = url.section('/', -1); |
| 6362 | − filename.remove(".zip?noDownload=false"); | |
| 6453 | + filename.remove(".zip"); | |
| 6363 | 6454 | } |
| 6364 | 6455 | |
| 6365 | 6456 | if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) { |
| @@ -6389,7 +6480,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { · 23 unmodified lines | ||
| 6389 | 6480 | } |
| 6390 | 6481 | if (url.contains("vr.google.com/downloads")) { |
| 6391 | 6482 | filename = url.section('/', -1); |
| 6392 | − filename.remove(".zip?noDownload=false"); | |
| 6483 | + filename.remove(".zip"); | |
| 6393 | 6484 | isBlocks = true; |
| 6394 | 6485 | } |
| 6395 | 6486 | |
| @@ -6406,6 +6497,7 @@ void Application::addAssetToWorldFromURLRequestFinished() { · 10 unmodified lines | ||
| 6406 | 6497 | if (tempFile.open(QIODevice::WriteOnly)) { |
| 6407 | 6498 | tempFile.write(request->getData()); |
| 6408 | 6499 | addAssetToWorldInfoClear(filename); // Remove message from list; next one added will have a different key. |
| 6500 | + tempFile.close(); | |
| 6409 | 6501 | qApp->getFileDownloadInterface()->runUnzip(downloadPath, url, true, false, isBlocks); |
| 6410 | 6502 | } else { |
| 6411 | 6503 | QString errorInfo = "Couldn't open temporary file for download"; |
| @@ -7223,14 +7315,6 @@ void Application::updateDisplayMode() { · 811 unmodified lines | ||
| 7223 | 7315 | qFatal("Attempted to switch display plugins from a non-main thread"); |
| 7224 | 7316 | } |
| 7225 | 7317 | |
| 7226 | − // Some plugins *cough* Oculus *cough* process message events from inside their | |
| 7227 | − // display function, and we don't want to change the display plugin underneath | |
| 7228 | − // the paintGL call, so we need to guard against that | |
| 7229 | − // The current oculus runtime doesn't do this anymore | |
| 7230 | − if (_inPaint) { | |
| 7231 | − qFatal("Attempted to switch display plugins while in painting"); | |
| 7232 | − } | |
| 7233 | − | |
| 7234 | 7318 | auto menu = Menu::getInstance(); |
| 7235 | 7319 | auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); |
| 7236 | 7320 | |
| @@ -7307,12 +7391,12 @@ void Application::updateDisplayMode() { · 70 unmodified lines | ||
| 7307 | 7391 | bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool(); |
| 7308 | 7392 | offscreenUi->getDesktop()->setProperty("repositionLocked", true); |
| 7309 | 7393 | |
| 7310 | − auto oldDisplayPlugin = _displayPlugin; | |
| 7311 | 7394 | if (_displayPlugin) { |
| 7312 | − disconnect(_displayPluginPresentConnection); | |
| 7395 | + disconnect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); | |
| 7313 | 7396 | _displayPlugin->deactivate(); |
| 7314 | 7397 | } |
| 7315 | 7398 | |
| 7399 | + auto oldDisplayPlugin = _displayPlugin; | |
| 7316 | 7400 | bool active = newDisplayPlugin->activate(); |
| 7317 | 7401 | |
| 7318 | 7402 | if (!active) { |
| @@ -7350,7 +7434,7 @@ void Application::updateDisplayMode() { · 31 unmodified lines | ||
| 7350 | 7434 | _offscreenContext->makeCurrent(); |
| 7351 | 7435 | getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); |
| 7352 | 7436 | _displayPlugin = newDisplayPlugin; |
| 7353 | − _displayPluginPresentConnection = connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); | |
| 7437 | + connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); | |
| 7354 | 7438 | offscreenUi->getDesktop()->setProperty("repositionLocked", wasRepositionLocked); |
| 7355 | 7439 | } |
| 7356 | 7440 | |
| @@ -7602,3 +7686,5 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) { · 245 unmodified lines | ||
| 7602 | 7686 | _avatarOverrideUrl = url; |
| 7603 | 7687 | _saveAvatarOverrideUrl = save; |
| 7604 | 7688 | } |
| 7689 | + | |
| 7690 | +#include "Application.moc" | |