// Copyright (c) 2018, 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" ERL_NIF_TERM display_mode_to_map(ErlNifEnv* env, SDL_DisplayMode* mode) { ERL_NIF_TERM map; map = enif_make_new_map(env); enif_make_map_put(env, map, atom_format, pixel_format_to_atom(mode->format), &map); enif_make_map_put(env, map, atom_w, enif_make_int(env, mode->w), &map); enif_make_map_put(env, map, atom_h, enif_make_int(env, mode->h), &map); enif_make_map_put(env, map, atom_refresh_rate, enif_make_int(env, mode->refresh_rate), &map); // There is also a driverdata field but it is unclear whether it has any use. return map; } // get_closest_display_mode NIF_CALL_HANDLER(thread_get_closest_display_mode) { SDL_DisplayMode mode, closest; mode.format = (long)args[1]; mode.w = (long)args[2]; mode.h = (long)args[3]; mode.refresh_rate = (long)args[4]; if (!SDL_GetClosestDisplayMode((long)args[0], &mode, &closest)) return atom_undefined; return display_mode_to_map(env, &closest); } NIF_FUNCTION(get_closest_display_mode) { int displayIndex; ERL_NIF_TERM term; Uint32 format = 0; int w = 0, h = 0, refresh_rate = 0; BADARG_IF(!enif_get_int(env, argv[0], &displayIndex)); BADARG_IF(!enif_is_map(env, argv[1])); // We default to 0 when a field is missing. if (enif_get_map_value(env, argv[1], atom_format, &term)) BADARG_IF(!atom_to_pixel_format(env, term, &format)); if (enif_get_map_value(env, argv[1], atom_w, &term)) BADARG_IF(!enif_get_int(env, term, &w)); if (enif_get_map_value(env, argv[1], atom_h, &term)) BADARG_IF(!enif_get_int(env, term, &h)); if (enif_get_map_value(env, argv[1], atom_refresh_rate, &term)) BADARG_IF(!enif_get_int(env, term, &refresh_rate)); return nif_thread_call(env, thread_get_closest_display_mode, 5, displayIndex, format, w, h, refresh_rate); } // get_current_display_mode NIF_CALL_HANDLER(thread_get_current_display_mode) { SDL_DisplayMode mode; if (SDL_GetCurrentDisplayMode((long)args[0], &mode)) return atom_undefined; return display_mode_to_map(env, &mode); } NIF_FUNCTION(get_current_display_mode) { int displayIndex; BADARG_IF(!enif_get_int(env, argv[0], &displayIndex)); return nif_thread_call(env, thread_get_current_display_mode, 1, displayIndex); } // get_current_video_driver NIF_CALL_HANDLER(thread_get_current_video_driver) { const char* name; ErlNifBinary bin; name = SDL_GetCurrentVideoDriver(); if (!name) return atom_undefined; enif_alloc_binary(strlen(name), &bin); memcpy(bin.data, name, bin.size); return enif_make_binary(env, &bin); } NIF_FUNCTION(get_current_video_driver) { return nif_thread_call(env, thread_get_current_video_driver, 0); } // get_desktop_display_mode NIF_CALL_HANDLER(thread_get_desktop_display_mode) { SDL_DisplayMode mode; if (SDL_GetDesktopDisplayMode((long)args[0], &mode)) return atom_undefined; return display_mode_to_map(env, &mode); } NIF_FUNCTION(get_desktop_display_mode) { int displayIndex; BADARG_IF(!enif_get_int(env, argv[0], &displayIndex)); return nif_thread_call(env, thread_get_desktop_display_mode, 1, displayIndex); } // get_display_bounds NIF_CALL_HANDLER(thread_get_display_bounds) { SDL_Rect rect; if (SDL_GetDisplayBounds((long)args[0], &rect)) return atom_undefined; return rect_to_map(env, &rect); } NIF_FUNCTION(get_display_bounds) { int index; BADARG_IF(!enif_get_int(env, argv[0], &index)); return nif_thread_call(env, thread_get_display_bounds, 1, index); } // get_display_dpi NIF_CALL_HANDLER(thread_get_display_dpi) { float ddpi, hdpi, vdpi; ERL_NIF_TERM map; if (SDL_GetDisplayDPI((long)args[0], &ddpi, &hdpi, &vdpi)) return atom_undefined; map = enif_make_new_map(env); enif_make_map_put(env, map, atom_diagonal, enif_make_double(env, ddpi), &map); enif_make_map_put(env, map, atom_horizontal, enif_make_double(env, hdpi), &map); enif_make_map_put(env, map, atom_vertical, enif_make_double(env, vdpi), &map); return map; } NIF_FUNCTION(get_display_dpi) { int index; BADARG_IF(!enif_get_int(env, argv[0], &index)); return nif_thread_call(env, thread_get_display_dpi, 1, index); } // get_display_mode NIF_CALL_HANDLER(thread_get_display_mode) { SDL_DisplayMode mode; if (SDL_GetDisplayMode((long)args[0], (long)args[1], &mode)) return atom_undefined; return display_mode_to_map(env, &mode); } NIF_FUNCTION(get_display_mode) { int displayIndex, index; BADARG_IF(!enif_get_int(env, argv[0], &displayIndex)); BADARG_IF(!enif_get_int(env, argv[1], &index)); return nif_thread_call(env, thread_get_display_mode, 2, displayIndex, index); } // get_display_name NIF_CALL_HANDLER(thread_get_display_name) { const char* name; ErlNifBinary bin; name = SDL_GetDisplayName((long)args[0]); if (!name) return atom_undefined; enif_alloc_binary(strlen(name), &bin); memcpy(bin.data, name, bin.size); return enif_make_binary(env, &bin); } NIF_FUNCTION(get_display_name) { int index; BADARG_IF(!enif_get_int(env, argv[0], &index)); return nif_thread_call(env, thread_get_display_name, 1, index); } // get_display_usable_bounds NIF_CALL_HANDLER(thread_get_display_usable_bounds) { SDL_Rect rect; if (SDL_GetDisplayUsableBounds((long)args[0], &rect)) return atom_undefined; return rect_to_map(env, &rect); } NIF_FUNCTION(get_display_usable_bounds) { int index; BADARG_IF(!enif_get_int(env, argv[0], &index)); return nif_thread_call(env, thread_get_display_usable_bounds, 1, index); } // get_num_display_modes NIF_CALL_HANDLER(thread_get_num_display_modes) { return enif_make_int(env, SDL_GetNumDisplayModes((long)args[0])); } NIF_FUNCTION(get_num_display_modes) { int displayIndex; BADARG_IF(!enif_get_int(env, argv[0], &displayIndex)); return nif_thread_call(env, thread_get_num_display_modes, 1, displayIndex); } // get_num_video_displays NIF_CALL_HANDLER(thread_get_num_video_displays) { return enif_make_int(env, SDL_GetNumVideoDisplays()); } NIF_FUNCTION(get_num_video_displays) { return nif_thread_call(env, thread_get_num_video_displays, 0); } // get_num_video_drivers NIF_FUNCTION(get_num_video_drivers) { return enif_make_int(env, SDL_GetNumVideoDrivers()); } // get_video_driver NIF_FUNCTION(get_video_driver) { int index; const char* name; ErlNifBinary bin; BADARG_IF(!enif_get_int(env, argv[0], &index)); name = SDL_GetVideoDriver(index); if (!name) return atom_undefined; enif_alloc_binary(strlen(name), &bin); memcpy(bin.data, name, bin.size); return enif_make_binary(env, &bin); } // video_init NIF_CALL_HANDLER(thread_video_init) { int result; result = SDL_VideoInit(args[0]); free(args[0]); if (result) return sdl_error_tuple(env); return atom_ok; } NIF_FUNCTION(video_init) { ErlNifBinary bin; char* name; BADARG_IF(!enif_inspect_binary(env, argv[0], &bin)); name = malloc(bin.size + 1); memcpy(name, bin.data, bin.size); name[bin.size] = '\0'; return nif_thread_call(env, thread_video_init, 1, name); } // video_quit NIF_CAST_HANDLER(thread_video_quit) { SDL_VideoQuit(); } NIF_FUNCTION(video_quit) { return nif_thread_cast(env, thread_video_quit, 0); }