From 245944afa32d73628a9025efe33372290fa4bac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 31 Jan 2018 10:36:03 +0100 Subject: Add all SDL_rect functions --- README.asciidoc | 2 +- c_src/esdl2.h | 6 ++++ c_src/sdl_rect.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/esdl2.erl | 24 +++++++++++++ src/sdl_rect.erl | 54 +++++++++++++++++++++++++++++ 5 files changed, 186 insertions(+), 1 deletion(-) diff --git a/README.asciidoc b/README.asciidoc index e3e7608..510407c 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -17,6 +17,7 @@ corresponding to the public headers. * 'SDL_mouse.h' * 'SDL_platform.h' * 'SDL_power.h' +* 'SDL_rect.h' * 'SDL_scancode.h' == Partially implemented @@ -62,7 +63,6 @@ corresponding to the public headers. ** `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_rect.h': Everything is missing except the map to point/rect conversion functions. * 'SDL_render.h': The following elements are missing: ** `SDL_TextureAccess` enum ** `SDL_TextureModulate` enum diff --git a/c_src/esdl2.h b/c_src/esdl2.h index 2cee676..d4aa683 100644 --- a/c_src/esdl2.h +++ b/c_src/esdl2.h @@ -362,6 +362,12 @@ F(get_platform, 0) \ /* sdl_power */ \ F(get_power_info, 0) \ + /* sdl_rect */ \ + F(enclose_points, 2) \ + F(has_intersection, 2) \ + F(intersect_rect, 2) \ + F(intersect_rect_and_line, 5) \ + F(union_rect, 2) \ /* sdl_renderer */ \ F(create_renderer, 3) \ F(get_num_render_drivers, 0) \ diff --git a/c_src/sdl_rect.c b/c_src/sdl_rect.c index 472cf01..ed42fdd 100644 --- a/c_src/sdl_rect.c +++ b/c_src/sdl_rect.c @@ -87,3 +87,104 @@ ERL_NIF_TERM rect_to_map(ErlNifEnv* env, const SDL_Rect* rect) return map; } + +// enclose_points + +NIF_FUNCTION(enclose_points) +{ + SDL_Point* points = NULL; + SDL_Rect clip, result; + SDL_bool b; + ERL_NIF_TERM list, head; + unsigned int count; + int i = 0; + + BADARG_IF(!enif_get_list_length(env, argv[0], &count)); + BADARG_IF(!map_to_rect(env, argv[1], &clip)); + + points = (SDL_Point*)enif_alloc(count * sizeof(SDL_Point)); + + list = argv[0]; + while (enif_get_list_cell(env, list, &head, &list)) { + if (!map_to_point(env, head, &(points[i++]))) { + enif_free(points); + return enif_make_badarg(env); + } + } + + b = SDL_EnclosePoints(points, count, &clip, &result); + + enif_free(points); + + if (!b) + return atom_false; + + return rect_to_map(env, &result); +} + +// has_intersection + +NIF_FUNCTION(has_intersection) +{ + SDL_Rect a, b; + + BADARG_IF(!map_to_rect(env, argv[0], &a)); + BADARG_IF(!map_to_rect(env, argv[1], &b)); + + if (SDL_HasIntersection(&a, &b)) + return atom_true; + + return atom_false; +} + +// intersect_rect + +NIF_FUNCTION(intersect_rect) +{ + SDL_Rect a, b, result; + + BADARG_IF(!map_to_rect(env, argv[0], &a)); + BADARG_IF(!map_to_rect(env, argv[1], &b)); + + if (!SDL_IntersectRect(&a, &b, &result)) + return atom_false; + + return rect_to_map(env, &result); +} + +// intersect_rect_and_line + +NIF_FUNCTION(intersect_rect_and_line) +{ + SDL_Rect rect; + int x1, y1, x2, y2; + + BADARG_IF(!map_to_rect(env, argv[0], &rect)); + BADARG_IF(!enif_get_int(env, argv[1], &x1)); + BADARG_IF(!enif_get_int(env, argv[2], &y1)); + BADARG_IF(!enif_get_int(env, argv[3], &x2)); + BADARG_IF(!enif_get_int(env, argv[4], &y2)); + + if (!SDL_IntersectRectAndLine(&rect, &x1, &y1, &x2, &y2)) + return atom_false; + + return enif_make_tuple4(env, + enif_make_int(env, x1), + enif_make_int(env, y1), + enif_make_int(env, x2), + enif_make_int(env, y2)); +} + +// union_rect + +NIF_FUNCTION(union_rect) +{ + SDL_Rect a, b, result; + + BADARG_IF(!map_to_rect(env, argv[0], &a)); + BADARG_IF(!map_to_rect(env, argv[1], &b)); + + SDL_UnionRect(&a, &b, &result); + + return rect_to_map(env, &result); +} diff --git a/src/esdl2.erl b/src/esdl2.erl index ae429e7..747b74e 100644 --- a/src/esdl2.erl +++ b/src/esdl2.erl @@ -114,6 +114,13 @@ %% sdl_power -export([get_power_info/0]). +%% sdl_rect +-export([enclose_points/2]). +-export([has_intersection/2]). +-export([intersect_rect/2]). +-export([intersect_rect_and_line/5]). +-export([union_rect/2]). + %% sdl_renderer -export([create_renderer/3]). -export([get_num_render_drivers/0]). @@ -487,6 +494,23 @@ get_platform() -> get_power_info() -> erlang:nif_error({not_loaded, ?MODULE}). +%% sdl_rect + +enclose_points(_, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + +has_intersection(_, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + +intersect_rect(_, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + +intersect_rect_and_line(_, _, _, _, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + +union_rect(_, _) -> + erlang:nif_error({not_loaded, ?MODULE}). + %% sdl_renderer create_renderer(_, _, _) -> diff --git a/src/sdl_rect.erl b/src/sdl_rect.erl index b747d64..b2589f5 100644 --- a/src/sdl_rect.erl +++ b/src/sdl_rect.erl @@ -12,10 +12,64 @@ %% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF %% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +%% The SDL_FORCE_INLINE functions have been reimplemented in Erlang. -module(sdl_rect). +-export([enclose_points/2]). +-export([has_intersection/2]). +-export([intersection/2]). +-export([intersection/3]). +-export([intersection/5]). +-export([is_empty/1]). +-export([is_equal/2]). +-export([is_in/2]). +-export([union/2]). + -type point() :: #{x=>integer(), y=>integer()}. -export_type([point/0]). -type rect() :: #{x=>integer(), y=>integer(), w=>integer(), h=>integer()}. -export_type([rect/0]). + +-spec enclose_points([point()], rect()) -> rect() | false. +enclose_points(Points, ClipRect) -> + esdl2:enclose_points(Points, ClipRect). + +-spec has_intersection(rect(), rect()) -> boolean(). +has_intersection(Rect1, Rect2) -> + esdl2:has_intersection(Rect1, Rect2). + +-spec intersection(rect(), rect()) -> rect() | false. +intersection(Rect1, Rect2) -> + esdl2:intersect_rect(Rect1, Rect2). + +-spec intersection(rect(), P1, P2) -> {P1, P2} | false when P1 :: point(), P2 :: point(). +intersection(Rect, #{x := X1, y := Y1}, #{x := X2, y := Y2}) -> + case intersection(Rect, X1, Y1, X2, Y2) of + false -> + false; + {ResX1, ResY1, ResX2, ResY2} -> + {#{x => ResX1, y => ResY1}, #{x => ResX2, y => ResY2}} + end. + +-spec intersection(rect(), X1, Y1, X2, Y2) -> {X1, Y1, X2, Y2} | false + when X1 :: integer(), Y1 :: integer(), X2 :: integer(), Y2 :: integer(). +intersection(Rect, X1, Y1, X2, Y2) -> + esdl2:intersect_rect_and_line(Rect, X1, Y1, X2, Y2). + +-spec is_empty(rect()) -> boolean(). +is_empty(#{w := W, h := H}) -> + (W =< 0) orelse (H =< 0). + +-spec is_equal(rect(), rect()) -> boolean(). +is_equal(Rect1, Rect2) -> + Rect1 =:= Rect2. + +-spec is_in(point(), rect()) -> boolean(). +is_in(#{x := PX, y := PY}, #{x := RX, y := RY, w := RW, h := RH}) -> + (PX >= RX) andalso (PX < RX + RW) + andalso (PY >= RY) andalso (PY < RY + RH). + +-spec union(rect(), rect()) -> rect(). +union(Rect1, Rect2) -> + esdl2:union_rect(Rect1, Rect2). -- cgit v1.2.3