= ESDL2

SDL2 Erlang NIF.

The following sections list the state of the implementation
as of SDL 2.0.7. The implementation is cut into sections
corresponding to the public headers.

== Fully implemented

* 'SDL.h'
* 'SDL_blendmode.h'
* 'SDL_cpuinfo.h'
* 'SDL_filesystem.h'
* 'SDL_keyboard.h'
* 'SDL_keycode.h'
* 'SDL_mouse.h'
* 'SDL_platform.h'
* 'SDL_power.h'
* 'SDL_rect.h'
* 'SDL_scancode.h'

== Partially implemented

* 'SDL_clipboard.h': We currently do not support UTF-8. We should probably switch to binaries as input/output to support it.
* 'SDL_events.h': The following events and functions are missing:
** `SDL_SYSWMEVENT`
** `SDL_TEXTEDITING`
** `SDL_TEXTINPUT`
** `SDL_JOYAXISMOTION`
** `SDL_JOYBALLMOTION`
** `SDL_JOYHATMOTION`
** `SDL_JOYBUTTONDOWN`
** `SDL_JOYBUTTONUP`
** `SDL_JOYDEVICEADDED`
** `SDL_JOYDEVICEREMOVED`
** `SDL_CONTROLLERAXISMOTION`
** `SDL_CONTROLLERBUTTONDOWN`
** `SDL_CONTROLLERBUTTONUP`
** `SDL_CONTROLLERDEVICEADDED`
** `SDL_CONTROLLERDEVICEREMOVED`
** `SDL_CONTROLLERDEVICEREMAPPED`
** `SDL_FINGERDOWN`
** `SDL_FINGERUP`
** `SDL_FINGERMOTION`
** `SDL_DOLLARGESTURE`
** `SDL_DOLLARRECORD`
** `SDL_MULTIGESTURE`
** `SDL_DROPFILE`
** `SDL_DROPTEXT`
** `SDL_DROPBEGIN`
** `SDL_DROPCOMPLETE`
** `SDL_AUDIODEVICEADDED`
** `SDL_AUDIODEVICEREMOVED`
** `SDL_PeepEvents` with action argument `SDL_ADDEVENT`
** `SDL_PushEvents`
** `SDL_SetEventFilter`
** `SDL_GetEventFilter`
** `SDL_AddEventWatch`
** `SDL_DelEventWatch`
** `SDL_FilterEvents`
** `SDL_EventState` and `SDL_GetEventState`
** `SDL_RegisterEvents`
* 'SDL_hints.h': We only have a proof of concept callback system.
* 'SDL_pixels.h': Only the pixel format enum and conversion function is defined.
* 'SDL_render.h': The following elements are missing:
** `SDL_TextureAccess` enum
** `SDL_TextureModulate` enum
** `SDL_CreateWindowAndRenderer` is currently located in `sdl_window`. Move it?
** `SDL_CreateSoftwareRenderer` (renderer)
** `SDL_CreateTexture` (texture)
** `SDL_QueryTexture` (texture)
** `SDL_UpdateTexture` (texture)
** `SDL_UpdateYUVTexture` (texture)
** `SDL_LockTexture` (texture)
** `SDL_UnlockTexture` (texture)
** `SDL_SetRenderTarget` (renderer)
** `SDL_GetRenderTarget` (renderer)
** `SDL_RenderIsClipEnabled` (renderer)
** `SDL_RenderReadPixels` (renderer)
* 'SDL_stdinc.h': SDL_bool is implemented in 'sdl_bool.c'. Do we need anything else?
* 'SDL_surface.h': Only surface creation (via `IMG_Load`) and destruction is implemented. Might be better to move IMG_* functions in their own space.
* 'SDL_version.h': `SDL_GetRevisionNumber` must be implemented. The macros may also be useful.
* 'SDL_video.h': The following elements are missing:
** `SDL_WINDOWPOS_*` values for different displays
** We currently do not support UTF-8. We should probably switch to binaries as input/output to support it for `SDL_SetWindowTitle` and `SDL_GetWindowTitle`
** `SDL_GetWindowSurface` (window)
** `SDL_UpdateWindowSurface` (window)
** `SDL_UpdateWindowSurfaceRects` (window)

