From 2aa35e2c108f954949ec001f1e33846379e7cc98 Mon Sep 17 00:00:00 2001 From: untir_l <87096069+untir-l@users.noreply.github.com> Date: Sat, 11 Jun 2022 21:13:23 +0530 Subject: Web: canvas now updates on the fly based on input Also some other minor changes to thw web README.md and the Makefile, and making some stuff const where they weren't throughout the lib/ tree as well. --- web/hitomezashi_web.c | 169 +++++++++++++++++++---------------------- web/hitomezashi_web.h | 33 ++------ web/hitomezashi_web_shell.html | 164 +++++++++++++++++++-------------------- 3 files changed, 166 insertions(+), 200 deletions(-) (limited to 'web') diff --git a/web/hitomezashi_web.c b/web/hitomezashi_web.c index 0a36a2c..413f727 100644 --- a/web/hitomezashi_web.c +++ b/web/hitomezashi_web.c @@ -1,120 +1,111 @@ #include "hitomezashi_web.h" - -#include -#include -#include - #include "SDL2/SDL.h" #include "emscripten.h" #include "hitomezashi.h" #include "hitomezashi_utils.h" +#include +#include +#include -int EMSCRIPTEN_KEEPALIVE main(void) { - char *param_str = hitomezashi_web_get_args(); +SDL_Window *window; - if (param_str[0] == 'i') { - return Hitomezashi_Web_Result_Err_Get_Params; - } +int EMSCRIPTEN_KEEPALIVE main(void) { + if (SDL_Init(SDL_INIT_VIDEO) != 0) + return EXIT_FAILURE; - char *x_pattern_str = strtok(param_str, "\n"); - int x_pattern_len = strlen(x_pattern_str); - // We needn't bother checking whether - // hitomezashi_ascii_binary_str_to_ints() was successful as the strings - // passed to it are validated by hitomezashi_web_get_args() in JS. - char *x_pattern = - hitomezashi_ascii_binary_str_to_ints(x_pattern_str, x_pattern_len); + // Stop SDL from capturing all input and stopping input elements from working + SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, "#canvas"); - char *y_pattern_str = strtok(NULL, "\n"); - int y_pattern_len = strlen(y_pattern_str); - char *y_pattern = - hitomezashi_ascii_binary_str_to_ints(y_pattern_str, y_pattern_len); + if (!(window = SDL_CreateWindow("", 0, 0, 100, 100, SDL_WINDOW_RESIZABLE))) + return EXIT_FAILURE; - int gap = strtol(strtok(NULL, "\n"), NULL, 0); - int line_thickness = strtol(strtok(NULL, "\n"), NULL, 0); + emscripten_set_main_loop(main_loop, -1, true); - Uint32 fg_colour = strtol(strtok(NULL, "\n"), NULL, 0); - Uint32 bg_colour = strtol(strtok(NULL, "\n"), NULL, 0); + return EXIT_SUCCESS; +} - if (SDL_Init(SDL_INIT_VIDEO) != 0) { - return Hitomezashi_Web_Result_Err_Sdl_Init; - } +void EMSCRIPTEN_KEEPALIVE main_loop(void) { + const char *x_pattern_raw = hitomezashi_web_get_x_pattern(); + const char *y_pattern_raw = hitomezashi_web_get_y_pattern(); + const int x_pattern_len = strlen(x_pattern_raw); + const int y_pattern_len = strlen(y_pattern_raw); + const char *x_pattern = + hitomezashi_ascii_binary_str_to_ints(x_pattern_raw, x_pattern_len); + const char *y_pattern = + hitomezashi_ascii_binary_str_to_ints(y_pattern_raw, y_pattern_len); - SDL_Window *window; - SDL_Renderer *renderer; - SDL_Texture *texture; + const int gap = hitomezashi_web_get_gap(); + const int line_thickness = hitomezashi_web_get_line_thickness(); - struct Hitomezashi_State state; - if (hitomezashi_state_init(&state, x_pattern_len, y_pattern_len, x_pattern, - y_pattern, gap, line_thickness, fg_colour, - bg_colour) != 0) { - return Hitomezashi_Web_Result_Err_State_Init; - } + const Uint32 fg_colour = hitomezashi_web_get_fg_colour(); + const Uint32 bg_colour = hitomezashi_web_get_bg_colour(); - // Stop SDL from capturing all input and stopping input elements from working - SDL_SetHint(SDL_HINT_EMSCRIPTEN_KEYBOARD_ELEMENT, "#canvas"); - SDL_CreateWindowAndRenderer(state.output_width, state.output_height, 0, - &window, &renderer); + // If any of these are 0, input was invalid + if (!(x_pattern_len && y_pattern_len && gap && line_thickness)) + return; + struct Hitomezashi_State state; + hitomezashi_state_init(&state, x_pattern_len, y_pattern_len, x_pattern, + y_pattern, gap, line_thickness, fg_colour, bg_colour); + SDL_SetWindowSize(window, state.output_width, state.output_height); hitomezashi_draw(&state); - texture = SDL_CreateTextureFromSurface(renderer, state.surface); - SDL_RenderClear(renderer); - SDL_RenderCopy(renderer, texture, NULL, NULL); - SDL_RenderPresent(renderer); - - // Since this is a short-lived application which is only run on page load, - // we do not need to delay the exit of main by freeing memory - it will be - // reclaimed by the browser automatically. + SDL_BlitSurface(state.surface, NULL, SDL_GetWindowSurface(window), NULL); + SDL_UpdateWindowSurface(window); - return Hitomezashi_Web_Result_Success; + free((char *)x_pattern_raw); + free((char *)y_pattern_raw); + free((char *)x_pattern); + free((char *)y_pattern); + SDL_FreeSurface(state.surface); } -EM_JS(char *, hitomezashi_web_get_args, (void), { - function validate_pattern(pattern) { - let valid = true; - for (let c of pattern) { - if (c != "0" && c != "1") { - valid = false; - break; - } +EM_JS(char *, hitomezashi_web_get_x_pattern, (void), { + let result_js = document.querySelector("input[name=\"x_pattern\"]").value; + for (let c of result_js) { + if (c != "0" && c != "1") { + result_js = ""; + break; } - return valid; } + const result_length_bytes = lengthBytesUTF8(result_js) + 1; + let result_wasm_heap = _malloc(result_length_bytes); + stringToUTF8(result_js, result_wasm_heap, result_length_bytes); + return result_wasm_heap; +}) - let result_js = ""; - - let search_params = new URLSearchParams(window.location.search); - - const x_pattern = search_params.get("x_pattern"); - const y_pattern = search_params.get("y_pattern"); - const gap = search_params.get("gap"); - const line_thickness = search_params.get("line_thickness"); - let fg_colour = search_params.get("fg_colour"); - let bg_colour = search_params.get("bg_colour"); - if (!fg_colour) { - fg_colour = "#000000"; - } - if (!bg_colour) { - bg_colour = "#FFFFFF"; - } - fg_colour = "0x" + fg_colour.slice(1); - bg_colour = "0x" + bg_colour.slice(1); - - if (!(x_pattern && y_pattern && gap && line_thickness)) { - result_js = "i"; - } else { - const patterns_are_valid = - validate_pattern(x_pattern) && validate_pattern(y_pattern); - if (!patterns_are_valid) { - result_js = "i"; - } else { - result_js = x_pattern + "\n" + y_pattern + "\n" + gap + "\n" + - line_thickness + "\n" + fg_colour + "\n" + bg_colour + "\n"; +EM_JS(char *, hitomezashi_web_get_y_pattern, (void), { + let result_js = document.querySelector("input[name=\"y_pattern\"]").value; + for (let c of result_js) { + if (c != "0" && c != "1") { + result_js = ""; + break; } } - const result_length_bytes = lengthBytesUTF8(result_js) + 1; let result_wasm_heap = _malloc(result_length_bytes); stringToUTF8(result_js, result_wasm_heap, result_length_bytes); return result_wasm_heap; }) + +EM_JS(unsigned int, hitomezashi_web_get_gap, (void), { + const result = +document.querySelector("input[name=\"gap\"").value; + return (result > 0 ? result : 0); +}) + +EM_JS(unsigned int, hitomezashi_web_get_line_thickness, (void), { + const result = +document.querySelector("input[name=\"line_thickness\"").value; + return (result > 0 ? result : 0); +}) + +EM_JS(Uint32, hitomezashi_web_get_fg_colour, (void), { + const result = parseInt( + document.querySelector("input[name=\"fg_colour\"]").value.slice(1), 16); + return (result ? result : 0); +}) + +EM_JS(Uint32, hitomezashi_web_get_bg_colour, (void), { + const result = parseInt( + document.querySelector("input[name=\"bg_colour\"]").value.slice(1), 16); + return (result ? result : 0); +}) diff --git a/web/hitomezashi_web.h b/web/hitomezashi_web.h index 361a8c2..c7db1c9 100644 --- a/web/hitomezashi_web.h +++ b/web/hitomezashi_web.h @@ -5,32 +5,13 @@ #include "SDL2/SDL.h" #include "emscripten.h" -enum Hitomezashi_Web_Result { - Hitomezashi_Web_Result_Success = 0, - Hitomezashi_Web_Result_Err_Get_Params = 1, - Hitomezashi_Web_Result_Err_Sdl_Init = 2, - Hitomezashi_Web_Result_Err_State_Init = 3, -}; +void main_loop(void); -int hitomezashi_web(int x_pattern_len, int y_pattern_len, char *x_pattern, - char *y_pattern, int gap, int line_thickness, - Uint32 fg_colour, Uint32 bg_colour); - -/** Parse the URL query string and return the parameters thereof. - * - * This is implemented in JS with EM_JS, in order to access the query string. - * The friction of interoperation is the reason for turning the query string - * into a different string that the C code must parse to the actual values, - * rather than sending the data back individually with the correct types. - * That is probably possible, but it seems unpleasant. - * - * The query string's x_pattern, y_pattern, gap, and line_thickness are - * parsed. If not all of them are present, "i" is returned. If x_pattern or - * y_pattern in the query string have characters other than ASCII digits 0 - * and 1, "i" is returned. Otherwise, the values are returned as a - * newline-delimited string in the order x_pattern, y_pattern, gap, - * line_thickness. - */ -char *hitomezashi_web_get_args(void); +char *hitomezashi_web_get_x_pattern(void); +char *hitomezashi_web_get_y_pattern(void); +unsigned int hitomezashi_web_get_gap(void); +unsigned int hitomezashi_web_get_line_thickness(void); +Uint32 hitomezashi_web_get_fg_colour(void); +Uint32 hitomezashi_web_get_bg_colour(void); #endif // HITOMEZASHI_WEB_H diff --git a/web/hitomezashi_web_shell.html b/web/hitomezashi_web_shell.html index a774f1e..e0e23d4 100644 --- a/web/hitomezashi_web_shell.html +++ b/web/hitomezashi_web_shell.html @@ -1,90 +1,84 @@ - - - - - Hitomezashi - - - -

See the README for information.

-
-

-

-

-

-

-

-

-
-
- -
- - - {{{ SCRIPT }}} - - + form>p { + display: table-row; + } + + form>p>label { + display: table-cell; + } + + form>p>label>input { + display: table-cell; + } + + button#downloadCanvas { + display: block; + margin: 0 auto; + } + + p#info { + text-align: center; + } + + p#info>a { + margin-left: 1ex; + margin-right: 1ex; + } + + + + +
+

+

+

+

+

+

+
+ + + + {{{ SCRIPT }}} + + + \ No newline at end of file -- cgit v1.2.3-57-g22cb