#include "iron_sys.h" #include "iron_array.h" #include "iron_draw.h" #include "iron_gc.h" #include "iron_input.h" #include "iron_map.h" #include "iron_string.h" #include "iron_system.h" #include #include void _iron_init(iron_window_options_t *ops); void _iron_set_update_callback(void (*callback)(void)); void _iron_set_drop_files_callback(void (*callback)(char *)); void iron_set_application_state_callback(void (*on_foreground)(void), void (*on_resume)(void), void (*on_pause)(void), void (*on_background)(void), void (*on_shutdown)(void)); void iron_set_keyboard_down_callback(void (*callback)(int)); void iron_set_keyboard_up_callback(void (*callback)(int)); void iron_set_mouse_down_callback(void (*callback)(int, int, int)); void iron_set_mouse_up_callback(void (*callback)(int, int, int)); void iron_set_mouse_move_callback(void (*callback)(int, int, int, int)); void iron_set_mouse_wheel_callback(void (*callback)(float)); void iron_set_touch_down_callback(void (*callback)(int, int, int)); void iron_set_touch_up_callback(void (*callback)(int, int, int)); void iron_set_touch_move_callback(void (*callback)(int, int, int)); void iron_set_pen_down_callback(void (*callback)(int, int, float)); void iron_set_pen_up_callback(void (*callback)(int, int, float)); void iron_set_pen_move_callback(void (*callback)(int, int, float)); buffer_t *iron_load_blob(char *file); i32 iron_display_width(i32 index); i32 iron_display_height(i32 index); i32 iron_display_frequency(i32 index); i32 iron_display_ppi(i32 index); bool iron_display_is_primary(i32 index); gpu_shader_t *gpu_create_shader(buffer_t *data, i32 shader_type); char *data_path(void); #ifdef WITH_GAMEPAD void iron_set_gamepad_axis_callback(void (*callback)(int, int, float)); void iron_set_gamepad_button_callback(void (*callback)(int, int, float)); #endif any_map_t *_sys_shaders = NULL; f32 _sys_start_time = 0.0f; char _sys_window_title[1024]; any_array_t *_sys_foreground_listeners = NULL; any_array_t *_sys_resume_listeners = NULL; any_array_t *_sys_pause_listeners = NULL; any_array_t *_sys_background_listeners = NULL; any_array_t *_sys_shutdown_listeners = NULL; any_array_t *_sys_drop_files_listeners = NULL; any_array_t *_sys_on_next_frames = NULL; any_array_t *_sys_on_end_frames = NULL; any_array_t *_sys_on_updates = NULL; any_array_t *_sys_on_renders = NULL; i32 _sys_lastw = -1; i32 _sys_lasth = -1; void (*sys_on_resize)(void) = NULL; i32 (*sys_on_w)(void) = NULL; i32 (*sys_on_h)(void) = NULL; i32 (*sys_on_x)(void) = NULL; i32 (*sys_on_y)(void) = NULL; static f32 _sys_time_last = 0.0f; static f32 _sys_time_real_delta = 0.0f; static i32 _sys_time_frequency = -1; static sys_callback_t *_sys_callback_create(void (*f)(void)) { sys_callback_t *cb = gc_alloc(sizeof(sys_callback_t)); cb->f = f; return cb; } static callback_t *_callback_create(void (*f)(void *data), void *data) { callback_t *cb = gc_alloc(sizeof(callback_t)); cb->f = f; cb->data = data; return cb; } void sys_start(iron_window_options_t *ops) { _sys_foreground_listeners = any_array_create(0); gc_root(_sys_foreground_listeners); _sys_resume_listeners = any_array_create(0); gc_root(_sys_resume_listeners); _sys_pause_listeners = any_array_create(0); gc_root(_sys_pause_listeners); _sys_background_listeners = any_array_create(0); gc_root(_sys_background_listeners); _sys_shutdown_listeners = any_array_create(0); gc_root(_sys_shutdown_listeners); _sys_drop_files_listeners = any_array_create(0); gc_root(_sys_drop_files_listeners); _sys_on_next_frames = any_array_create(0); gc_root(_sys_on_next_frames); _sys_on_end_frames = any_array_create(0); gc_root(_sys_on_end_frames); _sys_on_updates = any_array_create(0); gc_root(_sys_on_updates); _sys_on_renders = any_array_create(0); gc_root(_sys_on_renders); _sys_shaders = any_map_create(); gc_root(_sys_shaders); _iron_init(ops); _sys_start_time = (f32)iron_time(); char *dp = data_path(); char *ext = sys_shader_ext(); char path_image_vert[512]; char path_image_frag[512]; char path_image_transform_vert[512]; char path_image_transform_frag[512]; char path_rect_vert[512]; char path_rect_frag[512]; char path_tris_vert[512]; char path_tris_frag[512]; char path_text_vert[512]; char path_text_frag[512]; strcpy(path_image_vert, dp); strcat(path_image_vert, "draw_image.vert"); strcat(path_image_vert, ext); strcpy(path_image_frag, dp); strcat(path_image_frag, "draw_image.frag"); strcat(path_image_frag, ext); strcpy(path_image_transform_vert, dp); strcat(path_image_transform_vert, "draw_image_transform.vert"); strcat(path_image_transform_vert, ext); strcpy(path_image_transform_frag, dp); strcat(path_image_transform_frag, "draw_image_transform.frag"); strcat(path_image_transform_frag, ext); strcpy(path_rect_vert, dp); strcat(path_rect_vert, "draw_rect.vert"); strcat(path_rect_vert, ext); strcpy(path_rect_frag, dp); strcat(path_rect_frag, "draw_rect.frag"); strcat(path_rect_frag, ext); strcpy(path_tris_vert, dp); strcat(path_tris_vert, "draw_tris.vert"); strcat(path_tris_vert, ext); strcpy(path_tris_frag, dp); strcat(path_tris_frag, "draw_tris.frag"); strcat(path_tris_frag, ext); strcpy(path_text_vert, dp); strcat(path_text_vert, "draw_text.vert"); strcat(path_text_vert, ext); strcpy(path_text_frag, dp); strcat(path_text_frag, "draw_text.frag"); strcat(path_text_frag, ext); draw_init(iron_load_blob(path_image_vert), iron_load_blob(path_image_frag), iron_load_blob(path_image_transform_vert), iron_load_blob(path_image_transform_frag), iron_load_blob(path_rect_vert), iron_load_blob(path_rect_frag), iron_load_blob(path_tris_vert), iron_load_blob(path_tris_frag), iron_load_blob(path_text_vert), iron_load_blob(path_text_frag)); _iron_set_update_callback(sys_render); _iron_set_drop_files_callback(sys_drop_files_callback); iron_set_application_state_callback(sys_foreground_callback, sys_resume_callback, sys_pause_callback, sys_background_callback, sys_shutdown_callback); iron_set_keyboard_down_callback(sys_keyboard_down_callback); iron_set_keyboard_up_callback(sys_keyboard_up_callback); iron_set_mouse_down_callback(sys_mouse_down_callback); iron_set_mouse_up_callback(sys_mouse_up_callback); iron_set_mouse_move_callback(sys_mouse_move_callback); iron_set_mouse_wheel_callback(sys_mouse_wheel_callback); iron_set_touch_down_callback(sys_touch_down_callback); iron_set_touch_up_callback(sys_touch_up_callback); iron_set_touch_move_callback(sys_touch_move_callback); iron_set_pen_down_callback(sys_pen_down_callback); iron_set_pen_up_callback(sys_pen_up_callback); iron_set_pen_move_callback(sys_pen_move_callback); #ifdef WITH_GAMEPAD iron_set_gamepad_axis_callback(sys_gamepad_axis_callback); iron_set_gamepad_button_callback(sys_gamepad_button_callback); #endif input_register(); } void sys_notify_on_app_state(void (*on_foreground)(void), void (*on_resume)(void), void (*on_pause)(void), void (*on_background)(void), void (*on_shutdown)(void)) { if (on_foreground != NULL) { any_array_push(_sys_foreground_listeners, _sys_callback_create(on_foreground)); } if (on_resume != NULL) { any_array_push(_sys_resume_listeners, _sys_callback_create(on_resume)); } if (on_pause != NULL) { any_array_push(_sys_pause_listeners, _sys_callback_create(on_pause)); } if (on_background != NULL) { any_array_push(_sys_background_listeners, _sys_callback_create(on_background)); } if (on_shutdown != NULL) { any_array_push(_sys_shutdown_listeners, _sys_callback_create(on_shutdown)); } } void sys_notify_on_drop_files(void (*drop_files_listener)(char *s)) { sys_string_callback_t *cb = gc_alloc(sizeof(sys_string_callback_t)); cb->f = drop_files_listener; any_array_push(_sys_drop_files_listeners, cb); } void sys_foreground(void) { for (i32 i = 0; i < (i32)_sys_foreground_listeners->length; ++i) { sys_callback_t *cb = _sys_foreground_listeners->buffer[i]; cb->f(); } input_on_foreground(); } void sys_resume(void) { for (i32 i = 0; i < (i32)_sys_resume_listeners->length; ++i) { sys_callback_t *cb = _sys_resume_listeners->buffer[i]; cb->f(); } } void sys_pause(void) { for (i32 i = 0; i < (i32)_sys_pause_listeners->length; ++i) { sys_callback_t *cb = _sys_pause_listeners->buffer[i]; cb->f(); } } void sys_background(void) { for (i32 i = 0; i < (i32)_sys_background_listeners->length; ++i) { sys_callback_t *cb = _sys_background_listeners->buffer[i]; cb->f(); } } void sys_shutdown(void) { for (i32 i = 0; i < (i32)_sys_shutdown_listeners->length; ++i) { sys_callback_t *cb = _sys_shutdown_listeners->buffer[i]; cb->f(); } } void sys_drop_files(char *file_path) { for (i32 i = 0; i < (i32)_sys_drop_files_listeners->length; ++i) { sys_string_callback_t *cb = _sys_drop_files_listeners->buffer[i]; cb->f(file_path); } } f32 sys_time(void) { return (f32)iron_time() - _sys_start_time; } void sys_drop_files_callback(char *file_path) { sys_drop_files(file_path); } void sys_foreground_callback(void) { sys_foreground(); } void sys_resume_callback(void) { sys_resume(); } void sys_pause_callback(void) { sys_pause(); } void sys_background_callback(void) { sys_background(); } void sys_shutdown_callback(void) { sys_shutdown(); } void sys_keyboard_down_callback(i32 code) { keyboard_down_listener(code); } void sys_keyboard_up_callback(i32 code) { keyboard_up_listener(code); } void sys_mouse_down_callback(i32 button, i32 x, i32 y) { mouse_down_listener(button, x, y); } void sys_mouse_up_callback(i32 button, i32 x, i32 y) { mouse_up_listener(button, x, y); } void sys_mouse_move_callback(i32 x, i32 y, i32 mx, i32 my) { mouse_move_listener(x, y, mx, my); } void sys_mouse_wheel_callback(f32 delta) { mouse_wheel_listener(delta); } void sys_touch_down_callback(i32 index, i32 x, i32 y) { #if defined(IRON_ANDROID) || defined(IRON_IOS) mouse_on_touch_down(index, x, y); #endif } void sys_touch_up_callback(i32 index, i32 x, i32 y) { #if defined(IRON_ANDROID) || defined(IRON_IOS) mouse_on_touch_up(index, x, y); #endif } void sys_touch_move_callback(i32 index, i32 x, i32 y) { #if defined(IRON_ANDROID) || defined(IRON_IOS) mouse_on_touch_move(index, x, y); #endif } void sys_pen_down_callback(i32 x, i32 y, f32 pressure) { pen_down_listener(x, y, pressure); } void sys_pen_up_callback(i32 x, i32 y, f32 pressure) { pen_up_listener(x, y, pressure); } void sys_pen_move_callback(i32 x, i32 y, f32 pressure) { pen_move_listener(x, y, pressure); } #ifdef WITH_GAMEPAD void sys_gamepad_axis_callback(i32 gamepad, i32 axis, f32 value) { gamepad_axis_listener(gamepad, axis, value); } void sys_gamepad_button_callback(i32 gamepad, i32 button, f32 value) { gamepad_button_listener(gamepad, button, value); } #endif char *sys_title(void) { return _sys_window_title; } void sys_title_set(char *value) { iron_window_set_title(value); strcpy(_sys_window_title, value); } i32 sys_display_primary_id(void) { for (i32 i = 0; i < iron_count_displays(); ++i) { if (iron_display_is_primary(i)) { return i; } } return 0; } i32 sys_display_width(void) { return iron_display_width(sys_display_primary_id()); } i32 sys_display_height(void) { return iron_display_height(sys_display_primary_id()); } i32 sys_display_frequency(void) { return iron_display_frequency(sys_display_primary_id()); } i32 sys_display_ppi(void) { return iron_display_ppi(sys_display_primary_id()); } char *sys_shader_ext(void) { #if defined(IRON_VULKAN) return ".spirv"; #elif defined(IRON_METAL) return ".metal"; #elif defined(IRON_WASM) return ".wgsl"; #else return ".d3d11"; #endif } gpu_shader_t *sys_get_shader(char *name) { gpu_shader_t *shader = any_map_get(_sys_shaders, name); if (shader == NULL) { char path[512]; char *dp = data_path(); char *ext = sys_shader_ext(); strcpy(path, dp); strcat(path, name); strcat(path, ext); gpu_shader_type_t shader_type = ends_with(name, ".frag") ? GPU_SHADER_TYPE_FRAGMENT : GPU_SHADER_TYPE_VERTEX; shader = gpu_create_shader(iron_load_blob(path), (i32)shader_type); any_map_set(_sys_shaders, name, shader); } return shader; } i32 sys_w(void) { if (sys_on_w != NULL) { return sys_on_w(); } return iron_window_width(); } i32 sys_h(void) { if (sys_on_h != NULL) { return sys_on_h(); } return iron_window_height(); } i32 sys_x(void) { if (sys_on_x != NULL) { return sys_on_x(); } return 0; } i32 sys_y(void) { if (sys_on_y != NULL) { return sys_on_y(); } return 0; } static void _sys_run_callbacks(any_array_t *cbs) { for (i32 i = 0; i < (i32)cbs->length; ++i) { callback_t *cb = cbs->buffer[i]; cb->f(cb->data); } } f32 sys_delta(void) { if (_sys_time_frequency < 0) { _sys_time_frequency = sys_display_frequency(); } return 1.0f / (f32)_sys_time_frequency; } f32 sys_real_delta(void) { return _sys_time_real_delta; } void sys_render(void) { if (_sys_on_next_frames->length > 0) { _sys_run_callbacks(_sys_on_next_frames); array_splice(_sys_on_next_frames, 0, _sys_on_next_frames->length); } _sys_run_callbacks(_sys_on_updates); if (iron_window_width() > 0 && iron_window_height() > 0) { scene_render_frame(); _sys_run_callbacks(_sys_on_renders); } if (_sys_on_end_frames->length > 0) { _sys_run_callbacks(_sys_on_end_frames); array_splice(_sys_on_end_frames, 0, _sys_on_end_frames->length); } input_end_frame(); // Rebuild projection on window resize if (_sys_lastw == -1) { _sys_lastw = sys_w(); _sys_lasth = sys_h(); } if (_sys_lastw != sys_w() || _sys_lasth != sys_h()) { if (sys_on_resize != NULL) { sys_on_resize(); } } _sys_lastw = sys_w(); _sys_lasth = sys_h(); _sys_time_real_delta = sys_time() - _sys_time_last; _sys_time_last = sys_time(); } // Hooks void sys_notify_on_update(void (*f)(void *data), void *data) { any_array_push(_sys_on_updates, _callback_create(f, data)); } void sys_notify_on_render(void (*f)(void *data), void *data) { any_array_push(_sys_on_renders, _callback_create(f, data)); } void sys_notify_on_next_frame(void (*f)(void *data), void *data) { any_array_push(_sys_on_next_frames, _callback_create(f, data)); } void sys_notify_on_end_frame(void (*f)(void *data), void *data) { any_array_push(_sys_on_end_frames, _callback_create(f, data)); } static void _sys_remove_callback(any_array_t *ar, void (*f)(void *data)) { for (i32 i = 0; i < (i32)ar->length; ++i) { callback_t *cb = ar->buffer[i]; if (cb->f == f) { array_splice(ar, i, 1); break; } } } void sys_remove_update(void (*f)(void *data)) { _sys_remove_callback(_sys_on_updates, f); } void sys_remove_render(void (*f)(void *data)) { _sys_remove_callback(_sys_on_renders, f); } void sys_remove_end_frame(void (*f)(void *data)) { _sys_remove_callback(_sys_on_end_frames, f); } void video_unload(video_t *self) {} char *sys_buffer_to_string(buffer_t *b) { char *str = string_alloc(b->length + 1); memcpy(str, b->buffer, b->length); return str; } buffer_t *sys_string_to_buffer(char *str) { u8_array_t *b = u8_array_create(string_length(str)); memcpy(b->buffer, str, string_length(str)); return b; }