diff options
-rw-r--r-- | index.htm | 159 | ||||
-rw-r--r-- | reduced_system_layer.c | 363 |
2 files changed, 345 insertions, 177 deletions
@@ -76,7 +76,14 @@ this.sound_buffer_address = program.exports.js_sound_buffer(); this.pixels_address = program.exports.js_pixels(); - this.frames = new Float32Array(this.memory_buffer, this.sound_buffer_address, program.exports.js_max_num_sound_frames()); + this.max_drop_size = program.exports.js_max_drop_size(); + this.drop_address = program.exports.js_drop_buffer(); + + this.frames = new Float32Array( + this.memory_buffer, + this.sound_buffer_address, + program.exports.js_max_num_sound_frames() + ); let title_address = program.exports.js_title(); @@ -160,6 +167,50 @@ this.program.exports.js_keydown(ev.key, ev.mod, ev.ch); }, + + dragenter : (ev) => { + if (this.program === undefined) + return; + + this.program.exports.js_dragenter(); + }, + + dragleave : (ev) => { + if (this.program === undefined) + return; + + this.program.exports.js_dragenter(); + }, + + drop : (ev) => { + if (this.program === undefined) + return; + + for (let f of ev.files) { + if (f.name.byteLength + f.data.byteLength > this.max_drop_size) { + console.error("File too big"); + continue; + } + + new Uint8Array( + this.memory_buffer, + this.drop_address, + f.name.byteLength + ).set( + new Uint8Array(f.name) + ); + + new Uint8Array( + this.memory_buffer, + this.drop_address + f.name.byteLength, + f.data.byteLength + ).set( + new Uint8Array(f.data) + ); + + this.program.exports.js_drop(f.name.byteLength, f.data.byteLength); + } + }, }; this.port.onmessage = (ev) => { @@ -223,35 +274,26 @@ let program = await WebAssembly.instantiate( wasm, { - wasi_snapshot_preview1 : { - clock_time_get : () => {}, - args_sizes_get : () => {}, - args_get : () => {}, - proc_exit : () => {}, - fd_close : () => {}, - fd_write : () => {}, - fd_seek : () => {}, - }, env : { p_clipboard_write_impl : () => {}, p_time_impl : () => {}, - - floor : () => {}, - ceil : () => {}, - sqrt : () => {}, - cbrt : () => {}, - pow : () => {}, - log : () => {}, - log2 : () => {}, - log10 : () => {}, - exp : () => {}, - sin : () => {}, - cos : () => {}, - tan : () => {}, - asin : () => {}, - acos : () => {}, - atan : () => {}, - atan2 : () => {}, + floor : () => {}, + ceil : () => {}, + trunc : () => {}, + sqrt : () => {}, + cbrt : () => {}, + pow : () => {}, + log : () => {}, + log2 : () => {}, + log10 : () => {}, + exp : () => {}, + sin : () => {}, + cos : () => {}, + tan : () => {}, + asin : () => {}, + acos : () => {}, + atan : () => {}, + atan2 : () => {}, }, } ); @@ -568,7 +610,6 @@ }); window.addEventListener("wheel", (ev) => { - ev.preventDefault(); if (!sound_ready) return; @@ -592,6 +633,68 @@ ch : paste_ch, }); }); + + canvas.addEventListener("dragover", (ev) => { + ev.preventDefault(); + if (!sound_ready) { + ev.dataTransfer.dropEffect = "none"; + return; + } + + if (ev.clientX != undefined && ev.clientY != undefined) + sound_node.port.postMessage({ + id : "mousemove", + x : ev.clientX, + y : ev.clientY, + }); + }); + + canvas.addEventListener("dragenter", (ev) => { + ev.preventDefault(); + if (!sound_ready) + return; + + sound_node.port.postMessage({ + id : "dragenter", + }); + }); + + canvas.addEventListener("dragleave", (ev) => { + ev.preventDefault(); + if (!sound_ready) + return; + + sound_node.port.postMessage({ + id : "dragleave", + }); + }); + + canvas.addEventListener("drop", (ev) => { + ev.preventDefault(); + if (!sound_ready) + return; + + (async () => { + let files = []; + + for (let f of ev.dataTransfer.files) { + // Copy the buffer in case the underlaying buffer's size is larger. + let bytes = await f.bytes(); + let buffer = new ArrayBuffer(bytes.length); + new Uint8Array(buffer).set(bytes); + + files.push({ + name : new TextEncoder("utf8").encode(f.name), + data : buffer, + }); + } + + sound_node.port.postMessage({ + id : "drop", + files : files, + }); + })(); + }); } run({ diff --git a/reduced_system_layer.c b/reduced_system_layer.c index 6032ee3..a1bac25 100644 --- a/reduced_system_layer.c +++ b/reduced_system_layer.c @@ -176,6 +176,7 @@ i32 main(i32 argc, c8 **argv); #endif #ifndef MAX_INPUT_SIZE +// How many input events can be buffered during one frame. #define MAX_INPUT_SIZE 256 #endif @@ -203,22 +204,29 @@ i32 main(i32 argc, c8 **argv); #define MAX_PIXEL_SIZE (16.0) #endif -#ifndef PIXEL_SIZE_DELTA -#define PIXEL_SIZE_DELTA (0.1) +#ifndef DEFAULT_PIXEL_SIZE +#define DEFAULT_PIXEL_SIZE (8.0) #endif -#ifndef DEFAULT_PIXEL_SIZE -#define DEFAULT_PIXEL_SIZE (3.0) +#ifndef PIXEL_SIZE_DELTA +#define PIXEL_SIZE_DELTA (0.05) #endif #ifndef MIN_FRAME_DURATION +// The pixel size will decrease when the frame duration is lower. #define MIN_FRAME_DURATION 17 #endif #ifndef MAX_FRAME_DURATION +// The pixel size will increaseo when the frame duration is higher. #define MAX_FRAME_DURATION 34 #endif +#ifndef FRAME_DURATION_HARD_LIMIT +// The pixel size value will reset if the frame duration is higher. +#define FRAME_DURATION_HARD_LIMIT 500 +#endif + #ifndef NUM_FRAMES_AVERAGED #define NUM_FRAMES_AVERAGED 400 #endif @@ -924,7 +932,7 @@ static void drop_files_set_data_(i64 index, i64 data_size) { g_platform.drop_files[index].data = _drop_files_buffer + offset; } -i8 pixel_size_update_(i32 real_width, i32 real_height) { +static i8 pixel_size_update_(i32 real_width, i32 real_height) { i8 size_changed = 0; i32 width = real_width; @@ -954,13 +962,15 @@ i8 pixel_size_update_(i32 real_width, i32 real_height) { return size_changed; } -void pixel_size_calubrate_(i64 current_frame_duration) { +static void pixel_size_calubrate_(i64 current_frame_duration) { if (g_platform.exact_resolution) return; i64 frame_duration = average_frame_duration_(current_frame_duration); - if (g_platform.pixel_size < MAX_PIXEL_SIZE && frame_duration > MAX_FRAME_DURATION) + if (current_frame_duration > FRAME_DURATION_HARD_LIMIT) + g_platform.pixel_size = MAX_PIXEL_SIZE; + else if (g_platform.pixel_size < MAX_PIXEL_SIZE && frame_duration > MAX_FRAME_DURATION) g_platform.pixel_size += PIXEL_SIZE_DELTA * (frame_duration - MAX_FRAME_DURATION); else if (g_platform.pixel_size > MIN_PIXEL_SIZE && frame_duration < MIN_FRAME_DURATION) g_platform.pixel_size -= PIXEL_SIZE_DELTA * (MIN_FRAME_DURATION - frame_duration); @@ -2223,7 +2233,134 @@ void p_clipboard_write(i64 size, c8 *data) { // ================================================================ // -// WebAssembly +// Web startup options +// +// ================================================================ + +#if defined(__wasm__) + +static u16 _key_map[MAX_NUM_KEYS] = {0}; + +__attribute__((export_name("js_max_num_keys"))) i32 js_max_num_keys(void) { + return MAX_NUM_KEYS; +} + +__attribute__((export_name("js_key_map"))) void *js_key_map(void) { + i32 n = 0; + + _key_map[n++] = KEY_BACKSPACE; + _key_map[n++] = KEY_TAB; + _key_map[n++] = KEY_ENTER; + _key_map[n++] = KEY_LCTRL; + _key_map[n++] = KEY_RCTRL; + _key_map[n++] = KEY_LSHIFT; + _key_map[n++] = KEY_RSHIFT; + _key_map[n++] = KEY_LALT; + _key_map[n++] = KEY_RALT; + _key_map[n++] = KEY_LEFT; + _key_map[n++] = KEY_RIGHT; + _key_map[n++] = KEY_UP; + _key_map[n++] = KEY_DOWN; + _key_map[n++] = KEY_PAUSE; + _key_map[n++] = KEY_INSERT; + _key_map[n++] = KEY_HOME; + _key_map[n++] = KEY_END; + _key_map[n++] = KEY_PAGEUP; + _key_map[n++] = KEY_PAGEDOWN; + _key_map[n++] = KEY_ESCAPE; + _key_map[n++] = KEY_PRINTSCREEN; + _key_map[n++] = KEY_SPACE; + _key_map[n++] = KEY_LMETA; + _key_map[n++] = KEY_RMETA; + _key_map[n++] = KEY_QUOTE; + _key_map[n++] = KEY_COMMA; + _key_map[n++] = KEY_MINUS; + _key_map[n++] = KEY_PERIOD; + _key_map[n++] = KEY_SLASH; + _key_map[n++] = KEY_0; + _key_map[n++] = KEY_1; + _key_map[n++] = KEY_2; + _key_map[n++] = KEY_3; + _key_map[n++] = KEY_4; + _key_map[n++] = KEY_5; + _key_map[n++] = KEY_6; + _key_map[n++] = KEY_7; + _key_map[n++] = KEY_8; + _key_map[n++] = KEY_9; + _key_map[n++] = KEY_COLON; + _key_map[n++] = KEY_EQUAL; + _key_map[n++] = KEY_LBRACE; + _key_map[n++] = KEY_BACKSLASH; + _key_map[n++] = KEY_RBRACE; + _key_map[n++] = KEY_TILDE; + _key_map[n++] = KEY_A; + _key_map[n++] = KEY_B; + _key_map[n++] = KEY_C; + _key_map[n++] = KEY_D; + _key_map[n++] = KEY_E; + _key_map[n++] = KEY_F; + _key_map[n++] = KEY_G; + _key_map[n++] = KEY_H; + _key_map[n++] = KEY_I; + _key_map[n++] = KEY_J; + _key_map[n++] = KEY_K; + _key_map[n++] = KEY_L; + _key_map[n++] = KEY_M; + _key_map[n++] = KEY_N; + _key_map[n++] = KEY_O; + _key_map[n++] = KEY_P; + _key_map[n++] = KEY_Q; + _key_map[n++] = KEY_R; + _key_map[n++] = KEY_S; + _key_map[n++] = KEY_T; + _key_map[n++] = KEY_U; + _key_map[n++] = KEY_V; + _key_map[n++] = KEY_W; + _key_map[n++] = KEY_X; + _key_map[n++] = KEY_Y; + _key_map[n++] = KEY_Z; + _key_map[n++] = KEY_DELETE; + _key_map[n++] = KEY_F1; + _key_map[n++] = KEY_F2; + _key_map[n++] = KEY_F3; + _key_map[n++] = KEY_F4; + _key_map[n++] = KEY_F5; + _key_map[n++] = KEY_F6; + _key_map[n++] = KEY_F7; + _key_map[n++] = KEY_F8; + _key_map[n++] = KEY_F9; + _key_map[n++] = KEY_F10; + _key_map[n++] = KEY_F11; + _key_map[n++] = KEY_F12; + _key_map[n++] = KEY_F13; + _key_map[n++] = KEY_F14; + _key_map[n++] = KEY_F15; + _key_map[n++] = KEY_F16; + _key_map[n++] = KEY_F17; + _key_map[n++] = KEY_F18; + _key_map[n++] = KEY_F19; + _key_map[n++] = KEY_F20; + _key_map[n++] = KEY_F21; + _key_map[n++] = KEY_F22; + _key_map[n++] = KEY_F23; + _key_map[n++] = KEY_F24; + + return _key_map; +} + +__attribute__((export_name("js_sound_sample_rate"))) f64 js_sound_sample_rate(void) { + return (f64) SOUND_SAMPLE_RATE; +} + +__attribute__((export_name("js_num_sound_channels"))) i32 js_num_sound_channels(void) { + return NUM_SOUND_CHANNELS; +} + +#endif // defined(__wasm__) + +// ================================================================ +// +// Web // // ================================================================ @@ -2240,21 +2377,23 @@ static f64 _wheel_dy = 0; static b8 _wait_events = 0; static i64 _timeout = 0; static i64 _sound_read = 0; +static b8 _files_dragged = 0; +static b8 _files_dropped = 0; -static u16 _key_map [MAX_NUM_KEYS] = {0}; -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 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 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) { - // Not implemented + LOG_ERROR("Web sockets are not implemented."); return 0; } i64 p_send(u16 slot, IP_Address address, i64 size, u8 *data, u16 *local_port) { - // Not implemented + LOG_ERROR("Web sockets are not implemented."); return 0; } @@ -2288,17 +2427,27 @@ void p_init(void) { } i32 p_handle_events(void) { - g_platform.input_size = _input_size; - g_platform.cursor_dx = _cursor_dx; - g_platform.cursor_dy = _cursor_dy; - g_platform.wheel_dx = _wheel_dx; - g_platform.wheel_dy = _wheel_dy; - - _input_size = 0; - _cursor_dx = 0; - _cursor_dy = 0; - _wheel_dx = 0; - _wheel_dy = 0; + if (g_platform.files_dropped) + drop_files_clean_(); + + g_platform.input_size = _input_size; + g_platform.cursor_dx = _cursor_dx; + g_platform.cursor_dy = _cursor_dy; + g_platform.wheel_dx = _wheel_dx; + g_platform.wheel_dy = _wheel_dy; + g_platform.files_dragged = _files_dragged; + g_platform.files_dropped = _files_dropped; + + _input_size = 0; + _cursor_dx = 0; + _cursor_dy = 0; + _wheel_dx = 0; + _wheel_dy = 0; + + if (_files_dropped) { + _files_dragged = 0; + _files_dropped = 0; + } for (i64 i = 0; i < MAX_NUM_KEYS; ++i) g_platform.key_pressed[i] = _key_pressed[i]; @@ -2370,8 +2519,10 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { return; i64 num_frames = num_samples * NUM_SOUND_CHANNELS; - if (num_frames > MAX_NUM_SOUND_FRAMES) + if (num_frames > MAX_NUM_SOUND_FRAMES) { + LOG_ERROR("Sound buffer overflow."); return; + } i64 begin = (_sound_position + delay_in_samples * NUM_SOUND_CHANNELS) % MAX_NUM_SOUND_FRAMES; @@ -2389,121 +2540,6 @@ void p_queue_sound(i64 delay_in_samples, i64 num_samples, f32 *frames) { } } -__attribute__((export_name("js_max_num_keys"))) i32 js_max_num_keys(void) { - return MAX_NUM_KEYS; -} - -__attribute__((export_name("js_key_map"))) void *js_key_map(void) { - i32 n = 0; - - _key_map[n++] = KEY_BACKSPACE; - _key_map[n++] = KEY_TAB; - _key_map[n++] = KEY_ENTER; - _key_map[n++] = KEY_LCTRL; - _key_map[n++] = KEY_RCTRL; - _key_map[n++] = KEY_LSHIFT; - _key_map[n++] = KEY_RSHIFT; - _key_map[n++] = KEY_LALT; - _key_map[n++] = KEY_RALT; - _key_map[n++] = KEY_LEFT; - _key_map[n++] = KEY_RIGHT; - _key_map[n++] = KEY_UP; - _key_map[n++] = KEY_DOWN; - _key_map[n++] = KEY_PAUSE; - _key_map[n++] = KEY_INSERT; - _key_map[n++] = KEY_HOME; - _key_map[n++] = KEY_END; - _key_map[n++] = KEY_PAGEUP; - _key_map[n++] = KEY_PAGEDOWN; - _key_map[n++] = KEY_ESCAPE; - _key_map[n++] = KEY_PRINTSCREEN; - _key_map[n++] = KEY_SPACE; - _key_map[n++] = KEY_LMETA; - _key_map[n++] = KEY_RMETA; - _key_map[n++] = KEY_QUOTE; - _key_map[n++] = KEY_COMMA; - _key_map[n++] = KEY_MINUS; - _key_map[n++] = KEY_PERIOD; - _key_map[n++] = KEY_SLASH; - _key_map[n++] = KEY_0; - _key_map[n++] = KEY_1; - _key_map[n++] = KEY_2; - _key_map[n++] = KEY_3; - _key_map[n++] = KEY_4; - _key_map[n++] = KEY_5; - _key_map[n++] = KEY_6; - _key_map[n++] = KEY_7; - _key_map[n++] = KEY_8; - _key_map[n++] = KEY_9; - _key_map[n++] = KEY_COLON; - _key_map[n++] = KEY_EQUAL; - _key_map[n++] = KEY_LBRACE; - _key_map[n++] = KEY_BACKSLASH; - _key_map[n++] = KEY_RBRACE; - _key_map[n++] = KEY_TILDE; - _key_map[n++] = KEY_A; - _key_map[n++] = KEY_B; - _key_map[n++] = KEY_C; - _key_map[n++] = KEY_D; - _key_map[n++] = KEY_E; - _key_map[n++] = KEY_F; - _key_map[n++] = KEY_G; - _key_map[n++] = KEY_H; - _key_map[n++] = KEY_I; - _key_map[n++] = KEY_J; - _key_map[n++] = KEY_K; - _key_map[n++] = KEY_L; - _key_map[n++] = KEY_M; - _key_map[n++] = KEY_N; - _key_map[n++] = KEY_O; - _key_map[n++] = KEY_P; - _key_map[n++] = KEY_Q; - _key_map[n++] = KEY_R; - _key_map[n++] = KEY_S; - _key_map[n++] = KEY_T; - _key_map[n++] = KEY_U; - _key_map[n++] = KEY_V; - _key_map[n++] = KEY_W; - _key_map[n++] = KEY_X; - _key_map[n++] = KEY_Y; - _key_map[n++] = KEY_Z; - _key_map[n++] = KEY_DELETE; - _key_map[n++] = KEY_F1; - _key_map[n++] = KEY_F2; - _key_map[n++] = KEY_F3; - _key_map[n++] = KEY_F4; - _key_map[n++] = KEY_F5; - _key_map[n++] = KEY_F6; - _key_map[n++] = KEY_F7; - _key_map[n++] = KEY_F8; - _key_map[n++] = KEY_F9; - _key_map[n++] = KEY_F10; - _key_map[n++] = KEY_F11; - _key_map[n++] = KEY_F12; - _key_map[n++] = KEY_F13; - _key_map[n++] = KEY_F14; - _key_map[n++] = KEY_F15; - _key_map[n++] = KEY_F16; - _key_map[n++] = KEY_F17; - _key_map[n++] = KEY_F18; - _key_map[n++] = KEY_F19; - _key_map[n++] = KEY_F20; - _key_map[n++] = KEY_F21; - _key_map[n++] = KEY_F22; - _key_map[n++] = KEY_F23; - _key_map[n++] = KEY_F24; - - return _key_map; -} - -__attribute__((export_name("js_sound_sample_rate"))) f64 js_sound_sample_rate(void) { - return (f64) SOUND_SAMPLE_RATE; -} - -__attribute__((export_name("js_num_sound_channels"))) i32 js_num_sound_channels(void) { - return NUM_SOUND_CHANNELS; -} - __attribute__((export_name("js_max_num_sound_frames"))) i32 js_max_num_sound_frames(void) { return MAX_NUM_SOUND_FRAMES; } @@ -2521,11 +2557,6 @@ __attribute__((export_name("js_href_size"))) i32 js_href_size(void) { } __attribute__((export_name("js_main"))) void js_main(void) { - (void) drop_files_clean_; - (void) drop_files_set_num_; - (void) drop_files_set_name_; - (void) drop_files_set_data_; - main(1, (c8 *[1]) { _href }); } @@ -2545,7 +2576,7 @@ __attribute__((export_name("js_frame"))) void js_frame(i32 frame_width, i32 fram _frame_height = frame_height; } - _num_size += pixel_size_update_(_frame_width, _frame_height); + _num_events += pixel_size_update_(_frame_width, _frame_height); g_platform.done = 0; @@ -2642,6 +2673,40 @@ __attribute__((export_name("js_clipboard_buffer"))) void *js_clipboard_buffer(i3 return g_platform.clipboard; } +__attribute__((export_name("js_dragenter"))) void js_dragenter(void) { + _files_dragged = 1; +} + +__attribute__((export_name("js_dragleave"))) void js_dragleave(void) { + _files_dragged = 0; +} + +__attribute__((export_name("js_max_drop_size"))) i32 js_max_drop_size(void) { + return sizeof _drop_buffer; +} + +__attribute__((export_name("js_drop_buffer"))) void *js_drop_buffer(void) { + return _drop_buffer; +} + +__attribute__((export_name("js_drop"))) void js_drop(i32 name_len, i32 data_size) { + if (name_len + data_size > sizeof _drop_buffer) { + LOG_ERROR("File too big."); + return; + } + + i64 n = g_platform.num_drop_files; + + drop_files_set_num_(n + 1); + drop_files_set_name_(n, name_len, (c8 *) _drop_buffer); + drop_files_set_data_(n, data_size); + + for (i64 i = 0; i < data_size; ++i) + g_platform.drop_files[n].data[i] = _drop_buffer[name_len + i]; + + _files_dropped = 1; +} + #endif // defined(__wasm__) // ================================================================ |