diff options
-rwxr-xr-x | build_all.sh | 8 | ||||
-rw-r--r-- | examples/echo.c | 8 | ||||
-rw-r--r-- | examples/game_of_life.c | 20 | ||||
-rw-r--r-- | examples/graph.c | 6 | ||||
-rw-r--r-- | examples/julia_set.c | 26 | ||||
-rw-r--r-- | examples/labyrinth.c | 20 | ||||
-rw-r--r-- | examples/particles.c | 12 | ||||
-rw-r--r-- | examples/pixels.c | 44 | ||||
-rw-r--r-- | examples/proto.c | 5 | ||||
-rw-r--r-- | examples/screenshot.c | 8 | ||||
-rw-r--r-- | examples/sinewave.c | 30 | ||||
-rw-r--r-- | examples/ui.c | 6 | ||||
-rw-r--r-- | index.htm | 43 | ||||
-rw-r--r-- | reduced_system_layer.c | 380 | ||||
-rwxr-xr-x | stackless_coroutine.c | 68 |
15 files changed, 336 insertions, 348 deletions
diff --git a/build_all.sh b/build_all.sh index eb44f68..d5c2305 100755 --- a/build_all.sh +++ b/build_all.sh @@ -32,12 +32,8 @@ mkdir -p bin/web # gcc $FLAGS_X11 -o ./bin/x11/graph ./examples/graph.c # gcc $FLAGS_X11 -o ./bin/x11/julia_set ./examples/julia_set.c -# gcc $FLAGS_X11 -o ./bin/x11/game_of_life ./examples/game_of_life.c -# gcc $FLAGS_X11 -o ./bin/x11/labyrinth ./examples/labyrinth.c # gcc $FLAGS_X11 -o ./bin/x11/sinewave ./examples/sinewave.c -# gcc $FLAGS_X11 -o ./bin/x11/pixels ./examples/pixels.c # gcc $FLAGS_X11 -o ./bin/x11/ui ./examples/ui.c -# gcc $FLAGS_X11 -o ./bin/x11/proto ./examples/proto.c # gcc $FLAGS_X11 -o ./bin/x11/particles ./examples/particles.c # gcc $FLAGS_X11 -o ./bin/x11/echo ./examples/echo.c @@ -45,9 +41,5 @@ gcc $FLAGS_X11 -o ./bin/x11/screenshot ./examples/screenshot.c # clang $FLAGS_WEB -o ./bin/web/graph.wasm ./examples/graph.c # clang $FLAGS_WEB -o ./bin/web/julia_set.wasm ./examples/julia_set.c -# clang $FLAGS_WEB -o ./bin/web/game_of_life.wasm ./examples/game_of_life.c -# clang $FLAGS_WEB -o ./bin/web/labyrinth.wasm ./examples/labyrinth.c # clang $FLAGS_WEB -o ./bin/web/sinewave.wasm ./examples/sinewave.c -# clang $FLAGS_WEB -o ./bin/web/pixels.wasm ./examples/pixels.c # clang $FLAGS_WEB -o ./bin/web/ui.wasm ./examples/ui.c -# clang $FLAGS_WEB -o ./bin/web/proto.wasm ./examples/proto.c diff --git a/examples/echo.c b/examples/echo.c index 10f3cd5..1671be7 100644 --- a/examples/echo.c +++ b/examples/echo.c @@ -41,7 +41,7 @@ i32 main(i32 argc, c8 **argv) { printf("Receiving UDP messages on port %d\n\n", PORT); for (;;) { - i64 n = p_recv( + i64 n = network_recv( 0, (IP_Address) { .protocol = IPv4_UDP, @@ -61,7 +61,7 @@ i32 main(i32 argc, c8 **argv) { buf[n] = '\0'; printf("%s\n", buf); } else - p_sleep_for(10); + suspend_thread_for_milliseconds(10); } } break; @@ -75,7 +75,7 @@ i32 main(i32 argc, c8 **argv) { if (strcmp(buf, "!quit") == 0) break; - p_send( + network_send( 0, (IP_Address) { .protocol = IPv4_UDP, @@ -94,6 +94,6 @@ i32 main(i32 argc, c8 **argv) { default:; } - p_cleanup(); + shutdown_all_systems(); return 0; } diff --git a/examples/game_of_life.c b/examples/game_of_life.c deleted file mode 100644 index d95fb9e..0000000 --- a/examples/game_of_life.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "../reduced_system_layer.c" - -void update_and_render_frame(void) { - p_handle_events(); - p_render_frame(); - p_sleep_for(0); -} - -i32 main(i32 argc, c8 **argv) { - (void) argc; - (void) argv; - - g_platform = (Platform) { - .title = "Conway's Game of Life", - }; - - p_event_loop(); - - return 0; -} diff --git a/examples/graph.c b/examples/graph.c index f196d3d..c1c84f2 100644 --- a/examples/graph.c +++ b/examples/graph.c @@ -371,7 +371,7 @@ i64 drag_x0 = 0; i64 drag_y0 = 0; void update_and_render_frame(void) { - p_wait_events(); + wait_main_window_events(); // Input events @@ -520,7 +520,7 @@ void update_and_render_frame(void) { draw_graph(); - p_render_frame(); + render_main_window_frame(); } i32 main(i32 argc, c8 **argv) { @@ -539,7 +539,7 @@ i32 main(i32 argc, c8 **argv) { add_edge(0, 2); add_edge(1, 2); - p_event_loop(); + run_main_window_event_loop(); return 0; } diff --git a/examples/julia_set.c b/examples/julia_set.c index 288dac2..81aa02c 100644 --- a/examples/julia_set.c +++ b/examples/julia_set.c @@ -11,6 +11,13 @@ f64 radius = 2.; i64 limit = 1024; i64 time_0; +void inc_f64(f64 *x, i8 s) { + u64 *u = (u64 *) x; + if (((*u >> 52) & 2047) == 2047) + return; + *u += *x > 0 ? s : -s; +} + void apply_scale(f64 delta) { while (delta > SCALE_LIMIT) { apply_scale(SCALE_LIMIT); @@ -22,21 +29,24 @@ void apply_scale(f64 delta) { } f64 ds = view_s * delta * .1; - if (view_s + ds < 1e-12) + if (view_s + ds <= 0.0) return; f64 dx = (g_platform.cursor_x * 1. - g_platform.real_width * .5); f64 dy = (g_platform.cursor_y * 1. - g_platform.real_height * .5); view_x -= view_s * dx; view_y -= view_s * dy; - view_s += ds; + if (view_s == view_s + ds) + inc_f64(&view_s, ds > 0 ? 1 : -1); + else + view_s += ds; view_x += view_s * dx; view_y += view_s * dy; } void update_and_render_frame(void) { - i32 num_events = p_handle_events(); + i32 num_events = handle_main_window_events(); - i64 time_elapsed = p_time() - time_0; + i64 time_elapsed = current_utc_time_in_milliseconds() - time_0; time_0 += time_elapsed; b8 left = g_platform.key_down[KEY_LEFT]; @@ -45,7 +55,7 @@ void update_and_render_frame(void) { b8 down = g_platform.key_down[KEY_DOWN]; if (!left && !right && !up && !down && num_events == 0) { - p_sleep_for(1); + suspend_thread_for_milliseconds(1); return; } @@ -98,7 +108,7 @@ void update_and_render_frame(void) { g_platform.pixels[j * g_platform.frame_width + i] = vec4_from_vec3_f32(rgb_f32_from_u32(c), 1.f); } - p_render_frame(); + render_main_window_frame(); } i32 main(i32 argc, c8 **argv) { @@ -109,9 +119,9 @@ i32 main(i32 argc, c8 **argv) { .title = "Julia Set", }; - time_0 = p_time(); + time_0 = current_utc_time_in_milliseconds(); - p_event_loop(); + run_main_window_event_loop(); return 0; } diff --git a/examples/labyrinth.c b/examples/labyrinth.c deleted file mode 100644 index 01af7c6..0000000 --- a/examples/labyrinth.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "../reduced_system_layer.c" - -void update_and_render_frame(void) { - p_handle_events(); - p_render_frame(); - p_sleep_for(0); -} - -i32 main(i32 argc, c8 **argv) { - (void) argc; - (void) argv; - - g_platform = (Platform) { - .title = "Labyrinth", - }; - - p_event_loop(); - - return 0; -} diff --git a/examples/particles.c b/examples/particles.c index 894fee0..753698d 100644 --- a/examples/particles.c +++ b/examples/particles.c @@ -22,9 +22,9 @@ vec4_f32 background = { .0f, .0f, .08f, 1.f }; i64 time_0; void update_and_render_frame(void) { - p_handle_events(); + handle_main_window_events(); - i64 time_elapsed = p_time() - time_0; + i64 time_elapsed = current_utc_time_in_milliseconds() - time_0; time_0 += time_elapsed; if (g_platform.key_pressed[BUTTON_LEFT]) { @@ -109,7 +109,7 @@ void update_and_render_frame(void) { } } - p_render_frame(); + render_main_window_frame(); } i32 main(i32 argc, c8 **argv) { @@ -122,11 +122,11 @@ i32 main(i32 argc, c8 **argv) { .exact_resolution = 1, }; - time_0 = p_time(); + time_0 = current_utc_time_in_milliseconds(); - srand(p_time()); + srand(time_0); - p_event_loop(); + run_main_window_event_loop(); return 0; } diff --git a/examples/pixels.c b/examples/pixels.c deleted file mode 100644 index 0579361..0000000 --- a/examples/pixels.c +++ /dev/null @@ -1,44 +0,0 @@ -#define MIN_PIXEL_SIZE 16 -#include "../graphics.c" - -i64 t = 0; -f64 x = 100.; -f64 y = 100.; - -void update_and_render_frame(void) { - p_handle_events(); - - i64 time_elapsed = p_time() - t; - t += time_elapsed; - - if (g_platform.key_down[KEY_LEFT]) x -= .01 * time_elapsed; - if (g_platform.key_down[KEY_RIGHT]) x += .01 * time_elapsed; - if (g_platform.key_down[KEY_UP]) y -= .01 * time_elapsed; - if (g_platform.key_down[KEY_DOWN]) y += .01 * time_elapsed; - - Brush white = RGB(1.f, 1.f, 1.f); - Brush black = RGB(0.f, 0.f, 0.f); - - white.quick = 1; - - fill_rectangle(white, 0., 0., g_platform.real_width, g_platform.real_height); - fill_rectangle(black, x, y, 40., 40.); - - p_render_frame(); - p_sleep_for(0); -} - -i32 main(i32 argc, c8 **argv) { - (void) argc; - (void) argv; - - g_platform = (Platform) { - .title = "Pixels", - }; - - t = p_time(); - - p_event_loop(); - - return 0; -} diff --git a/examples/proto.c b/examples/proto.c deleted file mode 100644 index dbb64a8..0000000 --- a/examples/proto.c +++ /dev/null @@ -1,5 +0,0 @@ -int main(int argc, char **argv) { - (void) argc; - (void) argv; - return 0; -} diff --git a/examples/screenshot.c b/examples/screenshot.c index 33bbe99..c3c0ebd 100644 --- a/examples/screenshot.c +++ b/examples/screenshot.c @@ -6,11 +6,11 @@ b8 has_screenshot = 0; void update_and_render_frame(void) { if (!has_screenshot) { - p_screenshot(MAX_NUM_PIXELS, &width, &height, g_platform.sketch); + take_screenshot(MAX_NUM_PIXELS, &width, &height, g_platform.sketch); has_screenshot = 1; } - p_handle_events(); + handle_main_window_events(); draw_pixels((Brush) { .quick = 1, }, 0, 0, g_platform.real_width, g_platform.real_height, (Pixel_Buffer) { .width = width, @@ -19,7 +19,7 @@ void update_and_render_frame(void) { .pixels = g_platform.sketch, }); - p_render_frame(); + render_main_window_frame(); } i32 main(i32 argc, c8 **argv) { @@ -30,7 +30,7 @@ i32 main(i32 argc, c8 **argv) { .title = "Screenshot", }; - p_event_loop(); + run_main_window_event_loop(); return 0; } diff --git a/examples/sinewave.c b/examples/sinewave.c index f2b2580..0c33803 100644 --- a/examples/sinewave.c +++ b/examples/sinewave.c @@ -1,9 +1,6 @@ #include "../graphics.c" -i64 time_0 = 0; -i64 audio_samples = 0; - -f32 frames[SOUND_SAMPLE_RATE * NUM_SOUND_CHANNELS] = {0}; +f32 frames[PRIMARY_SOUND_SAMPLE_RATE * NUM_PRIMARY_SOUND_CHANNELS] = {0}; b8 ui_button(f64 x, f64 y, f64 width, f64 height) { b8 has_cursor = g_platform.cursor_x >= x && g_platform.cursor_x < x + width && @@ -22,21 +19,18 @@ b8 ui_button(f64 x, f64 y, f64 width, f64 height) { } void update_and_render_frame(void) { - i32 num_events = p_handle_events(); + i32 num_events = handle_main_window_events(); if (num_events > 0) { fill_rectangle(RGB(.1f, .1f, .1f), 0, 0, g_platform.frame_width, g_platform.frame_height); if (ui_button(100, 100, 200, 200)) - p_queue_sound(0, SOUND_SAMPLE_RATE, frames); + queue_primary_sound(0, PRIMARY_SOUND_SAMPLE_RATE, frames); } - i64 samples_elapsed = ((p_time() - time_0) * SOUND_SAMPLE_RATE) / 1000 - audio_samples; - audio_samples += samples_elapsed; - - p_handle_sound(); - p_render_frame(); - p_sleep_for(0); + handle_primary_sound(); + render_main_window_frame(); + suspend_thread_for_milliseconds(0); } i32 main(i32 argc, c8 **argv) { @@ -44,14 +38,14 @@ i32 main(i32 argc, c8 **argv) { (void) argv; g_platform = (Platform) { - .title = "Sine Wave", - .graceful_exit = 1, + .title = "Sine Wave", + .graceful_shutdown = 1, }; f64 frequency = 440.; - for (i64 i = 0; i < SOUND_SAMPLE_RATE; ++i) { - f64 t = ((f64) i) / SOUND_SAMPLE_RATE; + for (i64 i = 0; i < PRIMARY_SOUND_SAMPLE_RATE; ++i) { + f64 t = ((f64) i) / PRIMARY_SOUND_SAMPLE_RATE; f64 x = sin(t * (M_PI * 2.) * frequency); if (t < .005) x *= t / .005; @@ -61,8 +55,6 @@ i32 main(i32 argc, c8 **argv) { frames[i * 2 + 1] = (f32) (x * .5); } - time_0 = p_time(); - - p_event_loop(); + run_main_window_event_loop(); return 0; } diff --git a/examples/ui.c b/examples/ui.c index 022a463..a3ca476 100644 --- a/examples/ui.c +++ b/examples/ui.c @@ -12,7 +12,7 @@ i64 cursor = 0; i64 selection = 0; void update_and_render_frame(void) { - p_wait_events(); + wait_main_window_events(); Brush background = RGB(.2f, .1f, 0.f); background.quick = 1; @@ -226,7 +226,7 @@ void update_and_render_frame(void) { draw_text_area((Brush) { .color = color, }, x0, y0, w, h, 10., 10., text_len, text); draw_text_cursor((Brush) { .xor_color = 1, .color = { 1.f, 1.f, 1.f, 1.f }, }, x0, y0, w, h, 10., 10., cursor, selection, text_len, text); - p_render_frame(); + render_main_window_frame(); } i32 main(i32 argc, c8 **argv) { @@ -237,7 +237,7 @@ i32 main(i32 argc, c8 **argv) { .title = "UI", }; - p_event_loop(); + run_main_window_event_loop(); return 0; } @@ -34,7 +34,7 @@ fd_seek : () => { throw new Error("Unexpected fd_seek call"); }, }, env : { - p_clipboard_write_text_impl : (size, text) => { + write_clipboard_text_impl : (size, text) => { let text_buffer = new ArrayBuffer(size); new Uint8Array(text_buffer).set(new Uint8Array(this.memory_buffer, text, size)); @@ -43,7 +43,7 @@ text_buffer : text_buffer, }); }, - p_time : () => { return BigInt(Date.now()); }, + current_time_in_milliseconds : () => { return BigInt(Date.now()); }, floor : Math.floor, ceil : Math.ceil, @@ -275,25 +275,26 @@ wasm, { env : { - p_clipboard_write_impl : () => {}, - p_time : () => {}, - floor : () => {}, - ceil : () => {}, - trunc : () => {}, - sqrt : () => {}, - cbrt : () => {}, - pow : () => {}, - log : () => {}, - log2 : () => {}, - log10 : () => {}, - exp : () => {}, - sin : () => {}, - cos : () => {}, - tan : () => {}, - asin : () => {}, - acos : () => {}, - atan : () => {}, - atan2 : () => {}, + write_clipboard_impl : () => {}, + current_time_in_milliseconds : () => {}, + + floor : () => {}, + ceil : () => {}, + trunc : () => {}, + sqrt : () => {}, + cbrt : () => {}, + pow : () => {}, + log : () => {}, + log2 : () => {}, + log10 : () => {}, + exp : () => {}, + sin : () => {}, + cos : () => {}, + tan : () => {}, + asin : () => {}, + acos : () => {}, + atan : () => {}, + atan2 : () => {}, }, } ); diff --git a/reduced_system_layer.c b/reduced_system_layer.c index 38b80dd..fff4f44 100644 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -23,6 +23,18 @@ // - Optimized to use in a single source file. // Installation process? Ctrl+C, Ctrl+V, done. // +// STYLE CONVENTIONS +// +// - Capitalized_Snake_Case - Type name. +// - snake_case - Non-type name. +// - UPPER_SNAKE_CASE - Macro or constant. +// - g_ prefix - Global variable name. +// +// Most procedures have long and descriptive names. +// Some procedures have prefixes according to their domain. +// +// There may be exceptions if convenient. +// // ---------------------------------------------------------------- // // To-Do list @@ -62,10 +74,21 @@ // - Windows audio // - Recording // - Device selection +// - Switching canvases - Web // - Networking // - Windows sockets // - TCP -// - Switching canvases - Web +// - fetch - via libcurl on native platforms +// - Cross-platform networking - UDP + TCP + WebSocket +// Requires: +// - [ ] Sockets - UDP, TCP +// - [ ] HTTP client +// - [ ] HTTP server +// - [ ] Web sockets +// - [ ] Key exchange +// - [ ] Cipher suite (Lattice-based?) +// - [ ] TLS +// - [ ] Web sockets over TLS // - Long term // - dlopen - load libraries conditionally // - X11 @@ -79,14 +102,11 @@ // - Process // - Shared memory // - Shared mutex -// - Stackless coroutines // - Big integer // - Mersenne Twister 64 // - Arithmetic coding // - Threads - https://nachtimwald.com/2019/04/05/cross-platform-thread-wrapper -// - HTTP // - Cryptography - https://github.com/jedisct1/supercop -// - Web sockets // - macOS support // - Mobile devices support // @@ -101,6 +121,7 @@ // - Utility // - UTF-8 // - Testing +// - Stackless coroutines // - Graphics // - Font // - Adaptive resolution @@ -197,12 +218,18 @@ i32 main(i32 argc, c8 **argv); #define NO_X11 0 #endif +#ifndef STATIC_MEMORY_BUFFER_SIZE +#define STATIC_MEMORY_BUFFER_SIZE (10 * 1024 * 1024) +#endif + +// ---------------------------------------------------------------- +// TEMP: Static buffers. + #ifndef MAX_NUM_PIXELS #define MAX_NUM_PIXELS (4 * 1024 * 1024) #endif #ifndef MAX_INPUT_SIZE -// How many input events can be buffered during one frame. #define MAX_INPUT_SIZE 256 #endif @@ -222,6 +249,16 @@ i32 main(i32 argc, c8 **argv); #define MAX_NUM_KEYS 512 #endif +#ifndef MAX_NUM_PRIMARY_SOUND_FRAMES +#define MAX_NUM_PRIMARY_SOUND_FRAMES (4 * 2 * 44100) +#endif + +#ifndef DROP_FILES_BUFFER_SIZE +#define DROP_FILES_BUFFER_SIZE (8 * 1024 * 1024) +#endif + +// ---------------------------------------------------------------- + #ifndef MIN_PIXEL_SIZE #define MIN_PIXEL_SIZE (1.0) #endif @@ -238,19 +275,19 @@ i32 main(i32 argc, c8 **argv); #define PIXEL_SIZE_DELTA (0.05) #endif -#ifndef MIN_FRAME_DURATION // The pixel size will decrease when the frame duration is lower. +#ifndef MIN_FRAME_DURATION #define MIN_FRAME_DURATION 17 #endif -#ifndef MAX_FRAME_DURATION // The pixel size will increase when the frame duration is higher. -#define MAX_FRAME_DURATION 34 +#ifndef MAX_FRAME_DURATION +#define MAX_FRAME_DURATION 32 #endif -#ifndef FRAME_DURATION_HARD_LIMIT // The pixel size value will reset if the frame duration is higher. -#define FRAME_DURATION_HARD_LIMIT 400 +#ifndef FRAME_DURATION_HARD_LIMIT +#define FRAME_DURATION_HARD_LIMIT 200 #endif #ifndef NUM_FRAMES_AVERAGED @@ -258,33 +295,19 @@ i32 main(i32 argc, c8 **argv); #endif #ifndef AVERAGE_FRAME_BIAS -#if defined(__wasm__) -// NOTE: Web frame rate is quite unstable, so -// we always pick the longest frame. -#define AVERAGE_FRAME_BIAS (0.00) -#else #define AVERAGE_FRAME_BIAS (0.02) #endif -#endif - -#ifndef NUM_SOUND_CHANNELS -#define NUM_SOUND_CHANNELS 2 -#endif -#ifndef SOUND_SAMPLE_RATE -#define SOUND_SAMPLE_RATE 44100 +#ifndef NUM_PRIMARY_SOUND_CHANNELS +#define NUM_PRIMARY_SOUND_CHANNELS 2 #endif -#ifndef SOUND_AVAIL_MIN -#define SOUND_AVAIL_MIN 512 +#ifndef PRIMARY_SOUND_SAMPLE_RATE +#define PRIMARY_SOUND_SAMPLE_RATE 44100 #endif -#ifndef MAX_NUM_SOUND_FRAMES -#define MAX_NUM_SOUND_FRAMES (4 * SOUND_SAMPLE_RATE * NUM_SOUND_CHANNELS) -#endif - -#ifndef DROP_FILES_BUFFER_SIZE -#define DROP_FILES_BUFFER_SIZE (8 * 1024 * 1024) +#ifndef PRIMARY_SOUND_AVAIL_MIN +#define PRIMARY_SOUND_AVAIL_MIN 512 #endif #ifndef MOUSE_WHEEL_FACTOR @@ -570,7 +593,7 @@ typedef struct { i32 frame_height; f64 pixel_size; b8 exact_resolution; - b8 graceful_exit; + b8 graceful_shutdown; b8 done; b8 has_focus; @@ -603,6 +626,9 @@ typedef struct { f32 clipboard_sound [MAX_CLIPBOARD_SIZE]; b8 key_down [MAX_NUM_KEYS]; b8 key_pressed [MAX_NUM_KEYS]; + + i64 memory_buffer_size; + u8 *memory_buffer; } Platform; // UTF-8 @@ -612,35 +638,41 @@ UTF8_Char utf8_read (i64 len, c8 *s); i8 utf8_write(c32 c, c8 *buffer); // Time and sleep -i64 p_time(void); -void p_yield(void); -void p_sleep_for(i64 duration); +i64 current_utc_time_in_milliseconds(void); +void yield_thread_execution(void); +void suspend_thread_for_milliseconds(i64 duration); // Window -void p_init(void); -void p_cleanup(void); -i32 p_handle_events(void); -i32 p_wait_events(void); -void p_render_frame(void); +void init_main_window(void); +i32 handle_main_window_events(void); +i32 wait_main_window_events(void); +void render_main_window_frame(void); // Convenient helper procedure for the event loop -void p_event_loop(void); +void run_main_window_event_loop(void); // Clipboard -void p_clipboard_write_text(i64 size, c8 *data); -void p_clipboard_write_image(i64 width, i64 heiht, vec4_f32 *pixels); -void p_clipboard_write_sound(i8 num_channels, i64 num_samples, f32 *frames); +void write_clipboard_text(i64 size, c8 *data); +void write_clipboard_image(i64 width, i64 heiht, vec4_f32 *pixels); +void write_clipboard_sound(i8 num_channels, i64 num_samples, f32 *frames); // Take a screenshot -void p_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels); +void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels); // Sound -void p_handle_sound(void); -void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames); +void handle_primary_sound(void); +void queue_primary_sound(i64 delay_in_samples, i64 num_samples, f32 *frames); + +// Networking +i64 network_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address); +i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port); + +// NOTE: This will shutdown main window, networking and audio. +// If g_platform.graceful_shutdown is 0, this does nothing. +void shutdown_all_systems(void); -// UDP sockets -i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address); -i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port); +// Memory +void *seldom_memory_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data); #ifdef REDUCED_SYSTEM_LAYER_HEADER extern Platform g_platform; @@ -669,23 +701,23 @@ Platform g_platform = {0}; static i64 _sound_clock_time = 0; static i64 _sound_clock_carry = 0; static i64 _sound_position = 0; -static i64 _frame_index = 0; +static i64 _frame_index = 0; -static f32 _sound_ring [MAX_NUM_SOUND_FRAMES] = {0}; +static f32 _sound_ring [MAX_NUM_PRIMARY_SOUND_FRAMES] = {0}; static u8 _drop_files_buffer [DROP_FILES_BUFFER_SIZE] = {0}; -static i64 _frame_duration [NUM_FRAMES_AVERAGED] = {0}; +static i64 _frame_duration [NUM_FRAMES_AVERAGED] = {0}; -void p_event_loop(void) { - p_init(); +void run_main_window_event_loop(void) { + init_main_window(); #if !defined(__wasm__) while (!g_platform.done) update_and_render_frame(); - p_cleanup(); + shutdown_all_systems(); #endif } // ================================================================ // -// Utilities +// Log // // ================================================================ @@ -702,6 +734,45 @@ void p_event_loop(void) { } while (0) #endif +// ================================================================ +// +// Seldom memory allocator +// +// ================================================================ + +typedef struct { + i64 offset; + i64 size; +} Memory_Slot_; + +static u8 memory_buffer_[STATIC_MEMORY_BUFFER_SIZE] = {0}; + +static i64 num_memory_slots_(void) { + return *(i64 *) &g_platform.memory_buffer[g_platform.memory_buffer_size - 8]; +} + +void *seldom_memory_allocate(i64 size, i64 alignment, i64 previous_size, void *previous_data) { + if (g_platform.memory_buffer_size < 0) + LOG_ERROR("Invalid memory buffer size."); + if (g_platform.memory_buffer == NULL && g_platform.memory_buffer_size > 0) + LOG_ERROR("Invalid memory buffer."); + + if (g_platform.memory_buffer == NULL || g_platform.memory_buffer_size <= 0) { + g_platform.memory_buffer_size = sizeof memory_buffer_; + g_platform.memory_buffer = memory_buffer_; + } + + // TODO + LOG_ERROR("Not implemented."); + return NULL; +} + +// ================================================================ +// +// Utilities +// +// ================================================================ + i8 utf8_size(c32 c) { if ((c & 0x00007f) == c) return 1; if ((c & 0x0007ff) == c) return 2; @@ -825,13 +896,13 @@ static i64 average_frame_duration_(i64 duration) { static i64 sound_samples_elapsed_(void) { if (_sound_clock_time == 0) { - _sound_clock_time = p_time(); + _sound_clock_time = current_utc_time_in_milliseconds(); _sound_clock_carry = 0; return 0; } - i64 time_elapsed = p_time() - _sound_clock_time; - i64 delta = time_elapsed * SOUND_SAMPLE_RATE + _sound_clock_carry; + i64 time_elapsed = current_utc_time_in_milliseconds() - _sound_clock_time; + i64 delta = time_elapsed * PRIMARY_SOUND_SAMPLE_RATE + _sound_clock_carry; i64 num_samples = delta / 1000; _sound_clock_time += time_elapsed; @@ -922,12 +993,11 @@ static void drop_files_empty_data_after_(i64 index) { return; } - for (i64 i = index + 1; i < g_platform.num_drop_files; ++i) { + for (i64 i = index + 1; i < g_platform.num_drop_files; ++i) if (g_platform.drop_files[i].data_size != 0) { LOG_ERROR("Sanity"); g_platform.drop_files[i].data_size = 0; } - } } static void drop_files_set_name_(i64 index, i64 name_len, c8 *name) { @@ -1032,17 +1102,17 @@ static void pixel_size_calubrate_(i64 current_frame_duration) { #include <sched.h> #include <unistd.h> -i64 p_time(void) { +i64 current_utc_time_in_milliseconds(void) { struct timespec t; timespec_get(&t, TIME_UTC); - return 1000 * t.tv_sec + t.tv_nsec / 1000000; + return 1000ll * t.tv_sec + t.tv_nsec / 1000000ll; } -void p_yield(void) { +void yield_thread_execution(void) { sched_yield(); } -void p_sleep_for(i64 duration) { +void suspend_thread_for_milliseconds(i64 duration) { if (duration == 0) usleep(0); if (duration <= 0) @@ -1061,7 +1131,7 @@ void p_sleep_for(i64 duration) { // ================================================================ // -// UDP sockets +// Networking // // ================================================================ @@ -1080,18 +1150,18 @@ typedef struct { IP_Address address; } Socket_Slot; -static b8 _sockets_ready = 0; +static b8 _network_ready = 0; static Socket_Slot _sockets[MAX_NUM_SOCKETS] = {0}; -static void sockets_init(void) { - if (_sockets_ready) +static void network_init_(void) { + if (_network_ready) return; signal(SIGPIPE, SIG_IGN); - _sockets_ready = 1; + _network_ready = 1; } -static void sockets_cleanup(void) { +static void network_cleanup_(void) { for (i64 i = 0; i < MAX_NUM_SOCKETS; ++i) if (_sockets[i].ready) { close(_sockets[i].socket); @@ -1099,8 +1169,8 @@ static void sockets_cleanup(void) { } } -static b8 sockets_open(u16 slot, IP_Address address, u16 *local_port) { - sockets_init(); +static b8 network_open_(u16 slot, IP_Address address, u16 *local_port) { + network_init_(); b8 change_address = !_sockets[slot].ready @@ -1175,7 +1245,7 @@ static b8 sockets_open(u16 slot, IP_Address address, u16 *local_port) { return 1; } -i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address) { +i64 network_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address) { if (slot >= MAX_NUM_SOCKETS) { LOG_ERROR("Invalid slot %d.", (i32) (u32) slot); return 0; @@ -1186,7 +1256,7 @@ i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP return 0; } - if (!sockets_open(slot, address, local_port)) + if (!network_open_(slot, address, local_port)) return 0; if (size <= 0) return 0; @@ -1238,7 +1308,7 @@ i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP return received; } -i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { +i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { if (slot >= MAX_NUM_SOCKETS) { LOG_ERROR("Invalid slot %d.", (i32) (u32) slot); return 0; @@ -1252,7 +1322,7 @@ i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { IP_Address local_address = address; local_address.port = 0; - if (!sockets_open(slot, local_address, local_port)) + if (!network_open_(slot, local_address, local_port)) return 0; if (size <= 0) return 0; @@ -1311,10 +1381,10 @@ i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { #include <alsa/asoundlib.h> -static b8 _sound_ready = 0; -static snd_pcm_t *_sound_out = NULL; +static b8 _sound_ready = 0; +static snd_pcm_t *_sound_out = NULL; -static void sound_init(void) { +static void sound_init_(void) { if (_sound_ready) return; @@ -1343,11 +1413,11 @@ static void sound_init(void) { if (s < 0) LOG_ERROR("snd_pcm_hw_params_set_format failed: %s", snd_strerror(s)); - s = snd_pcm_hw_params_set_rate(_sound_out, hw_params, SOUND_SAMPLE_RATE, 0); + s = snd_pcm_hw_params_set_rate(_sound_out, hw_params, PRIMARY_SOUND_SAMPLE_RATE, 0); if (s < 0) LOG_ERROR("snd_pcm_hw_params_set_rate failed: %s", snd_strerror(s)); - s = snd_pcm_hw_params_set_channels(_sound_out, hw_params, NUM_SOUND_CHANNELS); + s = snd_pcm_hw_params_set_channels(_sound_out, hw_params, NUM_PRIMARY_SOUND_CHANNELS); if (s < 0) LOG_ERROR("snd_pcm_hw_params_set_channels failed: %s", snd_strerror(s)); @@ -1361,7 +1431,7 @@ static void sound_init(void) { if (s < 0) LOG_ERROR("snd_pcm_sw_params_current failed: %s", snd_strerror(s)); - s = snd_pcm_sw_params_set_avail_min(_sound_out, sw_params, SOUND_AVAIL_MIN); + s = snd_pcm_sw_params_set_avail_min(_sound_out, sw_params, PRIMARY_SOUND_AVAIL_MIN); if (s < 0) LOG_ERROR("snd_pcm_sw_params_set_avail_min failed: %s", snd_strerror(s)); @@ -1376,7 +1446,7 @@ static void sound_init(void) { _sound_ready = 1; } -static void sound_cleanup(void) { +static void sound_cleanup_(void) { if (!_sound_ready) return; @@ -1397,34 +1467,34 @@ static void sound_cleanup(void) { _sound_ready = 0; } -void p_handle_sound(void) { - sound_init(); +void handle_primary_sound(void) { + sound_init_(); g_platform.num_sound_samples_elapsed = sound_samples_elapsed_(); - i64 num_frames = g_platform.num_sound_samples_elapsed * NUM_SOUND_CHANNELS; + i64 num_frames = g_platform.num_sound_samples_elapsed * NUM_PRIMARY_SOUND_CHANNELS; - if (num_frames > MAX_NUM_SOUND_FRAMES) { + if (num_frames > MAX_NUM_PRIMARY_SOUND_FRAMES) { LOG_ERROR("Sound buffer overflow."); - num_frames = MAX_NUM_SOUND_FRAMES; + num_frames = MAX_NUM_PRIMARY_SOUND_FRAMES; } i32 s; - if (num_frames <= MAX_NUM_SOUND_FRAMES - _sound_position) { - s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, num_frames / NUM_SOUND_CHANNELS); + if (num_frames <= MAX_NUM_PRIMARY_SOUND_FRAMES - _sound_position) { + s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, num_frames / NUM_PRIMARY_SOUND_CHANNELS); if (s < 0) LOG_ERROR("snd_pcm_writei failed: %s", snd_strerror(s)); memset(_sound_ring + _sound_position, 0, num_frames * sizeof *_sound_ring); } else { - i64 part_one = MAX_NUM_SOUND_FRAMES - _sound_position; + i64 part_one = MAX_NUM_PRIMARY_SOUND_FRAMES - _sound_position; i64 part_two = num_frames - part_one; - s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, part_one / NUM_SOUND_CHANNELS); + s = snd_pcm_writei(_sound_out, _sound_ring + _sound_position, part_one / NUM_PRIMARY_SOUND_CHANNELS); if (s < 0) LOG_ERROR("snd_pcm_writei failed: %s", snd_strerror(s)); - s = snd_pcm_writei(_sound_out, _sound_ring, part_two / NUM_SOUND_CHANNELS); + s = snd_pcm_writei(_sound_out, _sound_ring, part_two / NUM_PRIMARY_SOUND_CHANNELS); if (s < 0) LOG_ERROR("snd_pcm_writei failed: %s", snd_strerror(s)); @@ -1432,17 +1502,17 @@ void p_handle_sound(void) { memset(_sound_ring, 0, part_two * sizeof *_sound_ring); } - _sound_position = (_sound_position + num_frames) % MAX_NUM_SOUND_FRAMES; + _sound_position = (_sound_position + num_frames) % MAX_NUM_PRIMARY_SOUND_FRAMES; } -void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { +void queue_primary_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { if (num_samples < 0) LOG_ERROR("Invalid num samples %lld.", num_samples); if (frames == NULL) return; if (delay_in_samples < 0) { - frames += -delay_in_samples * NUM_SOUND_CHANNELS; + frames += -delay_in_samples * NUM_PRIMARY_SOUND_CHANNELS; num_samples -= delay_in_samples; delay_in_samples = 0; } @@ -1450,22 +1520,22 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { if (num_samples <= 0) return; - i64 num_frames = num_samples * NUM_SOUND_CHANNELS; + i64 num_frames = num_samples * NUM_PRIMARY_SOUND_CHANNELS; - if (num_frames > MAX_NUM_SOUND_FRAMES) { + if (num_frames > MAX_NUM_PRIMARY_SOUND_FRAMES) { LOG_ERROR("Sound buffer overflow."); return; } - sound_init(); + sound_init_(); - i64 begin = (_sound_position + delay_in_samples) % MAX_NUM_SOUND_FRAMES; + i64 begin = (_sound_position + delay_in_samples) % MAX_NUM_PRIMARY_SOUND_FRAMES; - if (num_frames <= MAX_NUM_SOUND_FRAMES - begin) + if (num_frames <= MAX_NUM_PRIMARY_SOUND_FRAMES - begin) for (i64 i = 0; i < num_frames; ++i) _sound_ring[begin + i] += frames[i]; else { - i64 part_one = MAX_NUM_SOUND_FRAMES - begin; + i64 part_one = MAX_NUM_PRIMARY_SOUND_FRAMES - begin; i64 part_two = num_frames - part_one; for (i64 i = 0; i < part_one; ++i) @@ -2087,7 +2157,7 @@ i32 x11_error_handler_(Display *display, XErrorEvent *event) { return 0; } -void p_init(void) { +void init_main_window(void) { for (i64 i = 0; i < NUM_FRAMES_AVERAGED; ++i) _frame_duration[i] = (MIN_FRAME_DURATION + MAX_FRAME_DURATION) / 2; @@ -2241,6 +2311,11 @@ void p_init(void) { _window = XCreateWindow(_display, _root_window, x, y, g_platform.frame_width, g_platform.frame_height, 0, depth, InputOutput, visual, CWEventMask, &(XSetWindowAttributes) { .event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask | VisibilityChangeMask | FocusChangeMask | StructureNotifyMask | SubstructureNotifyMask, }); + if (_window == 0) { + LOG_ERROR("XCreateWindow failed."); + return; + } + _im = XOpenIM(_display, NULL, NULL, NULL); if (_im == NULL) { @@ -2309,8 +2384,10 @@ void p_init(void) { _mapped = 0; } -void p_cleanup(void) { - if (!g_platform.graceful_exit) +void shutdown_all_systems(void) { + g_platform.done = 1; + + if (!g_platform.graceful_shutdown) return; if (_window != 0) @@ -2318,17 +2395,18 @@ void p_cleanup(void) { if (_display != NULL) XCloseDisplay (_display); + _window = 0; _display = NULL; - sockets_cleanup(); - sound_cleanup(); + network_cleanup_(); + sound_cleanup_(); } -i32 p_handle_events(void) { +i32 handle_main_window_events(void) { if (_display == NULL) return 0; - _frame_time = p_time(); + _frame_time = current_utc_time_in_milliseconds(); i32 num_events = 0; @@ -2848,11 +2926,11 @@ i32 p_handle_events(void) { return num_events; } -i32 p_wait_events(void) { +i32 wait_main_window_events(void) { i32 num_events = 0; for (;;) { - num_events = p_handle_events(); + num_events = handle_main_window_events(); if (num_events != 0) break; usleep(0); @@ -2861,7 +2939,7 @@ i32 p_wait_events(void) { return num_events; } -void p_render_frame(void) { +void render_main_window_frame(void) { if (g_platform.done) return; @@ -2891,10 +2969,10 @@ void p_render_frame(void) { XPutImage(_display, _window, _gc, &_image, 0, 0, 0, 0, _image.width, _image.height); XFlush(_display); - pixel_size_calubrate_(p_time() - _frame_time); + pixel_size_calubrate_(current_utc_time_in_milliseconds() - _frame_time); } -void p_clipboard_write_text(i64 size, c8 *data) { +void write_clipboard_text(i64 size, c8 *data) { if (size > MAX_CLIPBOARD_SIZE) { LOG_ERROR("Size is too big %lld.", size); return; @@ -2951,7 +3029,7 @@ b8 x11_screenshot_(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels // ================================================================ #if defined(__linux__) && (!NO_X11 || !NO_WAYLAND) -void p_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { +void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { if (width == NULL || height == NULL) { LOG_ERROR("Invalid arguments."); return; @@ -3090,11 +3168,11 @@ __attribute__((export_name("js_key_map"))) void *js_key_map(void) { } __attribute__((export_name("js_sound_sample_rate"))) f64 js_sound_sample_rate(void) { - return (f64) SOUND_SAMPLE_RATE; + return (f64) PRIMARY_SOUND_SAMPLE_RATE; } __attribute__((export_name("js_num_sound_channels"))) i32 js_num_sound_channels(void) { - return NUM_SOUND_CHANNELS; + return NUM_PRIMARY_SOUND_CHANNELS; } #endif // defined(__wasm__) @@ -3125,26 +3203,30 @@ static c8 _href [4096] = {0}; static u32 _pixels_scaled [MAX_NUM_PIXELS] = {0}; static u32 _pixels_internal [MAX_NUM_PIXELS] = {0}; static b8 _key_pressed [MAX_NUM_KEYS] = {0}; -static f32 _sound_buffer [MAX_NUM_SOUND_FRAMES] = {0}; +static f32 _sound_buffer [MAX_NUM_PRIMARY_SOUND_FRAMES] = {0}; static u8 _drop_buffer [DROP_FILES_BUFFER_SIZE] = {0}; -i64 p_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address) { +void shutdown_all_systems(void) { + g_platform.done = 1; +} + +i64 network_recv(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port, IP_Address *remote_address) { LOG_ERROR("Web sockets are not implemented."); return 0; } -i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { +i64 network_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { LOG_ERROR("Web sockets are not implemented."); return 0; } -i64 p_time(void); +i64 current_utc_time_in_milliseconds(void); -void p_sleep_for(i64 duration) { +void suspend_thread_for_milliseconds(i64 duration) { if (duration <= 0) return; - i64 t = p_time(); + i64 t = current_utc_time_in_milliseconds(); if (_timeout < t) _timeout = t + duration; @@ -3152,7 +3234,7 @@ void p_sleep_for(i64 duration) { _timeout += duration; } -void p_init(void) { +void init_main_window(void) { (void) rgb_f32_from_u32_; ++_num_events; @@ -3162,10 +3244,10 @@ void p_init(void) { for (i64 i = 0; i < NUM_FRAMES_AVERAGED; ++i) _frame_duration[i] = (MIN_FRAME_DURATION + MAX_FRAME_DURATION) / 2; - _sound_read = (MAX_NUM_SOUND_FRAMES + ((-SOUND_AVAIL_MIN) % MAX_NUM_SOUND_FRAMES)) % MAX_NUM_SOUND_FRAMES; + _sound_read = (MAX_NUM_PRIMARY_SOUND_FRAMES + ((-PRIMARY_SOUND_AVAIL_MIN) % MAX_NUM_PRIMARY_SOUND_FRAMES)) % MAX_NUM_PRIMARY_SOUND_FRAMES; } -i32 p_handle_events(void) { +i32 handle_main_window_events(void) { if (g_platform.files_dropped) drop_files_clean_(); @@ -3198,13 +3280,13 @@ i32 p_handle_events(void) { return n; } -i32 p_wait_events(void) { +i32 wait_main_window_events(void) { _wait_events = 1; - return p_handle_events(); + return handle_main_window_events(); } -void p_render_frame(void) { +void render_main_window_frame(void) { if (_frame_width == g_platform.frame_width && _frame_height == g_platform.frame_height) { i64 size = g_platform.frame_width * g_platform.frame_height; for (i64 i = 0; i < size; ++i) @@ -3224,9 +3306,9 @@ void p_render_frame(void) { } } -void p_clipboard_write_text_impl(i32 size, c8 *data); +void write_clipboard_text_impl(i32 size, c8 *data); -void p_clipboard_write_text(i64 size, c8 *data) { +void write_clipboard_text(i64 size, c8 *data) { if (size < 0 || data == NULL) return; if (size > MAX_CLIPBOARD_SIZE) @@ -3236,10 +3318,10 @@ void p_clipboard_write_text(i64 size, c8 *data) { for (i64 i = 0; i < size; ++i) g_platform.clipboard[i] = data[i]; - p_clipboard_write_text_impl((i32) size, data); + write_clipboard_text_impl((i32) size, data); } -void p_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { +void take_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) { if (width == NULL || height == NULL) { LOG_ERROR("Invalid arguments."); return; @@ -3249,17 +3331,17 @@ void p_screenshot(i64 max_num_pixels, i64 *width, i64 *height, vec4_f32 *pixels) *height = 0; } -void p_handle_sound(void) { +void handle_primary_sound(void) { g_platform.num_sound_samples_elapsed = sound_samples_elapsed_(); - _sound_position = (_sound_position + g_platform.num_sound_samples_elapsed * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES; + _sound_position = (_sound_position + g_platform.num_sound_samples_elapsed * NUM_PRIMARY_SOUND_CHANNELS) % MAX_NUM_PRIMARY_SOUND_FRAMES; } -void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { +void queue_primary_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { if (frames == NULL) return; if (delay_in_samples < 0) { - frames += -delay_in_samples * NUM_SOUND_CHANNELS; + frames += -delay_in_samples * NUM_PRIMARY_SOUND_CHANNELS; num_samples -= delay_in_samples; delay_in_samples = 0; } @@ -3267,19 +3349,19 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { if (num_samples <= 0) return; - i64 num_frames = num_samples * NUM_SOUND_CHANNELS; - if (num_frames > MAX_NUM_SOUND_FRAMES) { + i64 num_frames = num_samples * NUM_PRIMARY_SOUND_CHANNELS; + if (num_frames > MAX_NUM_PRIMARY_SOUND_FRAMES) { LOG_ERROR("Sound buffer overflow."); return; } - i64 begin = (_sound_position + delay_in_samples * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES; + i64 begin = (_sound_position + delay_in_samples * NUM_PRIMARY_SOUND_CHANNELS) % MAX_NUM_PRIMARY_SOUND_FRAMES; - if (num_frames <= MAX_NUM_SOUND_FRAMES - begin) + if (num_frames <= MAX_NUM_PRIMARY_SOUND_FRAMES - begin) for (i64 i = 0; i < num_frames; ++i) _sound_ring[begin + i] += frames[i]; else { - i64 part_one = MAX_NUM_SOUND_FRAMES - begin; + i64 part_one = MAX_NUM_PRIMARY_SOUND_FRAMES - begin; i64 part_two = num_frames - part_one; for (i64 i = 0; i < part_one; ++i) @@ -3290,7 +3372,7 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { } __attribute__((export_name("js_max_num_sound_frames"))) i32 js_max_num_sound_frames(void) { - return MAX_NUM_SOUND_FRAMES; + return MAX_NUM_PRIMARY_SOUND_FRAMES; } __attribute__((export_name("js_sound_buffer"))) void *js_sound_buffer(void) { @@ -3318,7 +3400,7 @@ __attribute__((export_name("js_pixels"))) void *js_pixels(void) { } __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 frame_height, i32 num_samples) { - i64 frame_time = p_time(); + i64 frame_time = current_utc_time_in_milliseconds(); if (frame_width > 0 && frame_height > 0 && frame_width * frame_height <= MAX_NUM_PIXELS) { _frame_width = frame_width; @@ -3337,17 +3419,17 @@ __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 fram } // Convert interleaved frames to non-interleaved. - for (i64 j = 0; j < NUM_SOUND_CHANNELS; ++j) + for (i64 j = 0; j < NUM_PRIMARY_SOUND_CHANNELS; ++j) for (i64 i = 0; i < num_samples; ++i) { - i64 n = (_sound_read + i * NUM_SOUND_CHANNELS + j) % MAX_NUM_SOUND_FRAMES; + i64 n = (_sound_read + i * NUM_PRIMARY_SOUND_CHANNELS + j) % MAX_NUM_PRIMARY_SOUND_FRAMES; _sound_buffer[j * num_samples + i] = _sound_ring[n]; _sound_ring[n] = 0.f; } - _sound_read = (_sound_read + num_samples * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES; + _sound_read = (_sound_read + num_samples * NUM_PRIMARY_SOUND_CHANNELS) % MAX_NUM_PRIMARY_SOUND_FRAMES; if (do_render) - pixel_size_calubrate_(p_time() - frame_time); + pixel_size_calubrate_(current_utc_time_in_milliseconds() - frame_time); } __attribute__((export_name("js_mousemove"))) void js_mousemove(i32 x, i32 y) { diff --git a/stackless_coroutine.c b/stackless_coroutine.c index 705d11c..d819f35 100755 --- a/stackless_coroutine.c +++ b/stackless_coroutine.c @@ -246,9 +246,9 @@ static void stackless_coroutine_dispatch(void *promise) { promise_ = (Promise_Of(coro_)) { CORO_INITIAL_(0, coro_), __VA_ARGS__ }; \ } while (0) -#define CORO_INIT_ID(promise_, id_, ...) \ - do { \ - promise_ = (Promise_Of(coro_)) { CORO_INITIAL_CORO_INITIAL_(id_), coro_), __VA_ARGS__ }; \ +#define CORO_INIT_ID(promise_, id_, ...) \ + do { \ + promise_ = (Promise_Of(coro_)) { CORO_INITIAL_(id_, coro_), __VA_ARGS__ }; \ } while (0) #define coro_finished(promise_) ((promise_)._index == -1) @@ -291,37 +291,6 @@ CORO_IMPL(test_foo) { async_return(42); } CORO_END -CORO_DECL_STATIC(int, test_bar, ); - -CORO_IMPL(test_bar) { - yield_void; - async_return(42); -} CORO_END - -CORO_STATIC(int, test_gen, int i; int min; int max;) { - for (self->i = self->min; self->i < self->max; self->i++) - yield(self->i); - async_return(self->max); -} CORO_END - -CORO_STATIC_VOID(test_task, ) { - yield_void; - yield_void; - async_return_void; -} CORO_END - -CORO_STATIC_VOID(test_nest_task, Promise_Of(test_task) promise;) { - CORO_INIT(self->promise, test_task, ); - await(self->promise); - await(self->promise); - await(self->promise); -} CORO_END - -CORO_STATIC(int, test_nest_generator, Promise_Of(test_gen) promise;) { - CORO_INIT(self->promise, test_gen, .min = 1, .max = 3); - yield_await(self->promise); -} CORO_END - TEST("coroutine init") { Promise_Of(test_foo) promise; CORO_INIT(promise, test_foo, ); @@ -342,6 +311,13 @@ TEST("coroutine execute and return") { REQUIRE(coro_finished(promise)); } +CORO_DECL_STATIC(int, test_bar, ); + +CORO_IMPL(test_bar) { + yield_void; + async_return(42); +} CORO_END + TEST("coroutine execute two steps") { Promise_Of(test_bar) promise; CORO_INIT(promise, test_bar, .return_value = 0); @@ -351,6 +327,12 @@ TEST("coroutine execute two steps") { REQUIRE(promise.return_value == 42); } +CORO_STATIC(int, test_gen, int i; int min; int max;) { + for (self->i = self->min; self->i < self->max; self->i++) + yield(self->i); + async_return(self->max); +} CORO_END + TEST("coroutine generator") { int i; Promise_Of(test_gen) promise; @@ -368,6 +350,12 @@ TEST("coroutine status finished") { REQUIRE(coro_finished(promise)); } +CORO_STATIC_VOID(test_task, ) { + yield_void; + yield_void; + async_return_void; +} CORO_END + TEST("coroutine task") { Promise_Of(test_task) promise; CORO_INIT(promise, test_task, ); @@ -379,6 +367,13 @@ TEST("coroutine task") { REQUIRE(coro_finished(promise)); } +CORO_STATIC_VOID(test_nest_task, Promise_Of(test_task) promise;) { + CORO_INIT(self->promise, test_task, ); + await(self->promise); + await(self->promise); + await(self->promise); +} CORO_END + TEST("coroutine nested task") { Promise_Of(test_nest_task) promise; CORO_INIT(promise, test_nest_task, ); @@ -390,6 +385,11 @@ TEST("coroutine nested task") { REQUIRE(coro_finished(promise)); } +CORO_STATIC(int, test_nest_generator, Promise_Of(test_gen) promise;) { + CORO_INIT(self->promise, test_gen, .min = 1, .max = 3); + yield_await(self->promise); +} CORO_END + TEST("coroutine nested generator") { Promise_Of(test_nest_generator) promise; CORO_INIT(promise, test_nest_generator, ); |