SDL2 Erlang NIF.
This project tries to implement SDL2 and some of its extensions in one convenient NIF. The supported versions and features are listed below.
SDL >= 2.0.5
SDL_image 2.0.3
SDL_ttf 2.0.14
The implementation is cut into sections corresponding to the public headers.
'SDL.h'
'SDL_blendmode.h'
'SDL_clipboard.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'
'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': Erlang does not come with the functions copysign and scalbn.
'SDL_surface.h': Only surface creation (via IMG_Load) and destruction is implemented. Might be better to move IMG_* functions in their own space.
Everything in this header can be implemented as simple functions (as opposed to cast/call).
We’ll need to add functions to retrieve the pixel format and possibly pitch (though format+dimensions is enough to get it).
We’ll need to add extra functions for direct access to the pixels.
'SDL_ttf.h':
A function to obtain the SDL_ttf version could be useful
TTF_Linked_Version (if it makes sense, depends on how the library is loaded)
TTF_OpenFontRW (unclear if we need it)
TTF_OpenFontIndexRW (unclear if we need it)
'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
SDL_GetWindowSurface (window)
SDL_UpdateWindowSurface (window)
SDL_UpdateWindowSurfaceRects (window)
'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'
Other SDL extensions need to be investigated and implemented. We definitely want at least some of SDL_image and SDL_mixer. We probably do not need SDL_net or SDL_rtf.
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'
SDL_SetMainReady which has no public interface, only the NIF function.
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_stdinc.h': only a few functions are implemented, others are not interesting.
'SDL_thread.h'
'SDL_ttf.h': the rendering functions for Text and UNICODE are not interesting because they internally call the UTF8 functions so we may as well provide utf8-encoded binaries directly. The TTF_ByteSwappedUNICODE also falls in this category and is not provided.
'SDL_video.h': the functions SDL_CreateWindowFrom, SDL_SetWindowData and SDL_GetWindowData take external data as argument.
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'
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.
174 commits
C
58.5%
Erlang
41.0%
SDL2 Erlang NIF.
This project tries to implement SDL2 and some of its extensions in one convenient NIF. The supported versions and features are listed below.
SDL >= 2.0.5
SDL_image 2.0.3
SDL_ttf 2.0.14
The implementation is cut into sections corresponding to the public headers.
'SDL.h'
'SDL_blendmode.h'
'SDL_clipboard.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'
'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': Erlang does not come with the functions copysign and scalbn.
'SDL_surface.h': Only surface creation (via IMG_Load) and destruction is implemented. Might be better to move IMG_* functions in their own space.
Everything in this header can be implemented as simple functions (as opposed to cast/call).
We’ll need to add functions to retrieve the pixel format and possibly pitch (though format+dimensions is enough to get it).
We’ll need to add extra functions for direct access to the pixels.
'SDL_ttf.h':
A function to obtain the SDL_ttf version could be useful
TTF_Linked_Version (if it makes sense, depends on how the library is loaded)
TTF_OpenFontRW (unclear if we need it)
TTF_OpenFontIndexRW (unclear if we need it)
'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
SDL_GetWindowSurface (window)
SDL_UpdateWindowSurface (window)
SDL_UpdateWindowSurfaceRects (window)
'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'
Other SDL extensions need to be investigated and implemented. We definitely want at least some of SDL_image and SDL_mixer. We probably do not need SDL_net or SDL_rtf.
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'
SDL_SetMainReady which has no public interface, only the NIF function.
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_stdinc.h': only a few functions are implemented, others are not interesting.
'SDL_thread.h'
'SDL_ttf.h': the rendering functions for Text and UNICODE are not interesting because they internally call the UTF8 functions so we may as well provide utf8-encoded binaries directly. The TTF_ByteSwappedUNICODE also falls in this category and is not provided.
'SDL_video.h': the functions SDL_CreateWindowFrom, SDL_SetWindowData and SDL_GetWindowData take external data as argument.
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'
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.
174 commits
C
58.5%
Erlang
41.0%