diff options
author | Mitya Selivanov <automainint@guattari.tech> | 2024-11-01 03:28:20 +0100 |
---|---|---|
committer | Mitya Selivanov <automainint@guattari.tech> | 2024-11-01 03:28:20 +0100 |
commit | eb0c1592d49de956c8c4d83a831fab3cf0372acb (patch) | |
tree | 51af9b577499b85397267baed0db96046e12aefe | |
parent | 3d1e81ef18c4b2138b834459262f262e44a3397d (diff) | |
download | reduced_system_layer-eb0c1592d49de956c8c4d83a831fab3cf0372acb.zip |
Simple WebAssembly impl
-rw-r--r-- | Dockerfile | 2 | ||||
-rw-r--r-- | index.htm | 79 | ||||
-rw-r--r-- | nginx.conf | 1 | ||||
-rwxr-xr-x | reduced_system_layer.c | 81 |
4 files changed, 155 insertions, 8 deletions
@@ -1,6 +1,6 @@ FROM emscripten/emsdk as build COPY reduced_system_layer.c /usr/reduced_system_layer.c -RUN emcc -o /usr/index.wasm /usr/reduced_system_layer.c +RUN emcc -D REDUCED_SYSTEM_LAYER_EXAMPLE -s ERROR_ON_UNDEFINED_SYMBOLS=0 -s EXPORTED_FUNCTIONS=_js_main,_js_init,_js_pixels,_js_frame -o /usr/index.wasm /usr/reduced_system_layer.c FROM nginx:alpine EXPOSE 80 @@ -1,7 +1,80 @@ -<html> +<!DOCTYPE html> +<html style="height: 100%; overflow: hidden; overflow-x: hidden;"> <head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width,initial-scale=1"> + <link rel='icon' type='image/gif' href='/favicon.gif'> + <title> Reduced System Layer </title> </head> - <body> - Hello, Sailor! + <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() { + let canvas; + let program; + let memory_view; + let pixels_address; + let context; + let animation_frame; + + canvas = document.getElementById("frame"); + context = canvas.getContext("2d"); + + program = await WebAssembly.instantiateStreaming( + fetch("index.wasm"), + { + "wasi_snapshot_preview1" : { + args_sizes_get : (...args) => { console.log(`args_sizes_get: ${args}`); }, + args_get : (...args) => { console.log(`args_get: ${args}`); }, + proc_exit : (...args) => { console.log(`proc_exit: ${args}`); }, + clock_time_get : () => { return Date.now(); }, + fd_close : (...args) => { console.log(`fd_close: ${args}`); }, + fd_write : (...args) => { console.log(`fd_write: ${args}`); }, + fd_seek : (...args) => { console.log(`fd_seek: ${args}`); }, + }, + "env" : { + p_init : () => { + program.instance.exports.js_init(); + memory_view = new Uint8Array(program.instance.exports.memory.buffer); + pixels_address = program.instance.exports.js_pixels(); + }, + p_render_frame_impl : () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + + let data = new ImageData( + new Uint8ClampedArray( + memory_view.subarray( + pixels_address, + pixels_address + 4 * canvas.width * canvas.height + ) + ), + canvas.width, + canvas.height + ); + + context.putImageData(data, 0, 0); + }, + p_cleanup : () => {}, + p_handle_events : () => {}, + p_wait_events : () => {}, + p_sleep_for : (time) => {}, + p_time : Date.now, + }, + } + ); + + program.instance.exports.js_main(); + + animation_frame = (time) => { + program.instance.exports.js_frame(canvas.width, canvas.height); + window.requestAnimationFrame(animation_frame); + }; + + window.requestAnimationFrame(animation_frame); + } + + run().catch((e) => console.error(e)); + </script> </body> </html> @@ -8,6 +8,7 @@ events { http { types { text/html htm; + image/gif gif; application/wasm wasm; } default_type application/octet-stream; diff --git a/reduced_system_layer.c b/reduced_system_layer.c index 7963a2d..19c8a0c 100755 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -30,7 +30,7 @@ #/ To-Do list #/ #/ - Examples -#/ - Conway's Game if Life +#/ - Conway's Game of Life #/ - Julia Set #/ - Labyrinth #/ - Landscape @@ -119,6 +119,10 @@ typedef double f64; // // ================================================================ +#ifdef __cplusplus +extern "C" { +#endif + enum { MAX_NUM_PIXELS = 10 * 1024 * 1024, MAX_INPUT_SIZE = 256, @@ -225,6 +229,9 @@ i32 p_handle_events(void); i32 p_wait_events(void); void p_render_frame(void); +// User-defined proc +void p_frame(void); + // Clipboard void p_clipboard_write(i64 size, c8 *data); @@ -238,6 +245,10 @@ i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port); extern Platform platform; +#ifdef __cplusplus +} +#endif + // ================================================================ #endif // REDUCED_SYSTEM_LAYER_HEADER_GUARD_ @@ -250,6 +261,27 @@ extern Platform platform; #ifdef REDUCED_SYSTEM_LAYER_EXAMPLE +// NOTE +// This procedure is required for the WebAssembly compatibility. +void p_frame(void) { + p_handle_events(); + + i64 w = platform.frame_width / 2; + i64 h = platform.frame_height / 2; + i64 x = w / 2; + i64 y = h / 2; + + for (i64 j = 0; j < platform.frame_height; ++j) + for (i64 i = 0; i < platform.frame_width; ++i) + if (i < x || i >= x + w || j < y || j >= y + h) + platform.pixels[j * platform.frame_width + i] = 0xa0a0a0; + else + platform.pixels[j * platform.frame_width + i] = 0x131112; + + p_render_frame(); + p_sleep_for(0); +} + i32 main(i32 argc, c8 **argv) { (void) argc; (void) argv; @@ -263,9 +295,7 @@ i32 main(i32 argc, c8 **argv) { p_init(); while (!platform.done) { - p_handle_events(); - p_render_frame(); - p_sleep_for(0); + p_frame(); } p_cleanup(); @@ -1164,6 +1194,49 @@ void p_queue_sound(i64 delay, i64 num_samples, f32 *samples) { #endif // ================================================================ +// +// WebAssembly +// +// ================================================================ + +#ifdef __EMSCRIPTEN__ + +static u32 _buffer[MAX_NUM_PIXELS] = {0}; + +void p_render_frame_impl(void); + +void p_render_frame(void) { + // Make the canvas data opaque. + i64 size = platform.frame_width * platform.frame_height; + for (i64 i = 0; i < size; ++i) + platform.pixels[i] |= 0xff000000; + + p_render_frame_impl(); +} + +void js_main(c8 *href) { + main(1, &href); +} + +void js_init(void) { + platform.pixels = _buffer; + platform.done = 1; +} + +void *js_pixels(void) { + return platform.pixels; +} + +void js_frame(i32 frame_width, i32 frame_height) { + platform.frame_width = frame_width; + platform.frame_height = frame_height; + + p_frame(); +} + +#endif // __EMSCRIPTEN__ + +// ================================================================ #endif // REDUCED_SYSTEM_LAYER_IMPL_GUARD_ #endif // REDUCED_SYSTEM_LAYER_HEADER |