The code sometimes uses `malloc`. Use `enif_alloc` everywhere instead.

== To be implemented

* 'SDL_audio.h'
* 'SDL_error.h' (for completion)
* 'SDL_gamecontroller.h'
* 'SDL_gesture.h'
* 'SDL_haptic.h'
* 'SDL_joystick.h'
* 'SDL_messagebox.h'
* 'SDL_rwops.h' (unclear if we need it)
* 'SDL_shape.h'
* 'SDL_system.h'
* 'SDL_syswm.h'
* 'SDL_timer.h' (unclear if we need it)
* 'SDL_touch.h'

SDL extensions also need to be investigated and implemented.
We definitely want at least some of SDL_image, SDL_mixer
and SDL_ttf. We probably do not need SDL_net or SDL_rtf.

== OpenGL and Vulkan

For OpenGL we need to figure out whether we can call the functions from
wxErlang. If we can, great! If not, find an automated way to provide
access to OpenGL.

The following functions are related to OpenGL and Vulkan and still
need to be implemented:

* 'SDL_render.h':
** `SDL_GL_BindTexture`
** `SDL_GL_UnbindTexture`
* 'SDL_video.h':
** `SDL_GL_LoadLibrary` (unclear if we need it)
** `SDL_GL_GetProcAddress` (unclear if we need it)
** `SDL_GL_UnloadLibrary` (unclear if we need it)
** `SDL_GL_ExtensionSupported`
** `SDL_GL_ResetAttributes`
** `SDL_GL_SetAttribute`
** `SDL_GL_GetAttribute`
** `SDL_GL_MakeCurrent`
** `SDL_GL_GetCurrentWindow`
** `SDL_GL_GetCurrentContext`
** `SDL_GL_GetDrawableSize`
** `SDL_GL_SetSwapInterval`
** `SDL_GL_GetSwapInterval`
* 'SDL_vulkan.h'

== To be removed

* `SDL_SetMainReady` which has no public interface, only the NIF function.

== Don't implement

These don't make a lot of sense for Erlang.

* 'SDL_assert.h'
* 'SDL_atomic.h'
* 'SDL_bits.h'
* 'SDL_endian.h'
* 'SDL_events.h': the functions `SDL_WaitEvent` and `SDL_WaitEventTimeout` are blocking.
* 'SDL_loadso.h'
* 'SDL_log.h'
* 'SDL_main.h'
* 'SDL_mutex.h'
* 'SDL_quit.h' (only necessary when using `SDL_Main`?)
* 'SDL_thread.h'
* 'SDL_video.h': the functions `SDL_CreateWindowFrom`, `SDL_SetWindowData` and `SDL_GetWindowData` take external data as argument.

== Nothing to implement

These are either private headers, duplicated OpenGL/Vulkan
headers or simply deprecated.

* 'SDL_config.h'
* 'SDL_config_android.h'
* 'SDL_config_iphoneos.h'
* 'SDL_config_macosx.h'
* 'SDL_config_minimal.h'
* 'SDL_config_pandora.h'
* 'SDL_config_psp.h'
* 'SDL_config_windows.h'
* 'SDL_config_winrt.h'
* 'SDL_config_wiz.h'
* 'SDL_copying.h'
* 'SDL_egl.h'
* 'SDL_name.h'
* 'SDL_opengl.h'
* 'SDL_opengl_glext.h'
* 'SDL_opengles.h'
* 'SDL_opengles2.h'
* 'SDL_opengles2_gl2.h'
* 'SDL_opengles2_gl2ext.h'
* 'SDL_opengles2_gl2platform.h'
* 'SDL_opengles2_khrplatform.h'
* 'SDL_revision.h'
* 'SDL_test.h'
* 'SDL_test_assert.h'
* 'SDL_test_common.h'
* 'SDL_test_compare.h'
* 'SDL_test_crc32.h'
* 'SDL_test_font.h'
* 'SDL_test_fuzzer.h'
* 'SDL_test_harness.h'
* 'SDL_test_images.h'
* 'SDL_test_log.h'
* 'SDL_test_md5.h'
* 'SDL_test_memory.h'
* 'SDL_test_random.h'
* 'SDL_types.h'
* 'begin_code.h'
* 'close_code.h'

