summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMitya Selivanov <automainint@guattari.tech>2024-11-01 22:30:29 +0100
committerMitya Selivanov <automainint@guattari.tech>2024-11-01 22:30:29 +0100
commit2afdeaedbfb488f20cdc1cca7ce01a915df4d53a (patch)
tree76fc484f3663d54a158cda305e74d94ddcc12782
parent63c3b9bda3fe7eb8750f084ff070f40b967f9532 (diff)
downloadreduced_system_layer-2afdeaedbfb488f20cdc1cca7ce01a915df4d53a.zip
wasm: Implement some events
-rw-r--r--Dockerfile4
-rwxr-xr-xexamples/ui.c385
-rw-r--r--graphics.c25
-rw-r--r--index.htm106
-rwxr-xr-xreduced_system_layer.c98
5 files changed, 379 insertions, 239 deletions
diff --git a/Dockerfile b/Dockerfile
index 1967156..9875b94 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -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;
}
diff --git a/graphics.c b/graphics.c
index 3a4138c..d58f0d8 100644
--- a/graphics.c
+++ b/graphics.c
@@ -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);
diff --git a/index.htm b/index.htm
index 0ffcf89..e3e6872 100644
--- a/index.htm
+++ b/index.htm
@@ -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__