diff options
Diffstat (limited to 'modules/webxr/webxr_interface_js.cpp')
-rw-r--r-- | modules/webxr/webxr_interface_js.cpp | 164 |
1 files changed, 112 insertions, 52 deletions
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp index 10076327e2..2676b3cf80 100644 --- a/modules/webxr/webxr_interface_js.cpp +++ b/modules/webxr/webxr_interface_js.cpp @@ -35,6 +35,7 @@ #include "core/os/os.h" #include "emscripten.h" #include "godot_webxr.h" +#include "servers/rendering/renderer_compositor.h" #include <stdlib.h> void _emwebxr_on_session_supported(char *p_session_mode, int p_supported) { @@ -45,7 +46,7 @@ void _emwebxr_on_session_supported(char *p_session_mode, int p_supported) { ERR_FAIL_COND(interface.is_null()); String session_mode = String(p_session_mode); - interface->emit_signal("session_supported", session_mode, p_supported ? true : false); + interface->emit_signal(SNAME("session_supported"), session_mode, p_supported ? true : false); } void _emwebxr_on_session_started(char *p_reference_space_type) { @@ -57,7 +58,7 @@ void _emwebxr_on_session_started(char *p_reference_space_type) { String reference_space_type = String(p_reference_space_type); ((WebXRInterfaceJS *)interface.ptr())->_set_reference_space_type(reference_space_type); - interface->emit_signal("session_started"); + interface->emit_signal(SNAME("session_started")); } void _emwebxr_on_session_ended() { @@ -68,7 +69,7 @@ void _emwebxr_on_session_ended() { ERR_FAIL_COND(interface.is_null()); interface->uninitialize(); - interface->emit_signal("session_ended"); + interface->emit_signal(SNAME("session_ended")); } void _emwebxr_on_session_failed(char *p_message) { @@ -81,7 +82,7 @@ void _emwebxr_on_session_failed(char *p_message) { interface->uninitialize(); String message = String(p_message); - interface->emit_signal("session_failed", message); + interface->emit_signal(SNAME("session_failed"), message); } void _emwebxr_on_controller_changed() { @@ -160,11 +161,16 @@ String WebXRInterfaceJS::get_reference_space_type() const { return reference_space_type; } -XRPositionalTracker *WebXRInterfaceJS::get_controller(int p_controller_id) const { +Ref<XRPositionalTracker> WebXRInterfaceJS::get_controller(int p_controller_id) const { XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL_V(xr_server, nullptr); + ERR_FAIL_NULL_V(xr_server, Ref<XRPositionalTracker>()); - return xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id); + // TODO support more then two controllers + if (p_controller_id >= 0 && p_controller_id < 2) { + return controllers[p_controller_id]; + }; + + return Ref<XRPositionalTracker>(); } String WebXRInterfaceJS::get_visibility_state() const { @@ -198,12 +204,12 @@ StringName WebXRInterfaceJS::get_name() const { return "WebXR"; }; -int WebXRInterfaceJS::get_capabilities() const { +uint32_t WebXRInterfaceJS::get_capabilities() const { return XRInterface::XR_STEREO | XRInterface::XR_MONO; }; -bool WebXRInterfaceJS::is_stereo() { - return godot_webxr_get_view_count() == 2; +uint32_t WebXRInterfaceJS::get_view_count() { + return godot_webxr_get_view_count(); }; bool WebXRInterfaceJS::is_initialized() const { @@ -223,6 +229,13 @@ bool WebXRInterfaceJS::initialize() { return false; } + // we must create a tracker for our head + head_tracker.instantiate(); + head_tracker->set_tracker_type(XRServer::TRACKER_HEAD); + head_tracker->set_tracker_name("head"); + head_tracker->set_tracker_desc("Players head"); + xr_server->add_tracker(head_tracker); + // make this our primary interface xr_server->set_primary_interface(this); @@ -253,9 +266,17 @@ bool WebXRInterfaceJS::initialize() { void WebXRInterfaceJS::uninitialize() { if (initialized) { XRServer *xr_server = XRServer::get_singleton(); - if (xr_server != NULL) { - // no longer our primary interface - xr_server->clear_primary_interface_if(this); + if (xr_server != nullptr) { + if (head_tracker.is_valid()) { + xr_server->remove_tracker(head_tracker); + + head_tracker.unref(); + } + + if (xr_server->get_primary_interface() == this) { + // no longer our primary interface + xr_server->set_primary_interface(nullptr); + } } godot_webxr_uninitialize(); @@ -265,8 +286,8 @@ void WebXRInterfaceJS::uninitialize() { }; }; -Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) { - Transform transform; +Transform3D WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) { + Transform3D transform; transform.basis.elements[0].x = p_js_matrix[0]; transform.basis.elements[1].x = p_js_matrix[1]; @@ -284,12 +305,12 @@ Transform WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) { return transform; } -Size2 WebXRInterfaceJS::get_render_targetsize() { +Size2 WebXRInterfaceJS::get_render_target_size() { if (render_targetsize.width != 0 && render_targetsize.height != 0) { return render_targetsize; } - int *js_size = godot_webxr_get_render_targetsize(); + int *js_size = godot_webxr_get_render_target_size(); if (!initialized || js_size == nullptr) { // As a temporary default (until WebXR is fully initialized), use half the window size. Size2 temp = DisplayServer::get_singleton()->window_get_size(); @@ -305,13 +326,30 @@ Size2 WebXRInterfaceJS::get_render_targetsize() { return render_targetsize; }; -Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) { - Transform transform_for_eye; +Transform3D WebXRInterfaceJS::get_camera_transform() { + Transform3D transform_for_eye; + + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, transform_for_eye); + + float *js_matrix = godot_webxr_get_transform_for_eye(0); + if (!initialized || js_matrix == nullptr) { + return transform_for_eye; + } + + transform_for_eye = _js_matrix_to_transform(js_matrix); + free(js_matrix); + + return xr_server->get_reference_frame() * transform_for_eye; +}; + +Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) { + Transform3D transform_for_eye; XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL_V(xr_server, transform_for_eye); - float *js_matrix = godot_webxr_get_transform_for_eye(p_eye); + float *js_matrix = godot_webxr_get_transform_for_eye(p_view + 1); if (!initialized || js_matrix == nullptr) { transform_for_eye = p_cam_transform; return transform_for_eye; @@ -323,10 +361,10 @@ Transform WebXRInterfaceJS::get_transform_for_eye(XRInterface::Eyes p_eye, const return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye; }; -CameraMatrix WebXRInterfaceJS::get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) { +CameraMatrix WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) { CameraMatrix eye; - float *js_matrix = godot_webxr_get_projection_for_eye(p_eye); + float *js_matrix = godot_webxr_get_projection_for_eye(p_view + 1); if (!initialized || js_matrix == nullptr) { return eye; } @@ -347,24 +385,31 @@ CameraMatrix WebXRInterfaceJS::get_projection_for_eye(XRInterface::Eyes p_eye, r return eye; } -unsigned int WebXRInterfaceJS::get_external_texture_for_eye(XRInterface::Eyes p_eye) { +Vector<BlitToScreen> WebXRInterfaceJS::commit_views(RID p_render_target, const Rect2 &p_screen_rect) { + Vector<BlitToScreen> blit_to_screen; + if (!initialized) { - return 0; + return blit_to_screen; } - return godot_webxr_get_external_texture_for_eye(p_eye); -} -void WebXRInterfaceJS::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) { - if (!initialized) { - return; + // @todo Refactor this to be based on "views" rather than "eyes". + godot_webxr_commit_for_eye(1); + if (godot_webxr_get_view_count() > 1) { + godot_webxr_commit_for_eye(2); } - godot_webxr_commit_for_eye(p_eye); + + return blit_to_screen; }; void WebXRInterfaceJS::process() { if (initialized) { godot_webxr_sample_controller_data(); + if (head_tracker.is_valid()) { + // TODO set default pose to our head location (i.e. get_camera_transform without world scale and reference frame applied) + // head_tracker->set_pose("default", head_transform, Vector3(), Vector3()); + } + int controller_count = godot_webxr_get_controller_count(); if (controller_count == 0) { return; @@ -380,51 +425,70 @@ void WebXRInterfaceJS::_update_tracker(int p_controller_id) { XRServer *xr_server = XRServer::get_singleton(); ERR_FAIL_NULL(xr_server); - XRPositionalTracker *tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id + 1); + // need to support more then two controllers... + if (p_controller_id < 0 || p_controller_id > 1) { + return; + } + + Ref<XRPositionalTracker> tracker = controllers[p_controller_id]; if (godot_webxr_is_controller_connected(p_controller_id)) { - if (tracker == nullptr) { - tracker = memnew(XRPositionalTracker); + if (tracker.is_null()) { + tracker.instantiate(); tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER); // Controller id's 0 and 1 are always the left and right hands. if (p_controller_id < 2) { - tracker->set_tracker_name(p_controller_id == 0 ? "Left" : "Right"); + tracker->set_tracker_name(p_controller_id == 0 ? "left_hand" : "right_hand"); + tracker->set_tracker_desc(p_controller_id == 0 ? "Left hand controller" : "Right hand controller"); tracker->set_tracker_hand(p_controller_id == 0 ? XRPositionalTracker::TRACKER_HAND_LEFT : XRPositionalTracker::TRACKER_HAND_RIGHT); + } else { + char name[1024]; + sprintf(name, "tracker_%i", p_controller_id); + tracker->set_tracker_name(name); + tracker->set_tracker_desc(name); } - // Use the ids we're giving to our "virtual" gamepads. - tracker->set_joy_id(p_controller_id + 100); xr_server->add_tracker(tracker); } - Input *input = Input::get_singleton(); - float *tracker_matrix = godot_webxr_get_controller_transform(p_controller_id); if (tracker_matrix) { - Transform transform = _js_matrix_to_transform(tracker_matrix); - tracker->set_position(transform.origin); - tracker->set_orientation(transform.basis); + // Note, poses should NOT have world scale and our reference frame applied! + Transform3D transform = _js_matrix_to_transform(tracker_matrix); + tracker->set_pose("default", transform, Vector3(), Vector3()); free(tracker_matrix); } + // TODO implement additional poses such as "aim" and "grip" + int *buttons = godot_webxr_get_controller_buttons(p_controller_id); if (buttons) { + // TODO buttons should be named properly, this is just a temporary fix for (int i = 0; i < buttons[0]; i++) { - input->joy_button(p_controller_id + 100, i, *((float *)buttons + (i + 1))); + char name[1024]; + sprintf(name, "button_%i", i); + + float value = *((float *)buttons + (i + 1)); + bool state = value > 0.0; + tracker->set_input(name, state); } free(buttons); } int *axes = godot_webxr_get_controller_axes(p_controller_id); if (axes) { + // TODO again just a temporary fix, split these between proper float and vector2 inputs for (int i = 0; i < axes[0]; i++) { - Input::JoyAxisValue joy_axis; - joy_axis.min = -1; - joy_axis.value = *((float *)axes + (i + 1)); - input->joy_axis(p_controller_id + 100, i, joy_axis); + char name[1024]; + sprintf(name, "axis_%i", i); + + float value = *((float *)axes + (i + 1)); + ; + tracker->set_input(name, value); } free(axes); } - } else if (tracker) { + } else if (tracker.is_valid()) { xr_server->remove_tracker(tracker); + controllers[p_controller_id].unref(); } } @@ -434,16 +498,12 @@ void WebXRInterfaceJS::_on_controller_changed() { for (int i = 0; i < 2; i++) { bool controller_connected = godot_webxr_is_controller_connected(i); if (controllers_state[i] != controller_connected) { - Input::get_singleton()->joy_connection_changed(i + 100, controller_connected, i == 0 ? "Left" : "Right", ""); + // Input::get_singleton()->joy_connection_changed(i + 100, controller_connected, i == 0 ? "Left" : "Right", ""); controllers_state[i] = controller_connected; } } } -void WebXRInterfaceJS::notification(int p_what) { - // Nothing to do here. -} - WebXRInterfaceJS::WebXRInterfaceJS() { initialized = false; session_mode = "inline"; |