Browse Source

Platform: resize events in Sdl2App on Emscripten, autodetecting size.

I thought this would "just work", BUT NO. The only way is to poll for
canvas size once a frame, apparently.
pull/272/head
Vladimír Vondruš 8 years ago
parent
commit
934d9e6bf9
  1. 5
      doc/changelog.dox
  2. 85
      src/Magnum/Platform/Sdl2Application.cpp
  3. 38
      src/Magnum/Platform/Sdl2Application.h

5
doc/changelog.dox

@ -88,6 +88,8 @@ See also:
- Initial HiDPI support for Linux and Emscripten in
@ref Platform::Sdl2Application
- Implemented missing resize event support in @ref Platform::Sdl2Application
on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten"
- Implemented @ref Platform::GlfwApplication::MouseMoveEvent::buttons() for
feature parity with @ref Platform::Sdl2Application
- Added @ref Platform::Sdl2Application::GLConfiguration::setColorBufferSize() "GLConfiguration::setColorBufferSize()",
@ -189,6 +191,9 @@ See also:
- @ref Platform::BasicScreen::viewportEvent() "Platform::Screen::viewportEvent()"
is no longer pure virtual to be consistent with all `*Application`
implementations
- @ref Platform::Sdl2Application now defaults to the actual canvas size
on @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten", instead of hardcoded
@cpp {640, 480} @ce
- @ref Platform::Sdl2Application::Configuration::WindowFlags values that make
no sense on Emscripten are not available there anymore

85
src/Magnum/Platform/Sdl2Application.cpp

