From ed0a719da21e6150f25f36265fdc60bae4d1c84b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sun, 19 Aug 2018 18:57:32 +0200 Subject: [PATCH] Platform: pass a class to viewportEvent(). With HiDPI support it's no longer just about window size changing -- if the framebuffer size is different than window size, on resize both are changed to new (different) values. Other than that, for example, when moving a window from one display to another with a different DPI, all three of window size, framebuffer size and DPI scaling can change as well. This should be all reflected in the event. This change is done in all Application classes, but the full implementation is only in the SDL2 implementation at the moment, as the others don't have full HiDPI support implemented yet. The old viewportEvent(const Vector2i&) is deprecated and for backwards compatibility called with either framebufferSize() or windowSize() (depending on level of HiDPI support) from the new event. Overriding the old one will still work as expected (in case you build with MAGNUM_BUILD_DEPRECATED enabled and use the `override` keyword -- which you should); overriding the new one will cause the compat implementation to not be called anymore. In order to make it possible to preserve backwards compatibility, the viewportEvent() is no longer pure virtual in Screen. That's also consistent with all Application implementations. --- doc/changelog.dox | 10 +++ doc/snippets/MagnumGL-framebuffer.cpp | 4 +- doc/snippets/MagnumPlatform-portability.cpp | 2 +- doc/snippets/MagnumPlatform.cpp | 6 +- src/Magnum/Platform/AbstractXApplication.cpp | 16 +++- src/Magnum/Platform/AbstractXApplication.h | 41 ++++++++++- src/Magnum/Platform/AndroidApplication.cpp | 13 ++++ src/Magnum/Platform/AndroidApplication.h | 32 +++++++- src/Magnum/Platform/GlfwApplication.cpp | 16 +++- src/Magnum/Platform/GlfwApplication.h | 56 +++++++++++++- src/Magnum/Platform/GlutApplication.cpp | 18 +++++ src/Magnum/Platform/GlutApplication.h | 52 +++++++++++-- src/Magnum/Platform/Screen.h | 17 ++++- src/Magnum/Platform/ScreenedApplication.h | 5 +- src/Magnum/Platform/ScreenedApplication.hpp | 22 +++++- src/Magnum/Platform/Sdl2Application.cpp | 25 ++++--- src/Magnum/Platform/Sdl2Application.h | 77 ++++++++++++++++++-- 17 files changed, 370 insertions(+), 42 deletions(-) diff --git a/doc/changelog.dox b/doc/changelog.dox index 0618753af..564698968 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -173,6 +173,9 @@ See also: @subsubsection changelog-latest-changes-platform Platform libraries +- @ref Platform::Sdl2Application::viewportEvent() "Platform::*Application::viewportEvent()" + now gets all information needed for DPI-aware rendering instead of just + a framebuffer size --- now also window size and the DPI scaling value - @ref Platform::GlfwApplication now behaves the same as @ref Platform::Sdl2Application when creating an OpenGL context: first it attempts to create a forward-compatible core OpenGL 3.2+ context and if @@ -183,6 +186,9 @@ See also: pointer - @ref Platform::GlfwApplication now loads modifiers for mouse move and mouse scroll events lazily, only when needed +- @ref Platform::BasicScreen::viewportEvent() "Platform::Screen::viewportEvent()" + is no longer pure virtual to be consistent with all `*Application` + implementations @subsubsection changelog-latest-changes-shaders Shaders library @@ -271,6 +277,10 @@ See also: scheduled for removal in a future release. Please consider switching to @ref Platform::Sdl2Application or @ref Platform::GlfwApplication as soon as possible. +- `Platform::*Application::viewportEvent(const Vector2i&)` is deprecated + because it doesn't provide all information needed for DPI-aware rendering. + Override the @ref Platform::Sdl2Application::viewportEvent(ViewportEvent&) "viewportEvent(ViewportEvent&)" + function instead. - `Math::Geometry`, `Math::Geometry::Distance` and `Math::Geometry::Intersection` namespaces are deprecated for being too deeply nested, use @ref Math::Distance and @ref Math::Intersection instead diff --git a/doc/snippets/MagnumGL-framebuffer.cpp b/doc/snippets/MagnumGL-framebuffer.cpp index 53bf8ec90..7f1267284 100644 --- a/doc/snippets/MagnumGL-framebuffer.cpp +++ b/doc/snippets/MagnumGL-framebuffer.cpp @@ -31,8 +31,8 @@ using namespace Magnum; struct A: Platform::Sdl2Application { /* [DefaultFramebuffer-usage-viewport] */ -void viewportEvent(const Vector2i& size) override { - GL::defaultFramebuffer.setViewport({{}, size}); +void viewportEvent(ViewportEvent& event) override { + GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()}); // ... } diff --git a/doc/snippets/MagnumPlatform-portability.cpp b/doc/snippets/MagnumPlatform-portability.cpp index 971d50bfb..108e3d76c 100644 --- a/doc/snippets/MagnumPlatform-portability.cpp +++ b/doc/snippets/MagnumPlatform-portability.cpp @@ -38,7 +38,7 @@ class MyApplication: public Platform::Application { MyApplication(const Arguments& arguments); protected: - void viewportEvent(const Vector2i& size) override; + void viewportEvent(ViewportEvent& size) override; void drawEvent() override; void keyPressEvent(KeyEvent& event) override; }; diff --git a/doc/snippets/MagnumPlatform.cpp b/doc/snippets/MagnumPlatform.cpp index 5a6cdf618..c3f7ce440 100644 --- a/doc/snippets/MagnumPlatform.cpp +++ b/doc/snippets/MagnumPlatform.cpp @@ -65,13 +65,13 @@ class MyApplication: public Platform::Application { // ... private: - void viewportEvent(const Vector2i& size) override; + void viewportEvent(ViewportEvent& event) override; }; // ... -void MyApplication::viewportEvent(const Vector2i& size) { - GL::defaultFramebuffer.setViewport({{}, size}); +void MyApplication::viewportEvent(ViewportEvent& event) { + GL::defaultFramebuffer.setViewport({{}, event.framebufferSize()}); } /* [size] */ diff --git a/src/Magnum/Platform/AbstractXApplication.cpp b/src/Magnum/Platform/AbstractXApplication.cpp index 3b458d5e8..1ab74b5b8 100644 --- a/src/Magnum/Platform/AbstractXApplication.cpp +++ b/src/Magnum/Platform/AbstractXApplication.cpp @@ -156,7 +156,8 @@ int AbstractXApplication::exec() { Vector2i size(event.xconfigure.width, event.xconfigure.height); if(size != _windowSize) { _windowSize = size; - viewportEvent(size); + ViewportEvent e{size}; + viewportEvent(e); _flags |= Flag::Redraw; } } break; @@ -190,7 +191,20 @@ int AbstractXApplication::exec() { return 0; } +void AbstractXApplication::viewportEvent(ViewportEvent& event) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH + viewportEvent(event.framebufferSize()); + CORRADE_IGNORE_DEPRECATED_POP + #else + static_cast(event); + #endif +} + +#ifdef MAGNUM_BUILD_DEPRECATED void AbstractXApplication::viewportEvent(const Vector2i&) {} +#endif + void AbstractXApplication::keyPressEvent(KeyEvent&) {} void AbstractXApplication::keyReleaseEvent(KeyEvent&) {} void AbstractXApplication::mousePressEvent(MouseEvent&) {} diff --git a/src/Magnum/Platform/AbstractXApplication.h b/src/Magnum/Platform/AbstractXApplication.h index 284ef6d5f..755cf7dbd 100644 --- a/src/Magnum/Platform/AbstractXApplication.h +++ b/src/Magnum/Platform/AbstractXApplication.h @@ -73,6 +73,7 @@ class AbstractXApplication { class Configuration; class GLConfiguration; + class ViewportEvent; class InputEvent; class KeyEvent; class MouseEvent; @@ -211,8 +212,13 @@ class AbstractXApplication { #else private: #endif - /** @copydoc Sdl2Application::viewportEvent() */ - virtual void viewportEvent(const Vector2i& size); + /** @copydoc GlfwApplication::viewportEvent(ViewportEvent&) */ + virtual void viewportEvent(ViewportEvent& event); + + #ifdef MAGNUM_BUILD_DEPRECATED + /** @copydoc GlfwApplication::viewportEvent(const Vector2i&) */ + virtual CORRADE_DEPRECATED("use viewportEvent(ViewportEvent&) instead") void viewportEvent(const Vector2i& size); + #endif /** @copydoc Sdl2Application::drawEvent() */ virtual void drawEvent() = 0; @@ -363,6 +369,37 @@ class AbstractXApplication::Configuration { #endif }; +/** +@brief Viewport event + +@see @ref viewportEvent() +*/ +class AbstractXApplication::ViewportEvent { + public: + /** + * @brief Window size + * + * Same as @ref framebufferSize(). + * @see @ref AbstractXApplication::windowSize() + */ + Vector2i windowSize() const { return _size; } + + /** + * @brief Framebuffer size + * + * Same as @ref windowSize(). + * @see @ref AbstractXApplication::framebufferSize() + */ + Vector2i framebufferSize() const { return _size; } + + private: + friend AbstractXApplication; + + explicit ViewportEvent(const Vector2i& size): _size{size} {} + + Vector2i _size; +}; + /** @brief Base for input events diff --git a/src/Magnum/Platform/AndroidApplication.cpp b/src/Magnum/Platform/AndroidApplication.cpp index 48df834a7..448859708 100644 --- a/src/Magnum/Platform/AndroidApplication.cpp +++ b/src/Magnum/Platform/AndroidApplication.cpp @@ -174,7 +174,20 @@ void AndroidApplication::swapBuffers() { eglSwapBuffers(_display, _surface); } +void AndroidApplication::viewportEvent(ViewportEvent& event) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH + viewportEvent(event.windowSize()); + CORRADE_IGNORE_DEPRECATED_POP + #else + static_cast(event); + #endif +} + +#ifdef MAGNUM_BUILD_DEPRECATED void AndroidApplication::viewportEvent(const Vector2i&) {} +#endif + void AndroidApplication::mousePressEvent(MouseEvent&) {} void AndroidApplication::mouseReleaseEvent(MouseEvent&) {} void AndroidApplication::mouseMoveEvent(MouseMoveEvent&) {} diff --git a/src/Magnum/Platform/AndroidApplication.h b/src/Magnum/Platform/AndroidApplication.h index ceea514e1..e99e09fa2 100644 --- a/src/Magnum/Platform/AndroidApplication.h +++ b/src/Magnum/Platform/AndroidApplication.h @@ -143,6 +143,7 @@ class AndroidApplication { class Configuration; class GLConfiguration; + class ViewportEvent; class InputEvent; class MouseEvent; class MouseMoveEvent; @@ -324,8 +325,13 @@ class AndroidApplication { #else private: #endif - /** @copydoc Sdl2Application::viewportEvent() */ - virtual void viewportEvent(const Vector2i& size); + /** @copydoc GlfwApplication::viewportEvent(ViewportEvent&) */ + virtual void viewportEvent(ViewportEvent& event); + + #ifdef MAGNUM_BUILD_DEPRECATED + /** @copydoc GlfwApplication::viewportEvent(const Vector2i&) */ + virtual CORRADE_DEPRECATED("use viewportEvent(ViewportEvent&) instead") void viewportEvent(const Vector2i& size); + #endif /** @copydoc Sdl2Application::drawEvent() */ virtual void drawEvent() = 0; @@ -506,6 +512,28 @@ class AndroidApplication::Configuration { Vector2i _size; }; +/** +@brief Viewport event + +@see @ref viewportEvent() +*/ +class AndroidApplication::ViewportEvent { + public: + /** + * @brief Window size + * + * @see @ref AndroidApplication::windowSize() + */ + Vector2i windowSize() const { return _windowSize; } + + private: + friend AndroidApplication; + + explicit ViewportEvent(const Vector2i& windowSize): _windowSize{windowSize} {} + + Vector2i _windowSize; +}; + /** @brief Base for input events diff --git a/src/Magnum/Platform/GlfwApplication.cpp b/src/Magnum/Platform/GlfwApplication.cpp index 0fa165605..f3b33d5a6 100644 --- a/src/Magnum/Platform/GlfwApplication.cpp +++ b/src/Magnum/Platform/GlfwApplication.cpp @@ -355,7 +355,8 @@ void GlfwApplication::setupCallbacks() { static_cast(glfwGetWindowUserPointer(window))->drawEvent(); }); glfwSetFramebufferSizeCallback(_window, [](GLFWwindow* const window, const int w, const int h) { - static_cast(glfwGetWindowUserPointer(window))->viewportEvent({w, h}); + ViewportEvent e{{w, h}}; + static_cast(glfwGetWindowUserPointer(window))->viewportEvent(e); }); glfwSetKeyCallback(_window, [](GLFWwindow* const window, const int key, int, const int action, const int mods) { const auto instance = static_cast(glfwGetWindowUserPointer(window)); @@ -469,7 +470,20 @@ auto GlfwApplication::MouseScrollEvent::modifiers() -> Modifiers { return *_modifiers; } +void GlfwApplication::viewportEvent(ViewportEvent& event) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH + viewportEvent(event.windowSize()); + CORRADE_IGNORE_DEPRECATED_POP + #else + static_cast(event); + #endif +} + +#ifdef MAGNUM_BUILD_DEPRECATED void GlfwApplication::viewportEvent(const Vector2i&) {} +#endif + void GlfwApplication::keyPressEvent(KeyEvent&) {} void GlfwApplication::keyReleaseEvent(KeyEvent&) {} void GlfwApplication::mousePressEvent(MouseEvent&) {} diff --git a/src/Magnum/Platform/GlfwApplication.h b/src/Magnum/Platform/GlfwApplication.h index 7e89a871a..10231969e 100644 --- a/src/Magnum/Platform/GlfwApplication.h +++ b/src/Magnum/Platform/GlfwApplication.h @@ -130,6 +130,7 @@ class GlfwApplication { #ifdef MAGNUM_TARGET_GL class GLConfiguration; #endif + class ViewportEvent; class InputEvent; class KeyEvent; class MouseEvent; @@ -365,8 +366,37 @@ class GlfwApplication { #else private: #endif - /** @copydoc Sdl2Application::viewportEvent() */ - virtual void viewportEvent(const Vector2i& size); + /** + * @brief Viewport event + * + * Called when window size changes. The default implementation does + * nothing. If you want to respond to size changes, you should pass the + * new size to @ref GL::DefaultFramebuffer::setViewport() (if using + * OpenGL) and possibly elsewhere (to + * @ref SceneGraph::Camera::setViewport(), other framebuffers...). + * + * Note that this function might not get called at all if the window + * size doesn't change. You should configure the initial state of your + * cameras, framebuffers etc. in application constructor rather than + * relying on this function to be called. Size of the window can be + * retrieved also using @ref windowSize(). + * + * @todoc make this a copydoc of Sdl2Application once both have + * framebufferSize() and dpiScaling() + */ + virtual void viewportEvent(ViewportEvent& event); + + #ifdef MAGNUM_BUILD_DEPRECATED + /** @brief @copybrief viewportEvent(ViewportEvent&) + * @deprecated Use @ref viewportEvent(ViewportEvent&) instead. + * To preserve backwards compatibility, this function is called + * from @ref viewportEvent(ViewportEvent&) with + * @ref ViewportEvent::windowSize() passed to @p size. Overriding + * the new function will cause this function to not be called + * anymore. + */ + virtual CORRADE_DEPRECATED("use viewportEvent(ViewportEvent&) instead") void viewportEvent(const Vector2i& size); + #endif /** @copydoc Sdl2Application::drawEvent() */ virtual void drawEvent() = 0; @@ -862,6 +892,28 @@ class GlfwApplication::Configuration { CORRADE_ENUMSET_OPERATORS(GlfwApplication::Configuration::WindowFlags) +/** +@brief Viewport event + +@see @ref viewportEvent() +*/ +class GlfwApplication::ViewportEvent { + public: + /** + * @brief Window size + * + * @see @ref GlfwApplication::windowSize() + */ + Vector2i windowSize() const { return _windowSize; } + + private: + friend GlfwApplication; + + explicit ViewportEvent(const Vector2i& windowSize): _windowSize{windowSize} {} + + Vector2i _windowSize; +}; + /** @brief Base for input events diff --git a/src/Magnum/Platform/GlutApplication.cpp b/src/Magnum/Platform/GlutApplication.cpp index abc3304ba..cb11c27d9 100644 --- a/src/Magnum/Platform/GlutApplication.cpp +++ b/src/Magnum/Platform/GlutApplication.cpp @@ -134,6 +134,11 @@ bool GlutApplication::tryCreate(const Configuration& configuration, const GLConf GlutApplication::~GlutApplication() = default; +void GlutApplication::staticViewportEvent(int x, int y) { + ViewportEvent e{{x, y}}; + _instance->viewportEvent(e); +} + void GlutApplication::staticKeyPressEvent(unsigned char key, int x, int y) { KeyEvent e(static_cast(key), {x, y}); _instance->keyPressEvent(e); @@ -167,7 +172,20 @@ void GlutApplication::staticMouseMoveEvent(int x, int y) { _instance->mouseMoveEvent(e); } +void GlutApplication::viewportEvent(ViewportEvent& event) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH + viewportEvent(event.windowSize()); + CORRADE_IGNORE_DEPRECATED_POP + #else + static_cast(event); + #endif +} + +#ifdef MAGNUM_BUILD_DEPRECATED void GlutApplication::viewportEvent(const Vector2i&) {} +#endif + void GlutApplication::keyPressEvent(KeyEvent&) {} void GlutApplication::keyReleaseEvent(KeyEvent&) {} void GlutApplication::mousePressEvent(MouseEvent&) {} diff --git a/src/Magnum/Platform/GlutApplication.h b/src/Magnum/Platform/GlutApplication.h index 6441a6c10..ff65dcced 100644 --- a/src/Magnum/Platform/GlutApplication.h +++ b/src/Magnum/Platform/GlutApplication.h @@ -134,6 +134,7 @@ class CORRADE_DEPRECATED("Scheduled for removal. Consider switching to Sdl2Appli class Configuration; class GLConfiguration; + class ViewportEvent; class InputEvent; class KeyEvent; class MouseEvent; @@ -300,8 +301,33 @@ class CORRADE_DEPRECATED("Scheduled for removal. Consider switching to Sdl2Appli #else private: #endif - /** @copydoc Sdl2Application::viewportEvent() */ - virtual void viewportEvent(const Vector2i& size); + /** + * @brief Viewport event + * + * Called when window size changes. The default implementation does + * nothing. If you want to respond to size changes, you should pass the + * new size to @ref GL::DefaultFramebuffer::setViewport() (if using + * OpenGL) and possibly elsewhere (to + * @ref SceneGraph::Camera::setViewport(), other framebuffers...). + * + * Note that this function might not get called at all if the window + * size doesn't change. You should configure the initial state of your + * cameras, framebuffers etc. in application constructor rather than + * relying on this function to be called. + */ + virtual void viewportEvent(ViewportEvent& event); + + #ifdef MAGNUM_BUILD_DEPRECATED + /** @brief @copybrief viewportEvent(ViewportEvent&) + * @deprecated Use @ref viewportEvent(ViewportEvent&) instead. + * To preserve backwards compatibility, this function is called + * from @ref viewportEvent(ViewportEvent&) with + * @ref ViewportEvent::windowSize() passed to @p size. Overriding + * the new function will cause this function to not be called + * anymore. + */ + virtual CORRADE_DEPRECATED("use viewportEvent(ViewportEvent&) instead") void viewportEvent(const Vector2i& size); + #endif /** @copydoc Sdl2Application::drawEvent() */ virtual void drawEvent() = 0; @@ -374,9 +400,7 @@ class CORRADE_DEPRECATED("Scheduled for removal. Consider switching to Sdl2Appli /*@}*/ private: - static void staticViewportEvent(int x, int y) { - _instance->viewportEvent({x, y}); - } + static void staticViewportEvent(int x, int y); static void staticKeyPressEvent(unsigned char key, int x, int y); static void staticKeyReleaseEvent(unsigned char key, int x, int y); @@ -587,6 +611,24 @@ class GlutApplication::Configuration { #endif }; +/** +@brief Viewport event + +@see @ref viewportEvent() +*/ +class GlutApplication::ViewportEvent { + public: + /** @brief Window size */ + Vector2i windowSize() const { return _windowSize; } + + private: + friend GlutApplication; + + explicit ViewportEvent(const Vector2i& windowSize): _windowSize{windowSize} {} + + Vector2i _windowSize; +}; + /** @brief Base for input events diff --git a/src/Magnum/Platform/Screen.h b/src/Magnum/Platform/Screen.h index f1615ffa6..a879acd9d 100644 --- a/src/Magnum/Platform/Screen.h +++ b/src/Magnum/Platform/Screen.h @@ -102,6 +102,9 @@ template class BasicScreen: private Containers::LinkedListIte typedef Implementation::PropagatedScreenEvents PropagatedEvents; #endif + /** @brief Viewport event */ + typedef typename BasicScreenedApplication::ViewportEvent ViewportEvent; + /** @brief Input event */ typedef typename BasicScreenedApplication::InputEvent InputEvent; @@ -197,7 +200,19 @@ template class BasicScreen: private Containers::LinkedListIte * for more information. Setting viewport on default framebuffer should * be done by the holder application. */ - virtual void viewportEvent(const Vector2i& size) = 0; + virtual void viewportEvent(ViewportEvent& event); + + #ifdef MAGNUM_BUILD_DEPRECATED + /** @brief @copybrief viewportEvent(ViewportEvent&) + * @deprecated Use @ref viewportEvent(ViewportEvent&) instead. + * To preserve backwards compatibility, this function is called + * from @ref viewportEvent(ViewportEvent&) with + * @ref Sdl2Application::ViewportEvent::windowSize() "*Application::ViewportEvent::windowSize()" + * passed to @p size. Overriding the new function will cause this + * function to not be called anymore. + */ + virtual CORRADE_DEPRECATED("use viewportEvent(ViewportEvent&) instead") void viewportEvent(const Vector2i& size); + #endif /** * @brief Draw event diff --git a/src/Magnum/Platform/ScreenedApplication.h b/src/Magnum/Platform/ScreenedApplication.h index 551001bec..c9174bcf4 100644 --- a/src/Magnum/Platform/ScreenedApplication.h +++ b/src/Magnum/Platform/ScreenedApplication.h @@ -204,7 +204,7 @@ template class BasicScreenedApplication: public Application, * implementation does nothing. See @ref Sdl2Application::viewportEvent() "*Application::viewportEvent()" * for more information. */ - virtual void globalViewportEvent(const Vector2i& size); + virtual void globalViewportEvent(typename Application::ViewportEvent& size); /** * @brief Draw event @@ -222,11 +222,10 @@ template class BasicScreenedApplication: public Application, friend Containers::LinkedListItem, BasicScreenedApplication>; friend BasicScreen; #endif - /* The user is supposed to override only globalViewportEvent() and globalDrawEvent(), these implementations are dispatching the events to attached screens. */ - void viewportEvent(const Vector2i& size) override final; + void viewportEvent(typename Application::ViewportEvent& event) override final; void drawEvent() override final; void keyPressEvent(typename Application::KeyEvent& event) override final; void keyReleaseEvent(typename Application::KeyEvent& event) override final; diff --git a/src/Magnum/Platform/ScreenedApplication.hpp b/src/Magnum/Platform/ScreenedApplication.hpp index e1fb5c1b2..98d6b1435 100644 --- a/src/Magnum/Platform/ScreenedApplication.hpp +++ b/src/Magnum/Platform/ScreenedApplication.hpp @@ -37,6 +37,20 @@ namespace Magnum { namespace Platform { template BasicScreen::BasicScreen() = default; template BasicScreen::~BasicScreen() = default; +template void BasicScreen::viewportEvent(ViewportEvent& event) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH + viewportEvent(event.windowSize()); + CORRADE_IGNORE_DEPRECATED_POP + #else + static_cast(event); + #endif +} + +#ifdef MAGNUM_BUILD_DEPRECATED +template void BasicScreen::viewportEvent(const Vector2i&) {} +#endif + template void BasicScreen::keyPressEvent(KeyEvent&) {} template void BasicScreen::keyReleaseEvent(KeyEvent&) {} template void BasicScreen::mousePressEvent(MouseEvent&) {} @@ -78,13 +92,13 @@ template BasicScreenedApplication& BasicScreened return *this; } -template void BasicScreenedApplication::globalViewportEvent(const Vector2i&) {} +template void BasicScreenedApplication::globalViewportEvent(typename Application::ViewportEvent&) {} -template void BasicScreenedApplication::viewportEvent(const Vector2i& size) { +template void BasicScreenedApplication::viewportEvent(typename Application::ViewportEvent& event) { /* Call global event before all other (to resize framebuffer first) */ - globalViewportEvent(size); + globalViewportEvent(event); - for(BasicScreen& s: *this) s.viewportEvent(size); + for(BasicScreen& s: *this) s.viewportEvent(event); } template void BasicScreenedApplication::drawEvent() { diff --git a/src/Magnum/Platform/Sdl2Application.cpp b/src/Magnum/Platform/Sdl2Application.cpp index af7b37d22..52e6de855 100644 --- a/src/Magnum/Platform/Sdl2Application.cpp +++ b/src/Magnum/Platform/Sdl2Application.cpp @@ -573,15 +573,9 @@ void Sdl2Application::mainLoopIteration() { case SDL_WINDOWEVENT: switch(event.window.event) { case SDL_WINDOWEVENT_RESIZED: { - #ifndef CORRADE_TARGET_IOS - viewportEvent({event.window.data1, event.window.data2}); - #else - /* On iOS the window event is in points and not pixels, - but we need pixels to call glViewport() properly */ - Vector2i drawableSize; - SDL_GL_GetDrawableSize(_window, &drawableSize.x(), &drawableSize.y()); - viewportEvent(drawableSize); - #endif + ViewportEvent e{{event.window.data1, event.window.data2}, framebufferSize(), _dpiScaling}; + /** @todo handle also WM_DPICHANGED events when a window is moved between displays with different DPI */ + viewportEvent(e); _flags |= Flag::Redraw; } break; case SDL_WINDOWEVENT_EXPOSED: @@ -738,7 +732,20 @@ void Sdl2Application::tickEvent() { _flags |= Flag::NoTickEvent; } +void Sdl2Application::viewportEvent(ViewportEvent& event) { + #ifdef MAGNUM_BUILD_DEPRECATED + CORRADE_IGNORE_DEPRECATED_PUSH + viewportEvent(event.framebufferSize()); + CORRADE_IGNORE_DEPRECATED_POP + #else + static_cast(event); + #endif +} + +#ifdef MAGNUM_BUILD_DEPRECATED void Sdl2Application::viewportEvent(const Vector2i&) {} +#endif + void Sdl2Application::keyPressEvent(KeyEvent&) {} void Sdl2Application::keyReleaseEvent(KeyEvent&) {} void Sdl2Application::mousePressEvent(MouseEvent&) {} diff --git a/src/Magnum/Platform/Sdl2Application.h b/src/Magnum/Platform/Sdl2Application.h index e9de03375..db1c55033 100644 --- a/src/Magnum/Platform/Sdl2Application.h +++ b/src/Magnum/Platform/Sdl2Application.h @@ -339,6 +339,7 @@ class Sdl2Application { #ifdef MAGNUM_TARGET_GL class GLConfiguration; #endif + class ViewportEvent; class InputEvent; class KeyEvent; class MouseEvent; @@ -682,17 +683,34 @@ class Sdl2Application { * * Called when window size changes. The default implementation does * nothing. If you want to respond to size changes, you should pass the - * new size to @ref GL::DefaultFramebuffer::setViewport() (if using - * OpenGL) and possibly elsewhere (to - * @ref SceneGraph::Camera::setViewport(), other framebuffers...). + * new *framebuffer* size to @ref GL::DefaultFramebuffer::setViewport() + * (if using OpenGL) and possibly elsewhere (to + * @ref SceneGraph::Camera::setViewport(), other framebuffers...) and + * the new *window* size and DPI scaling to APIs that respond to user + * events or scale UI elements. * * Note that this function might not get called at all if the window * size doesn't change. You should configure the initial state of your * cameras, framebuffers etc. in application constructor rather than - * relying on this function to be called. Viewport of default - * framebuffer can be retrieved via @ref GL::DefaultFramebuffer::viewport(). + * relying on this function to be called. Size of the window can be + * retrieved using @ref windowSize(), size of the backing framebuffer + * via @ref framebufferSize() and DPI scaling using @ref dpiScaling(). + * See @ref Platform-Sdl2Application-dpi for detailed info about these + * values. */ - virtual void viewportEvent(const Vector2i& size); + virtual void viewportEvent(ViewportEvent& event); + + #ifdef MAGNUM_BUILD_DEPRECATED + /** @brief @copybrief viewportEvent(ViewportEvent&) + * @deprecated Use @ref viewportEvent(ViewportEvent&) instead. + * To preserve backwards compatibility, this function is called + * from @ref viewportEvent(ViewportEvent&) with + * @ref ViewportEvent::framebufferSize() passed to @p size. + * Overriding the new function will cause this function to not be + * called anymore. + */ + virtual CORRADE_DEPRECATED("use viewportEvent(ViewportEvent&) instead") void viewportEvent(const Vector2i& size); + #endif /** * @brief Draw event @@ -1432,6 +1450,53 @@ class Sdl2Application::Configuration { #endif }; +/** +@brief Viewport event + +@see @ref viewportEvent() +*/ +class Sdl2Application::ViewportEvent { + public: + /** + * @brief Window size + * + * On some platforms with HiDPI displays, window size can be different + * from @ref framebufferSize(). See @ref Platform-Sdl2Application-dpi + * for more information. + * @see @ref Sdl2Application::windowSize() + */ + Vector2i windowSize() const { return _windowSize; } + + /** + * @brief Framebuffer size + * + * On some platforms with HiDPI displays, framebuffer size can be + * different from @ref windowSize(). See + * @ref Platform-Sdl2Application-dpi for more information. + * @see @ref Sdl2Application::framebufferSize() + */ + Vector2i framebufferSize() const { return _framebufferSize; } + + /** + * @brief DPI scaling + * + * On some platforms moving an app between displays can result in DPI + * scaling value being changed in tandem with a window/framebuffer + * size. Simply resizing a window doesn't change the DPI scaling value. + * See @ref Platform-Sdl2Application-dpi for more information. + * @see @ref Sdl2Application::dpiScaling() + */ + Vector2 dpiScaling() const { return _dpiScaling; } + + private: + friend Sdl2Application; + + explicit ViewportEvent(const Vector2i& windowSize, const Vector2i& framebufferSize, const Vector2& dpiScaling): _windowSize{windowSize}, _framebufferSize{framebufferSize}, _dpiScaling{dpiScaling} {} + + Vector2i _windowSize, _framebufferSize; + Vector2 _dpiScaling; +}; + /** @brief Base for input events