== Thoughts on callbacks

SDL2 has a number of callback interfaces. While we probably
do not want to implement some of them (like the OS-specific
callbacks for Windows and iOS) we do need others.

Callbacks that have no return value are easy to implement.
The idea is to have an Erlang process that waits for messages
containing the callback MFA to execute. The following callbacks
have no return value and no other caveat:

* `SDL_AudioCallback`
* `SDL_iOSSetAnimationCallback` (iOS)
* `SDL_SetWindowsMessageHook` (Windows)

The callback functions for hints do not have a return value
either, but they have an extra caveat: there can be more
than one per hint. SDL2 identifies these callbacks with the
tuple `(callback, userdata)` and we need to give SDL2 this
same tuple in order to remove the callback.

The best way to handle this is probably to do it mostly via
Erlang where a process would take care of the callbacks and
would enable/disable the SDL2 callbacks when required. The
`userdata` would in this case always be `NULL` since all the
handling would be done from the Erlang side.

The alternative would be to create a resource per callback
that the user would have to keep around and that's not very
convenient.

The functions in question are:

* `SDL_AddHintCallback`
* `SDL_DelHintCallback`

Other callbacks have a return value but otherwise work in a
slightly different manner from each other. The callback can
be invoked in a similar manner to others, by sending a message
to the Erlang code. The difficulty comes in returning the
result to the NIF code. The solution for doing that
will vary depending on the callback in question.

There can be one window hit test callback per window. This
means we can use the window's user data for storing the
result and then signal the NIF to read from it using the
NIF mutex/cond mechanism. Both of those can also be stored
in the window's user data.

This means the window must be sent to Erlang and passed
back to the NIF when giving the result back, which should
be trivial. The callback data can stay empty since we
store everything in the window data.

The function in question is:

* `SDL_SetWindowHitTest`

The final set of callbacks is timers. When you add a timer
it returns a `TimerID` and you can use it to remove the
timer. In addition, the callback can decide to change the
timer interval or to stop the timer. Unlike for windows
there is no way to attach information to a `TimerID` so
a separate solution will be necessary. Since there can
be any number of timers and they can fire off at any
time then some kind of queue will be necessary to store
return values.

Even though we don't know the `TimerID` when setting up
the timer, we should be able to keep it around in the
same data structure used for the callback extra parameter.
There is however the concern of memory allocation: we
will probably need to hook into all functions that can
remove timers to make sure we free the memory we allocated
too.

They're the hardest callback functions to implement, but
thankfully they're also some of the least interesting
considering Erlang already comes with many ways to deal
with timers.

Even if we do implement them, their scope may be reduced
so that we always return the same interval as a return
value and therefore don't allow changing the interval or
stopping the timer from inside a timer callback.

The functions in question are:

* `SDL_AddTimer`
* `SDL_RemoveTimer`

Other than hints, it should be possible to have a common
mechanism for all callbacks. The following messages may
be sent from the NIF:

* `{callback, M, F, Args}` for `void`
* `{callback, M, F, Args, ResF, ResExtraArg}` for others

The `esdl2:ResF(Result, ResExtraArg)` function would be
called in the second case after the callback returns.
The NIF function can then decide what the appropriate
behavior is for sending the result back to the SDL2
callback.

The main concern when dealing with SDL2 callbacks is
the memory allocations since SDL2 will not free the
memory we allocate. Solutions should be extra careful
not to introduce leaks and try to avoid allocating
memory entirely for callbacks. When not possible then
the memory must be allocated and freed in the course
of running the Erlang callback and not be kept any
longer.