@ -303,12 +303,12 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, glConfiguration.isSRGBCapable());
#endif
/** @todo Remove when Emscripten has proper SDL2 support */
#ifndef CORRADE_TARGET_EMSCRIPTEN
/* Scale window based on DPI */
_dpiScaling = dpiScaling(configuration);
const Vector2i scaledWindowSize = configuration.size()*_dpiScaling;
/** @todo Remove when Emscripten has proper SDL2 support */
#ifndef CORRADE_TARGET_EMSCRIPTEN
/* Set context version, if user-specified */
if(glConfiguration.version() != GL::Version::None) {
Int major, minor;
@ -446,9 +446,42 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf
SDL_GL_GetDrawableSize(_window, &drawableSize.x(), &drawableSize.y());
glViewport(0, 0, drawableSize.x(), drawableSize.y());
#endif
#else
/* Emscripten-specific initialization */
if(!(_glContext = SDL_SetVideoMode(scaledWindowSize.x(), scaledWindowSize.y(), 24, SDL_OPENGL|SDL_HWSURFACE|SDL_DOUBLEBUF))) {
#else
/* Get CSS canvas size. This is used later to detect canvas resizes and
fire viewport events, because Emscripten doesn't do that. Related info:
https://github.com/kripken/emscripten/issues/1731 */
/** @todo don't hardcode "module" here, make it configurable from outside */
{
Vector2d canvasSize;
emscripten_get_element_css_size("module", &canvasSize.x(), &canvasSize.y());
_lastKnownCanvasSize = Vector2i{canvasSize};
}
/* By default Emscripten creates a 300x150 canvas. That's so freaking
random I'm getting mad. Use the real (CSS pixels) canvas size instead,
if the size is not hardcoded from the configuration. This is then
multiplied by the DPI scaling. */
Vector2i windowSize;
if(!configuration.size().isZero()) {
windowSize = configuration.size();
} else {
windowSize = _lastKnownCanvasSize;
Debug{_verboseLog ? Debug::output() : nullptr} << "Platform::Sdl2Application::tryCreate(): autodetected canvas size" << windowSize;
}
_dpiScaling = dpiScaling(configuration);
const Vector2i scaledWindowSize = windowSize*_dpiScaling;
Uint32 flags = SDL_OPENGL|SDL_HWSURFACE|SDL_DOUBLEBUF;
if(configuration.windowFlags() & Configuration::WindowFlag::Resizable) {
_flags |= Flag::Resizable;
/* Actually not sure if this makes any difference:
https://github.com/kripken/emscripten/issues/1731 */
flags |= SDL_RESIZABLE;
}
if(!(_glContext = SDL_SetVideoMode(scaledWindowSize.x(), scaledWindowSize.y(), 24, flags))) {
Error() << "Platform::Sdl2Application::tryCreate(): cannot create context:" << SDL_GetError();
return false;
}
@ -478,23 +511,23 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf
#endif
Vector2i Sdl2Application::windowSize() const {
#ifndef CORRADE_TARGET_EMSCRIPTEN
Vector2i size;
#ifndef CORRADE_TARGET_EMSCRIPTEN
SDL_GetWindowSize(_window, &size.x(), &size.y());
return size;
#else
return {_glContext->w, _glContext->h};
emscripten_get_canvas_element_size(nullptr, &size.x(), &size.y());
#endif
return size;
}
Vector2i Sdl2Application::framebufferSize() const {
#ifndef CORRADE_TARGET_EMSCRIPTEN
Vector2i size;
#ifndef CORRADE_TARGET_EMSCRIPTEN
SDL_GL_GetDrawableSize(_window, &size.x(), &size.y());
return size;
#else
return {_glContext->w, _glContext->h};
emscripten_get_canvas_element_size(nullptr, &size.x(), &size.y());
#endif
return size;
}
void Sdl2Application::swapBuffers() {
@ -567,16 +600,44 @@ void Sdl2Application::mainLoopIteration() {
const UnsignedInt timeBefore = _minimalLoopPeriod ? SDL_GetTicks() : 0;
#endif
#ifdef CORRADE_TARGET_EMSCRIPTEN
/* The resize event is not fired on window resize, so poll for the canvas
size here. But only if the window was requested to be resizable, to
avoid resizing the canvas when the user doesn't want that. Related
issue: https://github.com/kripken/emscripten/issues/1731 */
if(_flags & Flag::Resizable) {
/** @todo don't hardcode "module" here, make it configurable from outside */
Vector2d canvasSize;
emscripten_get_element_css_size("module", &canvasSize.x(), &canvasSize.y());
const Vector2i canvasSizei{canvasSize};
if(canvasSizei != _lastKnownCanvasSize) {
_lastKnownCanvasSize = canvasSizei;
const Vector2i size = _dpiScaling*canvasSizei;
emscripten_set_canvas_element_size(nullptr, size.x(), size.y());
ViewportEvent e{size, size, _dpiScaling};
viewportEvent(e);
_flags |= Flag::Redraw;
}
}
#endif
SDL_Event event;
while(SDL_PollEvent(&event)) {
switch(event.type) {
case SDL_WINDOWEVENT:
switch(event.window.event) {
case SDL_WINDOWEVENT_RESIZED: {
#ifdef CORRADE_TARGET_EMSCRIPTEN
/* If anybody sees this assert, then emscripten finally
implemented resize events. Praise them for that.
https://github.com/kripken/emscripten/issues/1731 */
CORRADE_ASSERT_UNREACHABLE();
#else
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;
#endif
} break;
case SDL_WINDOWEVENT_EXPOSED:
_flags |= Flag::Redraw;
@ -772,9 +833,7 @@ Sdl2Application::Configuration::Configuration():
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_IOS)
_title("Magnum SDL2 Application"),
#endif
#ifdef CORRADE_TARGET_EMSCRIPTEN
_size{640, 480},
#elif !defined(CORRADE_TARGET_IOS)
#if !defined(CORRADE_TARGET_IOS) && !defined(CORRADE_TARGET_EMSCRIPTEN)
_size{800, 600},
#else
_size{}, /* SDL2 detects someting for us */

38
src/Magnum/Platform/Sdl2Application.h

@ -230,6 +230,10 @@ to simplify porting.
@subsection Platform-Sdl2Application-usage-ios iOS specifics
Leaving a default (zero) window size in @ref Configuration will cause the app
to autodetect it based on the actual device screen size. This also depends on
@ref Platform-Sdl2Application-dpi "DPI awareness", see below for details.
As noted in the @ref platforms-ios-bundle "iOS platform guide", a lot of
options needs to be set via a `*.plist` file. Some options can be configured
from runtime when creating the SDL2 application window, see documentation of
@ -239,6 +243,17 @@ a particular value for details:
- @ref Configuration::WindowFlag::Resizable makes the application respond to
device orientation changes
@subsection Platform-Sdl2Application-usage-emscripten Emscripten specifics
Leaving a default (zero) window size in @ref Configuration will cause the app
to use a window size that corresponds to *CSS pixel size* of the
@cb{.html} <canvas> @ce element. The size is then multiplied by DPI scaling
value, see @ref Platform-Sdl2Application-dpi "DPI awareness" below for details.
If you enable @ref Configuration::WindowFlag::Resizable, the canvas will be
resized when size of the canvas changes and you get @ref viewportEvent(). If
the flag is not enabled, no canvas resizing is performed.
@section Platform-Sdl2Application-dpi DPI awareness
On displays that match the platform default DPI (96 or 72),
@ -880,7 +895,8 @@ class Sdl2Application {
Exit = 1 << 3
#endif
#ifdef CORRADE_TARGET_EMSCRIPTEN
TextInputActive = 1 << 4
TextInputActive = 1 << 4,
Resizable = 1 << 5
#endif
};
@ -897,6 +913,8 @@ class Sdl2Application {
#ifndef CORRADE_TARGET_EMSCRIPTEN
SDL_Window* _window;
UnsignedInt _minimalLoopPeriod;
#else
Vector2i _lastKnownCanvasSize;
#endif
#ifdef MAGNUM_TARGET_GL
@ -1159,8 +1177,12 @@ class Sdl2Application::Configuration {
enum class WindowFlag: Uint32 {
/**
* Resizable window. On iOS this allows the application to respond
* to display orientation changes. Implement @ref viewportEvent()
* to react to the resizing events.
* to display orientation changes, on
* @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten" this causes the
* framebuffer to be resized when the @cb{.html} <canvas> @ce size
* changes.
*
* Implement @ref viewportEvent() to react to the resizing events.
*/
Resizable = SDL_WINDOW_RESIZABLE,
@ -1365,11 +1387,11 @@ class Sdl2Application::Configuration {
* @param dpiScalingPolicy Policy based on which DPI scaling will be set
* @return Reference to self (for method chaining)
*
* Default is @cpp {800, 600} @ce and @cpp {640, 480} @ce on
* Emscripten with @p dpiScalingPolicy set to
* @ref DpiScalingPolicy::Default. On iOS it defaults to a size that
* matches display resolution. See @ref Platform-Sdl2Application-dpi
* for more information.
* Default is @cpp {800, 600} @ce on desktop platforms. On
* @ref CORRADE_TARGET_EMSCRIPTEN "Emscripten" and iOS the default is a
* zero vector, meaning a value that matches the display or canvas size
* is autodetected. See @ref Platform-Sdl2Application-dpi for more
* information.
* @see @ref setSize(const Vector2i&, const Vector2&)
*/
Configuration& setSize(const Vector2i& size, DpiScalingPolicy dpiScalingPolicy = DpiScalingPolicy::Default) {

Loading…
Cancel
Save