const MAGIC_CANVAS_NUMBER = 0x5052455A;
+function push_event_to_buffer(esp, event_size, event_kind, data) {
+ let WASM_U32 = new Uint32Array(wasm_instance.exports.memory.buffer);
+
+ if (WASM_U32[esp] >= WASM_U32[esp + 1]) {
+ console.log("Buffer full!");
+ return;
+ }
+
+ WASM_U32[esp] += 1;
+
+ let event_idx = esp + (WASM_U32[esp] - 1) * (event_size / 4) + 2;
+ WASM_U32[event_idx] = event_kind;
+ WASM_U32[event_idx + 1] = Date.now();
+
+ for (let i = 0; i < data.length; i++) {
+ WASM_U32[event_idx + 2 + i] = data[i];
+ }
+}
+
+
+let event_import_obj = {
+ setup(esp, event_size) {
+ // Indicies into a Uint32Array are not based on bytes,
+ // but on the index.
+ esp /= 4;
+
+ document.addEventListener("keydown", (ev) => {
+ if (ev.isComposing || ev.keyCode === 229) return;
+ push_event_to_buffer(esp, event_size, 0x04, [ ev.keyCode ]);
+ });
+
+ document.addEventListener("keyup", (ev) => {
+ if (ev.isComposing || ev.keyCode === 229) return;
+ push_event_to_buffer(esp, event_size, 0x05, [ ev.keyCode ]);
+ });
+
+ document.addEventListener("mousedown", (ev) => {
+ push_event_to_buffer(esp, event_size, 0x01, [ ev.clientX, ev.clientY, ev.button ]);
+ });
+
+ document.addEventListener("mouseup", (ev) => {
+ push_event_to_buffer(esp, event_size, 0x02, [ ev.clientX, ev.clientY, ev.button ]);
+ });
+
+ document.addEventListener("mousemove", (ev) => {
+ push_event_to_buffer(esp, event_size, 0x03, [ ev.clientX, ev.clientY, -1 ]);
+ });
+
+ document.addEventListener("wheel", (ev) => {
+ push_event_to_buffer(esp, event_size, 0x07, [ ev.clientX, ev.clientY, ev.deltaY >= 0 ? 0x04 : 0x03 ]);
+ });
+
+ window.addEventListener("resize", (ev) => {
+ push_event_to_buffer(esp, event_size, 0x06, [ window.innerWidth, window.innerHeight ]);
+ });
+
+ push_event_to_buffer(esp, event_size, 0x06, [ window.innerWidth, window.innerHeight ]);
+ }
+}
+
let canvas_import_obj = {
init(canvas_name, length) {
const text = new TextDecoder().decode(data);
let metrics = canvasCtx.measureText(text);
- console.log("TEST:", metrics);
let data_view = new DataView(wasm_instance.exports.memory.buffer, measure_ptr, 5 * 4);
data_view.setFloat32(0, metrics.width, true);
exit(status) { console.warn("Attempted to call host.exit()."); }
},
- canvas: canvas_import_obj
+ canvas: canvas_import_obj,
+ event: event_import_obj,
}
function main() {
--- /dev/null
+// This is a simple buffered system to receive events from the webbrowser
+// in a buffer that you can poll and consume all of the events. It is not
+// direclty used by the immediate mode graphics, but it makes standing up
+// a simple application much easier.
+
+package event
+
+#private_file Num_Buffered_Events :: 16
+
+// NOTE: These need to match exactly what is in the corresponding javascript
+DomEventKind :: enum {
+ None :: 0x00;
+
+ MouseDown :: 0x01;
+ MouseUp :: 0x02;
+ MouseMove :: 0x03;
+ MouseWheel :: 0x07;
+
+ KeyDown :: 0x04;
+ KeyUp :: 0x05;
+
+ Resize :: 0x06;
+}
+
+DomEvent :: struct {
+ kind : DomEventKind;
+ timestamp : u32;
+}
+
+KeyboardEvent :: struct {
+ use event : DomEvent;
+
+ keycode : u32;
+}
+
+MouseButton :: enum {
+ Left :: 0x00;
+ Middle :: 0x01;
+ Right :: 0x02;
+
+ WheelUp :: 0x03;
+ WheelDown :: 0x04;
+}
+
+MouseEvent :: struct {
+ use event : DomEvent;
+
+ pos_x : u32;
+ pos_y : u32;
+ button : MouseButton;
+}
+
+ResizeEvent :: struct {
+ use event : DomEvent;
+
+ width : u32;
+ height : u32;
+}
+
+Event :: struct #union {
+ use dom : DomEvent;
+
+ keyboard : KeyboardEvent;
+ mouse : MouseEvent;
+ resize : ResizeEvent;
+}
+
+clear_event :: (ev: ^Event) {
+ ev.kind = DomEventKind.None;
+ ev.timestamp = 0;
+}
+
+init :: () {
+ event_storage.event_count = 0;
+ event_storage.max_events = Num_Buffered_Events;
+
+ for ^ev: event_storage.event_buffer do clear_event(ev);
+
+ event_setup(^event_storage, sizeof Event);
+}
+
+poll :: (ev: ^Event) -> bool {
+ if event_storage.event_count == 0 do return false;
+
+ *ev = event_storage.event_buffer[0];
+ for i: 0 .. Num_Buffered_Events - 2 {
+ event_storage.event_buffer[i] = event_storage.event_buffer[i + 1];
+ }
+
+ event_storage.event_count -= 1;
+
+ return true;
+}
+
+/* Private members */
+
+#private_file EventStorage :: struct {
+ event_count : u32;
+ max_events : u32;
+ event_buffer : [Num_Buffered_Events] Event;
+}
+
+#private_file event_storage : EventStorage;
+#private_file event_setup :: (event_storage: ^EventStorage, event_size: u32) -> void #foreign "event" "setup" ---
use package core
+use package event as event
Canvas :: struct {
- Handle :: #type u32;
+ Handle :: #type u32
init :: (id: str) -> Handle #foreign "canvas" "init" ---
clear :: (handle: Handle, r: f32, g: f32, b: f32, a := 1.0f) -> Handle #foreign "canvas" "clear" ---
set_font :: (handle: Handle, font_name: str) -> u32 #foreign "canvas" "setFont" ---
TextMetrics :: struct {
- width : f32;
- box : struct {
+ width: f32;
+
+ box: struct {
left, right : f32;
top, bottom : f32;
};
font_metrics: TextMetrics;
measure_text(canvas, text, ^font_metrics);
- println(font_metrics.width);
x := (width - font_metrics.width) / 2;
fill_text(canvas, text, x, y_baseline);
}
+poll_events :: () {
+ use event.DomEventKind;
+
+ ev: event.Event;
+ while event.poll(^ev) do switch ev.kind {
+ case Resize {
+ printf("New window size: %i, %i", ev.resize.width, ev.resize.height);
+ }
+ }
+}
+
main :: (args: [] cstr) {
setup_canvas();
+ event.init();
draw_centered_text("Hello, World! This is a long title!", 100);
+
+ poll_events();
}