Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add WebXRInterface.xr_standard_mapping flag to attempt to convert button/axis ids to match other AR/VR interfaces #59994

Merged
merged 1 commit into from
Apr 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions modules/webxr/doc_classes/WebXRInterface.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@

webxr_interface = ARVRServer.find_interface("WebXR")
if webxr_interface:
# Map to the standard button/axis ids when possible.
webxr_interface.xr_standard_mapping = true

# WebXR uses a lot of asynchronous callbacks, so we connect to various
# signals in order to receive them.
webxr_interface.connect("session_supported", self, "_webxr_session_supported")
Expand Down Expand Up @@ -164,6 +167,10 @@
Indicates if the WebXR session's imagery is visible to the user.
Possible values come from [url=https://developer.mozilla.org/en-US/docs/Web/API/XRVisibilityState]WebXR's XRVisibilityState[/url], including [code]"hidden"[/code], [code]"visible"[/code], and [code]"visible-blurred"[/code].
</member>
<member name="xr_standard_mapping" type="bool" setter="set_xr_standard_mapping" getter="get_xr_standard_mapping">
If set to true, the button and axes ids will be converted to match the standard ids used by other AR/VR interfaces, when possible.
Otherwise, the ids will be passed through unaltered from WebXR.
</member>
</members>
<signals>
<signal name="reference_space_reset">
Expand Down
4 changes: 2 additions & 2 deletions modules/webxr/godot_webxr.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ extern void godot_webxr_sample_controller_data();
extern int godot_webxr_get_controller_count();
extern int godot_webxr_is_controller_connected(int p_controller);
extern float *godot_webxr_get_controller_transform(int p_controller);
extern int *godot_webxr_get_controller_buttons(int p_controller);
extern int *godot_webxr_get_controller_axes(int p_controller);
extern int *godot_webxr_get_controller_buttons(int p_controller, bool p_xr_standard_mapping);
extern int *godot_webxr_get_controller_axes(int p_controller, bool p_xr_standard_mapping);
extern int godot_webxr_get_controller_target_ray_mode(int p_controller);

extern char *godot_webxr_get_visibility_state();
Expand Down
95 changes: 77 additions & 18 deletions modules/webxr/native/library_godot_webxr.js
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,8 @@ const GodotWebXR = {
},

godot_webxr_get_controller_buttons__proxy: 'sync',
godot_webxr_get_controller_buttons__sig: 'ii',
godot_webxr_get_controller_buttons: function (p_controller) {
godot_webxr_get_controller_buttons__sig: 'iii',
godot_webxr_get_controller_buttons: function (p_controller, p_xr_standard_mapping) {
if (GodotWebXR.controllers.length === 0) {
return 0;
}
Expand All @@ -535,19 +535,55 @@ const GodotWebXR = {
return 0;
}

const button_count = controller.gamepad.buttons.length;
let buttons = controller.gamepad.buttons;
if (controller.gamepad.mapping === 'xr-standard' && p_xr_standard_mapping) {
buttons = [
// 0 = unused,
0,
// 1 = B/Y
buttons[5],
// 2 = Grip
buttons[1],
// 3
buttons[3],
// 4
buttons[6],
// 5
buttons[7],
// 6
buttons[8],
// 7 = A/X
buttons[4],
// 8
buttons[9],
// 9
buttons[10],
// 10
buttons[11],
// 11
buttons[12],
// 12
buttons[13],
// 13
buttons[14],
// 14 = Pad
buttons[2],
// 15 = Trigger
buttons[0],
];
}

const buf = GodotRuntime.malloc((button_count + 1) * 4);
GodotRuntime.setHeapValue(buf, button_count, 'i32');
for (let i = 0; i < button_count; i++) {
GodotRuntime.setHeapValue(buf + 4 + (i * 4), controller.gamepad.buttons[i].value, 'float');
const buf = GodotRuntime.malloc((buttons.length + 1) * 4);
GodotRuntime.setHeapValue(buf, buttons.length, 'i32');
for (let i = 0; i < buttons.length; i++) {
GodotRuntime.setHeapValue(buf + 4 + (i * 4), (buttons[i] ? buttons[i].value : 0.0), 'float');
}
return buf;
},

godot_webxr_get_controller_axes__proxy: 'sync',
godot_webxr_get_controller_axes__sig: 'ii',
godot_webxr_get_controller_axes: function (p_controller) {
godot_webxr_get_controller_axes__sig: 'iii',
godot_webxr_get_controller_axes: function (p_controller, p_xr_standard_mapping) {
if (GodotWebXR.controllers.length === 0) {
return 0;
}
Expand All @@ -557,18 +593,41 @@ const GodotWebXR = {
return 0;
}

const axes_count = controller.gamepad.axes.length;

const buf = GodotRuntime.malloc((axes_count + 1) * 4);
GodotRuntime.setHeapValue(buf, axes_count, 'i32');
for (let i = 0; i < axes_count; i++) {
let value = controller.gamepad.axes[i];
if (i === 1 || i === 3) {
let axes = controller.gamepad.axes;
if (controller.gamepad.mapping === 'xr-standard') {
if (p_xr_standard_mapping) {
const trigger_axis = controller.gamepad.buttons[0].value;
const grip_axis = controller.gamepad.buttons[1].value;
axes = [
// 0 = Thumbstick X
axes[2],
// 1 = Thumbstick Y
axes[3] * -1.0,
// 2 = Trigger
trigger_axis,
// 3 = Grip (to match mistake in Oculus mobile plugin).
grip_axis,
// 4 = Grip
grip_axis,
// 5 = unused
0,
// 6 = Trackpad X
axes[0],
// 7 = Trackpad Y
axes[1] * -1.0,
];
} else {
// Invert the Y-axis on thumbsticks and trackpads, in order to
// match OpenXR and other XR platform SDKs.
value *= -1.0;
axes[1] *= -1.0;
axes[3] *= -1.0;
}
GodotRuntime.setHeapValue(buf + 4 + (i * 4), value, 'float');
}

const buf = GodotRuntime.malloc((axes.length + 1) * 4);
GodotRuntime.setHeapValue(buf, axes.length, 'i32');
for (let i = 0; i < axes.length; i++) {
GodotRuntime.setHeapValue(buf + 4 + (i * 4), axes[i], 'float');
}
return buf;
},
Expand Down
3 changes: 3 additions & 0 deletions modules/webxr/webxr_interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ void WebXRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_controller_target_ray_mode", "controller_id"), &WebXRInterface::get_controller_target_ray_mode);
ClassDB::bind_method(D_METHOD("get_visibility_state"), &WebXRInterface::get_visibility_state);
ClassDB::bind_method(D_METHOD("get_bounds_geometry"), &WebXRInterface::get_bounds_geometry);
ClassDB::bind_method(D_METHOD("set_xr_standard_mapping"), &WebXRInterface::set_xr_standard_mapping);
ClassDB::bind_method(D_METHOD("get_xr_standard_mapping"), &WebXRInterface::get_xr_standard_mapping);

ADD_PROPERTY(PropertyInfo(Variant::STRING, "session_mode", PROPERTY_HINT_NONE), "set_session_mode", "get_session_mode");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "required_features", PROPERTY_HINT_NONE), "set_required_features", "get_required_features");
Expand All @@ -54,6 +56,7 @@ void WebXRInterface::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "reference_space_type", PROPERTY_HINT_NONE), "", "get_reference_space_type");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "visibility_state", PROPERTY_HINT_NONE), "", "get_visibility_state");
ADD_PROPERTY(PropertyInfo(Variant::POOL_VECTOR3_ARRAY, "bounds_geometry", PROPERTY_HINT_NONE), "", "get_bounds_geometry");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "xr_standard_mapping", PROPERTY_HINT_NONE), "set_xr_standard_mapping", "get_xr_standard_mapping");

