From 6709873fcd131ce2f57eb587cdbfa83bb269938d Mon Sep 17 00:00:00 2001 From: VIGNESH KUMAR <45727291+VICTORVICKIE@users.noreply.github.com> Date: Tue, 20 Feb 2024 14:40:58 +0530 Subject: [PATCH 01/12] abstract wasm ptr stuffs to ptr.js --- ptr.js | 415 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 ptr.js diff --git a/ptr.js b/ptr.js new file mode 100644 index 0000000..b567208 --- /dev/null +++ b/ptr.js @@ -0,0 +1,415 @@ +function cstrlen(mem, ptr) { + let len = 0; + while (mem[ptr] != 0) { + len++; + ptr++; + } + return len; +} + +function cstr_by_ptr(mem_buffer, ptr) { + const mem = new Uint8Array(mem_buffer); + const len = cstrlen(mem, ptr); + const bytes = new Uint8Array(mem_buffer, ptr, len); + return new TextDecoder().decode(bytes); +} + +function color_hex_unpacked(r, g, b, a) { + r = r.toString(16).padStart(2, "0"); + g = g.toString(16).padStart(2, "0"); + b = b.toString(16).padStart(2, "0"); + a = a.toString(16).padStart(2, "0"); + return "#" + r + g + b + a; +} + +function color_hex(color) { + const r = ((color >> (0 * 8)) & 0xff).toString(16).padStart(2, "0"); + const g = ((color >> (1 * 8)) & 0xff).toString(16).padStart(2, "0"); + const b = ((color >> (2 * 8)) & 0xff).toString(16).padStart(2, "0"); + const a = ((color >> (3 * 8)) & 0xff).toString(16).padStart(2, "0"); + return "#" + r + g + b + a; +} + +function getColorFromMemory(buffer, color_ptr) { + const [r, g, b, a] = new Uint8Array(buffer, color_ptr, 4); + return color_hex_unpacked(r, g, b, a); +} + +function cstr_fmt_by_ptr(mem_buffer, fmt_ptr, arg_ptr) { + const fmt = cstr_by_ptr(mem_buffer, fmt_ptr); + + // VarArgs Chunk + let args = mem_buffer.slice(arg_ptr); + let result = ""; + let fmt_buffer = fmt.split(""); + let fmt_cur = 0; + + let pad_width, + precision, + pad_with_zero, + pad_with_space, + justify_right, + pre_with_polarity, + pre_with_space, + pre_with_format, + capitalize, + precise, + bit_size, + radix; + + reset_state(); + + function reset_state() { + bit_size = 32; + pad_width = 0; + precision = 0; + radix = 10; + pad_with_zero = false; + pad_with_space = false; + justify_right = true; + + pre_with_polarity = false; + pre_with_space = false; + pre_with_format = false; + + capitalize = false; + precise = false; + } + + function parse_num(cursor) { + let width_end = cursor; + while (fmt_buffer[width_end]) { + if (/\d/.test(fmt_buffer[width_end])) width_end++; + else break; + } + let num = fmt_buffer.splice(cursor, width_end - cursor).join(""); + return parseInt(num); + } + + // Grab the view of args based on specifier and shift the args + function shift_args(view) { + args = args.slice(view.BYTES_PER_ELEMENT); + return view.at(0); + } + + while (fmt_cur < fmt_buffer.length) { + if (fmt_buffer[fmt_cur] !== "%") { + // Normal character, copy it to the temp string + const str = fmt_buffer[fmt_cur++]; + result += str; + continue; + } + + // Peek only next character and splice the modifiers. + // So we can always simply look one char ahead + const peek_idx = fmt_cur + 1; + const peek_char = fmt_buffer[peek_idx]; + switch (peek_char) { + case undefined: { + fmt_cur++; + break; + } + + case "%": { + result += "%"; + fmt_cur += 2; + break; + } + + case "+": { + pre_with_polarity = true; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case "-": { + justify_right = false; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case " ": { + pre_with_space = !pre_with_polarity; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case ".": { + precise = true; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case "#": { + pre_with_format = true; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case "0": { + if (precise) { + precision = parse_num(peek_idx); + } else { + pad_with_zero = true; + pad_width = parse_num(peek_idx); + } + break; + } + + case "1": + case "2": + case "3": + case "4": + case "5": + case "6": + case "7": + case "8": + case "9": { + if (precise) { + precision = parse_num(peek_idx); + } else { + pad_with_space = true; + pad_width = parse_num(peek_idx); + } + break; + } + + // Modifiers + case "l": { + bit_size = bit_size === 32 ? 64 : 32; + fmt_buffer.splice(peek_idx, 1); + } + + // In JS there are no number below 32 bit, so we are ignoring + // also clang bakes the overflown and underflown values as it is + case "h": { + fmt_buffer.splice(peek_idx, 1); + break; + } + + case "c": { + const char_code = shift_args(new Uint32Array(args)); + let str = String.fromCharCode(char_code); + let pad_char; + + if (pad_with_zero || pad_with_space) pad_char = " "; + else pad_char = ""; + + if (justify_right) str = str.padStart(pad_width, pad_char); + else str = str.padEnd(pad_width, pad_char); + + result += str; + fmt_cur += 2; + reset_state(); + break; + } + + case "s": { + const str_ptr = shift_args(new Uint32Array(args)); + let str = cstr_by_ptr(mem_buffer, str_ptr); + let pad_char; + + if (pad_with_zero || pad_with_space) pad_char = " "; + else pad_char = ""; + + if (justify_right) str = str.padStart(pad_width, pad_char); + else str = str.padEnd(pad_width, pad_char); + + if (precise) str = str.substring(0, precision); + + result += str; + fmt_cur += 2; + reset_state(); + break; + } + + case "o": + case "x": + case "X": + case "u": { + let num; + let pad_char, pre_char; + + if (peek_char === "o") { + radix = 8; + } else if (peek_char === "x") { + radix = 16; + } else if (peek_char === "X") { + radix = 16; + capitalize = true; + } else { + console.error("radix unreachable"); + } + + if (bit_size === 32) { + num = shift_args(new Uint32Array(args)); + } else { + unaligned = args.byteLength % 8; + args.slice(unaligned); + num = shift_args(new BigUint64Array(args)); + } + + if (pad_with_zero) pad_char = "0"; + else if (pad_with_space) pad_char = " "; + else pad_char = ""; + + if (pre_with_format && radix === 8) pre_char = "0"; + else if (pre_with_format && radix === 16) pre_char = "0x"; + else pre_char = ""; + + if (precise) { + pad_char = " "; + num = num.toString(radix).padStart(precision, "0"); + } + + if (justify_right) { + num = num.toString(radix).padStart(pad_width, pad_char); + } else { + pad_char = " "; + num = num.toString(radix).padEnd(pad_width, pad_char); + } + + num = pre_char + num; + + if (capitalize) num = num.toUpperCase(); + + result += num; + fmt_cur += 2; + reset_state(); + break; + } + + case "i": + case "d": { + let num; + let pad_char, pre_char; + + if (bit_size === 32) { + num = shift_args(new Int32Array(args)); + } else { + unaligned = args.byteLength % 8; + args = args.slice(unaligned); + num = shift_args(new BigInt64Array(args)); + } + + if (pad_with_zero) pad_char = "0"; + else if (pad_with_space) pad_char = " "; + else pad_char = ""; + + if (pre_with_polarity && num > 0) pre_char = "+"; + else if (pre_with_space && num > 0) pre_char = " "; + else pre_char = ""; + + if (precise) { + pad_char = " "; + num = num.toString().padStart(precision, "0"); + } + + if (justify_right) { + num = num.toString().padStart(pad_width, pad_char); + } else { + pad_char = " "; + num = num.toString().padEnd(pad_width, pad_char); + } + + num = pre_char + num; + + result += num; + fmt_cur += 2; + reset_state(); + break; + } + + case "E": { + capitalize = true; + } + case "e": { + // Align Bytes by 8 + unaligned = args.byteLength % 8; + args = args.slice(unaligned); + + let num = shift_args(new Float64Array(args)); + let pad_char, pre_char; + + if (pad_with_zero) pad_char = "0"; + else if (pad_with_space) pad_char = " "; + else pad_char = ""; + + if (pre_with_polarity && num > 0) pre_char = "+"; + else if (pre_with_space && num > 0) pre_char = " "; + else pre_char = ""; + + if (precise) num = num.toExponential(precision); + else num = num.toExponential(6); + + if (justify_right) { + num = num.toString().padStart(pad_width, pad_char); + } else { + pad_char = " "; + num = num.toString().padEnd(pad_width, pad_char); + } + + if (capitalize) num = num.toUpperCase(); + + num = pre_char + num; + + result += num; + fmt_cur += 2; + reset_state(); + break; + } + case "F": + case "G": { + capitalize = true; + } + case "g": + case "f": { + // Align Bytes by 8 + unaligned = args.byteLength % 8; + args = args.slice(unaligned); + + let num = shift_args(new Float64Array(args)); + let pad_char, pre_char; + + if (pad_with_zero) pad_char = "0"; + else if (pad_with_space) pad_char = " "; + else pad_char = ""; + + if (pre_with_polarity && num > 0) pre_char = "+"; + else if (pre_with_space && num > 0) pre_char = " "; + else pre_char = ""; + + if (precise) num = num.toFixed(precision); + else num = num.toFixed(6); + + if (justify_right) { + num = num.toString().padStart(pad_width, pad_char); + } else { + pad_char = " "; + num = num.toString().padEnd(pad_width, pad_char); + } + + if (capitalize) num = num.toUpperCase(); + + num = pre_char + num; + + result += num; + fmt_cur += 2; + reset_state(); + break; + } + + // TODO: unsupported format specifiers, copy it to the temp string + // Flags => * + // Len Mod => j z t L + // Specify => a A n p + default: { + const str = fmt_buffer[fmt_cur++]; + result += str; + break; + } + } + } + + return result; +} From 881a98ba59dd358946b12e653a966a53a6f8c356 Mon Sep 17 00:00:00 2001 From: VIGNESH KUMAR <45727291+VICTORVICKIE@users.noreply.github.com> Date: Tue, 20 Feb 2024 14:41:25 +0530 Subject: [PATCH 02/12] abstract example entry script to examples.js --- examples.js | 59 +++++++++++++++++++++++++++++++++++++++++ index.html | 75 +++++++---------------------------------------------- 2 files changed, 68 insertions(+), 66 deletions(-) create mode 100644 examples.js diff --git a/examples.js b/examples.js new file mode 100644 index 0000000..4e8a93d --- /dev/null +++ b/examples.js @@ -0,0 +1,59 @@ +const wasmPaths = { + tsoding: ["tsoding_ball", "tsoding_snake"], + core: ["core_basic_window", "core_basic_screen_manager", "core_input_keys", "core_input_mouse_wheel"], + shapes: ["shapes_colors_palette"], + text: ["text_writing_anim"], + textures: ["textures_logo_raylib"], +}; +const defaultWasm = Object.values(wasmPaths)[0][0]; + +const raylibExampleSelect = document.getElementById("raylib-example-select"); + +for (const exampleCategory in wasmPaths) { + raylibExampleSelect.innerHTML += ``; + for (const example of wasmPaths[exampleCategory]) { + raylibExampleSelect.innerHTML += ``; + } + raylibExampleSelect.innerHTML += ""; +} + +const { protocol } = window.location; +const isHosted = protocol !== "file:"; +let raylibJs = undefined; + +function startRaylib(selectedWasm) { + var queryParams = new URLSearchParams(window.location.search); + queryParams.set("example", selectedWasm); + history.pushState(null, null, "?" + queryParams.toString()); + raylibExampleSelect.value = selectedWasm; + + if (isHosted) { + if (raylibJs !== undefined) { + raylibJs.stop(); + } + raylibJs = new RaylibJs(); + raylibJs.start({ + wasmPath: `wasm/${selectedWasm}.wasm`, + canvasId: "game", + }); + } else { + window.addEventListener("load", () => { + document.body.innerHTML = ` +
+
+

Unfortunately, due to CORs restrictions, the wasm assembly cannot be fetched.

+

Please navigate to this location using a web server.

+

If you have Python 3 on your system you can just do:

+
+ $ python3 -m http.server 6969 +
+ `; + }); + } +} + +let queryParams = new URLSearchParams(window.location.search); +const exampleParam = queryParams.get("example") ?? defaultWasm; + +if (Object.values(wasmPaths).flat().includes(exampleParam)) startRaylib(exampleParam); +else startRaylib(defaultWasm); diff --git a/index.html b/index.html index 960a2cd..05d392b 100644 --- a/index.html +++ b/index.html @@ -1,9 +1,9 @@ + Hello, Raylib! + + - - + - + + From c3b1b7941f2591b618250990ebfad41e145d9e64 Mon Sep 17 00:00:00 2001 From: VIGNESH KUMAR <45727291+VICTORVICKIE@users.noreply.github.com> Date: Tue, 20 Feb 2024 14:41:38 +0530 Subject: [PATCH 03/12] implement TextFormat --- raylib.js | 52 +++++++++++++--------------------------------------- 1 file changed, 13 insertions(+), 39 deletions(-) diff --git a/raylib.js b/raylib.js index a6a0154..1eb02e5 100644 --- a/raylib.js +++ b/raylib.js @@ -197,11 +197,21 @@ class RaylibJs { return false; } - TextFormat(... args){ - // TODO: Implement printf style formatting for TextFormat - return args[0]; + TextFormat(text_ptr, args_ptr) { + const buffer = this.wasm.instance.exports.memory.buffer; + const fmt_text = cstr_fmt_by_ptr(buffer, text_ptr, args_ptr); + + // REVIEW: Is it safe to use the slots in memory buffer starting from 0? + // Is there any way to create a internal shared buffer that can be shared with wasm? + const bytes = new Uint8Array(buffer, 0, fmt_text.length + 1); + for (let i = 0; i < fmt_text.length; i++) { + bytes[i] = fmt_text.charCodeAt(i); + } + bytes[fmt_text.length] = 0; + return bytes; } + TraceLog(logLevel, text_ptr, ... args) { // TODO: Implement printf style formatting for TraceLog const buffer = this.wasm.instance.exports.memory.buffer; @@ -473,39 +483,3 @@ const glfwKeyMapping = { // GLFW_KEY_LAST GLFW_KEY_MENU } -function cstrlen(mem, ptr) { - let len = 0; - while (mem[ptr] != 0) { - len++; - ptr++; - } - return len; -} - -function cstr_by_ptr(mem_buffer, ptr) { - const mem = new Uint8Array(mem_buffer); - const len = cstrlen(mem, ptr); - const bytes = new Uint8Array(mem_buffer, ptr, len); - return new TextDecoder().decode(bytes); -} - -function color_hex_unpacked(r, g, b, a) { - r = r.toString(16).padStart(2, '0'); - g = g.toString(16).padStart(2, '0'); - b = b.toString(16).padStart(2, '0'); - a = a.toString(16).padStart(2, '0'); - return "#"+r+g+b+a; -} - -function color_hex(color) { - const r = ((color>>(0*8))&0xFF).toString(16).padStart(2, '0'); - const g = ((color>>(1*8))&0xFF).toString(16).padStart(2, '0'); - const b = ((color>>(2*8))&0xFF).toString(16).padStart(2, '0'); - const a = ((color>>(3*8))&0xFF).toString(16).padStart(2, '0'); - return "#"+r+g+b+a; -} - -function getColorFromMemory(buffer, color_ptr) { - const [r, g, b, a] = new Uint8Array(buffer, color_ptr, 4); - return color_hex_unpacked(r, g, b, a); -} From 89d4dd0b071fc876dbf4330bbd5773e80a5ec1c6 Mon Sep 17 00:00:00 2001 From: VIGNESH KUMAR <45727291+VICTORVICKIE@users.noreply.github.com> Date: Thu, 22 Feb 2024 14:19:31 +0530 Subject: [PATCH 04/12] use heap base --- nob.c | 1 + raylib.js | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/nob.c b/nob.c index 15ef36d..c3ee1e6 100644 --- a/nob.c +++ b/nob.c @@ -72,6 +72,7 @@ bool build_wasm(void) nob_cmd_append(&cmd, "-I./include"); nob_cmd_append(&cmd, "--no-standard-libraries"); nob_cmd_append(&cmd, "-Wl,--export-table"); + nob_cmd_append(&cmd, "-Wl,--export=__heap_base"); nob_cmd_append(&cmd, "-Wl,--no-entry"); nob_cmd_append(&cmd, "-Wl,--allow-undefined"); nob_cmd_append(&cmd, "-Wl,--export=main"); diff --git a/raylib.js b/raylib.js index 1eb02e5..55d3ede 100644 --- a/raylib.js +++ b/raylib.js @@ -201,14 +201,15 @@ class RaylibJs { const buffer = this.wasm.instance.exports.memory.buffer; const fmt_text = cstr_fmt_by_ptr(buffer, text_ptr, args_ptr); - // REVIEW: Is it safe to use the slots in memory buffer starting from 0? + const heap_base = this.wasm.instance.exports.__heap_base.value; + // REVIEW: Is it safe to use the slots in memory buffer starting from heap_base? // Is there any way to create a internal shared buffer that can be shared with wasm? - const bytes = new Uint8Array(buffer, 0, fmt_text.length + 1); + const bytes = new Uint8Array(buffer, heap_base, fmt_text.length + 1); for (let i = 0; i < fmt_text.length; i++) { bytes[i] = fmt_text.charCodeAt(i); } bytes[fmt_text.length] = 0; - return bytes; + return heap_base; } From 124b3aedc404bd6b644a530c103e34465b806bb2 Mon Sep 17 00:00:00 2001 From: VIGNESH KUMAR <45727291+VICTORVICKIE@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:11:18 +0530 Subject: [PATCH 05/12] back to solo file --- examples.js | 59 -------- index.html | 63 +++++++- ptr.js | 415 ---------------------------------------------------- raylib.js | 415 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 476 insertions(+), 476 deletions(-) delete mode 100644 examples.js delete mode 100644 ptr.js diff --git a/examples.js b/examples.js deleted file mode 100644 index 4e8a93d..0000000 --- a/examples.js +++ /dev/null @@ -1,59 +0,0 @@ -const wasmPaths = { - tsoding: ["tsoding_ball", "tsoding_snake"], - core: ["core_basic_window", "core_basic_screen_manager", "core_input_keys", "core_input_mouse_wheel"], - shapes: ["shapes_colors_palette"], - text: ["text_writing_anim"], - textures: ["textures_logo_raylib"], -}; -const defaultWasm = Object.values(wasmPaths)[0][0]; - -const raylibExampleSelect = document.getElementById("raylib-example-select"); - -for (const exampleCategory in wasmPaths) { - raylibExampleSelect.innerHTML += ``; - for (const example of wasmPaths[exampleCategory]) { - raylibExampleSelect.innerHTML += ``; - } - raylibExampleSelect.innerHTML += ""; -} - -const { protocol } = window.location; -const isHosted = protocol !== "file:"; -let raylibJs = undefined; - -function startRaylib(selectedWasm) { - var queryParams = new URLSearchParams(window.location.search); - queryParams.set("example", selectedWasm); - history.pushState(null, null, "?" + queryParams.toString()); - raylibExampleSelect.value = selectedWasm; - - if (isHosted) { - if (raylibJs !== undefined) { - raylibJs.stop(); - } - raylibJs = new RaylibJs(); - raylibJs.start({ - wasmPath: `wasm/${selectedWasm}.wasm`, - canvasId: "game", - }); - } else { - window.addEventListener("load", () => { - document.body.innerHTML = ` -
-
-

Unfortunately, due to CORs restrictions, the wasm assembly cannot be fetched.

-

Please navigate to this location using a web server.

-

If you have Python 3 on your system you can just do:

-
- $ python3 -m http.server 6969 -
- `; - }); - } -} - -let queryParams = new URLSearchParams(window.location.search); -const exampleParam = queryParams.get("example") ?? defaultWasm; - -if (Object.values(wasmPaths).flat().includes(exampleParam)) startRaylib(exampleParam); -else startRaylib(defaultWasm); diff --git a/index.html b/index.html index 05d392b..003b801 100644 --- a/index.html +++ b/index.html @@ -57,7 +57,6 @@ src: url(fonts/acme_7_wide_xtnd.woff); } - @@ -67,7 +66,67 @@ - + diff --git a/ptr.js b/ptr.js deleted file mode 100644 index b567208..0000000 --- a/ptr.js +++ /dev/null @@ -1,415 +0,0 @@ -function cstrlen(mem, ptr) { - let len = 0; - while (mem[ptr] != 0) { - len++; - ptr++; - } - return len; -} - -function cstr_by_ptr(mem_buffer, ptr) { - const mem = new Uint8Array(mem_buffer); - const len = cstrlen(mem, ptr); - const bytes = new Uint8Array(mem_buffer, ptr, len); - return new TextDecoder().decode(bytes); -} - -function color_hex_unpacked(r, g, b, a) { - r = r.toString(16).padStart(2, "0"); - g = g.toString(16).padStart(2, "0"); - b = b.toString(16).padStart(2, "0"); - a = a.toString(16).padStart(2, "0"); - return "#" + r + g + b + a; -} - -function color_hex(color) { - const r = ((color >> (0 * 8)) & 0xff).toString(16).padStart(2, "0"); - const g = ((color >> (1 * 8)) & 0xff).toString(16).padStart(2, "0"); - const b = ((color >> (2 * 8)) & 0xff).toString(16).padStart(2, "0"); - const a = ((color >> (3 * 8)) & 0xff).toString(16).padStart(2, "0"); - return "#" + r + g + b + a; -} - -function getColorFromMemory(buffer, color_ptr) { - const [r, g, b, a] = new Uint8Array(buffer, color_ptr, 4); - return color_hex_unpacked(r, g, b, a); -} - -function cstr_fmt_by_ptr(mem_buffer, fmt_ptr, arg_ptr) { - const fmt = cstr_by_ptr(mem_buffer, fmt_ptr); - - // VarArgs Chunk - let args = mem_buffer.slice(arg_ptr); - let result = ""; - let fmt_buffer = fmt.split(""); - let fmt_cur = 0; - - let pad_width, - precision, - pad_with_zero, - pad_with_space, - justify_right, - pre_with_polarity, - pre_with_space, - pre_with_format, - capitalize, - precise, - bit_size, - radix; - - reset_state(); - - function reset_state() { - bit_size = 32; - pad_width = 0; - precision = 0; - radix = 10; - pad_with_zero = false; - pad_with_space = false; - justify_right = true; - - pre_with_polarity = false; - pre_with_space = false; - pre_with_format = false; - - capitalize = false; - precise = false; - } - - function parse_num(cursor) { - let width_end = cursor; - while (fmt_buffer[width_end]) { - if (/\d/.test(fmt_buffer[width_end])) width_end++; - else break; - } - let num = fmt_buffer.splice(cursor, width_end - cursor).join(""); - return parseInt(num); - } - - // Grab the view of args based on specifier and shift the args - function shift_args(view) { - args = args.slice(view.BYTES_PER_ELEMENT); - return view.at(0); - } - - while (fmt_cur < fmt_buffer.length) { - if (fmt_buffer[fmt_cur] !== "%") { - // Normal character, copy it to the temp string - const str = fmt_buffer[fmt_cur++]; - result += str; - continue; - } - - // Peek only next character and splice the modifiers. - // So we can always simply look one char ahead - const peek_idx = fmt_cur + 1; - const peek_char = fmt_buffer[peek_idx]; - switch (peek_char) { - case undefined: { - fmt_cur++; - break; - } - - case "%": { - result += "%"; - fmt_cur += 2; - break; - } - - case "+": { - pre_with_polarity = true; - fmt_buffer.splice(peek_idx, 1); - break; - } - - case "-": { - justify_right = false; - fmt_buffer.splice(peek_idx, 1); - break; - } - - case " ": { - pre_with_space = !pre_with_polarity; - fmt_buffer.splice(peek_idx, 1); - break; - } - - case ".": { - precise = true; - fmt_buffer.splice(peek_idx, 1); - break; - } - - case "#": { - pre_with_format = true; - fmt_buffer.splice(peek_idx, 1); - break; - } - - case "0": { - if (precise) { - precision = parse_num(peek_idx); - } else { - pad_with_zero = true; - pad_width = parse_num(peek_idx); - } - break; - } - - case "1": - case "2": - case "3": - case "4": - case "5": - case "6": - case "7": - case "8": - case "9": { - if (precise) { - precision = parse_num(peek_idx); - } else { - pad_with_space = true; - pad_width = parse_num(peek_idx); - } - break; - } - - // Modifiers - case "l": { - bit_size = bit_size === 32 ? 64 : 32; - fmt_buffer.splice(peek_idx, 1); - } - - // In JS there are no number below 32 bit, so we are ignoring - // also clang bakes the overflown and underflown values as it is - case "h": { - fmt_buffer.splice(peek_idx, 1); - break; - } - - case "c": { - const char_code = shift_args(new Uint32Array(args)); - let str = String.fromCharCode(char_code); - let pad_char; - - if (pad_with_zero || pad_with_space) pad_char = " "; - else pad_char = ""; - - if (justify_right) str = str.padStart(pad_width, pad_char); - else str = str.padEnd(pad_width, pad_char); - - result += str; - fmt_cur += 2; - reset_state(); - break; - } - - case "s": { - const str_ptr = shift_args(new Uint32Array(args)); - let str = cstr_by_ptr(mem_buffer, str_ptr); - let pad_char; - - if (pad_with_zero || pad_with_space) pad_char = " "; - else pad_char = ""; - - if (justify_right) str = str.padStart(pad_width, pad_char); - else str = str.padEnd(pad_width, pad_char); - - if (precise) str = str.substring(0, precision); - - result += str; - fmt_cur += 2; - reset_state(); - break; - } - - case "o": - case "x": - case "X": - case "u": { - let num; - let pad_char, pre_char; - - if (peek_char === "o") { - radix = 8; - } else if (peek_char === "x") { - radix = 16; - } else if (peek_char === "X") { - radix = 16; - capitalize = true; - } else { - console.error("radix unreachable"); - } - - if (bit_size === 32) { - num = shift_args(new Uint32Array(args)); - } else { - unaligned = args.byteLength % 8; - args.slice(unaligned); - num = shift_args(new BigUint64Array(args)); - } - - if (pad_with_zero) pad_char = "0"; - else if (pad_with_space) pad_char = " "; - else pad_char = ""; - - if (pre_with_format && radix === 8) pre_char = "0"; - else if (pre_with_format && radix === 16) pre_char = "0x"; - else pre_char = ""; - - if (precise) { - pad_char = " "; - num = num.toString(radix).padStart(precision, "0"); - } - - if (justify_right) { - num = num.toString(radix).padStart(pad_width, pad_char); - } else { - pad_char = " "; - num = num.toString(radix).padEnd(pad_width, pad_char); - } - - num = pre_char + num; - - if (capitalize) num = num.toUpperCase(); - - result += num; - fmt_cur += 2; - reset_state(); - break; - } - - case "i": - case "d": { - let num; - let pad_char, pre_char; - - if (bit_size === 32) { - num = shift_args(new Int32Array(args)); - } else { - unaligned = args.byteLength % 8; - args = args.slice(unaligned); - num = shift_args(new BigInt64Array(args)); - } - - if (pad_with_zero) pad_char = "0"; - else if (pad_with_space) pad_char = " "; - else pad_char = ""; - - if (pre_with_polarity && num > 0) pre_char = "+"; - else if (pre_with_space && num > 0) pre_char = " "; - else pre_char = ""; - - if (precise) { - pad_char = " "; - num = num.toString().padStart(precision, "0"); - } - - if (justify_right) { - num = num.toString().padStart(pad_width, pad_char); - } else { - pad_char = " "; - num = num.toString().padEnd(pad_width, pad_char); - } - - num = pre_char + num; - - result += num; - fmt_cur += 2; - reset_state(); - break; - } - - case "E": { - capitalize = true; - } - case "e": { - // Align Bytes by 8 - unaligned = args.byteLength % 8; - args = args.slice(unaligned); - - let num = shift_args(new Float64Array(args)); - let pad_char, pre_char; - - if (pad_with_zero) pad_char = "0"; - else if (pad_with_space) pad_char = " "; - else pad_char = ""; - - if (pre_with_polarity && num > 0) pre_char = "+"; - else if (pre_with_space && num > 0) pre_char = " "; - else pre_char = ""; - - if (precise) num = num.toExponential(precision); - else num = num.toExponential(6); - - if (justify_right) { - num = num.toString().padStart(pad_width, pad_char); - } else { - pad_char = " "; - num = num.toString().padEnd(pad_width, pad_char); - } - - if (capitalize) num = num.toUpperCase(); - - num = pre_char + num; - - result += num; - fmt_cur += 2; - reset_state(); - break; - } - case "F": - case "G": { - capitalize = true; - } - case "g": - case "f": { - // Align Bytes by 8 - unaligned = args.byteLength % 8; - args = args.slice(unaligned); - - let num = shift_args(new Float64Array(args)); - let pad_char, pre_char; - - if (pad_with_zero) pad_char = "0"; - else if (pad_with_space) pad_char = " "; - else pad_char = ""; - - if (pre_with_polarity && num > 0) pre_char = "+"; - else if (pre_with_space && num > 0) pre_char = " "; - else pre_char = ""; - - if (precise) num = num.toFixed(precision); - else num = num.toFixed(6); - - if (justify_right) { - num = num.toString().padStart(pad_width, pad_char); - } else { - pad_char = " "; - num = num.toString().padEnd(pad_width, pad_char); - } - - if (capitalize) num = num.toUpperCase(); - - num = pre_char + num; - - result += num; - fmt_cur += 2; - reset_state(); - break; - } - - // TODO: unsupported format specifiers, copy it to the temp string - // Flags => * - // Len Mod => j z t L - // Specify => a A n p - default: { - const str = fmt_buffer[fmt_cur++]; - result += str; - break; - } - } - } - - return result; -} diff --git a/raylib.js b/raylib.js index 55d3ede..8a40148 100644 --- a/raylib.js +++ b/raylib.js @@ -484,3 +484,418 @@ const glfwKeyMapping = { // GLFW_KEY_LAST GLFW_KEY_MENU } +function cstrlen(mem, ptr) { + let len = 0; + while (mem[ptr] != 0) { + len++; + ptr++; + } + return len; +} + +function cstr_by_ptr(mem_buffer, ptr) { + const mem = new Uint8Array(mem_buffer); + const len = cstrlen(mem, ptr); + const bytes = new Uint8Array(mem_buffer, ptr, len); + return new TextDecoder().decode(bytes); +} + +function color_hex_unpacked(r, g, b, a) { + r = r.toString(16).padStart(2, "0"); + g = g.toString(16).padStart(2, "0"); + b = b.toString(16).padStart(2, "0"); + a = a.toString(16).padStart(2, "0"); + return "#" + r + g + b + a; +} + +function color_hex(color) { + const r = ((color >> (0 * 8)) & 0xff).toString(16).padStart(2, "0"); + const g = ((color >> (1 * 8)) & 0xff).toString(16).padStart(2, "0"); + const b = ((color >> (2 * 8)) & 0xff).toString(16).padStart(2, "0"); + const a = ((color >> (3 * 8)) & 0xff).toString(16).padStart(2, "0"); + return "#" + r + g + b + a; +} + +function getColorFromMemory(buffer, color_ptr) { + const [r, g, b, a] = new Uint8Array(buffer, color_ptr, 4); + return color_hex_unpacked(r, g, b, a); +} + +function cstr_fmt_by_ptr(mem_buffer, fmt_ptr, arg_ptr) { + const fmt = cstr_by_ptr(mem_buffer, fmt_ptr); + + // VarArgs Chunk + let args = mem_buffer.slice(arg_ptr); + let result = ""; + let fmt_buffer = fmt.split(""); + let fmt_cur = 0; + + let pad_width, + precision, + pad_with_zero, + pad_with_space, + justify_right, + pre_with_polarity, + pre_with_space, + pre_with_format, + capitalize, + precise, + bit_size, + radix; + + reset_state(); + + function reset_state() { + bit_size = 32; + pad_width = 0; + precision = 0; + radix = 10; + pad_with_zero = false; + pad_with_space = false; + justify_right = true; + + pre_with_polarity = false; + pre_with_space = false; + pre_with_format = false; + + capitalize = false; + precise = false; + } + + function parse_num(cursor) { + let width_end = cursor; + while (fmt_buffer[width_end]) { + if (/\d/.test(fmt_buffer[width_end])) width_end++; + else break; + } + let num = fmt_buffer.splice(cursor, width_end - cursor).join(""); + return parseInt(num); + } + + // Grab the view of args based on specifier and shift the args + function shift_args(view) { + args = args.slice(view.BYTES_PER_ELEMENT); + return view.at(0); + } + + while (fmt_cur < fmt_buffer.length) { + if (fmt_buffer[fmt_cur] !== "%") { + // Normal character, copy it to the temp string + const str = fmt_buffer[fmt_cur++]; + result += str; + continue; + } + + // Peek only next character and splice the modifiers. + // So we can always simply look one char ahead + const peek_idx = fmt_cur + 1; + const peek_char = fmt_buffer[peek_idx]; + switch (peek_char) { + case undefined: { + fmt_cur++; + break; + } + + case "%": { + result += "%"; + fmt_cur += 2; + break; + } + + case "+": { + pre_with_polarity = true; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case "-": { + justify_right = false; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case " ": { + pre_with_space = !pre_with_polarity; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case ".": { + precise = true; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case "#": { + pre_with_format = true; + fmt_buffer.splice(peek_idx, 1); + break; + } + + case "0": { + if (precise) { + precision = parse_num(peek_idx); + } else { + pad_with_zero = true; + pad_width = parse_num(peek_idx); + } + break; + } + + case "1": + case "2": + case "3": + case "4": + case "5": + case "6": + case "7": + case "8": + case "9": { + if (precise) { + precision = parse_num(peek_idx); + } else { + pad_with_space = true; + pad_width = parse_num(peek_idx); + } + break; + } + + // Modifiers + case "l": { + bit_size = bit_size === 32 ? 64 : 32; + fmt_buffer.splice(peek_idx, 1); + } + + // In JS there are no number below 32 bit, so we are ignoring + // also clang bakes the overflown and underflown values as it is + case "h": { + fmt_buffer.splice(peek_idx, 1); + break; + } + + case "c": { + const char_code = shift_args(new Uint32Array(args)); + let str = String.fromCharCode(char_code); + let pad_char; + + if (pad_with_zero || pad_with_space) pad_char = " "; + else pad_char = ""; + + if (justify_right) str = str.padStart(pad_width, pad_char); + else str = str.padEnd(pad_width, pad_char); + + result += str; + fmt_cur += 2; + reset_state(); + break; + } + + case "s": { + const str_ptr = shift_args(new Uint32Array(args)); + let str = cstr_by_ptr(mem_buffer, str_ptr); + let pad_char; + + if (pad_with_zero || pad_with_space) pad_char = " "; + else pad_char = ""; + + if (justify_right) str = str.padStart(pad_width, pad_char); + else str = str.padEnd(pad_width, pad_char); + + if (precise) str = str.substring(0, precision); + + result += str; + fmt_cur += 2; + reset_state(); + break; + } + + case "o": + case "x": + case "X": + case "u": { + let num; + let pad_char, pre_char; + + if (peek_char === "o") { + radix = 8; + } else if (peek_char === "x") { + radix = 16; + } else if (peek_char === "X") { + radix = 16; + capitalize = true; + } else { + console.error("radix unreachable"); + } + + if (bit_size === 32) { + num = shift_args(new Uint32Array(args)); + } else { + unaligned = args.byteLength % 8; + args.slice(unaligned); + num = shift_args(new BigUint64Array(args)); + } + + if (pad_with_zero) pad_char = "0"; + else if (pad_with_space) pad_char = " "; + else pad_char = ""; + + if (pre_with_format && radix === 8) pre_char = "0"; + else if (pre_with_format && radix === 16) pre_char = "0x"; + else pre_char = ""; + + if (precise) { + pad_char = " "; + num = num.toString(radix).padStart(precision, "0"); + } + + if (justify_right) { + num = num.toString(radix).padStart(pad_width, pad_char); + } else { + pad_char = " "; + num = num.toString(radix).padEnd(pad_width, pad_char); + } + + num = pre_char + num; + + if (capitalize) num = num.toUpperCase(); + + result += num; + fmt_cur += 2; + reset_state(); + break; + } + + case "i": + case "d": { + let num; + let pad_char, pre_char; + + if (bit_size === 32) { + num = shift_args(new Int32Array(args)); + } else { + unaligned = args.byteLength % 8; + args = args.slice(unaligned); + num = shift_args(new BigInt64Array(args)); + } + + if (pad_with_zero) pad_char = "0"; + else if (pad_with_space) pad_char = " "; + else pad_char = ""; + + if (pre_with_polarity && num > 0) pre_char = "+"; + else if (pre_with_space && num > 0) pre_char = " "; + else pre_char = ""; + + if (precise) { + pad_char = " "; + num = num.toString().padStart(precision, "0"); + } + + if (justify_right) { + num = num.toString().padStart(pad_width, pad_char); + } else { + pad_char = " "; + num = num.toString().padEnd(pad_width, pad_char); + } + + num = pre_char + num; + + result += num; + fmt_cur += 2; + reset_state(); + break; + } + + case "E": { + capitalize = true; + } + case "e": { + // Align Bytes by 8 + unaligned = args.byteLength % 8; + args = args.slice(unaligned); + + let num = shift_args(new Float64Array(args)); + let pad_char, pre_char; + + if (pad_with_zero) pad_char = "0"; + else if (pad_with_space) pad_char = " "; + else pad_char = ""; + + if (pre_with_polarity && num > 0) pre_char = "+"; + else if (pre_with_space && num > 0) pre_char = " "; + else pre_char = ""; + + if (precise) num = num.toExponential(precision); + else num = num.toExponential(6); + + if (justify_right) { + num = num.toString().padStart(pad_width, pad_char); + } else { + pad_char = " "; + num = num.toString().padEnd(pad_width, pad_char); + } + + if (capitalize) num = num.toUpperCase(); + + num = pre_char + num; + + result += num; + fmt_cur += 2; + reset_state(); + break; + } + case "F": + case "G": { + capitalize = true; + } + case "g": + case "f": { + // Align Bytes by 8 + unaligned = args.byteLength % 8; + args = args.slice(unaligned); + + let num = shift_args(new Float64Array(args)); + let pad_char, pre_char; + + if (pad_with_zero) pad_char = "0"; + else if (pad_with_space) pad_char = " "; + else pad_char = ""; + + if (pre_with_polarity && num > 0) pre_char = "+"; + else if (pre_with_space && num > 0) pre_char = " "; + else pre_char = ""; + + if (precise) num = num.toFixed(precision); + else num = num.toFixed(6); + + if (justify_right) { + num = num.toString().padStart(pad_width, pad_char); + } else { + pad_char = " "; + num = num.toString().padEnd(pad_width, pad_char); + } + + if (capitalize) num = num.toUpperCase(); + + num = pre_char + num; + + result += num; + fmt_cur += 2; + reset_state(); + break; + } + + // TODO: unsupported format specifiers, copy it to the temp string + // Flags => * + // Len Mod => j z t L + // Specify => a A n p + default: { + const str = fmt_buffer[fmt_cur++]; + result += str; + break; + } + } + } + + return result; +} From 49cab4beb8b5a68d3a779677877e34cec75d4e83 Mon Sep 17 00:00:00 2001 From: VIGNESH KUMAR <45727291+VICTORVICKIE@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:50:21 +0530 Subject: [PATCH 06/12] fmt --- index.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 003b801..18324ac 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + @@ -68,11 +68,11 @@ -