Browse Source

[wip] Platform: create a Sdl2ApplicationWindow base class.

Mostly just code motion and related documentation updates because
Doxygen is such a crap that it can link to functions defined in a base
class but not types! FFS.

No actual multi-window support yet, that'll be in the next commits to
avoid this noise obscuring them.

TODO: Sdl2Window instead?
TODO: unsure about certain APIs, whether they should be per-window or
not
 - contextless / gl / vulkan?
 - mouse warp?
 - ...?
pull/168/head
Vladimír Vondruš 3 years ago
parent
commit
a902b8475d
  1. 31
      doc/changelog-old.dox
  2. 53
      doc/changelog.dox
  3. 6
      doc/platform.dox
  4. 4
      src/Magnum/Platform/AndroidApplication.h
  5. 18
      src/Magnum/Platform/Screen.h
  6. 779
      src/Magnum/Platform/Sdl2Application.cpp
  7. 973
      src/Magnum/Platform/Sdl2Application.h
  8. 2
      src/Magnum/SceneGraph/Camera.h

31
doc/changelog-old.dox

@ -108,7 +108,7 @@ Released 2018-05-01, tagged as
- Ability to create @ref Platform::Sdl2Application and
@ref Platform::GlfwApplication classes without implicitly created OpenGL
context by passing @ref Platform::Sdl2Application::Configuration::WindowFlag::Contextless "Configuration::WindowFlag::Contextless"
context by passing @cpp Configuration::WindowFlag::Contextless @ce
to them. These two can be now also built completely without the GL library.
- Added @ref Platform::AndroidApplication::windowSize()
- Added @ref Platform::AndroidApplication::nativeActivity() to access
@ -157,10 +157,9 @@ Released 2018-05-01, tagged as
@subsubsection changelog-2018-04-changes-platform Platform libraries
- Separated @ref Platform::Sdl2Application::Configuration "Platform::*Application::Configuration"
into @ref Platform::Sdl2Application::Configuration "Configuration" and
@ref Platform::Sdl2Application::GLConfiguration "GLConfiguration" to allow
creation of non-GL application instances in the future
- Separated @cpp Platform::*Application::Configuration @ce
into @cpp Configuration @ce and @cpp GLConfiguration @ce to allow creation
of non-GL application instances in the future
@subsubsection changelog-2018-04-changes-plugins Plugins
@ -753,10 +752,10 @@ a high-level overview.
possible
- Ported @ref magnum-gl-info "magnum-info" to Emscripten
- First-class support for scroll events in
@ref Platform::Sdl2Application::MouseScrollEvent (see
[mosra/magnum#157](https://github.com/mosra/magnum/pull/157))
- Added @ref Platform::Sdl2Application::MouseEvent::clickCount()
- Added @ref Platform::Sdl2Application::multiGestureEvent()
@cpp Platform::Sdl2Application::MouseScrollEvent @ce
(see [mosra/magnum#157](https://github.com/mosra/magnum/pull/157))
- Added @cpp Platform::Sdl2Application::MouseEvent::clickCount() @ce
- Added @cpp Platform::Sdl2Application::multiGestureEvent() @ce
- Exposing key repeat in
@ref Platform::Sdl2Application::KeyEvent::isRepeated() "Platform::*Application::KeyEvent::isRepeated()"
(see [mosra/magnum#161](https://github.com/mosra/magnum/issues/161),
@ -773,8 +772,8 @@ a high-level overview.
version is not what the application wants (as opposed to just aborting the
application) (see [mosra/magnum#105](https://github.com/mosra/magnum/issues/105))
- Added @cpp Platform::Sdl2Application::Configuration::setSRGBCapable() @ce
- Added @ref Platform::Sdl2Application::Configuration::WindowFlag::Borderless
and `Platform::Sdl2Application::Configuration::WindowFlag::AllowHighDpi`
- Added @cpp Platform::Sdl2Application::Configuration::WindowFlag::Borderless @ce
and @cpp Platform::Sdl2Application::Configuration::WindowFlag::AllowHighDpi @ce
for iOS and macOS
- Added @ref Platform::WindowlessGlxApplication::Configuration::setFlags() "Platform::Windowless*Application::Configuration::setFlags()" with
@ref Platform::WindowlessGlxApplication::Configuration::Flag::Debug "Flag::Debug"
@ -786,7 +785,7 @@ a high-level overview.
with @ref Platform::GlfwApplication
- Added modifier keys to
@ref Platform::Sdl2Application::KeyEvent::Key "Platform::*Application::KeyEvent::Key"
- Added @ref Platform::Sdl2Application::InputEvent::Modifier::Super to be
- Added @cpp Platform::Sdl2Application::InputEvent::Modifier::Super @ce to be
consistent with @ref Platform::GlfwApplication (see
[mosra/magnum#159](https://github.com/mosra/magnum/pull/159))
- Added @ref Platform::Sdl2Application::KeyEvent::keyName() "Platform::*Application::KeyEvent::keyName()"
@ -1102,10 +1101,10 @@ a high-level overview.
`Platform::GlfwApplication::MouseEvent::Button::WheelDown` mouse events are
deprecated, use @ref Platform::Sdl2Application::mouseScrollEvent() /
@ref Platform::GlfwApplication::mouseScrollEvent() and
@ref Platform::Sdl2Application::MouseScrollEvent /
@cpp Platform::Sdl2Application::MouseScrollEvent @ce /
@ref Platform::GlfwApplication::MouseScrollEvent instead
- @ref Platform::Sdl2Application::Sdl2Application() "Platform::*Application::*Application()"
and @ref Platform::WindowlessGlxApplication::WindowlessGlxApplication() "Platform::Windowless*Application::Windowless*Application()"
- @cpp Platform::*Application::*Application() @ce and
@ref Platform::WindowlessGlxApplication::WindowlessGlxApplication() "Platform::Windowless*Application::Windowless*Application()"
constructors taking @cpp nullptr @ce are deprecated, use constructors
taking @ref NoCreateT instead to create an application without creating
OpenGL context
@ -1844,7 +1843,7 @@ for a high-level overview.
purely integral coordinates, useful e.g. for UI or 2D platformers.
- Detailed collision queries and new `InvertedSphere` shape in Shapes library
- Texture support in @cpp Shaders::Flat @ce
- Mouse button queries in @ref Platform::Sdl2Application::MouseMoveEvent "Platform::*Application::MouseMoveEvent"
- Mouse button queries in @cpp Platform::*Application::MouseMoveEvent @ce
@subsection changelog-2013-10-changes Changes

53
doc/changelog.dox

@ -732,13 +732,13 @@ See also:
- Added @ref Platform::EmscriptenApplication::Configuration::addWindowFlags()
and @ref Platform::EmscriptenApplication::Configuration::clearWindowFlags()
for consistency with other application implementations
- Added @ref Platform::Sdl2Application::KeyEvent::Key::CapsLock,
@relativeref{Platform::Sdl2Application::KeyEvent::Key,ScrollLock},
@relativeref{Platform::Sdl2Application::KeyEvent::Key,NumLock},
@relativeref{Platform::Sdl2Application::KeyEvent::Key,PrintScreen},
@relativeref{Platform::Sdl2Application::KeyEvent::Key,Pause} and
@relativeref{Platform::Sdl2Application::KeyEvent::Key,Menu} for consistency
with @ref Platform::EmscriptenApplication and
- Added @ref Platform::Sdl2ApplicationWindow::KeyEvent::Key::CapsLock,
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,ScrollLock},
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,NumLock},
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,PrintScreen},
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,Pause} and
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent::Key,Menu} for
consistency with @ref Platform::EmscriptenApplication and
@ref Platform::GlfwApplication (see [mosra/magnum#547](https://github.com/mosra/magnum/pull/547))
- @ref Platform::Sdl2Application now overrides SDL's default behavior that
prevents computer from entering a power-saving mode while the application
@ -1103,9 +1103,9 @@ See also:
destroyed could fail with an error saying "cannot make the previous context
current" on certain system. This was due to EGL not destroying the context
if it's still made current.
- Fixed handling of @ref Platform::Sdl2Application::InputEvent::Modifier::Super,
which was misreported as @relativeref{Platform::Sdl2Application::InputEvent::Modifier,Alt} (see
[mosra/magnum#547](https://github.com/mosra/magnum/pull/547))
- Fixed handling of @ref Platform::Sdl2ApplicationWindow::InputEvent::Modifier::Super,
which was misreported as @relativeref{Platform::Sdl2ApplicationWindow::InputEvent::Modifier,Alt}
(see [mosra/magnum#547](https://github.com/mosra/magnum/pull/547))
- For meshes with multiple sets of vertex attributes (such as texture
coordinates), @ref MeshTools::compile() should be using only the first set
but it wasn't.
@ -1969,12 +1969,12 @@ Released 2020-06-27, tagged as
@ref Platform::AbstractXApplication::mainLoopIteration() for consistency
with @ref Platform::Sdl2Application (see
[mosra/magnum#387](https://github.com/mosra/magnum/pull/387))
- Added @ref Platform::Sdl2Application::KeyEvent::Key::Quote "Key::Quote",
@ref Platform::Sdl2Application::KeyEvent::Key::LeftBracket "Key::LeftBracket",
@ref Platform::Sdl2Application::KeyEvent::Key::RightBracket "Key::RightBracket",
@ref Platform::Sdl2Application::KeyEvent::Key::Backslash "Key::Backslash" and
@ref Platform::Sdl2Application::KeyEvent::Key::Backquote "Key::Backquote"
keys to @ref Platform::Sdl2Application::KeyEvent and
- Added @relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::Quote},
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::LeftBracket},
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::RightBracket},
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::Backslash} and
@relativeref{Platform::Sdl2ApplicationWindow::KeyEvent,Key::Backquote}
keys to @cpp Platform::Sdl2Application::KeyEvent @ce and
@ref Platform::GlfwApplication::KeyEvent
- Added @ref Platform::GlfwApplication::KeyEvent::Key::World1 and
@ref Platform::GlfwApplication::KeyEvent::Key::World2
@ -1992,12 +1992,9 @@ Released 2020-06-27, tagged as
- CUDA device selection in @ref Platform::WindowlessEglApplication (see
[mosra/magnum#449](https://github.com/mosra/magnum/pull/449))
- Added @ref Platform::GlfwApplication::Configuration::WindowFlag::Borderless
- Added @ref Platform::Sdl2Application::Configuration::WindowFlag::FullscreenDesktop,
@ref Platform::Sdl2Application::Configuration::WindowFlag::AlwaysOnTop "AlwaysOnTop",
@ref Platform::Sdl2Application::Configuration::WindowFlag::SkipTaskbar "SkipTaskbar",
@ref Platform::Sdl2Application::Configuration::WindowFlag::Utility "Utility",
@ref Platform::Sdl2Application::Configuration::WindowFlag::Tooltip "Tooltip"
and @ref Platform::Sdl2Application::Configuration::WindowFlag::PopupMenu "PopupMenu"
- Added @cpp Platform::Sdl2Application::Configuration::WindowFlag::FullscreenDesktop @ce,
@cpp AlwaysOnTop @ce, @cpp SkipTaskbar @ce, @cpp Utility @ce,
@cpp Tooltip @ce and @cpp PopupMenu @ce
- Added @ref Platform::Sdl2Application::Configuration::addWindowFlags() and
@ref Platform::Sdl2Application::Configuration::clearWindowFlags() "clearWindowFlags()"
for consistency with similar functions in
@ -2299,7 +2296,7 @@ Released 2020-06-27, tagged as
- The @ref Primitives::cylinderSolid() and @ref Primitives::coneSolid()
primitives were missing a face when both caps and texture coordinates were
enabled (see [mosra/magnum#386](https://github.com/mosra/magnum/issues/386))
- @ref Platform::Sdl2Application::Configuration::WindowFlag::Vulkan was
- @cpp Platform::Sdl2Application::Configuration::WindowFlag::Vulkan @ce was
enabled conditionally only for SDL >= 2.0.6, but the version defines were
never included so it was always disabled
- Fixed missing handling of
@ -2330,7 +2327,7 @@ Released 2020-06-27, tagged as
caused @ref Platform::Sdl2Application::setMinimalLoopPeriod() "setMinimalLoopPeriod()"
to be ignored even though Vsync was in fact not enabled.
- It was not possible to override DPI scaling using
@ref Platform::Sdl2Application::Configuration as command-line arguments
@cpp Platform::Sdl2Application::Configuration @ce as command-line arguments
always got a priority (see [mosra/magnum#416](https://github.com/mosra/magnum/issues/416))
- Fixed an otherwise harmless OOB access in @ref MeshTools::tipsifyInPlace()
that could trigger ASan or debug iterator errors
@ -2832,10 +2829,10 @@ Released 2019-10-24, tagged as
in @ref Platform::GlfwApplication and @ref Platform::EmscriptenApplication)
for changing window title at runtime as opposed to setting them on
application startup
- Added @ref Platform::Sdl2Application::Configuration::WindowFlag::OpenGL and
@ref Platform::Sdl2Application::Configuration::WindowFlag::Vulkan "WindowFlag::Vulkan",
meant to be used together with @ref Platform::Sdl2Application::Configuration::WindowFlag::Contextless for
manual creation of OpenGL contexts and Vulkan instances
- Added @cpp Platform::Sdl2Application::Configuration::WindowFlag::OpenGL @ce
and @cpp WindowFlag::Vulkan @ce, meant to be used together with
@cpp Platform::Sdl2Application::Configuration::WindowFlag::Contextless @ce
for manual creation of OpenGL contexts and Vulkan instances
- @ref Platform::WindowlessEglApplication now uses the
@m_class{m-doc-external} [EGL_EXT_device_enumeration](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_enumeration.txt),
@m_class{m-doc-external} [EGL_EXT_platform_base](https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_platform_base.txt) and

6
doc/platform.dox

@ -136,8 +136,8 @@ target_link_libraries(myapplication
@section platform-configuration Specifying configuration
By default the application is created with some reasonable defaults (e.g.
window size 800x600 pixels). If you want something else, you can pass
@ref Platform::Sdl2Application::Configuration "Configuration" instance to
window size 800x600 pixels). If you want something else, you can pass a
@relativeref{Platform::Sdl2ApplicationWindow,Configuration} instance to the
application constructor. Using method chaining it can be done conveniently like
this:
@ -148,7 +148,7 @@ this:
Sometimes you may want to set up the application based on a configuration file
or system introspection, which can't really be done inside the base class
initializer. You can specify @ref NoCreate in the constructor instead and pass
the @relativeref{Platform::Sdl2Application,Configuration} later to a
the @relativeref{Platform::Sdl2ApplicationWindow,Configuration} later to a
@relativeref{Platform::Sdl2Application,create()} function:
@snippet MagnumPlatform.cpp createcontext

4
src/Magnum/Platform/AndroidApplication.h

@ -149,8 +149,8 @@ to simplify porting.
@section Platform-AndroidApplication-resizing Responding to viewport events
Unlike in desktop application implementations, where this is controlled via
@ref Sdl2Application::Configuration::WindowFlag::Resizable, for example, on
Android you have to describe this in the `AndroidManifest.xml` file, as by
@ref Sdl2ApplicationWindow::Configuration::WindowFlag::Resizable, for example,
on Android you have to describe this in the `AndroidManifest.xml` file, as by
default the application gets killed and relaunched on screen orientation
change. See the @ref platforms-android-apps-manifest-screen-resize "manifest file docs"
for more information.

18
src/Magnum/Platform/Screen.h

@ -175,7 +175,7 @@ template<class Application> class BasicScreen:
* @brief Key event
*
* Defined only if the application has a
* @ref Sdl2Application::KeyEvent "KeyEvent".
* @relativeref{Sdl2ApplicationWindow,KeyEvent}.
*/
typedef typename BasicScreenedApplication<Application>::KeyEvent KeyEvent;
#endif
@ -192,7 +192,7 @@ template<class Application> class BasicScreen:
* @m_since{2019,10}
*
* Defined only if the application has a
* @ref Sdl2Application::MouseScrollEvent "MouseScrollEvent".
* @relativeref{Sdl2ApplicationWindow,MouseScrollEvent}.
*/
typedef typename BasicScreenedApplication<Application>::MouseScrollEvent MouseScrollEvent;
@ -201,7 +201,7 @@ template<class Application> class BasicScreen:
* @m_since{2019,10}
*
* Defined only if the application has a
* @ref Sdl2Application::TextInputEvent "TextInputEvent".
* @relativeref{Sdl2ApplicationWindow,TextInputEvent}.
*/
typedef typename BasicScreenedApplication<Application>::TextInputEvent TextInputEvent;
@ -210,7 +210,7 @@ template<class Application> class BasicScreen:
* @m_since{2019,10}
*
* Defined only if the application has a
* @ref Sdl2Application::TextEditingEvent "TextEditingEvent".
* @relativeref{Sdl2ApplicationWindow,TextEditingEvent}.
*/
typedef typename BasicScreenedApplication<Application>::TextEditingEvent TextEditingEvent;
#endif
@ -379,7 +379,7 @@ template<class Application> class BasicScreen:
* Called when @ref PropagatedEvent::Input is enabled and an key is
* pressed. See @ref Sdl2Application::keyPressEvent() "*Application::keyPressEvent()"
* for more information. Defined only if the application has a
* @ref Sdl2Application::KeyEvent "KeyEvent".
* @relativeref{Sdl2ApplicationWindow,KeyEvent}.
*/
virtual void keyPressEvent(KeyEvent& event);
@ -389,7 +389,7 @@ template<class Application> class BasicScreen:
* Called when @ref PropagatedEvent::Input is enabled and an key is
* released. See @ref Sdl2Application::keyReleaseEvent() "*Application::keyReleaseEvent()"
* for more information. Defined only if the application has a
* @ref Sdl2Application::KeyEvent "KeyEvent".
* @relativeref{Sdl2ApplicationWindow,KeyEvent}.
*/
virtual void keyReleaseEvent(KeyEvent& event);
#endif
@ -437,7 +437,7 @@ template<class Application> class BasicScreen:
* Called when @ref PropagatedEvent::Input is enabled and mouse wheel
* is rotated. See @ref Sdl2Application::mouseScrollEvent() "*Application::mouseScrollEvent()"
* for more information. Defined only if the application has a
* @ref Sdl2Application::MouseScrollEvent "MouseScrollEvent".
* @relativeref{Sdl2ApplicationWindow,MouseScrollEvent}.
*/
virtual void mouseScrollEvent(MouseScrollEvent& event);
#endif
@ -457,7 +457,7 @@ template<class Application> class BasicScreen:
*
* Called when @ref PropagatedEvent::Input is enabled and text is being
* input. Defined only if the application has a
* @ref Sdl2Application::TextInputEvent "TextInputEvent".
* @relativeref{Sdl2ApplicationWindow,TextInputEvent}.
*/
virtual void textInputEvent(TextInputEvent& event);
@ -467,7 +467,7 @@ template<class Application> class BasicScreen:
*
* Called when @ref PropagatedEvent::Input and the text is being
* edited. Defined only if the application has a
* @ref Sdl2Application::TextEditingEvent "TextEditingEvent".
* @relativeref{Sdl2ApplicationWindow,TextEditingEvent}.
*/
virtual void textEditingEvent(TextEditingEvent& event);
#endif

779
src/Magnum/Platform/Sdl2Application.cpp

@ -78,142 +78,25 @@ namespace Magnum { namespace Platform {
using namespace Containers::Literals;
namespace {
/*
* Fix up the modifiers -- we want >= operator to work properly on Shift,
* Ctrl, Alt, but SDL generates different event for left / right keys, thus
* (modifiers >= Shift) would pass only if both left and right were pressed,
* which is usually not what the developers wants.
*/
Sdl2Application::InputEvent::Modifiers fixedModifiers(Uint16 mod) {
Sdl2Application::InputEvent::Modifiers modifiers(static_cast<Sdl2Application::InputEvent::Modifier>(mod));
if(modifiers & Sdl2Application::InputEvent::Modifier::Shift) modifiers |= Sdl2Application::InputEvent::Modifier::Shift;
if(modifiers & Sdl2Application::InputEvent::Modifier::Ctrl) modifiers |= Sdl2Application::InputEvent::Modifier::Ctrl;
if(modifiers & Sdl2Application::InputEvent::Modifier::Alt) modifiers |= Sdl2Application::InputEvent::Modifier::Alt;
if(modifiers & Sdl2Application::InputEvent::Modifier::Super) modifiers |= Sdl2Application::InputEvent::Modifier::Super;
return modifiers;
}
}
enum class Sdl2Application::Flag: UnsignedByte {
enum class Sdl2ApplicationWindow::WindowFlag: UnsignedByte {
Redraw = 1 << 0,
VSyncEnabled = 1 << 1,
NoTickEvent = 1 << 2,
NoAnyEvent = 1 << 3,
Exit = 1 << 4,
#ifdef CORRADE_TARGET_EMSCRIPTEN
TextInputActive = 1 << 5,
Resizable = 1 << 6,
#endif
#ifdef CORRADE_TARGET_APPLE
HiDpiWarningPrinted = 1 << 7
TextInputActive = 1 << 1,
Resizable = 1 << 2,
#endif
};
Sdl2Application::Sdl2Application(const Arguments& arguments): Sdl2Application{arguments, Configuration{}} {}
Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration): Sdl2Application{arguments, NoCreate} {
create(configuration);
}
#ifdef MAGNUM_TARGET_GL
Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration, const GLConfiguration& glConfiguration): Sdl2Application{arguments, NoCreate} {
create(configuration, glConfiguration);
}
#endif
Sdl2ApplicationWindow::Sdl2ApplicationWindow(Sdl2Application& application, NoCreateT): _application{application}, _windowFlags{WindowFlag::Redraw} {}
Sdl2Application::Sdl2Application(const Arguments& arguments, NoCreateT):
Sdl2ApplicationWindow::~Sdl2ApplicationWindow() {
/* SDL_DestroyWindow(_window) crashes on windows when _window is nullptr
(it doesn't seem to crash on Linux) */
#ifndef CORRADE_TARGET_EMSCRIPTEN
_minimalLoopPeriod{0},
#endif
_flags{Flag::Redraw}
{
Utility::Arguments args{Implementation::windowScalingArguments()};
#ifdef MAGNUM_TARGET_GL
_context.emplace(NoCreate, args, arguments.argc, arguments.argv);
#else
/** @todo this is duplicated here, in GlfwApplication and in
EmscriptenApplication, figure out a nice non-duplicated way to handle
this */
args.addOption("log", "default").setHelp("log", "console logging", "default|quiet|verbose")
.setFromEnvironment("log")
.parse(arguments.argc, arguments.argv);
#endif
/* Available since 2.0.4, disables interception of SIGINT and SIGTERM so
it's possible to Ctrl-C the application even if exitEvent() doesn't set
event.setAccepted(). */
#ifdef SDL_HINT_NO_SIGNAL_HANDLERS
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
#endif
/* Available since 2.0.6, uses dedicated OpenGL ES drivers if EGL is used,
and desktop GLES context otherwise. */
#if defined(MAGNUM_TARGET_GLES) && defined(MAGNUM_TARGET_EGL) && defined(SDL_HINT_OPENGL_ES_DRIVER)
SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1");
#endif
/* Available since 2.0.8, disables compositor bypass on X11, which causes
flickering on KWin as the compositor gets shut down on every startup */
#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
#endif
/* By default, SDL behaves like if it was playing a video or whatever,
preventing the computer from turning off the screen or going to sleep.
While it sorta makes sense for games, it's useless and annoying for
regular apps. Together with the compositor disabling those two are the
most stupid defaults. */
#ifdef SDL_HINT_VIDEO_ALLOW_SCREENSAVER
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
#endif
/* Available since 2.0.12, use EGL if desired */
#if defined(MAGNUM_TARGET_EGL) && defined(SDL_HINT_VIDEO_X11_FORCE_EGL)
SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1");
#endif
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
Error() << "Cannot initialize SDL:" << SDL_GetError();
std::exit(1);
}
/* Save command-line arguments */
if(args.value("log") == "verbose") _verboseLog = true;
const Containers::StringView dpiScaling = args.value<Containers::StringView>("dpi-scaling");
if(dpiScaling == "default"_s)
_commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Default;
#ifdef CORRADE_TARGET_APPLE
else if(dpiScaling == "framebuffer"_s)
_commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Framebuffer;
#endif
#ifndef CORRADE_TARGET_APPLE
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_ANDROID)
else if(dpiScaling == "virtual"_s)
_commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Virtual;
#endif
else if(dpiScaling == "physical"_s)
_commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Physical;
if(_window) SDL_DestroyWindow(_window);
#endif
else if(dpiScaling.containsAny(" \t\n"_s))
_commandLineDpiScaling = args.value<Vector2>("dpi-scaling");
else
_commandLineDpiScaling = Vector2{args.value<Float>("dpi-scaling")};
}
void Sdl2Application::create() {
create(Configuration{});
}
void Sdl2Application::create(const Configuration& configuration) {
if(!tryCreate(configuration)) std::exit(1);
}
#ifdef MAGNUM_TARGET_GL
void Sdl2Application::create(const Configuration& configuration, const GLConfiguration& glConfiguration) {
if(!tryCreate(configuration, glConfiguration)) std::exit(1);
}
#endif
Vector2 Sdl2Application::dpiScaling(const Configuration& configuration) {
Vector2 Sdl2ApplicationWindow::dpiScaling(const Configuration& configuration) {
/* Print a helpful warning in case some extra steps are needed for HiDPI
support */
#ifdef CORRADE_TARGET_APPLE
@ -229,18 +112,18 @@ Vector2 Sdl2Application::dpiScaling(const Configuration& configuration) {
return dpiScalingInternal(configuration.dpiScalingPolicy(), configuration.dpiScaling());
}
Vector2 Sdl2Application::dpiScalingInternal(const Implementation::Sdl2DpiScalingPolicy configurationDpiScalingPolicy, const Vector2& configurationDpiScaling) const {
std::ostream* verbose = _verboseLog ? Debug::output() : nullptr;
Vector2 Sdl2ApplicationWindow::dpiScalingInternal(const Implementation::Sdl2DpiScalingPolicy configurationDpiScalingPolicy, const Vector2& configurationDpiScaling) const {
std::ostream* verbose = _application._verboseLog ? Debug::output() : nullptr;
/* Use values from the configuration only if not overridden on command line
to something non-default. In any case explicit scaling has a precedence
before the policy. */
Implementation::Sdl2DpiScalingPolicy dpiScalingPolicy{};
if(!_commandLineDpiScaling.isZero()) {
Debug{verbose} << "Platform::Sdl2Application: user-defined DPI scaling" << _commandLineDpiScaling;
return _commandLineDpiScaling;
} else if(_commandLineDpiScalingPolicy != Implementation::Sdl2DpiScalingPolicy::Default) {
dpiScalingPolicy = _commandLineDpiScalingPolicy;
if(!_application._commandLineDpiScaling.isZero()) {
Debug{verbose} << "Platform::Sdl2Application: user-defined DPI scaling" << _application._commandLineDpiScaling;
return _application._commandLineDpiScaling;
} else if(_application._commandLineDpiScalingPolicy != Implementation::Sdl2DpiScalingPolicy::Default) {
dpiScalingPolicy = _application._commandLineDpiScalingPolicy;
} else if(!configurationDpiScaling.isZero()) {
Debug{verbose} << "Platform::Sdl2Application: app-defined DPI scaling" << configurationDpiScaling;
return configurationDpiScaling;
@ -322,72 +205,360 @@ Vector2 Sdl2Application::dpiScalingInternal(const Implementation::Sdl2DpiScaling
#else
Debug{verbose} << "Platform::Sdl2Application: sorry, physical DPI scaling only available on SDL 2.0.4+";
#endif
return Vector2{1.0f};
return Vector2{1.0f};
/* HOWEVER, on Windows it gets the virtual DPI scaling, which we don't
want, so we need to call Windows APIs directly instead. Consistency my
ass. Related bug report that will probably never get actually
implemented: https://bugzilla.libsdl.org/show_bug.cgi?id=2473 */
#elif defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)
HDC hDC = GetWindowDC(nullptr);
Vector2i monitorSize{GetDeviceCaps(hDC, HORZSIZE), GetDeviceCaps(hDC, VERTSIZE)};
SDL_DisplayMode mode;
CORRADE_INTERNAL_ASSERT(SDL_GetDesktopDisplayMode(0, &mode) == 0);
auto dpi = Vector2{Vector2i{mode.w, mode.h}*25.4f/Vector2{monitorSize}};
const Vector2 dpiScaling{dpi/96.0f};
Debug{verbose} << "Platform::Sdl2Application: physical DPI scaling" << dpiScaling;
return dpiScaling;
/* Not implemented otherwise */
#else
Debug{verbose} << "Platform::Sdl2Application: sorry, physical DPI scaling not implemented on this platform yet";
return Vector2{1.0f};
#endif
#endif
}
void Sdl2ApplicationWindow::setWindowTitle(const Containers::StringView title) {
#ifndef CORRADE_TARGET_EMSCRIPTEN
SDL_SetWindowTitle(_window,
Containers::String::nullTerminatedGlobalView(title).data());
#else
/* We don't have the _window because SDL_CreateWindow() doesn't exist in
the SDL1/2 hybrid. But it's not used anyway, so pass nullptr there. */
SDL_SetWindowTitle(nullptr,
Containers::String::nullTerminatedGlobalView(title).data());
#endif
}
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && SDL_MAJOR_VERSION*1000 + SDL_MINOR_VERSION*100 + SDL_PATCHLEVEL >= 2005
void Sdl2ApplicationWindow::setWindowIcon(const ImageView2D& image) {
Uint32 format; /** @todo handle sRGB differently? */
switch(image.format()) {
case PixelFormat::RGB8Srgb:
case PixelFormat::RGB8Unorm:
format = SDL_PIXELFORMAT_RGB24;
break;
case PixelFormat::RGBA8Srgb:
case PixelFormat::RGBA8Unorm:
format = SDL_PIXELFORMAT_RGBA32;
break;
default:
CORRADE_ASSERT_UNREACHABLE("Platform::Sdl2ApplicationWindow::setWindowIcon(): unexpected format" << image.format(), );
}
/* Images are loaded with origin at bottom left, flip it to top left. SDL
only accepted a negative stride until version 2.23.1 and commit
https://github.com/libsdl-org/SDL/commit/535fdc3adcdc08a193ab0d45540014fd536cf251
so we need to manually flip the image now */
/** @todo take ImageFlag::YUp into account once it exists */
Image2D flippedImage{PixelStorage{}.setAlignment(1), image.format(), image.size(), Containers::Array<char>{NoInit, std::size_t(image.size().product()*image.pixelSize())}};
const Containers::StridedArrayView3D<char> flippedPixels = flippedImage.pixels();
Utility::copy(image.pixels().flipped<0>(), flippedPixels);
SDL_Surface* const icon = SDL_CreateRGBSurfaceWithFormatFrom(const_cast<void*>(flippedPixels.data()) , flippedImage.size().x(), flippedImage.size().y(), 32, flippedPixels.stride()[0], format);
CORRADE_INTERNAL_ASSERT(icon);
SDL_SetWindowIcon(_window, icon);
SDL_FreeSurface(icon);
}
#endif
Vector2i Sdl2ApplicationWindow::windowSize() const {
Vector2i size;
#ifndef CORRADE_TARGET_EMSCRIPTEN
CORRADE_ASSERT(_window, "Platform::Sdl2Application::windowSize(): no window opened", {});
SDL_GetWindowSize(_window, &size.x(), &size.y());
#else
CORRADE_ASSERT(_surface, "Platform::Sdl2Application::windowSize(): no window opened", {});
emscripten_get_canvas_element_size("#canvas", &size.x(), &size.y());
#endif
return size;
}
#ifndef CORRADE_TARGET_EMSCRIPTEN
void Sdl2ApplicationWindow::setWindowSize(const Vector2i& size) {
CORRADE_ASSERT(_window, "Platform::Sdl2Application::setWindowSize(): no window opened", );
const Vector2i newSize = dpiScaling()*size;
SDL_SetWindowSize(_window, newSize.x(), newSize.y());
}
void Sdl2ApplicationWindow::setMinWindowSize(const Vector2i& size) {
CORRADE_ASSERT(_window, "Platform::Sdl2Application::setMinWindowSize(): no window opened", );
const Vector2i newSize = dpiScaling()*size;
SDL_SetWindowMinimumSize(_window, newSize.x(), newSize.y());
}
void Sdl2ApplicationWindow::setMaxWindowSize(const Vector2i& size) {
CORRADE_ASSERT(_window, "Platform::Sdl2Application::setMaxWindowSize(): no window opened", );
const Vector2i newSize = dpiScaling()*size;
SDL_SetWindowMaximumSize(_window, newSize.x(), newSize.y());
}
#endif
#ifdef MAGNUM_TARGET_GL
Vector2i Sdl2ApplicationWindow::framebufferSize() const {
Vector2i size;
#ifndef CORRADE_TARGET_EMSCRIPTEN
CORRADE_ASSERT(_window, "Platform::Sdl2Application::framebufferSize(): no window opened", {});
SDL_GL_GetDrawableSize(_window, &size.x(), &size.y());
#else
CORRADE_ASSERT(_surface, "Platform::Sdl2Application::framebufferSize(): no window opened", {});
emscripten_get_canvas_element_size("#canvas", &size.x(), &size.y());
#endif
return size;
}
#endif
Vector2 Sdl2ApplicationWindow::dpiScaling() const {
return dpiScalingInternal(_application._configurationDpiScalingPolicy, _application._configurationDpiScaling);
}
void Sdl2ApplicationWindow::redraw() { _windowFlags |= WindowFlag::Redraw; }
namespace {
#ifndef CORRADE_TARGET_EMSCRIPTEN
constexpr SDL_SystemCursor CursorMap[] {
SDL_SYSTEM_CURSOR_ARROW,
SDL_SYSTEM_CURSOR_IBEAM,
SDL_SYSTEM_CURSOR_WAIT,
SDL_SYSTEM_CURSOR_CROSSHAIR,
SDL_SYSTEM_CURSOR_WAITARROW,
SDL_SYSTEM_CURSOR_SIZENWSE,
SDL_SYSTEM_CURSOR_SIZENESW,
SDL_SYSTEM_CURSOR_SIZEWE,
SDL_SYSTEM_CURSOR_SIZENS,
SDL_SYSTEM_CURSOR_SIZEALL,
SDL_SYSTEM_CURSOR_NO,
SDL_SYSTEM_CURSOR_HAND
};
#else
constexpr Containers::StringView CursorMap[] {
"default"_s,
"text"_s,
"wait"_s,
"crosshair"_s,
"progress"_s,
"nwse-resize"_s,
"nesw-resize"_s,
"ew-resize"_s,
"ns-resize"_s,
"move"_s,
"not-allowed"_s,
"pointer"_s,
"none"_s
/* Hidden & locked not supported yet */
};
#endif
}
void Sdl2ApplicationWindow::setCursor(Cursor cursor) {
#ifndef CORRADE_TARGET_EMSCRIPTEN
CORRADE_ASSERT(_window, "Platform::Sdl2ApplicationWindow::setCursor(): no window opened", );
if(cursor == Cursor::Hidden) {
SDL_ShowCursor(SDL_DISABLE);
SDL_SetWindowGrab(_window, SDL_FALSE);
SDL_SetRelativeMouseMode(SDL_FALSE);
return;
} else if(cursor == Cursor::HiddenLocked) {
SDL_SetWindowGrab(_window, SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_TRUE);
return;
} else {
SDL_ShowCursor(SDL_ENABLE);
SDL_SetWindowGrab(_window, SDL_FALSE);
SDL_SetRelativeMouseMode(SDL_FALSE);
}
/* The second condition could be a static assert but it doesn't let me
because "this pointer only accessible in a constexpr function". Thanks
for nothing, C++. */
CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(_application._cursors) && Containers::arraySize(_application._cursors) == Containers::arraySize(CursorMap));
if(!_application._cursors[UnsignedInt(cursor)])
_application._cursors[UnsignedInt(cursor)] = SDL_CreateSystemCursor(CursorMap[UnsignedInt(cursor)]);
SDL_SetCursor(_application._cursors[UnsignedInt(cursor)]);
#else
CORRADE_ASSERT(_surface, "Platform::Sdl2Application::setCursor(): no window opened", );
_cursor = cursor;
CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(CursorMap));
magnumPlatformSetCursor(CursorMap[UnsignedInt(cursor)].data(),
CursorMap[UnsignedInt(cursor)].size());
#endif
}
Sdl2Application::Cursor Sdl2ApplicationWindow::cursor() {
#ifndef CORRADE_TARGET_EMSCRIPTEN
if(SDL_GetRelativeMouseMode())
return Cursor::HiddenLocked;
else if(!SDL_ShowCursor(SDL_QUERY))
return Cursor::Hidden;
SDL_Cursor* cursor = SDL_GetCursor();
if(cursor) for(UnsignedInt i = 0; i < sizeof(_application._cursors); i++)
if(_application._cursors[i] == cursor) return Cursor(i);
return Cursor::Arrow;
#else
return _cursor;
#endif
}
void Sdl2ApplicationWindow::viewportEvent(ViewportEvent&) {}
void Sdl2ApplicationWindow::keyPressEvent(KeyEvent&) {}
void Sdl2ApplicationWindow::keyReleaseEvent(KeyEvent&) {}
void Sdl2ApplicationWindow::mousePressEvent(MouseEvent&) {}
void Sdl2ApplicationWindow::mouseReleaseEvent(MouseEvent&) {}
void Sdl2ApplicationWindow::mouseMoveEvent(MouseMoveEvent&) {}
void Sdl2ApplicationWindow::mouseScrollEvent(MouseScrollEvent&) {}
void Sdl2ApplicationWindow::multiGestureEvent(MultiGestureEvent&) {}
void Sdl2ApplicationWindow::textInputEvent(TextInputEvent&) {}
void Sdl2ApplicationWindow::textEditingEvent(TextEditingEvent&) {}
namespace {
/*
* Fix up the modifiers -- we want >= operator to work properly on Shift,
* Ctrl, Alt, but SDL generates different event for left / right keys, thus
* (modifiers >= Shift) would pass only if both left and right were pressed,
* which is usually not what the developers wants.
*/
Sdl2Application::InputEvent::Modifiers fixedModifiers(Uint16 mod) {
Sdl2Application::InputEvent::Modifiers modifiers(static_cast<Sdl2Application::InputEvent::Modifier>(mod));
if(modifiers & Sdl2Application::InputEvent::Modifier::Shift) modifiers |= Sdl2Application::InputEvent::Modifier::Shift;
if(modifiers & Sdl2Application::InputEvent::Modifier::Ctrl) modifiers |= Sdl2Application::InputEvent::Modifier::Ctrl;
if(modifiers & Sdl2Application::InputEvent::Modifier::Alt) modifiers |= Sdl2Application::InputEvent::Modifier::Alt;
if(modifiers & Sdl2Application::InputEvent::Modifier::Super) modifiers |= Sdl2Application::InputEvent::Modifier::Super;
return modifiers;
}
}
enum class Sdl2Application::Flag: UnsignedByte {
VSyncEnabled = 1 << 0,
NoTickEvent = 1 << 1,
NoAnyEvent = 1 << 2,
Exit = 1 << 3,
#ifdef CORRADE_TARGET_APPLE
HiDpiWarningPrinted = 1 << 4
#endif
};
Sdl2Application::Sdl2Application(const Arguments& arguments): Sdl2Application{arguments, Configuration{}} {}
Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration): Sdl2Application{arguments, NoCreate} {
create(configuration);
}
#ifdef MAGNUM_TARGET_GL
Sdl2Application::Sdl2Application(const Arguments& arguments, const Configuration& configuration, const GLConfiguration& glConfiguration): Sdl2Application{arguments, NoCreate} {
create(configuration, glConfiguration);
}
#endif
Sdl2Application::Sdl2Application(const Arguments& arguments, NoCreateT): Sdl2ApplicationWindow{*this, NoCreate}
#ifndef CORRADE_TARGET_EMSCRIPTEN
, _minimalLoopPeriod{0}
#endif
{
Utility::Arguments args{Implementation::windowScalingArguments()};
#ifdef MAGNUM_TARGET_GL
_context.emplace(NoCreate, args, arguments.argc, arguments.argv);
#else
/** @todo this is duplicated here, in GlfwApplication and in
EmscriptenApplication, figure out a nice non-duplicated way to handle
this */
args.addOption("log", "default").setHelp("log", "console logging", "default|quiet|verbose")
.setFromEnvironment("log")
.parse(arguments.argc, arguments.argv);
#endif
/* Available since 2.0.4, disables interception of SIGINT and SIGTERM so
it's possible to Ctrl-C the application even if exitEvent() doesn't set
event.setAccepted(). */
#ifdef SDL_HINT_NO_SIGNAL_HANDLERS
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
#endif
/* Available since 2.0.6, uses dedicated OpenGL ES drivers if EGL is used,
and desktop GLES context otherwise. */
#if defined(MAGNUM_TARGET_GLES) && defined(MAGNUM_TARGET_EGL) && defined(SDL_HINT_OPENGL_ES_DRIVER)
SDL_SetHint(SDL_HINT_OPENGL_ES_DRIVER, "1");
#endif
/* Available since 2.0.8, disables compositor bypass on X11, which causes
flickering on KWin as the compositor gets shut down on every startup */
#ifdef SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
#endif
/* By default, SDL behaves like if it was playing a video or whatever,
preventing the computer from turning off the screen or going to sleep.
While it sorta makes sense for games, it's useless and annoying for
regular apps. Together with the compositor disabling those two are the
most stupid defaults. */
#ifdef SDL_HINT_VIDEO_ALLOW_SCREENSAVER
SDL_SetHint(SDL_HINT_VIDEO_ALLOW_SCREENSAVER, "1");
#endif
/* Available since 2.0.12, use EGL if desired */
#if defined(MAGNUM_TARGET_EGL) && defined(SDL_HINT_VIDEO_X11_FORCE_EGL)
SDL_SetHint(SDL_HINT_VIDEO_X11_FORCE_EGL, "1");
#endif
/* HOWEVER, on Windows it gets the virtual DPI scaling, which we don't
want, so we need to call Windows APIs directly instead. Consistency my
ass. Related bug report that will probably never get actually
implemented: https://bugzilla.libsdl.org/show_bug.cgi?id=2473 */
#elif defined(CORRADE_TARGET_WINDOWS) && !defined(CORRADE_TARGET_WINDOWS_RT)
HDC hDC = GetWindowDC(nullptr);
Vector2i monitorSize{GetDeviceCaps(hDC, HORZSIZE), GetDeviceCaps(hDC, VERTSIZE)};
SDL_DisplayMode mode;
CORRADE_INTERNAL_ASSERT(SDL_GetDesktopDisplayMode(0, &mode) == 0);
auto dpi = Vector2{Vector2i{mode.w, mode.h}*25.4f/Vector2{monitorSize}};
const Vector2 dpiScaling{dpi/96.0f};
Debug{verbose} << "Platform::Sdl2Application: physical DPI scaling" << dpiScaling;
return dpiScaling;
if(SDL_Init(SDL_INIT_VIDEO) < 0) {
Error() << "Cannot initialize SDL:" << SDL_GetError();
std::exit(1);
}
/* Not implemented otherwise */
#else
Debug{verbose} << "Platform::Sdl2Application: sorry, physical DPI scaling not implemented on this platform yet";
return Vector2{1.0f};
/* Save command-line arguments */
if(args.value("log") == "verbose") _verboseLog = true;
const Containers::StringView dpiScaling = args.value<Containers::StringView>("dpi-scaling");
if(dpiScaling == "default"_s)
_commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Default;
#ifdef CORRADE_TARGET_APPLE
else if(dpiScaling == "framebuffer"_s)
_commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Framebuffer;
#endif
#ifndef CORRADE_TARGET_APPLE
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_ANDROID)
else if(dpiScaling == "virtual"_s)
_commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Virtual;
#endif
}
void Sdl2Application::setWindowTitle(const Containers::StringView title) {
#ifndef CORRADE_TARGET_EMSCRIPTEN
SDL_SetWindowTitle(_window,
Containers::String::nullTerminatedGlobalView(title).data());
#else
/* We don't have the _window because SDL_CreateWindow() doesn't exist in
the SDL1/2 hybrid. But it's not used anyway, so pass nullptr there. */
SDL_SetWindowTitle(nullptr,
Containers::String::nullTerminatedGlobalView(title).data());
else if(dpiScaling == "physical"_s)
_commandLineDpiScalingPolicy = Implementation::Sdl2DpiScalingPolicy::Physical;
#endif
else if(dpiScaling.containsAny(" \t\n"_s))
_commandLineDpiScaling = args.value<Vector2>("dpi-scaling");
else
_commandLineDpiScaling = Vector2{args.value<Float>("dpi-scaling")};
}
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && SDL_MAJOR_VERSION*1000 + SDL_MINOR_VERSION*100 + SDL_PATCHLEVEL >= 2005
void Sdl2Application::setWindowIcon(const ImageView2D& image) {
Uint32 format; /** @todo handle sRGB differently? */
switch(image.format()) {
case PixelFormat::RGB8Srgb:
case PixelFormat::RGB8Unorm:
format = SDL_PIXELFORMAT_RGB24;
break;
case PixelFormat::RGBA8Srgb:
case PixelFormat::RGBA8Unorm:
format = SDL_PIXELFORMAT_RGBA32;
break;
default:
CORRADE_ASSERT_UNREACHABLE("Platform::Sdl2Application::setWindowIcon(): unexpected format" << image.format(), );
}
/* Images are loaded with origin at bottom left, flip it to top left. SDL
only accepted a negative stride until version 2.23.1 and commit
https://github.com/libsdl-org/SDL/commit/535fdc3adcdc08a193ab0d45540014fd536cf251
so we need to manually flip the image now */
/** @todo take ImageFlag::YUp into account once it exists */
Image2D flippedImage{PixelStorage{}.setAlignment(1), image.format(), image.size(), Containers::Array<char>{NoInit, std::size_t(image.size().product()*image.pixelSize())}};
const Containers::StridedArrayView3D<char> flippedPixels = flippedImage.pixels();
Utility::copy(image.pixels().flipped<0>(), flippedPixels);
void Sdl2Application::create() {
create(Configuration{});
}
SDL_Surface* const icon = SDL_CreateRGBSurfaceWithFormatFrom(const_cast<void*>(flippedPixels.data()) , flippedImage.size().x(), flippedImage.size().y(), 32, flippedPixels.stride()[0], format);
CORRADE_INTERNAL_ASSERT(icon);
void Sdl2Application::create(const Configuration& configuration) {
if(!tryCreate(configuration)) std::exit(1);
}
SDL_SetWindowIcon(_window, icon);
SDL_FreeSurface(icon);
#ifdef MAGNUM_TARGET_GL
void Sdl2Application::create(const Configuration& configuration, const GLConfiguration& glConfiguration) {
if(!tryCreate(configuration, glConfiguration)) std::exit(1);
}
#endif
@ -735,66 +906,13 @@ bool Sdl2Application::tryCreate(const Configuration& configuration, const GLConf
}
#endif
Vector2i Sdl2Application::windowSize() const {
Vector2i size;
#ifndef CORRADE_TARGET_EMSCRIPTEN
CORRADE_ASSERT(_window, "Platform::Sdl2Application::windowSize(): no window opened", {});
SDL_GetWindowSize(_window, &size.x(), &size.y());
#else
CORRADE_ASSERT(_surface, "Platform::Sdl2Application::windowSize(): no window opened", {});
emscripten_get_canvas_element_size("#canvas", &size.x(), &size.y());
#endif
return size;
}
#ifndef CORRADE_TARGET_EMSCRIPTEN
void Sdl2Application::setWindowSize(const Vector2i& size) {
CORRADE_ASSERT(_window, "Platform::Sdl2Application::setWindowSize(): no window opened", );
const Vector2i newSize = dpiScaling()*size;
SDL_SetWindowSize(_window, newSize.x(), newSize.y());
}
void Sdl2Application::setMinWindowSize(const Vector2i& size) {
CORRADE_ASSERT(_window, "Platform::Sdl2Application::setMinWindowSize(): no window opened", );
const Vector2i newSize = dpiScaling()*size;
SDL_SetWindowMinimumSize(_window, newSize.x(), newSize.y());
}
void Sdl2Application::setMaxWindowSize(const Vector2i& size) {
CORRADE_ASSERT(_window, "Platform::Sdl2Application::setMaxWindowSize(): no window opened", );
const Vector2i newSize = dpiScaling()*size;
SDL_SetWindowMaximumSize(_window, newSize.x(), newSize.y());
}
#endif
#ifdef MAGNUM_TARGET_GL
Vector2i Sdl2Application::framebufferSize() const {
Vector2i size;
#ifndef CORRADE_TARGET_EMSCRIPTEN
CORRADE_ASSERT(_window, "Platform::Sdl2Application::framebufferSize(): no window opened", {});
SDL_GL_GetDrawableSize(_window, &size.x(), &size.y());
#else
CORRADE_ASSERT(_surface, "Platform::Sdl2Application::framebufferSize(): no window opened", {});
emscripten_get_canvas_element_size("#canvas", &size.x(), &size.y());
#endif
return size;
}
#endif
Vector2 Sdl2Application::dpiScaling() const {
return dpiScalingInternal(_configurationDpiScalingPolicy, _configurationDpiScaling);
}
#ifdef CORRADE_TARGET_EMSCRIPTEN
void Sdl2Application::setContainerCssClass(const Containers::StringView cssClass) {
magnumPlatformSetContainerCssClass(cssClass.data(), cssClass.size());
}
#endif
void Sdl2Application::swapBuffers() {
void Sdl2ApplicationWindow::swapBuffers() {
#ifndef CORRADE_TARGET_EMSCRIPTEN
SDL_GL_SwapWindow(_window);
#else
@ -827,8 +945,6 @@ bool Sdl2Application::setSwapInterval(const Int interval) {
return true;
}
void Sdl2Application::redraw() { _flags |= Flag::Redraw; }
Sdl2Application::~Sdl2Application() {
/* SDL_DestroyWindow(_window) crashes on windows when _window is nullptr
(it doesn't seem to crash on Linux). Because this seems to be yet
@ -852,9 +968,14 @@ Sdl2Application::~Sdl2Application() {
SDL_FreeCursor(cursor);
#endif
#ifndef CORRADE_TARGET_EMSCRIPTEN
if(_window) SDL_DestroyWindow(_window);
#endif
/* The window would be destroyed in the base ~Sdl2ApplicationWindow(), but
that's too late. Do it before calling SDL_Quit() and then reset the
window pointer so it's not called again after. */
if(_window) {
SDL_DestroyWindow(_window);
_window = nullptr;
}
SDL_Quit();
}
@ -946,14 +1067,14 @@ bool Sdl2Application::mainLoopIteration() {
dpiScaling()};
/** @todo handle also WM_DPICHANGED events when a window is moved between displays with different DPI */
viewportEvent(e);
_flags |= Flag::Redraw;
_windowFlags |= WindowFlag::Redraw;
#endif
} break;
/* Direct everything that wasn't exposed via a callback to
anyEvent(), so users can implement event handling for
things not present in the Application APIs */
case SDL_WINDOWEVENT_EXPOSED:
_flags |= Flag::Redraw;
_windowFlags |= WindowFlag::Redraw;
if(!(_flags & Flag::NoAnyEvent)) anyEvent(event);
break;
default:
@ -1027,8 +1148,8 @@ bool Sdl2Application::mainLoopIteration() {
if(!(_flags & Flag::NoTickEvent)) tickEvent();
/* Draw event */
if(_flags & Flag::Redraw) {
_flags &= ~Flag::Redraw;
if(_windowFlags & WindowFlag::Redraw) {
_windowFlags &= ~WindowFlag::Redraw;
drawEvent();
#ifndef CORRADE_TARGET_EMSCRIPTEN
@ -1058,99 +1179,6 @@ bool Sdl2Application::mainLoopIteration() {
return !(_flags & Flag::Exit);
}
namespace {
#ifndef CORRADE_TARGET_EMSCRIPTEN
constexpr SDL_SystemCursor CursorMap[] {
SDL_SYSTEM_CURSOR_ARROW,
SDL_SYSTEM_CURSOR_IBEAM,
SDL_SYSTEM_CURSOR_WAIT,
SDL_SYSTEM_CURSOR_CROSSHAIR,
SDL_SYSTEM_CURSOR_WAITARROW,
SDL_SYSTEM_CURSOR_SIZENWSE,
SDL_SYSTEM_CURSOR_SIZENESW,
SDL_SYSTEM_CURSOR_SIZEWE,
SDL_SYSTEM_CURSOR_SIZENS,
SDL_SYSTEM_CURSOR_SIZEALL,
SDL_SYSTEM_CURSOR_NO,
SDL_SYSTEM_CURSOR_HAND
};
#else
constexpr Containers::StringView CursorMap[] {
"default"_s,
"text"_s,
"wait"_s,
"crosshair"_s,
"progress"_s,
"nwse-resize"_s,
"nesw-resize"_s,
"ew-resize"_s,
"ns-resize"_s,
"move"_s,
"not-allowed"_s,
"pointer"_s,
"none"_s
/* Hidden & locked not supported yet */
};
#endif
}
void Sdl2Application::setCursor(Cursor cursor) {
#ifndef CORRADE_TARGET_EMSCRIPTEN
CORRADE_ASSERT(_window, "Platform::Sdl2Application::setCursor(): no window opened", );
if(cursor == Cursor::Hidden) {
SDL_ShowCursor(SDL_DISABLE);
SDL_SetWindowGrab(_window, SDL_FALSE);
SDL_SetRelativeMouseMode(SDL_FALSE);
return;
} else if(cursor == Cursor::HiddenLocked) {
SDL_SetWindowGrab(_window, SDL_TRUE);
SDL_SetRelativeMouseMode(SDL_TRUE);
return;
} else {
SDL_ShowCursor(SDL_ENABLE);
SDL_SetWindowGrab(_window, SDL_FALSE);
SDL_SetRelativeMouseMode(SDL_FALSE);
}
/* The second condition could be a static assert but it doesn't let me
because "this pointer only accessible in a constexpr function". Thanks
for nothing, C++. */
CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(_cursors) && Containers::arraySize(_cursors) == Containers::arraySize(CursorMap));
if(!_cursors[UnsignedInt(cursor)])
_cursors[UnsignedInt(cursor)] = SDL_CreateSystemCursor(CursorMap[UnsignedInt(cursor)]);
SDL_SetCursor(_cursors[UnsignedInt(cursor)]);
#else
CORRADE_ASSERT(_surface, "Platform::Sdl2Application::setCursor(): no window opened", );
_cursor = cursor;
CORRADE_INTERNAL_ASSERT(UnsignedInt(cursor) < Containers::arraySize(CursorMap));
magnumPlatformSetCursor(CursorMap[UnsignedInt(cursor)].data(),
CursorMap[UnsignedInt(cursor)].size());
#endif
}
Sdl2Application::Cursor Sdl2Application::cursor() {
#ifndef CORRADE_TARGET_EMSCRIPTEN
if(SDL_GetRelativeMouseMode())
return Cursor::HiddenLocked;
else if(!SDL_ShowCursor(SDL_QUERY))
return Cursor::Hidden;
SDL_Cursor* cursor = SDL_GetCursor();
if(cursor) for(UnsignedInt i = 0; i < sizeof(_cursors); i++)
if(_cursors[i] == cursor) return Cursor(i);
return Cursor::Arrow;
#else
return _cursor;
#endif
}
#ifdef MAGNUM_BUILD_DEPRECATED
void Sdl2Application::setMouseLocked(bool enabled) {
/** @todo Implement this in Emscripten */
@ -1207,34 +1235,7 @@ void Sdl2Application::anyEvent(SDL_Event&) {
_flags |= Flag::NoAnyEvent;
}
void Sdl2Application::viewportEvent(ViewportEvent&) {}
void Sdl2Application::keyPressEvent(KeyEvent&) {}
void Sdl2Application::keyReleaseEvent(KeyEvent&) {}
void Sdl2Application::mousePressEvent(MouseEvent&) {}
void Sdl2Application::mouseReleaseEvent(MouseEvent&) {}
void Sdl2Application::mouseMoveEvent(MouseMoveEvent&) {}
void Sdl2Application::mouseScrollEvent(MouseScrollEvent&) {}
void Sdl2Application::multiGestureEvent(MultiGestureEvent&) {}
void Sdl2Application::textInputEvent(TextInputEvent&) {}
void Sdl2Application::textEditingEvent(TextEditingEvent&) {}
#ifdef MAGNUM_TARGET_GL
Sdl2Application::GLConfiguration::GLConfiguration():
_colorBufferSize{8, 8, 8, 8}, _depthBufferSize{24}, _stencilBufferSize{0},
_sampleCount(0)
#ifndef CORRADE_TARGET_EMSCRIPTEN
, _version{GL::Version::None}, _srgbCapable{false}
#endif
{
#ifndef MAGNUM_TARGET_GLES
addFlags(Flag::ForwardCompatible);
#endif
}
Sdl2Application::GLConfiguration::~GLConfiguration() = default;
#endif
Sdl2Application::Configuration::Configuration():
Sdl2ApplicationWindow::Configuration::Configuration():
#if !defined(CORRADE_TARGET_EMSCRIPTEN) && !defined(CORRADE_TARGET_IOS)
_title(Containers::String::nullTerminatedGlobalView("Magnum SDL2 Application"_s)),
#endif
@ -1245,38 +1246,54 @@ Sdl2Application::Configuration::Configuration():
#endif
_dpiScalingPolicy{DpiScalingPolicy::Default} {}
Sdl2Application::Configuration::~Configuration() = default;
Sdl2ApplicationWindow::Configuration::~Configuration() = default;
Containers::StringView Sdl2Application::KeyEvent::keyName(const Key key) {
Containers::StringView Sdl2ApplicationWindow::KeyEvent::keyName(const Key key) {
return SDL_GetKeyName(SDL_Keycode(key));
}
Containers::StringView Sdl2Application::KeyEvent::keyName() const {
Containers::StringView Sdl2ApplicationWindow::KeyEvent::keyName() const {
return keyName(_key);
}
Sdl2Application::InputEvent::Modifiers Sdl2Application::MouseEvent::modifiers() {
Sdl2ApplicationWindow::InputEvent::Modifiers Sdl2ApplicationWindow::MouseEvent::modifiers() {
if(_modifiers) return *_modifiers;
return *(_modifiers = fixedModifiers(Uint16(SDL_GetModState())));
}
Sdl2Application::InputEvent::Modifiers Sdl2Application::MouseMoveEvent::modifiers() {
Sdl2ApplicationWindow::InputEvent::Modifiers Sdl2ApplicationWindow::MouseMoveEvent::modifiers() {
if(_modifiers) return *_modifiers;
return *(_modifiers = fixedModifiers(Uint16(SDL_GetModState())));
}
Vector2i Sdl2Application::MouseScrollEvent::position() {
Vector2i Sdl2ApplicationWindow::MouseScrollEvent::position() {
if(_position) return *_position;
_position = Vector2i{};
SDL_GetMouseState(&_position->x(), &_position->y());
return *_position;
}
Sdl2Application::InputEvent::Modifiers Sdl2Application::MouseScrollEvent::modifiers() {
Sdl2ApplicationWindow::InputEvent::Modifiers Sdl2ApplicationWindow::MouseScrollEvent::modifiers() {
if(_modifiers) return *_modifiers;
return *(_modifiers = fixedModifiers(Uint16(SDL_GetModState())));
}
#ifdef MAGNUM_TARGET_GL
Sdl2Application::GLConfiguration::GLConfiguration():
_colorBufferSize{8, 8, 8, 8}, _depthBufferSize{24}, _stencilBufferSize{0},
_sampleCount(0)
#ifndef CORRADE_TARGET_EMSCRIPTEN
, _version{GL::Version::None}, _srgbCapable{false}
#endif
{
#ifndef MAGNUM_TARGET_GLES
addFlags(Flag::ForwardCompatible);
#endif
}
Sdl2Application::GLConfiguration::~GLConfiguration() = default;
#endif
template class BasicScreen<Sdl2Application>;
template class BasicScreenedApplication<Sdl2Application>;

973
src/Magnum/Platform/Sdl2Application.h

File diff suppressed because it is too large Load Diff

2
src/Magnum/SceneGraph/Camera.h

@ -156,7 +156,7 @@ template<UnsignedInt dimensions, class T> class Camera: public AbstractFeature<d
*
* Conversion from integer window-space coordinates with origin in top
* left corner and Y down (e.g. from
* @ref Platform::Sdl2Application::MouseEvent "Platform::*Application::MouseEvent")
* @ref Platform::Sdl2ApplicationWindow::MouseEvent "Platform::*Application::MouseEvent")
* to floating-point coordinates on near XY plane with origin at camera
* position and Y up can be done using the following snippet:
*

Loading…
Cancel
Save