ADD_SIGNAL(MethodInfo("session_supported", PropertyInfo(Variant::STRING, "session_mode"), PropertyInfo(Variant::BOOL, "supported")));
ADD_SIGNAL(MethodInfo("session_started"));
Expand Down
2 changes: 2 additions & 0 deletions modules/webxr/webxr_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ class WebXRInterface : public ARVRInterface {
virtual TargetRayMode get_controller_target_ray_mode(int p_controller_id) const = 0;
virtual String get_visibility_state() const = 0;
virtual PoolVector3Array get_bounds_geometry() const = 0;
virtual void set_xr_standard_mapping(bool p_xr_standard_mapping) = 0;
virtual bool get_xr_standard_mapping() const = 0;
};

VARIANT_ENUM_CAST(WebXRInterface::TargetRayMode);
Expand Down
18 changes: 13 additions & 5 deletions modules/webxr/webxr_interface_js.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,14 @@ PoolVector3Array WebXRInterfaceJS::get_bounds_geometry() const {
return ret;
}

void WebXRInterfaceJS::set_xr_standard_mapping(bool p_xr_standard_mapping) {
xr_standard_mapping = p_xr_standard_mapping;
}

bool WebXRInterfaceJS::get_xr_standard_mapping() const {
return xr_standard_mapping;
}

