Files
armorpaint/base/sources/iron_sys.c
T
2026-08-21 22:35:30 +02:00

486 lines
14 KiB
C

#include "iron_sys.h"
#include "iron_array.h"
#include "iron_draw.h"
#include "iron_alloc.h"
#include "iron_input.h"
#include "iron_map.h"
#include "iron_string.h"
#include "iron_system.h"
#include <stdbool.h>
#include <string.h>
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_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);
void iron_delete_blob(buffer_t *buffer);
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_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;
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 = calloc(1, sizeof(sys_callback_t));
cb->f = f;
return cb;
}
static callback_t *_callback_create(void (*f)(void *data), void *data) {
callback_t *cb = calloc(1, 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);
_sys_background_listeners = any_array_create(0);
_sys_shutdown_listeners = any_array_create(0);
_sys_drop_files_listeners = any_array_create(0);
_sys_on_next_frames = any_array_create(0);
_sys_on_end_frames = any_array_create(0);
_sys_on_updates = any_array_create(0);
_sys_shaders = any_map_create();
_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_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_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);
buffer_t *draw_blobs[8] = {iron_load_blob(path_image_vert), iron_load_blob(path_image_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)};
draw_init(draw_blobs[0], draw_blobs[1], draw_blobs[2], draw_blobs[3], draw_blobs[4], draw_blobs[5], draw_blobs[6], draw_blobs[7]);
for (int i = 0; i < 8; ++i) {
iron_delete_blob(draw_blobs[i]);
}
_iron_set_update_callback(sys_render);
_iron_set_drop_files_callback(sys_drop_files_callback);
iron_set_application_state_callback(sys_foreground_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_background)(void), void (*on_shutdown)(void)) {
if (on_foreground != NULL) {
any_array_push(_sys_foreground_listeners, _sys_callback_create(on_foreground));
}
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 = calloc(1, 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_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_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;
buffer_t *blob = iron_load_blob(path);
shader = gpu_create_shader(blob, (i32)shader_type);
iron_delete_blob(blob);
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;
}
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;
}
static void _sys_run_callbacks(any_array_t *cbs, i32 len) {
for (i32 i = 0; i < len; ++i) {
callback_t *cb = cbs->buffer[i];
if (cb != NULL) { // Callback may have been removed
cb->f(cb->data);
}
}
}
static void _sys_run_callbacks_once(any_array_t *cbs, i32 len) {
for (i32 i = 0; i < len; ++i) {
callback_t *cb = cbs->buffer[i];
if (cb != NULL) {
cb->f(cb->data);
free(cb);
}
}
array_splice(cbs, 0, len);
}
void sys_render(void) {
i32 len = _sys_on_next_frames->length;
_sys_run_callbacks_once(_sys_on_next_frames, len);
scene_render_frame();
_sys_run_callbacks(_sys_on_updates, _sys_on_updates->length);
len = _sys_on_end_frames->length;
_sys_run_callbacks_once(_sys_on_end_frames, len);
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_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 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;
}