diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-11-01 22:30:29 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-11-01 22:30:29 +0100 |
commit | 2afdeaedbfb488f20cdc1cca7ce01a915df4d53a (patch) | |
tree | 76fc484f3663d54a158cda305e74d94ddcc12782 | |
parent | 63c3b9bda3fe7eb8750f084ff070f40b967f9532 (diff) | |
download | reduced_system_layer-2afdeaedbfb488f20cdc1cca7ce01a915df4d53a.zip |
wasm: Implement some events
-rw-r--r-- | Dockerfile | 4 | ||||
-rwxr-xr-x | examples/ui.c | 385 | ||||
-rw-r--r-- | graphics.c | 25 | ||||
-rw-r--r-- | index.htm | 106 | ||||
-rwxr-xr-x | reduced_system_layer.c | 98 |
5 files changed, 379 insertions, 239 deletions
@@ -1,7 +1,9 @@ FROM alpine as build RUN apk add clang lld +COPY examples/ui.c /usr/examples/ui.c COPY reduced_system_layer.c /usr/reduced_system_layer.c -RUN clang -D REDUCED_SYSTEM_LAYER_EXAMPLE --target=wasm32 -nostdlib -Wl,--no-entry,--allow-undefined -o /usr/index.wasm /usr/reduced_system_layer.c +COPY graphics.c /usr/graphics.c +RUN clang --target=wasm32 -nostdlib -Wl,--no-entry,--allow-undefined -o /usr/index.wasm /usr/examples/ui.c FROM nginx:alpine EXPOSE 80 diff --git a/examples/ui.c b/examples/ui.c index 4730a9d..dc54cc0 100755 --- a/examples/ui.c +++ b/examples/ui.c @@ -27,164 +27,192 @@ exit $? # */ #include "../graphics.c" -i32 main(i32 argc, c8 **argv) { - (void) argc; - (void) argv; - - platform = (Platform) { - .title = "UI", - .frame_width = 960, - .frame_height = 720, - }; - - p_init(); - - b8 button_0_down = 0; - b8 button_1_down = 0; - b8 button_1_checked = 0; - - i64 text_len = 0; - static c32 text[512] = {0}; - - i64 cursor = 0; - i64 selection = 0; - - while (!platform.done) { - p_wait_events(); - - for (i32 j = 0; j < platform.frame_height; ++j) - for (i32 i = 0; i < platform.frame_width; ++i) - platform.pixels[j * platform.frame_width + i] = 0x302000; - - if (platform.cursor_x >= 40 && platform.cursor_x < 100 && platform.cursor_y >= 40 && platform.cursor_y < 100) { - button_0_down = platform.key_down[BUTTON_LEFT]; - if (button_0_down) - fill_rectangle(OP_SET, 0xffffff, 40, 40, 60, 60); - else - fill_rectangle(OP_SET, 0x00ff00, 40, 40, 60, 60); - } else { - button_0_down = 0; - fill_rectangle(OP_SET, 0x208020, 40, 40, 60, 60); - } - - if (platform.cursor_x >= 40 && platform.cursor_x < 100 && platform.cursor_y >= 120 && platform.cursor_y < 180) { - button_1_down = platform.key_down[BUTTON_LEFT]; - if (platform.key_pressed[BUTTON_LEFT]) - button_1_checked = !button_1_checked; - if (button_1_down) - fill_rectangle(OP_SET, 0xffffff, 40, 120, 60, 60); - else if (button_1_checked) - fill_rectangle(OP_SET, 0xff8080, 40, 120, 60, 60); - else - fill_rectangle(OP_SET, 0x80ff80, 40, 120, 60, 60); - } else { - button_1_down = 0; - if (button_1_checked) - fill_rectangle(OP_SET, 0xff0000, 40, 120, 60, 60); - else - fill_rectangle(OP_SET, 0x00ff00, 40, 120, 60, 60); - } - - i64 w = platform.frame_width / 2; - i64 h = platform.frame_height / 2; - i64 x0 = w / 2; - i64 y0 = h / 2; - - i64 color = 0xff7f7f; - - if (platform.cursor_x >= x0 && platform.cursor_x < x0 + w && - platform.cursor_y >= y0 && platform.cursor_y < y0 + h) - color = 0xffffff; - - for (i64 i = 0; i < platform.input_size; ++i) - if (platform.input[i].ctrl) - switch (platform.input[i].key) { - case 'v': { - if (selection != 0) { - i64 i0 = selection < 0 ? cursor + selection : cursor; - i64 i1 = selection < 0 ? cursor : cursor + selection; - for (i64 i = 0; i1 + i < text_len; ++i) - text[i0 + i] = text[i1 + i]; - selection = 0; - cursor = i0; - text_len -= i1 - i0; - } +b8 button_0_down = 0; +b8 button_1_down = 0; +b8 button_1_checked = 0; + +i64 text_len = 0; +static c32 text[512] = {0}; + +i64 cursor = 0; +i64 selection = 0; + +void update_and_render_frame(void) { + p_wait_events(); + + for (i32 j = 0; j < platform.frame_height; ++j) + for (i32 i = 0; i < platform.frame_width; ++i) + platform.pixels[j * platform.frame_width + i] = 0x302000; + + if (platform.cursor_x >= 40 && platform.cursor_x < 100 && platform.cursor_y >= 40 && platform.cursor_y < 100) { + button_0_down = platform.key_down[BUTTON_LEFT]; + if (button_0_down) + fill_rectangle(OP_SET, 0xffffff, 40, 40, 60, 60); + else + fill_rectangle(OP_SET, 0x00ff00, 40, 40, 60, 60); + } else { + button_0_down = 0; + fill_rectangle(OP_SET, 0x208020, 40, 40, 60, 60); + } - for (i64 n = 0; n < platform.clipboard_size;) { - c32 c = utf8_read(platform.clipboard_size - n, platform.clipboard + n); + if (platform.cursor_x >= 40 && platform.cursor_x < 100 && platform.cursor_y >= 120 && platform.cursor_y < 180) { + button_1_down = platform.key_down[BUTTON_LEFT]; + if (platform.key_pressed[BUTTON_LEFT]) + button_1_checked = !button_1_checked; + if (button_1_down) + fill_rectangle(OP_SET, 0xffffff, 40, 120, 60, 60); + else if (button_1_checked) + fill_rectangle(OP_SET, 0xff8080, 40, 120, 60, 60); + else + fill_rectangle(OP_SET, 0x80ff80, 40, 120, 60, 60); + } else { + button_1_down = 0; + if (button_1_checked) + fill_rectangle(OP_SET, 0xff0000, 40, 120, 60, 60); + else + fill_rectangle(OP_SET, 0x00ff00, 40, 120, 60, 60); + } - if (text_len < (i64) (sizeof text / sizeof *text)) { - for (i64 j = text_len; j > cursor; --j) - text[j] = text[j - 1]; - text[cursor++] = c; - ++text_len; - } + i64 w = platform.frame_width / 2; + i64 h = platform.frame_height / 2; + i64 x0 = w / 2; + i64 y0 = h / 2; - n += utf8_size(c); - } - } break; + i64 color = 0xff7f7f; - case 'x': { - i64 len = 0; - static c8 buf[1024]; + if (platform.cursor_x >= x0 && platform.cursor_x < x0 + w && + platform.cursor_y >= y0 && platform.cursor_y < y0 + h) + color = 0xffffff; + for (i64 i = 0; i < platform.input_size; ++i) + if (platform.input[i].ctrl) + switch (platform.input[i].key) { + case 'v': { + if (selection != 0) { i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; - for (i64 i = 0; len + 4 <= (i64) sizeof buf && i < i1 - i0; ++i) - len += utf8_write(text[i0 + i], buf + len); - - if (len > 0) - p_clipboard_write(len, buf); - for (i64 i = 0; i1 + i < text_len; ++i) text[i0 + i] = text[i1 + i]; selection = 0; cursor = i0; text_len -= i1 - i0; - } break; + } - case 'c': { - i64 len = 0; - static c8 buf[1024]; + for (i64 n = 0; n < platform.clipboard_size;) { + c32 c = utf8_read(platform.clipboard_size - n, platform.clipboard + n); - i64 i0 = selection < 0 ? cursor + selection : cursor; - i64 i1 = selection < 0 ? cursor : cursor + selection; - for (i64 i = 0; len + 4 <= (i64) sizeof buf && i < i1 - i0; ++i) - len += utf8_write(text[i0 + i], buf + len); - - if (len > 0) - p_clipboard_write(len, buf); - } break; - - default:; - } - else - switch (platform.input[i].key) { - case KEY_LEFT: - if (platform.key_down[MOD_SHIFT]) { - if (cursor > 0) - ++selection; - } else if (selection != 0) { - cursor = selection < 0 ? cursor + selection + 1 : cursor + 1; - selection = 0; + if (text_len < (i64) (sizeof text / sizeof *text)) { + for (i64 j = text_len; j > cursor; --j) + text[j] = text[j - 1]; + text[cursor++] = c; + ++text_len; } + + n += utf8_size(c); + } + } break; + + case 'x': { + i64 len = 0; + static c8 buf[1024]; + + i64 i0 = selection < 0 ? cursor + selection : cursor; + i64 i1 = selection < 0 ? cursor : cursor + selection; + for (i64 i = 0; len + 4 <= (i64) sizeof buf && i < i1 - i0; ++i) + len += utf8_write(text[i0 + i], buf + len); + + if (len > 0) + p_clipboard_write(len, buf); + + for (i64 i = 0; i1 + i < text_len; ++i) + text[i0 + i] = text[i1 + i]; + selection = 0; + cursor = i0; + text_len -= i1 - i0; + } break; + + case 'c': { + i64 len = 0; + static c8 buf[1024]; + + i64 i0 = selection < 0 ? cursor + selection : cursor; + i64 i1 = selection < 0 ? cursor : cursor + selection; + for (i64 i = 0; len + 4 <= (i64) sizeof buf && i < i1 - i0; ++i) + len += utf8_write(text[i0 + i], buf + len); + + if (len > 0) + p_clipboard_write(len, buf); + } break; + + default:; + } + else + switch (platform.input[i].key) { + case KEY_LEFT: + if (platform.key_down[MOD_SHIFT]) { if (cursor > 0) - --cursor; - break; - - case KEY_RIGHT: - if (platform.key_down[MOD_SHIFT]) { - if (cursor < text_len) - --selection; - } else if (selection != 0) { - cursor = selection < 0 ? cursor - 1 : cursor + selection - 1; - selection = 0; - } + ++selection; + } else if (selection != 0) { + cursor = selection < 0 ? cursor + selection + 1 : cursor + 1; + selection = 0; + } + if (cursor > 0) + --cursor; + break; + + case KEY_RIGHT: + if (platform.key_down[MOD_SHIFT]) { if (cursor < text_len) - ++cursor; - break; + --selection; + } else if (selection != 0) { + cursor = selection < 0 ? cursor - 1 : cursor + selection - 1; + selection = 0; + } + if (cursor < text_len) + ++cursor; + break; - case '\b': + case '\b': + if (selection != 0) { + i64 i0 = selection < 0 ? cursor + selection : cursor; + i64 i1 = selection < 0 ? cursor : cursor + selection; + for (i64 i = 0; i1 + i < text_len; ++i) + text[i0 + i] = text[i1 + i]; + selection = 0; + cursor = i0; + text_len -= i1 - i0; + } else if (cursor > 0 && text_len > 0) { + for (i64 i = cursor; i < text_len; ++i) + text[i - 1] = text[i]; + --cursor; + --text_len; + } + break; + + case KEY_DELETE: + if (selection != 0) { + i64 i0 = selection < 0 ? cursor + selection : cursor; + i64 i1 = selection < 0 ? cursor : cursor + selection; + for (i64 i = 0; i1 + i < text_len; ++i) + text[i0 + i] = text[i1 + i]; + selection = 0; + cursor = i0; + text_len -= i1 - i0; + } else if (cursor < text_len) { + for (i64 i = cursor + 1; i < text_len; ++i) + text[i - 1] = text[i]; + --text_len; + } + break; + + case '\n': + case '\r': + case '\t': + platform.input[i].c = platform.input[i].key; + // fallthrough + + default: + if (platform.input[i].c) { if (selection != 0) { i64 i0 = selection < 0 ? cursor + selection : cursor; i64 i1 = selection < 0 ? cursor : cursor + selection; @@ -193,64 +221,35 @@ i32 main(i32 argc, c8 **argv) { selection = 0; cursor = i0; text_len -= i1 - i0; - } else if (cursor > 0 && text_len > 0) { - for (i64 i = cursor; i < text_len; ++i) - text[i - 1] = text[i]; - --cursor; - --text_len; } - break; - case KEY_DELETE: - if (selection != 0) { - i64 i0 = selection < 0 ? cursor + selection : cursor; - i64 i1 = selection < 0 ? cursor : cursor + selection; - for (i64 i = 0; i1 + i < text_len; ++i) - text[i0 + i] = text[i1 + i]; - selection = 0; - cursor = i0; - text_len -= i1 - i0; - } else if (cursor < text_len) { - for (i64 i = cursor + 1; i < text_len; ++i) - text[i - 1] = text[i]; - --text_len; + if (text_len < (i64) (sizeof text / sizeof *text)) { + for (i64 i = text_len; i > cursor; --i) + text[i] = text[i - 1]; + text[cursor++] = platform.input[i].c; + ++text_len; } - break; - - case '\n': - case '\r': - case '\t': - platform.input[i].c = platform.input[i].key; - // fallthrough - - default: - if (platform.input[i].c) { - if (selection != 0) { - i64 i0 = selection < 0 ? cursor + selection : cursor; - i64 i1 = selection < 0 ? cursor : cursor + selection; - for (i64 i = 0; i1 + i < text_len; ++i) - text[i0 + i] = text[i1 + i]; - selection = 0; - cursor = i0; - text_len -= i1 - i0; - } - - if (text_len < (i64) (sizeof text / sizeof *text)) { - for (i64 i = text_len; i > cursor; --i) - text[i] = text[i - 1]; - text[cursor++] = platform.input[i].c; - ++text_len; - } - } - } + } + } - draw_text_area(0, x0 + 8, y0 - 8, w, h, 10., 10., text_len, text); - draw_text_area(color, x0, y0, w, h, 10., 10., text_len, text); - draw_selection_cursor(0xffffff, x0, y0, w, h, 10., 10., cursor, selection, text_len, text); + draw_text_area(0, x0 + 8, y0 - 8, w, h, 10., 10., text_len, text); + draw_text_area(color, x0, y0, w, h, 10., 10., text_len, text); + draw_selection_cursor(0xffffff, x0, y0, w, h, 10., 10., cursor, selection, text_len, text); - p_render_frame(); - } + p_render_frame(); +} + +i32 main(i32 argc, c8 **argv) { + (void) argc; + (void) argv; + + platform = (Platform) { + .title = "UI", + .frame_width = 960, + .frame_height = 720, + }; + + p_event_loop(); - p_cleanup(); return 0; } @@ -47,8 +47,6 @@ void draw_selection_cursor(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 #ifndef GRAPHICS_IMPL_GUARD_ #define GRAPHICS_IMPL_GUARD_ -#include <math.h> - f64 min3(f64 a, f64 b, f64 c) { if (a < b && a < c) return a; @@ -157,7 +155,8 @@ i64 char_width(c32 c) { } i64 char_spacing(i64 num_chars, c32 *text, i64 index) { - assert(text != NULL); + if (text == NULL) + return 0; if (index < 0 || index + 1 >= num_chars) return 0; @@ -172,7 +171,8 @@ i64 char_spacing(i64 num_chars, c32 *text, i64 index) { } i64 text_cursor(i64 num_chars, c32 *text) { - assert(text != NULL); + if (text == NULL) + return 0; i64 cursor = 0; @@ -195,7 +195,8 @@ i64 text_cursor(i64 num_chars, c32 *text) { } i64 enum_text_columns(i64 num_chars, c32 *text) { - assert(text != NULL); + if (text == NULL) + return 0; i64 cols = 0; i64 n = 0; @@ -228,7 +229,8 @@ i64 enum_text_columns(i64 num_chars, c32 *text) { } i64 enum_text_rows(i64 num_chars, c32 *text) { - assert(text != NULL); + if (text == NULL) + return 0; i64 rows = 0; @@ -243,7 +245,8 @@ i64 enum_text_rows(i64 num_chars, c32 *text) { } void draw_text(u32 color, f64 x0, f64 y0, f64 scale_x, f64 scale_y, i64 num_chars, c32 *text) { - assert(text != NULL); + if (text == NULL) + return; f64 x = x0; f64 y = y0; @@ -436,8 +439,8 @@ void fill_line(u32 op, u32 color, f64 x0, f64 y0, f64 x1, f64 y1, f64 width) { } void draw_text_area(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 num_chars, c32 *text) { - assert(max_scale_x > 1e-6); - assert(max_scale_y > 1e-6); + if (max_scale_x < 1e-6 || max_scale_y < 1e-6) + return; i64 num_columns = enum_text_columns(num_chars, text); i64 num_rows = enum_text_rows(num_chars, text); @@ -457,8 +460,8 @@ void draw_text_area(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_sc } void draw_selection_cursor(u32 color, f64 x0, f64 y0, f64 width, f64 height, f64 max_scale_x, f64 max_scale_y, i64 cursor, i64 selection, i64 num_chars, c32 *text) { - assert(max_scale_x > 1e-6); - assert(max_scale_y > 1e-6); + if (max_scale_x < 1e-6 || max_scale_y < 1e-6) + return; i64 num_columns = enum_text_columns(num_chars, text); i64 num_rows = enum_text_rows(num_chars, text); @@ -9,15 +9,27 @@ <body style="margin: 0; height: 100%; overflow: hidden; overflow-x: hidden;"> <canvas style="margin: 0; width: 100%; height: 100%;" id="frame" oncontextmenu="event.preventDefault()"></canvas> <script type="text/javascript"> - async function run() { + function string_from_memory(memory, offset) { + let len = 0; + console.log(memory); + while (memory[offset + len] != 0) { + ++len; + } + return new TextDecoder().decode(memory.subarray(offset, offset + len)); + } + + async function run(attrs) { + let wait_for_events = false; + let sleep_duration = 0; + let canvas; let program; - let memory_view; + let memory; let pixels_address; let context; let animation_frame; - canvas = document.getElementById("frame"); + canvas = document.getElementById(attrs.id); context = canvas.getContext("2d"); program = await WebAssembly.instantiateStreaming( @@ -35,16 +47,14 @@ "env" : { p_init : () => { program.instance.exports.js_init(); - memory_view = new Uint8Array(program.instance.exports.memory.buffer); + memory = new Uint8Array(program.instance.exports.memory.buffer); pixels_address = program.instance.exports.js_pixels(); + document.title = string_from_memory(memory, program.instance.exports.js_title()); }, p_render_frame_impl : () => { - canvas.width = window.innerWidth; - canvas.height = window.innerHeight; - let data = new ImageData( new Uint8ClampedArray( - memory_view.subarray( + memory.subarray( pixels_address, pixels_address + 4 * canvas.width * canvas.height ) @@ -55,18 +65,23 @@ context.putImageData(data, 0, 0); }, - p_cleanup : () => {}, - p_handle_events : () => {}, - p_wait_events : () => {}, - p_sleep_for : (time) => {}, - p_time : Date.now, + p_clipboard_write : (size, text) => { + navigator.clipboard.writeText( + new TextDecoder().decode(memory.subarray(text, text + size)) + ).catch((e) => { console.error(e); }); + }, + p_cleanup : () => {}, + p_wait_events_impl : () => { wait_for_events = true; }, + p_sleep_for : (time) => { sleep_duration += time; }, + p_time : Date.now, + sqrt : Math.sqrt, + floor : Math.floor, + ceil : Math.ceil, memset : (dst, val, num) => { - // FIXME PERF for (let i = 0; i < num; ++i) dst[i] = val; }, memcpy : (dst, src, num) => { - // FIXME PERF for (let i = 0; i < num; ++i) dst[i] = src[i]; }, @@ -77,14 +92,71 @@ program.instance.exports.js_main(); animation_frame = (time) => { + if (attrs.fit_window) { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + } + + wait_for_events = false; program.instance.exports.js_frame(canvas.width, canvas.height); - window.requestAnimationFrame(animation_frame); + + if (!wait_for_events) { + if (sleep_duration > 0) { + sleep_duration = 0; + setTimeout(() => { + window.requestAnimationFrame(animation_frame); + }, sleep_duration); + } else + window.requestAnimationFrame(animation_frame); + } }; + window.addEventListener("resize", (ev) => { + window.requestAnimationFrame(animation_frame); + }); + + canvas.addEventListener("mousedown", (ev) => { + program.instance.exports.js_mousedown(ev.buttons); + window.requestAnimationFrame(animation_frame); + }); + + canvas.addEventListener("mouseup", (ev) => { + program.instance.exports.js_mouseup(ev.buttons); + window.requestAnimationFrame(animation_frame); + }); + + canvas.addEventListener("mousemove", (ev) => { + program.instance.exports.js_mousemove(ev.clientX, ev.clientY); + window.requestAnimationFrame(animation_frame); + }); + + canvas.addEventListener("mouseenter", (ev) => { + console.log(ev); + window.requestAnimationFrame(animation_frame); + }); + + canvas.addEventListener("mouseleave", (ev) => { + console.log(ev); + window.requestAnimationFrame(animation_frame); + }); + + window.addEventListener("keydown", (ev) => { + console.log(ev); + window.requestAnimationFrame(animation_frame); + }); + + window.addEventListener("keyup", (ev) => { + console.log(ev); + window.requestAnimationFrame(animation_frame); + }); + window.requestAnimationFrame(animation_frame); } - run().catch((e) => console.error(e)); + run({ + id : "frame", + fit_window : true, + }).catch((e) => console.error(e)); </script> </body> </html> diff --git a/reduced_system_layer.c b/reduced_system_layer.c index 5ddd3ab..7cbfd93 100755 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -108,6 +108,13 @@ typedef double f64; // // ================================================================ +#if !defined(__wasm__) +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include <math.h> +#endif + #ifdef __cplusplus extern "C" { #endif @@ -118,6 +125,7 @@ enum { MAX_CLIPBOARD_SIZE = 10 * 1024 * 1024, MAX_NUM_AUDIO_SAMPLES = 0, MAX_NUM_SOCKETS = 64, + MAX_NUM_KEYS = 512, AUDIO_NUM_CHANNELS = 2, AUDIO_SAMPLE_RATE = 44100, @@ -186,8 +194,8 @@ typedef struct { i32 cursor_dx; i32 cursor_dy; i64 wheel_dy; - b8 key_down[512]; - b8 key_pressed[512]; + b8 key_down[MAX_NUM_KEYS]; + b8 key_pressed[MAX_NUM_KEYS]; } Platform; typedef struct { @@ -219,8 +227,9 @@ i32 p_wait_events(void); void p_render_frame(void); // User-defined proc -void p_frame(void); +void update_and_render_frame(void); +// Convenient helper for the event loop void p_event_loop(void); // Clipboard @@ -238,6 +247,14 @@ extern Platform platform; #ifdef __wasm__ i32 main(i32 argc, c8 **argv); + +f64 sqrt(f64 x); +f64 floor(f64 x); +f64 ceil(f64 x); + +#ifndef NULL +#define NULL ((void *) 0) +#endif #endif #ifdef __cplusplus @@ -258,7 +275,7 @@ i32 main(i32 argc, c8 **argv); // NOTE // This procedure is required for the WebAssembly compatibility. -void p_frame(void) { +void update_and_render_frame(void) { p_handle_events(); i64 w = platform.frame_width / 2; @@ -282,7 +299,7 @@ i32 main(i32 argc, c8 **argv) { (void) argv; platform = (Platform) { - .title = "Reduced System Layer", + .title = "Example", .frame_width = 1280, .frame_height = 720, }; @@ -308,7 +325,7 @@ Platform platform = {0}; void p_event_loop(void) { p_init(); - while (!platform.done) p_frame(); + while (!platform.done) update_and_render_frame(); p_cleanup(); } @@ -392,10 +409,6 @@ i32 utf8_write(c32 c, c8 *buffer) { #if defined(__unix__) -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - #include <time.h> #include <sched.h> #include <unistd.h> @@ -669,8 +682,8 @@ i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { #include <X11/Xutil.h> #include <X11/Xatom.h> -static i16 _key_table[512] = {0}; -static b8 _key_repeat[512] = {0}; +static i16 _key_table[MAX_NUM_KEYS] = {0}; +static b8 _key_repeat[MAX_NUM_KEYS] = {0}; static u32 _buffer[MAX_NUM_PIXELS] = {0}; static Input_Key _input[MAX_INPUT_SIZE] = {0}; static c8 _clipboard_buffer[MAX_CLIPBOARD_SIZE] = {0}; @@ -1205,12 +1218,31 @@ void p_queue_sound(i64 delay, i64 num_samples, f32 *samples) { #ifdef __wasm__ -static u32 _buffer[MAX_NUM_PIXELS] = {0}; +static u32 _buffer[MAX_NUM_PIXELS] = {0}; +static i32 _num_events = 0; +static b8 _key_pressed[MAX_NUM_KEYS] = {0}; + +i32 p_handle_events(void) { + for (i64 i = 0; i < MAX_NUM_KEYS; ++i) + platform.key_pressed[i] = _key_pressed[i]; + for (i64 i = 0; i < MAX_NUM_KEYS; ++i) + _key_pressed[i] = 0; + i32 n = _num_events; + _num_events = 0; + return n; +} + +i32 p_wait_events_impl(void); + +i32 p_wait_events(void) { + p_wait_events_impl(); + return p_handle_events(); +} void p_render_frame_impl(void); void p_render_frame(void) { - // Make the canvas data opaque. + // Make canvas pixels opaque. i64 size = platform.frame_width * platform.frame_height; for (i64 i = 0; i < size; ++i) platform.pixels[i] |= 0xff000000; @@ -1227,15 +1259,47 @@ __attribute__((export_name("js_init"))) void js_init(void) { platform.done = 1; } +__attribute__((export_name("js_title"))) c8 *js_title(void) { + return platform.title; +} + __attribute__((export_name("js_pixels"))) void *js_pixels(void) { return platform.pixels; } __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 frame_height) { - platform.frame_width = frame_width; - platform.frame_height = frame_height; + if (platform.frame_width != frame_width || platform.frame_height != frame_height) { + ++_num_events; + platform.frame_width = frame_width; + platform.frame_height = frame_height; + } + + update_and_render_frame(); +} + +__attribute__((export_name("js_mousemove"))) void js_mousemove(i32 x, i32 y) { + ++_num_events; + platform.cursor_dx = x - platform.cursor_x; + platform.cursor_dy = y - platform.cursor_y; + platform.cursor_x = x; + platform.cursor_y = y; +} + +__attribute__((export_name("js_mousedown"))) void js_mousedown(u32 buttons) { + ++_num_events; + if ((buttons & 1) && !platform.key_down[BUTTON_LEFT]) _key_pressed[BUTTON_LEFT] = 1; + if ((buttons & 2) && !platform.key_down[BUTTON_RIGHT]) _key_pressed[BUTTON_RIGHT] = 1; + if ((buttons & 4) && !platform.key_down[BUTTON_MIDDLE]) _key_pressed[BUTTON_MIDDLE] = 1; + if (buttons & 1) platform.key_down[BUTTON_LEFT] = 1; + if (buttons & 2) platform.key_down[BUTTON_RIGHT] = 1; + if (buttons & 4) platform.key_down[BUTTON_MIDDLE] = 1; +} - p_frame(); +__attribute__((export_name("js_mouseup"))) void js_mouseup(u32 buttons) { + ++_num_events; + if (!(buttons & 1)) platform.key_down[BUTTON_LEFT] = 0; + if (!(buttons & 2)) platform.key_down[BUTTON_RIGHT] = 0; + if (!(buttons & 4)) platform.key_down[BUTTON_MIDDLE] = 0; } #endif // __wasm__ |