StringName WebXRInterfaceJS::get_name() const {
return "WebXR";
};
Expand Down Expand Up @@ -417,15 +425,15 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) {
free(tracker_matrix);
}

int *buttons = godot_webxr_get_controller_buttons(p_controller_id);
int *buttons = godot_webxr_get_controller_buttons(p_controller_id, xr_standard_mapping);
if (buttons) {
for (int i = 0; i < buttons[0]; i++) {
input->joy_button(joy_id, i, *((float *)buttons + (i + 1)));
}
free(buttons);
}

int *axes = godot_webxr_get_controller_axes(p_controller_id);
int *axes = godot_webxr_get_controller_axes(p_controller_id, xr_standard_mapping);
if (axes) {
WebXRInterface::TargetRayMode target_ray_mode = (WebXRInterface::TargetRayMode)godot_webxr_get_controller_target_ray_mode(p_controller_id);
if (target_ray_mode == WebXRInterface::TARGET_RAY_MODE_SCREEN) {
Expand Down Expand Up @@ -481,7 +489,7 @@ void WebXRInterfaceJS::_on_input_event(int p_event_type, int p_input_source) {
touching[touch_index] = (p_event_type == WEBXR_INPUT_EVENT_SELECTSTART);
}

int *axes = godot_webxr_get_controller_axes(p_input_source);
int *axes = godot_webxr_get_controller_axes(p_input_source, false);
if (axes) {
Vector2 joy_vector = _get_joy_vector_from_axes(axes);
Vector2 position = _get_screen_position_from_joy_vector(joy_vector);
Expand Down Expand Up @@ -554,8 +562,7 @@ Vector2 WebXRInterfaceJS::_get_joy_vector_from_axes(int *p_axes) {
}

Vector2 WebXRInterfaceJS::_get_screen_position_from_joy_vector(const Vector2 &p_joy_vector) {
// Invert the y-axis.
Vector2 position_percentage((p_joy_vector.x + 1.0f) / 2.0f, ((-p_joy_vector.y) + 1.0f) / 2.0f);
Vector2 position_percentage((p_joy_vector.x + 1.0f) / 2.0f, ((p_joy_vector.y) + 1.0f) / 2.0f);
Vector2 position = get_render_targetsize() * position_percentage;

return position;
Expand All @@ -567,6 +574,7 @@ void WebXRInterfaceJS::notification(int p_what) {

WebXRInterfaceJS::WebXRInterfaceJS() {
initialized = false;
xr_standard_mapping = false;
session_mode = "inline";
requested_reference_space_types = "local";
};
Expand Down
3 changes: 3 additions & 0 deletions modules/webxr/webxr_interface_js.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class WebXRInterfaceJS : public WebXRInterface {

private:
bool initialized;
bool xr_standard_mapping;

String session_mode;
String required_features;
Expand Down Expand Up @@ -80,6 +81,8 @@ class WebXRInterfaceJS : public WebXRInterface {
virtual TargetRayMode get_controller_target_ray_mode(int p_controller_id) const;
virtual String get_visibility_state() const;
virtual PoolVector3Array get_bounds_geometry() const;
virtual void set_xr_standard_mapping(bool p_xr_standard_mapping);
virtual bool get_xr_standard_mapping() const;

virtual StringName get_name() const;
virtual int get_capabilities() const;
Expand Down