aboutsummaryrefslogtreecommitdiff
path: root/core/sys/wasm
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2024-09-22 19:29:05 +0100
committergingerBill <bill@gingerbill.org>2024-09-22 19:29:05 +0100
commit95721fe29670e404a2fb5e5fe5e51b39f5c7b9d6 (patch)
tree2c31e09149bb133dafadddef54b6bc408c806048 /core/sys/wasm
parent66e83ef30d990f544abf08fe47f1d83c4bc18168 (diff)
Add gamepad support
Diffstat (limited to 'core/sys/wasm')
-rw-r--r--core/sys/wasm/js/events.odin60
-rw-r--r--core/sys/wasm/js/events_all_targets.odin3
-rw-r--r--core/sys/wasm/js/odin.js111
3 files changed, 142 insertions, 32 deletions
diff --git a/core/sys/wasm/js/events.odin b/core/sys/wasm/js/events.odin
index 71191e3ab..905b3eba9 100644
--- a/core/sys/wasm/js/events.odin
+++ b/core/sys/wasm/js/events.odin
@@ -192,11 +192,8 @@ KEYBOARD_MAX_CODE_SIZE :: 16
GAMEPAD_MAX_ID_SIZE :: 64
GAMEPAD_MAX_MAPPING_SIZE :: 64
-Gamepad_Button :: struct {
- pressed: bool,
- touched: bool,
- value: f64,
-}
+GAMEPAD_MAX_BUTTONS :: 64
+GAMEPAD_MAX_AXES :: 16
Event_Target_Kind :: enum u32 {
Element = 0,
@@ -218,6 +215,30 @@ Event_Option :: enum u8 {
}
Event_Options :: distinct bit_set[Event_Option; u8]
+Gamepad_Button :: struct {
+ value: f64,
+ pressed: bool,
+ touched: bool,
+}
+
+Gamepad_State :: struct {
+ id: string,
+ mapping: string,
+ index: int,
+ connected: bool,
+ timestamp: f64,
+
+ button_count: int,
+ axis_count: int,
+ buttons: [GAMEPAD_MAX_BUTTONS]Gamepad_Button `fmt:"v,button_count"`,
+ axes: [GAMEPAD_MAX_AXES]f64 `fmt:"v,axes_count"`,
+
+ _id_len: int `fmt:"-"`,
+ _mapping_len: int `fmt:"-"`,
+ _id_buf: [GAMEPAD_MAX_ID_SIZE]byte `fmt:"-"`,
+ _mapping_buf: [GAMEPAD_MAX_MAPPING_SIZE]byte `fmt:"-"`,
+}
+
Event :: struct {
kind: Event_Kind,
target_kind: Event_Target_Kind,
@@ -276,20 +297,7 @@ Event :: struct {
buttons: bit_set[0..<16; u16],
},
- gamepad: struct {
- id: string,
- mapping: string,
- index: int,
- connected: bool,
- timestamp: f64,
- button_count: int,
- axes_count: int,
-
- _id_len: int `fmt:"-"`,
- _mapping_len: int `fmt:"-"`,
- _id_buf: [GAMEPAD_MAX_ID_SIZE]byte `fmt:"-"`,
- _mapping_buf: [GAMEPAD_MAX_MAPPING_SIZE]byte `fmt:"-"`,
- },
+ gamepad: Gamepad_State,
},
@@ -366,6 +374,20 @@ remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr
return _remove_event_listener(id, name, user_data, callback)
}
+get_gamepad_state :: proc "contextless" (index: int, s: ^Gamepad_State) -> bool {
+ @(default_calling_convention="contextless")
+ foreign dom_lib {
+ @(link_name="get_gamepad_state")
+ _get_gamepad_state :: proc(index: int, s: ^Gamepad_State) -> bool ---
+ }
+
+ if s == nil {
+ return false
+ }
+ return _get_gamepad_state(index, s)
+}
+
+
@(export, link_name="odin_dom_do_event_callback")
do_event_callback :: proc(user_data: rawptr, callback: proc(e: Event)) {
@(default_calling_convention="contextless")
diff --git a/core/sys/wasm/js/events_all_targets.odin b/core/sys/wasm/js/events_all_targets.odin
index ccf39015d..b7e01ca10 100644
--- a/core/sys/wasm/js/events_all_targets.odin
+++ b/core/sys/wasm/js/events_all_targets.odin
@@ -284,5 +284,4 @@ add_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, c
}
remove_custom_event_listener :: proc(id: string, name: string, user_data: rawptr, callback: proc(e: Event)) -> bool {
panic("vendor:wasm/js not supported on non JS targets")
-}
-
+} \ No newline at end of file
diff --git a/core/sys/wasm/js/odin.js b/core/sys/wasm/js/odin.js
index 26c47255c..bf002da74 100644
--- a/core/sys/wasm/js/odin.js
+++ b/core/sys/wasm/js/odin.js
@@ -1533,28 +1533,47 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, ev
wmi.storeU8(off(1), !!e.repeat);
- wmi.storeInt(off(W), e.key.length)
- wmi.storeInt(off(W), e.code.length)
+ wmi.storeInt(off(W, W), e.key.length)
+ wmi.storeInt(off(W, W), e.code.length)
wmi.storeString(off(16, 1), e.key);
wmi.storeString(off(16, 1), e.code);
} else if (e.type === 'scroll') {
- wmi.storeF64(off(8), window.scrollX);
- wmi.storeF64(off(8), window.scrollY);
+ wmi.storeF64(off(8, 8), window.scrollX);
+ wmi.storeF64(off(8, 8), window.scrollY);
} else if (e.type === 'visibilitychange') {
wmi.storeU8(off(1), !document.hidden);
} else if (e instanceof GamepadEvent) {
const idPtr = off(W*2, W);
const mappingPtr = off(W*2, W);
- wmi.storeI32(off(W), e.gamepad.index);
+ wmi.storeI32(off(W, W), e.gamepad.index);
wmi.storeU8(off(1), !!e.gamepad.connected);
- wmi.storeF64(off(8), e.gamepad.timestamp);
-
- wmi.storeInt(off(W), e.gamepad.buttons.length);
- wmi.storeInt(off(W), e.gamepad.axes.length);
+ wmi.storeF64(off(8, 8), e.gamepad.timestamp);
+
+ wmi.storeInt(off(W, W), e.gamepad.buttons.length);
+ wmi.storeInt(off(W, W), e.gamepad.axes.length);
+
+ for (let i = 0; i < 64; i++) {
+ if (i < e.gamepad.buttons.length) {
+ let b = e.gamepad.buttons[i];
+ wmi.storeF64(off(8, 8), b.value);
+ wmi.storeU8(off(1), !!b.pressed);
+ wmi.storeU8(off(1), !!b.touched);
+ } else {
+ off(16, 8);
+ }
+ }
+ for (let i = 0; i < 16; i++) {
+ if (i < e.gamepad.axes.length) {
+ let a = e.gamepad.axes[i];
+ wmi.storeF64(off(8, 8), a);
+ } else {
+ off(8, 8);
+ }
+ }
- wmi.storeInt(off(W), e.gamepad.id.length)
- wmi.storeInt(off(W), e.gamepad.mapping.length)
+ wmi.storeInt(off(W, W), e.gamepad.id.length)
+ wmi.storeInt(off(W, W), e.gamepad.mapping.length)
wmi.storeString(off(64, 1), e.gamepad.id);
wmi.storeString(off(64, 1), e.gamepad.mapping);
}
@@ -1661,6 +1680,76 @@ function odinSetupDefaultImports(wasmMemoryInterface, consoleElement, memory, ev
return false;
},
+ get_gamepad_state: (gamepad_id, ep) => {
+ let index = gamepad_id;
+ let gps = navigator.getGamepads();
+ if (0 <= index && index < gps.length) {
+ let gamepad = gps[index];
+ if (!gamepad) {
+ return false;
+ }
+
+ const W = wasmMemoryInterface.intSize;
+ let offset = ep;
+ let off = (amount, alignment) => {
+ if (alignment === undefined) {
+ alignment = Math.min(amount, W);
+ }
+ if (offset % alignment != 0) {
+ offset += alignment - (offset%alignment);
+ }
+ let x = offset;
+ offset += amount;
+ return x;
+ };
+
+ let align = (alignment) => {
+ const modulo = offset & (alignment-1);
+ if (modulo != 0) {
+ offset += alignment - modulo
+ }
+ };
+
+ let wmi = wasmMemoryInterface;
+
+ const idPtr = off(W*2, W);
+ const mappingPtr = off(W*2, W);
+
+ wmi.storeI32(off(W), gamepad.index);
+ wmi.storeU8(off(1), !!gamepad.connected);
+ wmi.storeF64(off(8), gamepad.timestamp);
+
+ wmi.storeInt(off(W), gamepad.buttons.length);
+ wmi.storeInt(off(W), gamepad.axes.length);
+
+ for (let i = 0; i < 64; i++) {
+ if (i < gamepad.buttons.length) {
+ let b = gamepad.buttons[i];
+ wmi.storeF64(off(8, 8), b.value);
+ wmi.storeU8(off(1), !!b.pressed);
+ wmi.storeU8(off(1), !!b.touched);
+ } else {
+ off(16, 8);
+ }
+ }
+ for (let i = 0; i < 16; i++) {
+ if (i < gamepad.axes.length) {
+ wmi.storeF64(off(8, 8), gamepad.axes[i]);
+ } else {
+ off(8, 8);
+ }
+ }
+
+ wmi.storeInt(off(W, W), gamepad.id.length)
+ wmi.storeInt(off(W, W), gamepad.mapping.length)
+ wmi.storeString(off(64, 1), gamepad.id);
+ wmi.storeString(off(64, 1), gamepad.mapping);
+
+ return true;
+ }
+ return false;
+ },
+
get_element_value_f64: (id_ptr, id_len) => {
let id = wasmMemoryInterface.loadString(id_ptr, id_len);
let element = getElement(id);