From b0950785e72d9d59c6fd816c01d203ecb083c663 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 20 Dec 2017 20:03:16 +0100 Subject: Add the sdl_mouse module implementing half of sdl_mouse.h The latter half will be part of sdl_cursor. This depends on some changes to nif_helper. The sdl_gl part of the code is probably slithly broken now, the dependency on the window is gone. This will be resolved later on. --- c_src/esdl2.c | 4 + c_src/esdl2.h | 37 ++++++++ c_src/esdl2_renderers.c | 104 ++++++++++++++++++++++ c_src/esdl2_windows.c | 97 +++++++++++++++++++++ c_src/sdl_gl.c | 5 +- c_src/sdl_mouse.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++ c_src/sdl_renderer.c | 12 ++- c_src/sdl_window.c | 14 ++- 8 files changed, 488 insertions(+), 9 deletions(-) create mode 100644 c_src/esdl2_renderers.c create mode 100644 c_src/esdl2_windows.c create mode 100644 c_src/sdl_mouse.c (limited to 'c_src') diff --git a/c_src/esdl2.c b/c_src/esdl2.c index 1790dd7..82bea2d 100644 --- a/c_src/esdl2.c +++ b/c_src/esdl2.c @@ -27,6 +27,8 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) *priv_data = nif_create_main_thread("esdl2"); + esdl2_windows_init(); + loads++; return 0; @@ -46,6 +48,8 @@ static void unload(ErlNifEnv* env, void* priv_data) if (loads == 1) nif_destroy_main_thread(priv_data); + esdl2_windows_free(); + loads--; } diff --git a/c_src/esdl2.h b/c_src/esdl2.h index 10508ff..ca9a424 100644 --- a/c_src/esdl2.h +++ b/c_src/esdl2.h @@ -23,6 +23,7 @@ A(accelerated) \ A(add) \ A(allow_high_dpi) \ + A(arrow) \ A(audio) \ A(blend) \ A(borderless) \ @@ -34,6 +35,7 @@ A(charging) \ A(clicks) \ A(close) \ + A(crosshair) \ A(data) \ A(enter) \ A(error) \ @@ -42,6 +44,7 @@ A(everything) \ A(exposed) \ A(false) \ + A(flipped) \ A(focus_gained) \ A(focus_lost) \ A(foreign) \ @@ -49,9 +52,11 @@ A(fullscreen_desktop) \ A(game_controller) \ A(h) \ + A(hand) \ A(haptic) \ A(hidden) \ A(horizontal) \ + A(ibeam) \ A(input_focus) \ A(input_grabbed) \ A(joystick) \ @@ -69,14 +74,17 @@ A(minimized) \ A(mod) \ A(mode) \ + A(mouse_capture) \ A(mouse_down) \ A(mouse_focus) \ A(mouse_motion) \ A(mouse_up) \ A(mouse_wheel) \ A(moved) \ + A(no) \ A(no_battery) \ A(none) \ + A(normal) \ A(num) \ A(on_battery) \ A(opengl) \ @@ -93,7 +101,12 @@ A(right_shift) \ A(scancode) \ A(shown) \ + A(size_all) \ A(size_changed) \ + A(size_nesw) \ + A(size_ns) \ + A(size_nwse) \ + A(size_we) \ A(software) \ A(state) \ A(sym) \ @@ -108,6 +121,8 @@ A(vertical) \ A(video) \ A(w) \ + A(wait) \ + A(wait_arrow) \ A(which) \ A(window) \ A(window_id) \ @@ -175,6 +190,16 @@ F(is_text_input_active, 0) \ F(start_text_input, 0) \ F(stop_text_input, 0) \ + /* sdl_mouse */ \ + F(capture_mouse, 1) \ + F(get_global_mouse_state, 0) \ + F(get_mouse_focus, 0) \ + F(get_mouse_state, 0) \ + F(get_relative_mouse_mode, 0) \ + F(get_relative_mouse_state, 0) \ + F(set_relative_mouse_mode, 1) \ + F(warp_mouse_global, 2) \ + F(warp_mouse_in_window, 3) \ /* sdl_power */ \ F(get_power_info, 0) \ /* sdl_renderer */ \ @@ -265,6 +290,18 @@ NIF_ENUM_TO_ATOM_FUNCTION_DECL(blend_mode_to_atom, SDL_BlendMode) // -- +void esdl2_windows_init(void); +void esdl2_windows_insert(SDL_Window*, obj_Window*); +ERL_NIF_TERM esdl2_windows_find(ErlNifEnv*, SDL_Window*); +void esdl2_windows_remove(SDL_Window*); +void esdl2_windows_free(void); + +void esdl2_renderers_init(void); +void esdl2_renderers_insert(SDL_Renderer*, obj_Renderer*, obj_Window*); +ERL_NIF_TERM esdl2_renderers_find(ErlNifEnv*, SDL_Renderer*); +void esdl2_renderers_remove(SDL_Renderer*); +void esdl2_renderers_free(void); + ErlNifPid* get_callback_process(void); #define sdl_error_tuple(env) \ diff --git a/c_src/esdl2_renderers.c b/c_src/esdl2_renderers.c new file mode 100644 index 0000000..281079c --- /dev/null +++ b/c_src/esdl2_renderers.c @@ -0,0 +1,104 @@ +// Copyright (c) 2017, Loïc Hoguin +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "esdl2.h" +#include + +struct esdl2_renderer { + LIST_ENTRY(esdl2_renderer) entries; + + SDL_Renderer* renderer; + obj_Renderer* res; + obj_Window* window_res; +}; + +static LIST_HEAD(esdl2_renderer_list, esdl2_renderer) renderers; + +void esdl2_renderers_init() +{ + LIST_INIT(&renderers); +} + +void esdl2_renderers_insert(SDL_Renderer* renderer, obj_Renderer* res, obj_Window* window_res) +{ + struct esdl2_renderer* item; + + item = malloc(sizeof(struct esdl2_renderer)); + item->renderer = renderer; + item->res = res; + item->window_res = window_res; + + enif_keep_resource(window_res); + + LIST_INSERT_HEAD(&renderers, item, entries); +} + +struct esdl2_renderer* esdl2_renderers_find_entry(SDL_Renderer* renderer); + +struct esdl2_renderer* esdl2_renderers_find_entry(SDL_Renderer* renderer) +{ + struct esdl2_renderer* head; + + head = LIST_FIRST(&renderers); + while (head != NULL) { + if (head->renderer == renderer) + return head; + + head = LIST_NEXT(head, entries); + } + + return NULL; +} + +ERL_NIF_TERM esdl2_renderers_find(ErlNifEnv* env, SDL_Renderer* renderer) +{ + struct esdl2_renderer* entry; + ERL_NIF_TERM term; + + entry = esdl2_renderers_find_entry(renderer); + + if (entry == NULL) + return atom_undefined; + + term = enif_make_resource(env, entry->res); + + return term; +} + +void esdl2_renderers_remove(SDL_Renderer* renderer) +{ + struct esdl2_renderer* entry; + + entry = esdl2_renderers_find_entry(renderer); + + if (entry == NULL) + return; + + enif_release_resource(entry->window_res); + + LIST_REMOVE(entry, entries); +} + +void esdl2_renderers_free() +{ + struct esdl2_renderer *head, *next; + + head = LIST_FIRST(&renderers); + while (head != NULL) { + next = LIST_NEXT(head, entries); + free(head); + head = next; + } +} + diff --git a/c_src/esdl2_windows.c b/c_src/esdl2_windows.c new file mode 100644 index 0000000..8855987 --- /dev/null +++ b/c_src/esdl2_windows.c @@ -0,0 +1,97 @@ +// Copyright (c) 2017, Loïc Hoguin +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "esdl2.h" +#include + +struct esdl2_window { + LIST_ENTRY(esdl2_window) entries; + + SDL_Window* window; + obj_Window* res; +}; + +static LIST_HEAD(esdl2_window_list, esdl2_window) windows; + +void esdl2_windows_init() +{ + LIST_INIT(&windows); +} + +void esdl2_windows_insert(SDL_Window* window, obj_Window* res) +{ + struct esdl2_window* item; + + item = malloc(sizeof(struct esdl2_window)); + item->window = window; + item->res = res; + + LIST_INSERT_HEAD(&windows, item, entries); +} + +struct esdl2_window* esdl2_windows_find_entry(SDL_Window* window); + +struct esdl2_window* esdl2_windows_find_entry(SDL_Window* window) +{ + struct esdl2_window* head; + + head = LIST_FIRST(&windows); + while (head != NULL) { + if (head->window == window) + return head; + + head = LIST_NEXT(head, entries); + } + + return NULL; +} + +ERL_NIF_TERM esdl2_windows_find(ErlNifEnv* env, SDL_Window* window) +{ + struct esdl2_window* entry; + ERL_NIF_TERM term; + + entry = esdl2_windows_find_entry(window); + + if (entry == NULL) + return atom_undefined; + + term = enif_make_resource(env, entry->res); + + return term; +} + +void esdl2_windows_remove(SDL_Window* window) +{ + struct esdl2_window* entry; + + entry = esdl2_windows_find_entry(window); + + if (entry == NULL) + return; + + LIST_REMOVE(entry, entries); +} + +void esdl2_windows_free() +{ + struct esdl2_window *head, *next; + + head = LIST_FIRST(&windows); + while (head != NULL) { + next = LIST_NEXT(head, entries); + free(head); + head = next; + } +} diff --git a/c_src/sdl_gl.c b/c_src/sdl_gl.c index febd49f..71fef6a 100644 --- a/c_src/sdl_gl.c +++ b/c_src/sdl_gl.c @@ -17,7 +17,7 @@ void dtor_GLContext(ErlNifEnv* env, void* obj) { SDL_GL_DeleteContext(NIF_RES_GET(GLContext, obj)); - enif_release_resource(NIF_RES_DEP(GLContext, obj)); +// @todo enif_release_resource(NIF_RES_DEP(GLContext, obj)); } // gl_create_context @@ -33,7 +33,8 @@ NIF_CALL_HANDLER(thread_gl_create_context) enif_keep_resource(args[0]); - NIF_RES_TO_TERM_WITH_DEP(GLContext, context, term, args[0]); +// @todo NIF_RES_TO_TERM_WITH_DEP(GLContext, context, term, args[0]); + NIF_RES_TO_TERM(GLContext, context, term); return enif_make_tuple2(env, atom_ok, diff --git a/c_src/sdl_mouse.c b/c_src/sdl_mouse.c new file mode 100644 index 0000000..b74d088 --- /dev/null +++ b/c_src/sdl_mouse.c @@ -0,0 +1,224 @@ +// Copyright (c) 2017, Loïc Hoguin +// +// Permission to use, copy, modify, and/or distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +#include "esdl2.h" + +#define SYSTEM_CURSOR_ENUM(E) \ + E(arrow, SDL_SYSTEM_CURSOR_ARROW) \ + E(ibeam, SDL_SYSTEM_CURSOR_IBEAM) \ + E(wait, SDL_SYSTEM_CURSOR_WAIT) \ + E(crosshair, SDL_SYSTEM_CURSOR_CROSSHAIR) \ + E(wait_arrow, SDL_SYSTEM_CURSOR_WAITARROW) \ + E(size_nwse, SDL_SYSTEM_CURSOR_SIZENWSE) \ + E(size_nesw, SDL_SYSTEM_CURSOR_SIZENESW) \ + E(size_we, SDL_SYSTEM_CURSOR_SIZEWE) \ + E(size_ns, SDL_SYSTEM_CURSOR_SIZENS) \ + E(size_all, SDL_SYSTEM_CURSOR_SIZEALL) \ + E(no, SDL_SYSTEM_CURSOR_NO) \ + E(hand, SDL_SYSTEM_CURSOR_HAND) + +static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_system_cursor, int, SYSTEM_CURSOR_ENUM) + +#define MOUSEWHEEL_DIRECTION_ENUM(E) \ + E(normal, SDL_MOUSEWHEEL_NORMAL) \ + E(flipped, SDL_MOUSEWHEEL_FLIPPED) + +static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_mousewheel_direction, int, MOUSEWHEEL_DIRECTION_ENUM) + +static ERL_NIF_TERM get_mouse_state_common(ErlNifEnv* env, int x, int y, Uint32 state) +{ + ERL_NIF_TERM list; + + list = enif_make_list(env, 0); + + if (state & SDL_BUTTON_LMASK) + list = enif_make_list_cell(env, atom_left, list); + if (state & SDL_BUTTON_MMASK) + list = enif_make_list_cell(env, atom_middle, list); + if (state & SDL_BUTTON_RMASK) + list = enif_make_list_cell(env, atom_right, list); + if (state & SDL_BUTTON_X1MASK) + list = enif_make_list_cell(env, atom_x1, list); + if (state & SDL_BUTTON_X2MASK) + list = enif_make_list_cell(env, atom_x2, list); + + return enif_make_tuple3(env, + enif_make_int(env, x), + enif_make_int(env, y), + list + ); +} + +// capture_mouse + +NIF_CALL_HANDLER(thread_capture_mouse) +{ + if (SDL_CaptureMouse((long)args[0])) + return sdl_error_tuple(env); + + return atom_ok; +} + +NIF_FUNCTION(capture_mouse) +{ + SDL_bool b; + + BADARG_IF(!atom_to_bool(env, argv[0], &b)); + + return nif_thread_call(env, thread_capture_mouse, 1, b); +} + +// get_global_mouse_state + +NIF_CALL_HANDLER(thread_get_global_mouse_state) +{ + Uint32 state; + int x, y; + + state = SDL_GetGlobalMouseState(&x, &y); + + return get_mouse_state_common(env, x, y, state); +} + +NIF_FUNCTION(get_global_mouse_state) +{ + return nif_thread_call(env, thread_get_global_mouse_state, 0); +} + +// get_mouse_focus + +NIF_CALL_HANDLER(thread_get_mouse_focus) +{ + SDL_Window* window; + + window = SDL_GetMouseFocus(); + + if (!window) + return atom_undefined; + + return esdl2_windows_find(env, window); +} + +NIF_FUNCTION(get_mouse_focus) +{ + return nif_thread_call(env, thread_get_mouse_focus, 0); +} + +// get_mouse_state + +NIF_CALL_HANDLER(thread_get_mouse_state) +{ + Uint32 state; + int x, y; + + state = SDL_GetMouseState(&x, &y); + + return get_mouse_state_common(env, x, y, state); +} + +NIF_FUNCTION(get_mouse_state) +{ + return nif_thread_call(env, thread_get_mouse_state, 0); +} + +// get_relative_mouse_mode + +NIF_CALL_HANDLER(thread_get_relative_mouse_mode) +{ + if (SDL_GetRelativeMouseMode()) + return atom_true; + + return atom_false; +} + +NIF_FUNCTION(get_relative_mouse_mode) +{ + return nif_thread_call(env, thread_get_relative_mouse_mode, 0); +} + +// get_relative_mouse_state + +NIF_CALL_HANDLER(thread_get_relative_mouse_state) +{ + Uint32 state; + int x, y; + + state = SDL_GetRelativeMouseState(&x, &y); + + return get_mouse_state_common(env, x, y, state); +} + +NIF_FUNCTION(get_relative_mouse_state) +{ + return nif_thread_call(env, thread_get_relative_mouse_state, 0); +} + +// set_relative_mouse_mode + +NIF_CALL_HANDLER(thread_set_relative_mouse_mode) +{ + if (SDL_SetRelativeMouseMode((long)args[0])) + return sdl_error_tuple(env); + + return atom_ok; +} + +NIF_FUNCTION(set_relative_mouse_mode) +{ + SDL_bool b; + + BADARG_IF(!atom_to_bool(env, argv[0], &b)); + + return nif_thread_call(env, thread_set_relative_mouse_mode, 1, b); +} + +// warp_mouse_global + +NIF_CALL_HANDLER(thread_warp_mouse_global) +{ + if (SDL_WarpMouseGlobal((long)args[0], (long)args[1])) + return sdl_error_tuple(env); + + return atom_ok; +} + +NIF_FUNCTION(warp_mouse_global) +{ + int x, y; + + BADARG_IF(!enif_get_int(env, argv[0], &x)); + BADARG_IF(!enif_get_int(env, argv[1], &y)); + + return nif_thread_call(env, thread_warp_mouse_global, 2, x, y); +} + +// warp_mouse_in_window + +NIF_CAST_HANDLER(thread_warp_mouse_in_window) +{ + SDL_WarpMouseInWindow(args[0], (long)args[1], (long)args[2]); +} + +NIF_FUNCTION(warp_mouse_in_window) +{ + void* window_res; + int x, y; + + BADARG_IF(!enif_get_resource(env, argv[0], res_Window, &window_res)); + BADARG_IF(!enif_get_int(env, argv[1], &x)); + BADARG_IF(!enif_get_int(env, argv[2], &y)); + + return nif_thread_cast(env, thread_warp_mouse_in_window, 3, + NIF_RES_GET(Window, window_res), x, y); +} diff --git a/c_src/sdl_renderer.c b/c_src/sdl_renderer.c index 5344199..81e60c4 100644 --- a/c_src/sdl_renderer.c +++ b/c_src/sdl_renderer.c @@ -16,8 +16,10 @@ void dtor_Renderer(ErlNifEnv* env, void* obj) { - SDL_DestroyRenderer(NIF_RES_GET(Renderer, obj)); - enif_release_resource(NIF_RES_DEP(Renderer, obj)); + SDL_Renderer* renderer = NIF_RES_GET(Renderer, obj); + + SDL_DestroyRenderer(renderer); + esdl2_renderers_remove(renderer); } #define RENDERER_FLAGS(F) \ @@ -91,14 +93,16 @@ static int map_to_rect(ErlNifEnv* env, ERL_NIF_TERM map, SDL_Rect* rect) NIF_CALL_HANDLER(thread_create_renderer) { SDL_Renderer* renderer; + obj_Renderer* res; ERL_NIF_TERM term; renderer = SDL_CreateRenderer(NIF_RES_GET(Window, args[0]), (long)args[1], (long)args[2]); if (!renderer) return sdl_error_tuple(env); - enif_keep_resource(args[0]); - NIF_RES_TO_TERM_WITH_DEP(Renderer, renderer, term, args[0]); + NIF_RES_TO_PTR_AND_TERM(Renderer, renderer, res, term); + + esdl2_renderers_insert(renderer, res, args[0]); return enif_make_tuple2(env, atom_ok, diff --git a/c_src/sdl_window.c b/c_src/sdl_window.c index ef3647b..c286da0 100644 --- a/c_src/sdl_window.c +++ b/c_src/sdl_window.c @@ -14,9 +14,13 @@ #include "esdl2.h" +// @todo These operations should probably occur in the thread. void dtor_Window(ErlNifEnv* env, void* obj) { - SDL_DestroyWindow(NIF_RES_GET(Window, obj)); + SDL_Window* window = NIF_RES_GET(Window, obj); + + SDL_DestroyWindow(window); + esdl2_windows_remove(window); } #define WINDOW_FLAGS(F) \ @@ -33,7 +37,8 @@ void dtor_Window(ErlNifEnv* env, void* obj) F(input_focus, SDL_WINDOW_INPUT_FOCUS) \ F(mouse_focus, SDL_WINDOW_MOUSE_FOCUS) \ F(foreign, SDL_WINDOW_FOREIGN) \ - F(allow_high_dpi, SDL_WINDOW_ALLOW_HIGHDPI) + F(allow_high_dpi, SDL_WINDOW_ALLOW_HIGHDPI) \ + F(mouse_capture, SDL_WINDOW_MOUSE_CAPTURE) static NIF_LIST_TO_FLAGS_FUNCTION(list_to_window_flags, Uint32, WINDOW_FLAGS) static NIF_FLAGS_TO_LIST_FUNCTION(window_flags_to_list, Uint32, WINDOW_FLAGS) @@ -56,6 +61,7 @@ static NIF_ATOM_TO_ENUM_FUNCTION(atom_to_window_fullscreen, Uint32, WINDOW_FULLS NIF_CALL_HANDLER(thread_create_window) { SDL_Window* window; + obj_Window* res; ERL_NIF_TERM term; window = SDL_CreateWindow(args[0], (long)args[1], (long)args[2], (long)args[3], (long)args[4], (long)args[5]); @@ -65,7 +71,9 @@ NIF_CALL_HANDLER(thread_create_window) if (!window) return sdl_error_tuple(env); - NIF_RES_TO_TERM(Window, window, term); + NIF_RES_TO_PTR_AND_TERM(Window, window, res, term); + + esdl2_windows_insert(window, res); return enif_make_tuple2(env, atom_ok, -- cgit v1.2.3