Showing the changes to interface/src/Application.cpp (1 of 81 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" |
| @@ -212,6 +212,73 @@ extern "C" { · 67 unmodified lines | ||
| 212 | 212 | } |
| 213 | 213 | #endif |
| 214 | 214 | |
| 215 | +enum ApplicationEvent { | |
| 216 | + // Execute a lambda function | |
| 217 | + Lambda = QEvent::User + 1, | |
| 218 | + // Trigger the next render | |
| 219 | + Render, | |
| 220 | + // Trigger the next idle | |
| 221 | + Idle, | |
| 222 | +}; | |
| 223 | + | |
| 224 | + | |
| 225 | +class RenderEventHandler : public QObject { | |
| 226 | + using Parent = QObject; | |
| 227 | + Q_OBJECT | |
| 228 | +public: | |
| 229 | + RenderEventHandler(QOpenGLContext* context) { | |
| 230 | + _renderContext = new OffscreenGLCanvas(); | |
| 231 | + _renderContext->setObjectName("RenderContext"); | |
| 232 | + _renderContext->create(context); | |
| 233 | + if (!_renderContext->makeCurrent()) { | |
| 234 | + qFatal("Unable to make rendering context current"); | |
| 235 | + } | |
| 236 | + _renderContext->doneCurrent(); | |
| 237 | + | |
| 238 | + // Deleting the object with automatically shutdown the thread | |
| 239 | + connect(qApp, &QCoreApplication::aboutToQuit, this, &QObject::deleteLater); | |
| 240 | + | |
| 241 | + // Transfer to a new thread | |
| 242 | + moveToNewNamedThread(this, "RenderThread", [this](QThread* renderThread) { | |
| 243 | + hifi::qt::addBlockingForbiddenThread("Render", renderThread); | |
| 244 | + _renderContext->moveToThreadWithContext(renderThread); | |
| 245 | + qApp->_lastTimeRendered.start(); | |
| 246 | + }, std::bind(&RenderEventHandler::initialize, this), QThread::HighestPriority); | |
| 247 | + } | |
| 248 | + | |
| 249 | +private: | |
| 250 | + void initialize() { | |
| 251 | + PROFILE_SET_THREAD_NAME("Render"); | |
| 252 | + if (!_renderContext->makeCurrent()) { | |
| 253 | + qFatal("Unable to make rendering context current on render thread"); | |
| 254 | + } | |
| 255 | + } | |
| 256 | + | |
| 257 | + void render() { | |
| 258 | + if (qApp->shouldPaint()) { | |
| 259 | + qApp->paintGL(); | |
| 260 | + } | |
| 261 | + } | |
| 262 | + | |
| 263 | + bool event(QEvent* event) override { | |
| 264 | + switch ((int)event->type()) { | |
| 265 | + case ApplicationEvent::Render: | |
| 266 | + render(); | |
| 267 | + // Ensure we never back up the render events. Each render should be triggered only in response | |
| 268 | + // to the NEXT render event after the last render occured | |
| 269 | + QCoreApplication::removePostedEvents(this, ApplicationEvent::Render); | |
| 270 | + return true; | |
| 271 | + | |
| 272 | + default: | |
| 273 | + break; | |
| 274 | + } | |
| 275 | + return Parent::event(event); | |
| 276 | + } | |
| 277 | + | |
| 278 | + OffscreenGLCanvas* _renderContext { nullptr }; | |
| 279 | +}; | |
| 280 | + | |
| 281 | + | |
| 215 | 282 | Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") |
| 216 | 283 | |
| 217 | 284 | using namespace std; |
| @@ -427,10 +494,10 @@ class LambdaEvent : public QEvent { · 209 unmodified lines | ||
| 427 | 494 | std::function<void()> _fun; |
| 428 | 495 | public: |
| 429 | 496 | LambdaEvent(const std::function<void()> & fun) : |
| 430 | − QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) { | |
| 497 | + QEvent(static_cast<QEvent::Type>(ApplicationEvent::Lambda)), _fun(fun) { | |
| 431 | 498 | } |
| 432 | 499 | LambdaEvent(std::function<void()> && fun) : |
| 433 | − QEvent(static_cast<QEvent::Type>(Application::Lambda)), _fun(fun) { | |
| 500 | + QEvent(static_cast<QEvent::Type>(ApplicationEvent::Lambda)), _fun(fun) { | |
| 434 | 501 | } |
| 435 | 502 | void call() const { _fun(); } |
| 436 | 503 | }; |
| @@ -1367,8 +1434,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 930 unmodified lines | ||
| 1367 | 1434 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 1368 | 1435 | connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, |
| 1369 | 1436 | [this](const EntityItemID& entityItemID, const PointerEvent& event) { |
| 1370 | − auto entity = getEntities()->getTree()->findEntityByID(entityItemID); | |
| 1371 | − if (entity && entity->wantsKeyboardFocus()) { | |
| 1437 | + if (getEntities()->wantsKeyboardFocus(entityItemID)) { | |
| 1372 | 1438 | setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); |
| 1373 | 1439 | setKeyboardFocusEntity(entityItemID); |
| 1374 | 1440 | } else { |
| @@ -1692,7 +1758,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 317 unmodified lines | ||
| 1692 | 1758 | _defaultSkybox->setCubemap(_defaultSkyboxTexture); |
| 1693 | 1759 | } |
| 1694 | 1760 | |
| 1695 | − EntityItem::setEntitiesShouldFadeFunction([this]() { | |
| 1761 | + EntityTreeRenderer::setEntitiesShouldFadeFunction([this]() { | |
| 1696 | 1762 | SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer); |
| 1697 | 1763 | return entityServerNode && !isPhysicsEnabled(); |
| 1698 | 1764 | }); |
| @@ -2099,6 +2165,13 @@ void Application::initializeGL() { · 400 unmodified lines | ||
| 2099 | 2165 | _renderEngine->load(); |
| 2100 | 2166 | _renderEngine->registerScene(_main3DScene); |
| 2101 | 2167 | |
| 2168 | + _offscreenContext = new OffscreenGLCanvas(); | |
| 2169 | + _offscreenContext->setObjectName("MainThreadContext"); | |
| 2170 | + _offscreenContext->create(_glWidget->qglContext()); | |
| 2171 | + if (!_offscreenContext->makeCurrent()) { | |
| 2172 | + qFatal("Unable to make offscreen context current"); | |
| 2173 | + } | |
| 2174 | + | |
| 2102 | 2175 | // The UI can't be created until the primary OpenGL |
| 2103 | 2176 | // context is created, because it needs to share |
| 2104 | 2177 | // texture resources |
| @@ -2122,14 +2195,15 @@ void Application::initializeGL() { · 17 unmodified lines | ||
| 2122 | 2195 | |
| 2123 | 2196 | _idleLoopStdev.reset(); |
| 2124 | 2197 | |
| 2125 | − _offscreenContext = new OffscreenGLCanvas(); | |
| 2126 | − _offscreenContext->setObjectName("MainThreadContext"); | |
| 2127 | − _offscreenContext->create(_glWidget->qglContext()); | |
| 2128 | − _offscreenContext->makeCurrent(); | |
| 2198 | + _renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); | |
| 2199 | + | |
| 2200 | + // Restore the primary GL content for the main thread | |
| 2201 | + if (!_offscreenContext->makeCurrent()) { | |
| 2202 | + qFatal("Unable to make offscreen context current"); | |
| 2203 | + } | |
| 2129 | 2204 | |
| 2130 | 2205 | // update before the first render |
| 2131 | 2206 | update(0); |
| 2132 | − | |
| 2133 | 2207 | } |
| 2134 | 2208 | |
| 2135 | 2209 | FrameTimingsScriptingInterface _frameTimingsScriptingInterface; |
| @@ -2137,6 +2211,9 @@ FrameTimingsScriptingInterface _frameTimingsScriptingInterface; · 1 unmodified line | ||
| 2137 | 2211 | extern void setupPreferences(); |
| 2138 | 2212 | |
| 2139 | 2213 | void Application::initializeUi() { |
| 2214 | + // Make sure all QML surfaces share the main thread GL context | |
| 2215 | + OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext()); | |
| 2216 | + | |
| 2140 | 2217 | AddressBarDialog::registerType(); |
| 2141 | 2218 | ErrorDialog::registerType(); |
| 2142 | 2219 | LoginDialog::registerType(); |
| @@ -2147,7 +2224,7 @@ void Application::initializeUi() { · 4 unmodified lines | ||
| 2147 | 2224 | qmlRegisterType<Preference>("Hifi", 1, 0, "Preference"); |
| 2148 | 2225 | |
| 2149 | 2226 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 2150 | − offscreenUi->create(_glWidget->qglContext()); | |
| 2227 | + offscreenUi->create(); | |
| 2151 | 2228 | |
| 2152 | 2229 | auto surfaceContext = offscreenUi->getSurfaceContext(); |
| 2153 | 2230 | |
| @@ -2292,14 +2369,12 @@ void Application::initializeUi() { · 138 unmodified lines | ||
| 2292 | 2369 | |
| 2293 | 2370 | void Application::paintGL() { |
| 2294 | 2371 | // Some plugins process message events, allowing paintGL to be called reentrantly. |
| 2295 | − if (_inPaint || _aboutToQuit || _window->isMinimized()) { | |
| 2372 | + if (_aboutToQuit || _window->isMinimized()) { | |
| 2296 | 2373 | return; |
| 2297 | 2374 | } |
| 2298 | 2375 | |
| 2299 | − _inPaint = true; | |
| 2300 | − Finally clearFlag([this] { _inPaint = false; }); | |
| 2301 | − | |
| 2302 | 2376 | _frameCount++; |
| 2377 | + _lastTimeRendered.start(); | |
| 2303 | 2378 | |
| 2304 | 2379 | auto lastPaintBegin = usecTimestampNow(); |
| 2305 | 2380 | PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_frameCount); |
| @@ -2315,18 +2390,11 @@ void Application::paintGL() { · 9 unmodified lines | ||
| 2315 | 2390 | displayPlugin = getActiveDisplayPlugin(); |
| 2316 | 2391 | } |
| 2317 | 2392 | |
| 2318 | − { | |
| 2319 | − PROFILE_RANGE(render, "/offscreenMakeCurrent"); | |
| 2320 | − // FIXME not needed anymore? | |
| 2321 | − _offscreenContext->makeCurrent(); | |
| 2322 | − } | |
| 2323 | − | |
| 2324 | 2393 | { |
| 2325 | 2394 | PROFILE_RANGE(render, "/pluginBeginFrameRender"); |
| 2326 | 2395 | // If a display plugin loses it's underlying support, it |
| 2327 | 2396 | // needs to be able to signal us to not use it |
| 2328 | 2397 | if (!displayPlugin->beginFrameRender(_frameCount)) { |
| 2329 | − _inPaint = false; | |
| 2330 | 2398 | updateDisplayMode(); |
| 2331 | 2399 | return; |
| 2332 | 2400 | } |
| @@ -2394,12 +2462,6 @@ void Application::paintGL() { · 61 unmodified lines | ||
| 2394 | 2462 | auto myAvatar = getMyAvatar(); |
| 2395 | 2463 | boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD; |
| 2396 | 2464 | |
| 2397 | − if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { | |
| 2398 | − Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); | |
| 2399 | − Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); | |
| 2400 | − cameraMenuChanged(); | |
| 2401 | − } | |
| 2402 | − | |
| 2403 | 2465 | // The render mode is default or mirror if the camera is in mirror mode, assigned further below |
| 2404 | 2466 | renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; |
| 2405 | 2467 | |
| @@ -2707,15 +2769,6 @@ void Application::resizeGL() { · 301 unmodified lines | ||
| 2707 | 2769 | QMutexLocker viewLocker(&_viewMutex); |
| 2708 | 2770 | _myCamera.loadViewFrustum(_viewFrustum); |
| 2709 | 2771 | } |
| 2710 | − | |
| 2711 | − auto offscreenUi = DependencyManager::get<OffscreenUi>(); | |
| 2712 | − auto uiSize = displayPlugin->getRecommendedUiSize(); | |
| 2713 | − // Bit of a hack since there's no device pixel ratio change event I can find. | |
| 2714 | − if (offscreenUi->size() != fromGlm(uiSize)) { | |
| 2715 | − qCDebug(interfaceapp) << "Device pixel ratio changed, triggering resize to " << uiSize; | |
| 2716 | − offscreenUi->resize(fromGlm(uiSize), true); | |
| 2717 | − _offscreenContext->makeCurrent(); | |
| 2718 | − } | |
| 2719 | 2772 | } |
| 2720 | 2773 | |
| 2721 | 2774 | void Application::handleSandboxStatus(QNetworkReply* reply) { |
| @@ -2889,56 +2942,26 @@ bool Application::importFromZIP(const QString& filePath) { · 167 unmodified lines | ||
| 2889 | 2942 | } |
| 2890 | 2943 | |
| 2891 | 2944 | void Application::onPresent(quint32 frameCount) { |
| 2892 | − if (shouldPaint()) { | |
| 2893 | − postEvent(this, new QEvent(static_cast<QEvent::Type>(Idle)), Qt::HighEventPriority); | |
| 2894 | − postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority); | |
| 2945 | + postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); | |
| 2946 | + if (_renderEventHandler && !isAboutToQuit()) { | |
| 2947 | + postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render)); | |
| 2895 | 2948 | } |
| 2896 | 2949 | } |
| 2897 | 2950 | |
| 2898 | −bool _renderRequested { false }; | |
| 2899 | − | |
| 2900 | −bool Application::event(QEvent* event) { | |
| 2901 | − if (!Menu::getInstance()) { | |
| 2902 | − return false; | |
| 2903 | − } | |
| 2904 | − | |
| 2905 | − int type = event->type(); | |
| 2906 | − switch (type) { | |
| 2907 | − case Event::Lambda: | |
| 2908 | − static_cast<LambdaEvent*>(event)->call(); | |
| 2909 | − return true; | |
| 2910 | − | |
| 2911 | − // Explicit idle keeps the idle running at a lower interval, but without any rendering | |
| 2912 | − // see (windowMinimizedChanged) | |
| 2913 | − case Event::Idle: | |
| 2914 | − idle(); | |
| 2915 | − // Clear the event queue of pending idle calls | |
| 2916 | − removePostedEvents(this, Idle); | |
| 2917 | − return true; | |
| 2918 | − | |
| 2919 | − case Event::Paint: | |
| 2920 | − // NOTE: This must be updated as close to painting as possible, | |
| 2921 | − // or AvatarInputs will mysteriously move to the bottom-right | |
| 2922 | − AvatarInputs::getInstance()->update(); | |
| 2923 | − paintGL(); | |
| 2924 | − // Clear the event queue of pending paint calls | |
| 2925 | − removePostedEvents(this, Paint); | |
| 2926 | − return true; | |
| 2927 | − | |
| 2928 | − default: | |
| 2929 | − break; | |
| 2930 | − } | |
| 2951 | +static inline bool isKeyEvent(QEvent::Type type) { | |
| 2952 | + return type == QEvent::KeyPress || type == QEvent::KeyRelease; | |
| 2953 | +} | |
| 2931 | 2954 | |
| 2932 | − { | |
| 2933 | − if (!_keyboardFocusedEntity.get().isInvalidID()) { | |
| 2934 | − switch (event->type()) { | |
| 2935 | − case QEvent::KeyPress: | |
| 2936 | − case QEvent::KeyRelease: { | |
| 2937 | − //auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | |
| 2938 | − auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get()); | |
| 2939 | − if (entity && entity->getEventHandler()) { | |
| 2955 | +bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { | |
| 2956 | + if (!_keyboardFocusedEntity.get().isInvalidID()) { | |
| 2957 | + switch (event->type()) { | |
| 2958 | + case QEvent::KeyPress: | |
| 2959 | + case QEvent::KeyRelease: | |
| 2960 | + { | |
| 2961 | + auto eventHandler = getEntities()->getEventHandler(_keyboardFocusedEntity.get()); | |
| 2962 | + if (eventHandler) { | |
| 2940 | 2963 | event->setAccepted(false); |
| 2941 | − QCoreApplication::sendEvent(entity->getEventHandler(), event); | |
| 2964 | + QCoreApplication::sendEvent(eventHandler, event); | |
| 2942 | 2965 | if (event->isAccepted()) { |
| 2943 | 2966 | _lastAcceptedKeyPress = usecTimestampNow(); |
| 2944 | 2967 | return true; |
| @@ -2946,20 +2969,17 @@ bool Application::event(QEvent* event) { · 1 unmodified line | ||
| 2946 | 2969 | } |
| 2947 | 2970 | break; |
| 2948 | 2971 | } |
| 2949 | − default: | |
| 2950 | − break; | |
| 2951 | − } | |
| 2972 | + default: | |
| 2973 | + break; | |
| 2952 | 2974 | } |
| 2953 | 2975 | } |
| 2954 | 2976 | |
| 2955 | − { | |
| 2956 | − if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) { | |
| 2957 | − switch (event->type()) { | |
| 2958 | − case QEvent::KeyPress: | |
| 2959 | − case QEvent::KeyRelease: { | |
| 2977 | + if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) { | |
| 2978 | + switch (event->type()) { | |
| 2979 | + case QEvent::KeyPress: | |
| 2980 | + case QEvent::KeyRelease: { | |
| 2960 | 2981 | // Only Web overlays can have focus. |
| 2961 | − auto overlay = | |
| 2962 | − std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); | |
| 2982 | + auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); | |
| 2963 | 2983 | if (overlay && overlay->getEventHandler()) { |
| 2964 | 2984 | event->setAccepted(false); |
| 2965 | 2985 | QCoreApplication::sendEvent(overlay->getEventHandler(), event); |
| @@ -2968,15 +2988,52 @@ bool Application::event(QEvent* event) { · 2 unmodified lines | ||
| 2968 | 2988 | return true; |
| 2969 | 2989 | } |
| 2970 | 2990 | } |
| 2971 | − break; | |
| 2972 | − } | |
| 2973 | − default: | |
| 2974 | − break; | |
| 2975 | 2991 | } |
| 2992 | + break; | |
| 2993 | + | |
| 2994 | + default: | |
| 2995 | + break; | |
| 2996 | + } | |
| 2997 | + } | |
| 2998 | + | |
| 2999 | + return false; | |
| 3000 | +} | |
| 3001 | + | |
| 3002 | +bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) { | |
| 3003 | + QUrl url = fileEvent->url(); | |
| 3004 | + if (!url.isEmpty()) { | |
| 3005 | + QString urlString = url.toString(); | |
| 3006 | + if (canAcceptURL(urlString)) { | |
| 3007 | + return acceptURL(urlString); | |
| 2976 | 3008 | } |
| 2977 | 3009 | } |
| 3010 | + return false; | |
| 3011 | +} | |
| 3012 | + | |
| 3013 | +bool Application::event(QEvent* event) { | |
| 3014 | + if (!Menu::getInstance()) { | |
| 3015 | + return false; | |
| 3016 | + } | |
| 3017 | + | |
| 3018 | + // Allow focused Entities and Overlays to handle keyboard input | |
| 3019 | + if (isKeyEvent(event->type()) && handleKeyEventForFocusedEntityOrOverlay(event)) { | |
| 3020 | + return true; | |
| 3021 | + } | |
| 3022 | + | |
| 3023 | + int type = event->type(); | |
| 3024 | + switch (type) { | |
| 3025 | + case ApplicationEvent::Lambda: | |
| 3026 | + static_cast<LambdaEvent*>(event)->call(); | |
| 3027 | + return true; | |
| 3028 | + | |
| 3029 | + // Explicit idle keeps the idle running at a lower interval, but without any rendering | |
| 3030 | + // see (windowMinimizedChanged) | |
| 3031 | + case ApplicationEvent::Idle: | |
| 3032 | + idle(); | |
| 3033 | + // Don't process extra idle events that arrived in the event queue while we were doing this idle | |
| 3034 | + QCoreApplication::removePostedEvents(this, ApplicationEvent::Idle); | |
| 3035 | + return true; | |
| 2978 | 3036 | |
| 2979 | − switch (event->type()) { | |
| 2980 | 3037 | case QEvent::MouseMove: |
| 2981 | 3038 | mouseMoveEvent(static_cast<QMouseEvent*>(event)); |
| 2982 | 3039 | return true; |
| @@ -3017,26 +3074,15 @@ bool Application::event(QEvent* event) { · 34 unmodified lines | ||
| 3017 | 3074 | case QEvent::Drop: |
| 3018 | 3075 | dropEvent(static_cast<QDropEvent*>(event)); |
| 3019 | 3076 | return true; |
| 3020 | − default: | |
| 3021 | − break; | |
| 3022 | − } | |
| 3023 | − | |
| 3024 | − // handle custom URL | |
| 3025 | − if (event->type() == QEvent::FileOpen) { | |
| 3026 | − | |
| 3027 | − QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event); | |
| 3028 | − | |
| 3029 | − QUrl url = fileEvent->url(); | |
| 3030 | − | |
| 3031 | − if (!url.isEmpty()) { | |
| 3032 | − QString urlString = url.toString(); | |
| 3033 | 3077 | |
| 3034 | − if (canAcceptURL(urlString)) { | |
| 3035 | − | |
| 3036 | − return acceptURL(urlString); | |
| 3078 | + case QEvent::FileOpen: | |
| 3079 | + if (handleFileOpenEvent(static_cast<QFileOpenEvent*>(event))) { | |
| 3080 | + return true; | |
| 3037 | 3081 | } |
| 3038 | − } | |
| 3039 | − return false; | |
| 3082 | + break; | |
| 3083 | + | |
| 3084 | + default: | |
| 3085 | + break; | |
| 3040 | 3086 | } |
| 3041 | 3087 | |
| 3042 | 3088 | if (HFActionEvent::types().contains(event->type())) { |
| @@ -3741,11 +3787,12 @@ bool Application::acceptSnapshot(const QString& urlString) { · 698 unmodified lines | ||
| 3741 | 3787 | |
| 3742 | 3788 | static uint32_t _renderedFrameIndex { INVALID_FRAME }; |
| 3743 | 3789 | |
| 3744 | −bool Application::shouldPaint() { | |
| 3790 | +bool Application::shouldPaint() const { | |
| 3745 | 3791 | if (_aboutToQuit) { |
| 3746 | 3792 | return false; |
| 3747 | 3793 | } |
| 3748 | 3794 | |
| 3795 | + | |
| 3749 | 3796 | auto displayPlugin = getActiveDisplayPlugin(); |
| 3750 | 3797 | |
| 3751 | 3798 | #ifdef DEBUG_PAINT_DELAY |
| @@ -3763,13 +3810,12 @@ bool Application::shouldPaint() { · 11 unmodified lines | ||
| 3763 | 3810 | #endif |
| 3764 | 3811 | |
| 3765 | 3812 | // Throttle if requested |
| 3766 | − if (displayPlugin->isThrottled() && (_lastTimeUpdated.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) { | |
| 3813 | + if (displayPlugin->isThrottled() && (_lastTimeRendered.elapsed() < THROTTLED_SIM_FRAME_PERIOD_MS)) { | |
| 3767 | 3814 | return false; |
| 3768 | 3815 | } |
| 3769 | 3816 | |
| 3770 | 3817 | // Sync up the _renderedFrameIndex |
| 3771 | 3818 | _renderedFrameIndex = displayPlugin->presentCount(); |
| 3772 | − | |
| 3773 | 3819 | return true; |
| 3774 | 3820 | } |
| 3775 | 3821 | |
| @@ -3979,7 +4025,6 @@ void setupCpuMonitorThread() { · 203 unmodified lines | ||
| 3979 | 4025 | |
| 3980 | 4026 | #endif |
| 3981 | 4027 | |
| 3982 | − | |
| 3983 | 4028 | void Application::idle() { |
| 3984 | 4029 | PerformanceTimer perfTimer("idle"); |
| 3985 | 4030 | |
| @@ -4010,9 +4055,17 @@ void Application::idle() { · 24 unmodified lines | ||
| 4010 | 4055 | }); |
| 4011 | 4056 | #endif |
| 4012 | 4057 | |
| 4013 | − | |
| 4014 | − | |
| 4015 | 4058 | auto displayPlugin = getActiveDisplayPlugin(); |
| 4059 | + if (displayPlugin) { | |
| 4060 | + auto uiSize = displayPlugin->getRecommendedUiSize(); | |
| 4061 | + // Bit of a hack since there's no device pixel ratio change event I can find. | |
| 4062 | + if (offscreenUi->size() != fromGlm(uiSize)) { | |
| 4063 | + qCDebug(interfaceapp) << "Device pixel ratio changed, triggering resize to " << uiSize; | |
| 4064 | + offscreenUi->resize(fromGlm(uiSize), true); | |
| 4065 | + _offscreenContext->makeCurrent(); | |
| 4066 | + } | |
| 4067 | + } | |
| 4068 | + | |
| 4016 | 4069 | if (displayPlugin) { |
| 4017 | 4070 | PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate()); |
| 4018 | 4071 | } |
| @@ -4060,6 +4113,10 @@ void Application::idle() { · 41 unmodified lines | ||
| 4060 | 4113 | bool showWarnings = getLogger()->extraDebugging(); |
| 4061 | 4114 | PerformanceWarning warn(showWarnings, "idle()"); |
| 4062 | 4115 | |
| 4116 | + if (!_offscreenContext->makeCurrent()) { | |
| 4117 | + qFatal("Unable to make main thread context current"); | |
| 4118 | + } | |
| 4119 | + | |
| 4063 | 4120 | { |
| 4064 | 4121 | PerformanceTimer perfTimer("update"); |
| 4065 | 4122 | PerformanceWarning warn(showWarnings, "Application::idle()... update()"); |
| @@ -4122,6 +4179,13 @@ void Application::idle() { · 56 unmodified lines | ||
| 4122 | 4179 | } |
| 4123 | 4180 | |
| 4124 | 4181 | _overlayConductor.update(secondsSinceLastUpdate); |
| 4182 | + | |
| 4183 | + auto myAvatar = getMyAvatar(); | |
| 4184 | + if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON || _myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { | |
| 4185 | + Menu::getInstance()->setIsOptionChecked(MenuOption::FirstPerson, myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN); | |
| 4186 | + Menu::getInstance()->setIsOptionChecked(MenuOption::ThirdPerson, !(myAvatar->getBoomLength() <= MyAvatar::ZOOM_MIN)); | |
| 4187 | + cameraMenuChanged(); | |
| 4188 | + } | |
| 4125 | 4189 | } |
| 4126 | 4190 | |
| 4127 | 4191 | ivec2 Application::getMouse() const { |
| @@ -4376,7 +4440,6 @@ void Application::init() { · 248 unmodified lines | ||
| 4376 | 4440 | _timerStart.start(); |
| 4377 | 4441 | _lastTimeUpdated.start(); |
| 4378 | 4442 | |
| 4379 | − | |
| 4380 | 4443 | if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { |
| 4381 | 4444 | // when +connect_lobby in command line, join steam lobby |
| 4382 | 4445 | const QString STEAM_LOBBY_COMMAND_LINE_KEY = "+connect_lobby"; |
| @@ -4425,14 +4488,7 @@ void Application::init() { · 42 unmodified lines | ||
| 4425 | 4488 | |
| 4426 | 4489 | // Make sure any new sounds are loaded as soon as know about them. |
| 4427 | 4490 | connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) { |
| 4428 | − EntityTreePointer tree = getEntities()->getTree(); | |
| 4429 | − if (auto entity = tree->findEntityByEntityItemID(id)) { | |
| 4430 | − auto sound = DependencyManager::get<SoundCache>()->getSound(newURL); | |
| 4431 | − auto renderable = entity->getRenderableInterface(); | |
| 4432 | − if (renderable) { | |
| 4433 | − renderable->setCollisionSound(sound); | |
| 4434 | − } | |
| 4435 | − } | |
| 4491 | + getEntities()->setCollisionSound(id, DependencyManager::get<SoundCache>()->getSound(newURL)); | |
| 4436 | 4492 | }, Qt::QueuedConnection); |
| 4437 | 4493 | connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) { |
| 4438 | 4494 | if (auto avatar = getMyAvatar()) { |
| @@ -4743,9 +4799,12 @@ void Application::setKeyboardFocusEntity(EntityItemID entityItemID) { · 304 unmodified lines | ||
| 4743 | 4799 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 4744 | 4800 | auto properties = entityScriptingInterface->getEntityProperties(entityItemID); |
| 4745 | 4801 | if (!properties.getLocked() && properties.getVisible()) { |
| 4746 | − auto entity = getEntities()->getTree()->findEntityByID(entityItemID); | |
| 4747 | − if (entity && entity->wantsKeyboardFocus()) { | |
| 4748 | − entity->setProxyWindow(_window->windowHandle()); | |
| 4802 | + | |
| 4803 | + auto entities = getEntities(); | |
| 4804 | + auto entityId = _keyboardFocusedEntity.get(); | |
| 4805 | + if (entities->wantsKeyboardFocus(entityId)) { | |
| 4806 | + entities->setProxyWindow(entityId, _window->windowHandle()); | |
| 4807 | + auto entity = getEntities()->getEntity(entityId); | |
| 4749 | 4808 | if (_keyboardMouseDevice->isActive()) { |
| 4750 | 4809 | _keyboardMouseDevice->pluginFocusOutEvent(); |
| 4751 | 4810 | } |
| @@ -5021,7 +5080,7 @@ void Application::update(float deltaTime) { · 269 unmodified lines | ||
| 5021 | 5080 | PerformanceTimer perfTimer("physics"); |
| 5022 | 5081 | |
| 5023 | 5082 | { |
| 5024 | − PROFILE_RANGE_EX(simulation_physics, "UpdateStats", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount()); | |
| 5083 | + PROFILE_RANGE_EX(simulation_physics, "UpdateStates", 0xffffff00, (uint64_t)getActiveDisplayPlugin()->presentCount()); | |
| 5025 | 5084 | |
| 5026 | 5085 | PerformanceTimer perfTimer("updateStates)"); |
| 5027 | 5086 | static VectorOfMotionStates motionStates; |
| @@ -5090,7 +5149,7 @@ void Application::update(float deltaTime) { · 62 unmodified lines | ||
| 5090 | 5149 | |
| 5091 | 5150 | // NOTE: the getEntities()->update() call below will wait for lock |
| 5092 | 5151 | // and will simulate entity motion (the EntityTree has been given an EntitySimulation). |
| 5093 | − getEntities()->update(); // update the models... | |
| 5152 | + getEntities()->update(true); // update the models... | |
| 5094 | 5153 | } |
| 5095 | 5154 | |
| 5096 | 5155 | myAvatar->harvestResultsFromPhysicsSimulation(deltaTime); |
| @@ -5103,6 +5162,9 @@ void Application::update(float deltaTime) { · 6 unmodified lines | ||
| 5103 | 5162 | _physicsEngine->dumpStatsIfNecessary(); |
| 5104 | 5163 | } |
| 5105 | 5164 | } |
| 5165 | + } else { | |
| 5166 | + // update the rendering without any simulation | |
| 5167 | + getEntities()->update(false); | |
| 5106 | 5168 | } |
| 5107 | 5169 | |
| 5108 | 5170 | // AvatarManager update |
| @@ -7255,14 +7317,6 @@ void Application::updateDisplayMode() { · 2146 unmodified lines | ||
| 7255 | 7317 | qFatal("Attempted to switch display plugins from a non-main thread"); |
| 7256 | 7318 | } |
| 7257 | 7319 | |
| 7258 | − // Some plugins *cough* Oculus *cough* process message events from inside their | |
| 7259 | − // display function, and we don't want to change the display plugin underneath | |
| 7260 | − // the paintGL call, so we need to guard against that | |
| 7261 | − // The current oculus runtime doesn't do this anymore | |
| 7262 | − if (_inPaint) { | |
| 7263 | − qFatal("Attempted to switch display plugins while in painting"); | |
| 7264 | − } | |
| 7265 | − | |
| 7266 | 7320 | auto menu = Menu::getInstance(); |
| 7267 | 7321 | auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); |
| 7268 | 7322 | |
| @@ -7339,12 +7393,12 @@ void Application::updateDisplayMode() { · 70 unmodified lines | ||
| 7339 | 7393 | bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool(); |
| 7340 | 7394 | offscreenUi->getDesktop()->setProperty("repositionLocked", true); |
| 7341 | 7395 | |
| 7342 | − auto oldDisplayPlugin = _displayPlugin; | |
| 7343 | 7396 | if (_displayPlugin) { |
| 7344 | − disconnect(_displayPluginPresentConnection); | |
| 7397 | + disconnect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); | |
| 7345 | 7398 | _displayPlugin->deactivate(); |
| 7346 | 7399 | } |
| 7347 | 7400 | |
| 7401 | + auto oldDisplayPlugin = _displayPlugin; | |
| 7348 | 7402 | bool active = newDisplayPlugin->activate(); |
| 7349 | 7403 | |
| 7350 | 7404 | if (!active) { |
| @@ -7382,7 +7436,7 @@ void Application::updateDisplayMode() { · 31 unmodified lines | ||
| 7382 | 7436 | _offscreenContext->makeCurrent(); |
| 7383 | 7437 | getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); |
| 7384 | 7438 | _displayPlugin = newDisplayPlugin; |
| 7385 | − _displayPluginPresentConnection = connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); | |
| 7439 | + connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); | |
| 7386 | 7440 | offscreenUi->getDesktop()->setProperty("repositionLocked", wasRepositionLocked); |
| 7387 | 7441 | } |
| 7388 | 7442 | |
| @@ -7634,3 +7688,5 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) { · 245 unmodified lines | ||
| 7634 | 7688 | _avatarOverrideUrl = url; |
| 7635 | 7689 | _saveAvatarOverrideUrl = save; |
| 7636 | 7690 | } |
| 7691 | + | |
| 7692 | +#include "Application.moc" | |