Showing the changes to interface/src/Application.cpp (1 of 81 files). Show all
Unified · Split
| @@ -113,7 +113,6 @@ · 112 unmodified lines | |||
| 113 | #include <plugins/SteamClientPlugin.h> | 113 | #include <plugins/SteamClientPlugin.h> |
| 114 | #include <plugins/InputConfiguration.h> | 114 | #include <plugins/InputConfiguration.h> |
| 115 | #include <RecordingScriptingInterface.h> | 115 | #include <RecordingScriptingInterface.h> |
| 116 | #include <RenderableWebEntityItem.h> | ||
| 117 | #include <UpdateSceneTask.h> | 116 | #include <UpdateSceneTask.h> |
| 118 | #include <RenderViewTask.h> | 117 | #include <RenderViewTask.h> |
| 119 | #include <SecondaryCamera.h> | 118 | #include <SecondaryCamera.h> |
| @@ -139,6 +138,7 @@ · 19 unmodified lines | |||
| 139 | #include <display-plugins/CompositorHelper.h> | 138 | #include <display-plugins/CompositorHelper.h> |
| 140 | #include <trackers/EyeTracker.h> | 139 | #include <trackers/EyeTracker.h> |
| 141 | #include <avatars-renderer/ScriptAvatar.h> | 140 | #include <avatars-renderer/ScriptAvatar.h> |
| 141 | #include <RenderableEntityItem.h> | ||
| 142 | 142 | ||
| 143 | #include "AudioClient.h" | 143 | #include "AudioClient.h" |
| 144 | #include "audio/AudioScope.h" | 144 | #include "audio/AudioScope.h" |
| @@ -212,6 +212,73 @@ extern "C" { · 67 unmodified lines | |||
| 212 | } | 212 | } |
| 213 | #endif | 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 | Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") | 282 | Q_LOGGING_CATEGORY(trace_app_input_mouse, "trace.app.input.mouse") |
| 216 | 283 | ||
| 217 | using namespace std; | 284 | using namespace std; |
| @@ -427,10 +494,10 @@ class LambdaEvent : public QEvent { · 209 unmodified lines | |||
| 427 | std::function<void()> _fun; | 494 | std::function<void()> _fun; |
| 428 | public: | 495 | public: |
| 429 | LambdaEvent(const std::function<void()> & fun) : | 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 | LambdaEvent(std::function<void()> && fun) : | 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 | void call() const { _fun(); } | 502 | void call() const { _fun(); } |
| 436 | }; | 503 | }; |
| @@ -1367,8 +1434,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 930 unmodified lines | |||
| 1367 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | 1434 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 1368 | connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, | 1435 | connect(entityScriptingInterface.data(), &EntityScriptingInterface::clickDownOnEntity, |
| 1369 | [this](const EntityItemID& entityItemID, const PointerEvent& event) { | 1436 | [this](const EntityItemID& entityItemID, const PointerEvent& event) { |
| 1370 | auto entity = getEntities()->getTree()->findEntityByID(entityItemID); | 1437 | if (getEntities()->wantsKeyboardFocus(entityItemID)) { |
| 1371 | if (entity && entity->wantsKeyboardFocus()) { | ||
| 1372 | setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); | 1438 | setKeyboardFocusOverlay(UNKNOWN_OVERLAY_ID); |
| 1373 | setKeyboardFocusEntity(entityItemID); | 1439 | setKeyboardFocusEntity(entityItemID); |
| 1374 | } else { | 1440 | } else { |
| @@ -1692,7 +1758,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo · 317 unmodified lines | |||
| 1692 | _defaultSkybox->setCubemap(_defaultSkyboxTexture); | 1758 | _defaultSkybox->setCubemap(_defaultSkyboxTexture); |
| 1693 | } | 1759 | } |
| 1694 | 1760 | ||
| 1695 | EntityItem::setEntitiesShouldFadeFunction([this]() { | 1761 | EntityTreeRenderer::setEntitiesShouldFadeFunction([this]() { |
| 1696 | SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer); | 1762 | SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer); |
| 1697 | return entityServerNode && !isPhysicsEnabled(); | 1763 | return entityServerNode && !isPhysicsEnabled(); |
| 1698 | }); | 1764 | }); |
| @@ -2099,6 +2165,13 @@ void Application::initializeGL() { · 400 unmodified lines | |||
| 2099 | _renderEngine->load(); | 2165 | _renderEngine->load(); |
| 2100 | _renderEngine->registerScene(_main3DScene); | 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 | // The UI can't be created until the primary OpenGL | 2175 | // The UI can't be created until the primary OpenGL |
| 2103 | // context is created, because it needs to share | 2176 | // context is created, because it needs to share |
| 2104 | // texture resources | 2177 | // texture resources |
| @@ -2122,14 +2195,15 @@ void Application::initializeGL() { · 17 unmodified lines | |||
| 2122 | 2195 | ||
| 2123 | _idleLoopStdev.reset(); | 2196 | _idleLoopStdev.reset(); |
| 2124 | 2197 | ||
| 2125 | _offscreenContext = new OffscreenGLCanvas(); | 2198 | _renderEventHandler = new RenderEventHandler(_glWidget->qglContext()); |
| 2126 | _offscreenContext->setObjectName("MainThreadContext"); | 2199 | |
| 2127 | _offscreenContext->create(_glWidget->qglContext()); | 2200 | // Restore the primary GL content for the main thread |
| 2128 | _offscreenContext->makeCurrent(); | 2201 | if (!_offscreenContext->makeCurrent()) { |
| 2202 | qFatal("Unable to make offscreen context current"); | ||
| 2203 | } | ||
| 2129 | 2204 | ||
| 2130 | // update before the first render | 2205 | // update before the first render |
| 2131 | update(0); | 2206 | update(0); |
| 2132 | |||
| 2133 | } | 2207 | } |
| 2134 | 2208 | ||
| 2135 | FrameTimingsScriptingInterface _frameTimingsScriptingInterface; | 2209 | FrameTimingsScriptingInterface _frameTimingsScriptingInterface; |
| @@ -2137,6 +2211,9 @@ FrameTimingsScriptingInterface _frameTimingsScriptingInterface; · 1 unmodified line | |||
| 2137 | extern void setupPreferences(); | 2211 | extern void setupPreferences(); |
| 2138 | 2212 | ||
| 2139 | void Application::initializeUi() { | 2213 | void Application::initializeUi() { |
| 2214 | // Make sure all QML surfaces share the main thread GL context | ||
| 2215 | OffscreenQmlSurface::setSharedContext(_offscreenContext->getContext()); | ||
| 2216 | |||
| 2140 | AddressBarDialog::registerType(); | 2217 | AddressBarDialog::registerType(); |
| 2141 | ErrorDialog::registerType(); | 2218 | ErrorDialog::registerType(); |
| 2142 | LoginDialog::registerType(); | 2219 | LoginDialog::registerType(); |
| @@ -2147,7 +2224,7 @@ void Application::initializeUi() { · 4 unmodified lines | |||
| 2147 | qmlRegisterType<Preference>("Hifi", 1, 0, "Preference"); | 2224 | qmlRegisterType<Preference>("Hifi", 1, 0, "Preference"); |
| 2148 | 2225 | ||
| 2149 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); | 2226 | auto offscreenUi = DependencyManager::get<OffscreenUi>(); |
| 2150 | offscreenUi->create(_glWidget->qglContext()); | 2227 | offscreenUi->create(); |
| 2151 | 2228 | ||
| 2152 | auto surfaceContext = offscreenUi->getSurfaceContext(); | 2229 | auto surfaceContext = offscreenUi->getSurfaceContext(); |
| 2153 | 2230 | ||
| @@ -2292,14 +2369,12 @@ void Application::initializeUi() { · 138 unmodified lines | |||
| 2292 | 2369 | ||
| 2293 | void Application::paintGL() { | 2370 | void Application::paintGL() { |
| 2294 | // Some plugins process message events, allowing paintGL to be called reentrantly. | 2371 | // Some plugins process message events, allowing paintGL to be called reentrantly. |
| 2295 | if (_inPaint || _aboutToQuit || _window->isMinimized()) { | 2372 | if (_aboutToQuit || _window->isMinimized()) { |
| 2296 | return; | 2373 | return; |
| 2297 | } | 2374 | } |
| 2298 | 2375 | ||
| 2299 | _inPaint = true; | ||
| 2300 | Finally clearFlag([this] { _inPaint = false; }); | ||
| 2301 | |||
| 2302 | _frameCount++; | 2376 | _frameCount++; |
| 2377 | _lastTimeRendered.start(); | ||
| 2303 | 2378 | ||
| 2304 | auto lastPaintBegin = usecTimestampNow(); | 2379 | auto lastPaintBegin = usecTimestampNow(); |
| 2305 | PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_frameCount); | 2380 | PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_frameCount); |
| @@ -2315,18 +2390,11 @@ void Application::paintGL() { · 9 unmodified lines | |||
| 2315 | displayPlugin = getActiveDisplayPlugin(); | 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 | PROFILE_RANGE(render, "/pluginBeginFrameRender"); | 2394 | PROFILE_RANGE(render, "/pluginBeginFrameRender"); |
| 2326 | // If a display plugin loses it's underlying support, it | 2395 | // If a display plugin loses it's underlying support, it |
| 2327 | // needs to be able to signal us to not use it | 2396 | // needs to be able to signal us to not use it |
| 2328 | if (!displayPlugin->beginFrameRender(_frameCount)) { | 2397 | if (!displayPlugin->beginFrameRender(_frameCount)) { |
| 2329 | _inPaint = false; | ||
| 2330 | updateDisplayMode(); | 2398 | updateDisplayMode(); |
| 2331 | return; | 2399 | return; |
| 2332 | } | 2400 | } |
| @@ -2394,12 +2462,6 @@ void Application::paintGL() { · 61 unmodified lines | |||
| 2394 | auto myAvatar = getMyAvatar(); | 2462 | auto myAvatar = getMyAvatar(); |
| 2395 | boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD; | 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 | // The render mode is default or mirror if the camera is in mirror mode, assigned further below | 2465 | // The render mode is default or mirror if the camera is in mirror mode, assigned further below |
| 2404 | renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; | 2466 | renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE; |
| 2405 | 2467 | ||
| @@ -2707,15 +2769,6 @@ void Application::resizeGL() { · 301 unmodified lines | |||
| 2707 | QMutexLocker viewLocker(&_viewMutex); | 2769 | QMutexLocker viewLocker(&_viewMutex); |
| 2708 | _myCamera.loadViewFrustum(_viewFrustum); | 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 | void Application::handleSandboxStatus(QNetworkReply* reply) { | 2774 | void Application::handleSandboxStatus(QNetworkReply* reply) { |
| @@ -2889,56 +2942,26 @@ bool Application::importFromZIP(const QString& filePath) { · 167 unmodified lines | |||
| 2889 | } | 2942 | } |
| 2890 | 2943 | ||
| 2891 | void Application::onPresent(quint32 frameCount) { | 2944 | void Application::onPresent(quint32 frameCount) { |
| 2892 | if (shouldPaint()) { | 2945 | postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); |
| 2893 | postEvent(this, new QEvent(static_cast<QEvent::Type>(Idle)), Qt::HighEventPriority); | 2946 | if (_renderEventHandler && !isAboutToQuit()) { |
| 2894 | postEvent(this, new QEvent(static_cast<QEvent::Type>(Paint)), Qt::HighEventPriority); | 2947 | postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render)); |
| 2895 | } | 2948 | } |
| 2896 | } | 2949 | } |
| 2897 | 2950 | ||
| 2898 | bool _renderRequested { false }; | 2951 | static inline bool isKeyEvent(QEvent::Type type) { |
| 2899 | 2952 | return type == QEvent::KeyPress || type == QEvent::KeyRelease; | |
| 2900 | bool Application::event(QEvent* event) { | 2953 | } |
| 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 | } | ||
| 2931 | 2954 | ||
| 2932 | { | 2955 | bool Application::handleKeyEventForFocusedEntityOrOverlay(QEvent* event) { |
| 2933 | if (!_keyboardFocusedEntity.get().isInvalidID()) { | 2956 | if (!_keyboardFocusedEntity.get().isInvalidID()) { |
| 2934 | switch (event->type()) { | 2957 | switch (event->type()) { |
| 2935 | case QEvent::KeyPress: | 2958 | case QEvent::KeyPress: |
| 2936 | case QEvent::KeyRelease: { | 2959 | case QEvent::KeyRelease: |
| 2937 | //auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | 2960 | { |
| 2938 | auto entity = getEntities()->getTree()->findEntityByID(_keyboardFocusedEntity.get()); | 2961 | auto eventHandler = getEntities()->getEventHandler(_keyboardFocusedEntity.get()); |
| 2939 | if (entity && entity->getEventHandler()) { | 2962 | if (eventHandler) { |
| 2940 | event->setAccepted(false); | 2963 | event->setAccepted(false); |
| 2941 | QCoreApplication::sendEvent(entity->getEventHandler(), event); | 2964 | QCoreApplication::sendEvent(eventHandler, event); |
| 2942 | if (event->isAccepted()) { | 2965 | if (event->isAccepted()) { |
| 2943 | _lastAcceptedKeyPress = usecTimestampNow(); | 2966 | _lastAcceptedKeyPress = usecTimestampNow(); |
| 2944 | return true; | 2967 | return true; |
| @@ -2946,20 +2969,17 @@ bool Application::event(QEvent* event) { · 1 unmodified line | |||
| 2946 | } | 2969 | } |
| 2947 | break; | 2970 | break; |
| 2948 | } | 2971 | } |
| 2949 | default: | 2972 | default: |
| 2950 | break; | 2973 | break; |
| 2951 | } | ||
| 2952 | } | 2974 | } |
| 2953 | } | 2975 | } |
| 2954 | 2976 | ||
| 2955 | { | 2977 | if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) { |
| 2956 | if (_keyboardFocusedOverlay.get() != UNKNOWN_OVERLAY_ID) { | 2978 | switch (event->type()) { |
| 2957 | switch (event->type()) { | 2979 | case QEvent::KeyPress: |
| 2958 | case QEvent::KeyPress: | 2980 | case QEvent::KeyRelease: { |
| 2959 | case QEvent::KeyRelease: { | ||
| 2960 | // Only Web overlays can have focus. | 2981 | // Only Web overlays can have focus. |
| 2961 | auto overlay = | 2982 | auto overlay = std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); |
| 2962 | std::dynamic_pointer_cast<Web3DOverlay>(getOverlays().getOverlay(_keyboardFocusedOverlay.get())); | ||
| 2963 | if (overlay && overlay->getEventHandler()) { | 2983 | if (overlay && overlay->getEventHandler()) { |
| 2964 | event->setAccepted(false); | 2984 | event->setAccepted(false); |
| 2965 | QCoreApplication::sendEvent(overlay->getEventHandler(), event); | 2985 | QCoreApplication::sendEvent(overlay->getEventHandler(), event); |
| @@ -2968,15 +2988,52 @@ bool Application::event(QEvent* event) { · 2 unmodified lines | |||
| 2968 | return true; | 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 | case QEvent::MouseMove: | 3037 | case QEvent::MouseMove: |
| 2981 | mouseMoveEvent(static_cast<QMouseEvent*>(event)); | 3038 | mouseMoveEvent(static_cast<QMouseEvent*>(event)); |
| 2982 | return true; | 3039 | return true; |
| @@ -3017,26 +3074,15 @@ bool Application::event(QEvent* event) { · 34 unmodified lines | |||
| 3017 | case QEvent::Drop: | 3074 | case QEvent::Drop: |
| 3018 | dropEvent(static_cast<QDropEvent*>(event)); | 3075 | dropEvent(static_cast<QDropEvent*>(event)); |
| 3019 | return true; | 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)) { | 3078 | case QEvent::FileOpen: |
| 3035 | 3079 | if (handleFileOpenEvent(static_cast<QFileOpenEvent*>(event))) { | |
| 3036 | return acceptURL(urlString); | 3080 | return true; |
| 3037 | } | 3081 | } |
| 3038 | } | 3082 | break; |
| 3039 | return false; | 3083 | |
| 3084 | default: | ||
| 3085 | break; | ||
| 3040 | } | 3086 | } |
| 3041 | 3087 | ||
| 3042 | if (HFActionEvent::types().contains(event->type())) { | 3088 | if (HFActionEvent::types().contains(event->type())) { |
| @@ -3741,11 +3787,12 @@ bool Application::acceptSnapshot(const QString& urlString) { · 698 unmodified lines | |||
| 3741 | 3787 | ||
| 3742 | static uint32_t _renderedFrameIndex { INVALID_FRAME }; | 3788 | static uint32_t _renderedFrameIndex { INVALID_FRAME }; |
| 3743 | 3789 | ||
| 3744 | bool Application::shouldPaint() { | 3790 | bool Application::shouldPaint() const { |
| 3745 | if (_aboutToQuit) { | 3791 | if (_aboutToQuit) { |
| 3746 | return false; | 3792 | return false; |
| 3747 | } | 3793 | } |
| 3748 | 3794 | ||
| 3795 | |||
| 3749 | auto displayPlugin = getActiveDisplayPlugin(); | 3796 | auto displayPlugin = getActiveDisplayPlugin(); |
| 3750 | 3797 | ||
| 3751 | #ifdef DEBUG_PAINT_DELAY | 3798 | #ifdef DEBUG_PAINT_DELAY |
| @@ -3763,13 +3810,12 @@ bool Application::shouldPaint() { · 11 unmodified lines | |||
| 3763 | #endif | 3810 | #endif |
| 3764 | 3811 | ||
| 3765 | // Throttle if requested | 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 | return false; | 3814 | return false; |
| 3768 | } | 3815 | } |
| 3769 | 3816 | ||
| 3770 | // Sync up the _renderedFrameIndex | 3817 | // Sync up the _renderedFrameIndex |
| 3771 | _renderedFrameIndex = displayPlugin->presentCount(); | 3818 | _renderedFrameIndex = displayPlugin->presentCount(); |
| 3772 | |||
| 3773 | return true; | 3819 | return true; |
| 3774 | } | 3820 | } |
| 3775 | 3821 | ||
| @@ -3979,7 +4025,6 @@ void setupCpuMonitorThread() { · 203 unmodified lines | |||
| 3979 | 4025 | ||
| 3980 | #endif | 4026 | #endif |
| 3981 | 4027 | ||
| 3982 | |||
| 3983 | void Application::idle() { | 4028 | void Application::idle() { |
| 3984 | PerformanceTimer perfTimer("idle"); | 4029 | PerformanceTimer perfTimer("idle"); |
| 3985 | 4030 | ||
| @@ -4010,9 +4055,17 @@ void Application::idle() { · 24 unmodified lines | |||
| 4010 | }); | 4055 | }); |
| 4011 | #endif | 4056 | #endif |
| 4012 | 4057 | ||
| 4013 | |||
| 4014 | |||
| 4015 | auto displayPlugin = getActiveDisplayPlugin(); | 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 | if (displayPlugin) { | 4069 | if (displayPlugin) { |
| 4017 | PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate()); | 4070 | PROFILE_COUNTER_IF_CHANGED(app, "present", float, displayPlugin->presentRate()); |
| 4018 | } | 4071 | } |
| @@ -4060,6 +4113,10 @@ void Application::idle() { · 41 unmodified lines | |||
| 4060 | bool showWarnings = getLogger()->extraDebugging(); | 4113 | bool showWarnings = getLogger()->extraDebugging(); |
| 4061 | PerformanceWarning warn(showWarnings, "idle()"); | 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 | PerformanceTimer perfTimer("update"); | 4121 | PerformanceTimer perfTimer("update"); |
| 4065 | PerformanceWarning warn(showWarnings, "Application::idle()... update()"); | 4122 | PerformanceWarning warn(showWarnings, "Application::idle()... update()"); |
| @@ -4122,6 +4179,13 @@ void Application::idle() { · 56 unmodified lines | |||
| 4122 | } | 4179 | } |
| 4123 | 4180 | ||
| 4124 | _overlayConductor.update(secondsSinceLastUpdate); | 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 | ivec2 Application::getMouse() const { | 4191 | ivec2 Application::getMouse() const { |
| @@ -4376,7 +4440,6 @@ void Application::init() { · 248 unmodified lines | |||
| 4376 | _timerStart.start(); | 4440 | _timerStart.start(); |
| 4377 | _lastTimeUpdated.start(); | 4441 | _lastTimeUpdated.start(); |
| 4378 | 4442 | ||
| 4379 | |||
| 4380 | if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { | 4443 | if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) { |
| 4381 | // when +connect_lobby in command line, join steam lobby | 4444 | // when +connect_lobby in command line, join steam lobby |
| 4382 | const QString STEAM_LOBBY_COMMAND_LINE_KEY = "+connect_lobby"; | 4445 | const QString STEAM_LOBBY_COMMAND_LINE_KEY = "+connect_lobby"; |
| @@ -4425,14 +4488,7 @@ void Application::init() { · 42 unmodified lines | |||
| 4425 | 4488 | ||
| 4426 | // Make sure any new sounds are loaded as soon as know about them. | 4489 | // Make sure any new sounds are loaded as soon as know about them. |
| 4427 | connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) { | 4490 | connect(tree.get(), &EntityTree::newCollisionSoundURL, this, [this](QUrl newURL, EntityItemID id) { |
| 4428 | EntityTreePointer tree = getEntities()->getTree(); | 4491 | getEntities()->setCollisionSound(id, DependencyManager::get<SoundCache>()->getSound(newURL)); |
| 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 | } | ||
| 4436 | }, Qt::QueuedConnection); | 4492 | }, Qt::QueuedConnection); |
| 4437 | connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) { | 4493 | connect(getMyAvatar().get(), &MyAvatar::newCollisionSoundURL, this, [this](QUrl newURL) { |
| 4438 | if (auto avatar = getMyAvatar()) { | 4494 | if (auto avatar = getMyAvatar()) { |
| @@ -4743,9 +4799,12 @@ void Application::setKeyboardFocusEntity(EntityItemID entityItemID) { · 304 unmodified lines | |||
| 4743 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); | 4799 | auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); |
| 4744 | auto properties = entityScriptingInterface->getEntityProperties(entityItemID); | 4800 | auto properties = entityScriptingInterface->getEntityProperties(entityItemID); |
| 4745 | if (!properties.getLocked() && properties.getVisible()) { | 4801 | if (!properties.getLocked() && properties.getVisible()) { |
| 4746 | auto entity = getEntities()->getTree()->findEntityByID(entityItemID); | 4802 | |
| 4747 | if (entity && entity->wantsKeyboardFocus()) { | 4803 | auto entities = getEntities(); |
| 4748 | entity->setProxyWindow(_window->windowHandle()); | 4804 | auto entityId = _keyboardFocusedEntity.get(); |
| 4805 | if (entities->wantsKeyboardFocus(entityId)) { | ||
| 4806 | entities->setProxyWindow(entityId, _window->windowHandle()); | ||
| 4807 | auto entity = getEntities()->getEntity(entityId); | ||
| 4749 | if (_keyboardMouseDevice->isActive()) { | 4808 | if (_keyboardMouseDevice->isActive()) { |
| 4750 | _keyboardMouseDevice->pluginFocusOutEvent(); | 4809 | _keyboardMouseDevice->pluginFocusOutEvent(); |
| 4751 | } | 4810 | } |
| @@ -5021,7 +5080,7 @@ void Application::update(float deltaTime) { · 269 unmodified lines | |||
| 5021 | PerformanceTimer perfTimer("physics"); | 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 | PerformanceTimer perfTimer("updateStates)"); | 5085 | PerformanceTimer perfTimer("updateStates)"); |
| 5027 | static VectorOfMotionStates motionStates; | 5086 | static VectorOfMotionStates motionStates; |
| @@ -5090,7 +5149,7 @@ void Application::update(float deltaTime) { · 62 unmodified lines | |||
| 5090 | 5149 | ||
| 5091 | // NOTE: the getEntities()->update() call below will wait for lock | 5150 | // NOTE: the getEntities()->update() call below will wait for lock |
| 5092 | // and will simulate entity motion (the EntityTree has been given an EntitySimulation). | 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 | myAvatar->harvestResultsFromPhysicsSimulation(deltaTime); | 5155 | myAvatar->harvestResultsFromPhysicsSimulation(deltaTime); |
| @@ -5103,6 +5162,9 @@ void Application::update(float deltaTime) { · 6 unmodified lines | |||
| 5103 | _physicsEngine->dumpStatsIfNecessary(); | 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 | // AvatarManager update | 5170 | // AvatarManager update |
| @@ -7255,14 +7317,6 @@ void Application::updateDisplayMode() { · 2146 unmodified lines | |||
| 7255 | qFatal("Attempted to switch display plugins from a non-main thread"); | 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 | auto menu = Menu::getInstance(); | 7320 | auto menu = Menu::getInstance(); |
| 7267 | auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); | 7321 | auto displayPlugins = PluginManager::getInstance()->getDisplayPlugins(); |
| 7268 | 7322 | ||
| @@ -7339,12 +7393,12 @@ void Application::updateDisplayMode() { · 70 unmodified lines | |||
| 7339 | bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool(); | 7393 | bool wasRepositionLocked = offscreenUi->getDesktop()->property("repositionLocked").toBool(); |
| 7340 | offscreenUi->getDesktop()->setProperty("repositionLocked", true); | 7394 | offscreenUi->getDesktop()->setProperty("repositionLocked", true); |
| 7341 | 7395 | ||
| 7342 | auto oldDisplayPlugin = _displayPlugin; | ||
| 7343 | if (_displayPlugin) { | 7396 | if (_displayPlugin) { |
| 7344 | disconnect(_displayPluginPresentConnection); | 7397 | disconnect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); |
| 7345 | _displayPlugin->deactivate(); | 7398 | _displayPlugin->deactivate(); |
| 7346 | } | 7399 | } |
| 7347 | 7400 | ||
| 7401 | auto oldDisplayPlugin = _displayPlugin; | ||
| 7348 | bool active = newDisplayPlugin->activate(); | 7402 | bool active = newDisplayPlugin->activate(); |
| 7349 | 7403 | ||
| 7350 | if (!active) { | 7404 | if (!active) { |
| @@ -7382,7 +7436,7 @@ void Application::updateDisplayMode() { · 31 unmodified lines | |||
| 7382 | _offscreenContext->makeCurrent(); | 7436 | _offscreenContext->makeCurrent(); |
| 7383 | getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); | 7437 | getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); |
| 7384 | _displayPlugin = newDisplayPlugin; | 7438 | _displayPlugin = newDisplayPlugin; |
| 7385 | _displayPluginPresentConnection = connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); | 7439 | connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); |
| 7386 | offscreenUi->getDesktop()->setProperty("repositionLocked", wasRepositionLocked); | 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 | _avatarOverrideUrl = url; | 7688 | _avatarOverrideUrl = url; |
| 7635 | _saveAvatarOverrideUrl = save; | 7689 | _saveAvatarOverrideUrl = save; |
| 7636 | } | 7690 | } |
| 7691 | |||
| 7692 | #include "Application.moc" | ||