|
@@ -47,13 +47,45 @@ void XRCamera3D::_notification(int p_what) {
|
|
|
case NOTIFICATION_EXIT_TREE: {
|
|
|
// need to find our XROrigin3D parent and let it know we're no longer its camera!
|
|
|
XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
|
|
|
- if (origin != nullptr) {
|
|
|
- origin->clear_tracked_camera_if(this);
|
|
|
+ if (origin != nullptr && origin->get_tracked_camera() == this) {
|
|
|
+ origin->set_tracked_camera(nullptr);
|
|
|
}
|
|
|
}; break;
|
|
|
};
|
|
|
};
|
|
|
|
|
|
+void XRCamera3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
|
|
|
+ if (p_tracker_name == tracker_name) {
|
|
|
+ XRServer *xr_server = XRServer::get_singleton();
|
|
|
+ ERR_FAIL_NULL(xr_server);
|
|
|
+
|
|
|
+ tracker = xr_server->get_tracker(p_tracker_name);
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ tracker->connect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
|
|
|
+
|
|
|
+ Ref<XRPose> pose = tracker->get_pose(pose_name);
|
|
|
+ if (pose.is_valid()) {
|
|
|
+ set_transform(pose->get_adjusted_transform());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void XRCamera3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
|
|
|
+ if (p_tracker_name == tracker_name) {
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ tracker->disconnect("pose_changed", callable_mp(this, &XRCamera3D::_pose_changed));
|
|
|
+ }
|
|
|
+ tracker.unref();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void XRCamera3D::_pose_changed(const Ref<XRPose> &p_pose) {
|
|
|
+ if (p_pose->get_name() == pose_name) {
|
|
|
+ set_transform(p_pose->get_adjusted_transform());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
TypedArray<String> XRCamera3D::get_configuration_warnings() const {
|
|
|
TypedArray<String> warnings = Node::get_configuration_warnings();
|
|
|
|
|
@@ -172,195 +204,215 @@ Vector<Plane> XRCamera3D::get_frustum() const {
|
|
|
return cm.get_projection_planes(get_camera_transform());
|
|
|
};
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
+XRCamera3D::XRCamera3D() {
|
|
|
+ XRServer *xr_server = XRServer::get_singleton();
|
|
|
+ ERR_FAIL_NULL(xr_server);
|
|
|
|
|
|
-void XRController3D::_notification(int p_what) {
|
|
|
- switch (p_what) {
|
|
|
- case NOTIFICATION_ENTER_TREE: {
|
|
|
- set_process_internal(true);
|
|
|
- }; break;
|
|
|
- case NOTIFICATION_EXIT_TREE: {
|
|
|
- set_process_internal(false);
|
|
|
- }; break;
|
|
|
- case NOTIFICATION_INTERNAL_PROCESS: {
|
|
|
- // get our XRServer
|
|
|
- XRServer *xr_server = XRServer::get_singleton();
|
|
|
- ERR_FAIL_NULL(xr_server);
|
|
|
-
|
|
|
- // find the tracker for our controller
|
|
|
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
|
|
|
- if (!tracker.is_valid()) {
|
|
|
- // this controller is currently turned off
|
|
|
- is_active = false;
|
|
|
- button_states = 0;
|
|
|
- } else {
|
|
|
- is_active = true;
|
|
|
- set_transform(tracker->get_transform(true));
|
|
|
-
|
|
|
- int joy_id = tracker->get_joy_id();
|
|
|
- if (joy_id >= 0) {
|
|
|
- int mask = 1;
|
|
|
- // check button states
|
|
|
- for (int i = 0; i < 16; i++) {
|
|
|
- bool was_pressed = (button_states & mask) == mask;
|
|
|
- bool is_pressed = Input::get_singleton()->is_joy_button_pressed(joy_id, (JoyButton)i);
|
|
|
-
|
|
|
- if (!was_pressed && is_pressed) {
|
|
|
- emit_signal(SNAME("button_pressed"), i);
|
|
|
- button_states += mask;
|
|
|
- } else if (was_pressed && !is_pressed) {
|
|
|
- emit_signal(SNAME("button_released"), i);
|
|
|
- button_states -= mask;
|
|
|
- };
|
|
|
-
|
|
|
- mask = mask << 1;
|
|
|
- };
|
|
|
-
|
|
|
- } else {
|
|
|
- button_states = 0;
|
|
|
- };
|
|
|
-
|
|
|
- // check for an updated mesh
|
|
|
- Ref<Mesh> trackerMesh = tracker->get_mesh();
|
|
|
- if (mesh != trackerMesh) {
|
|
|
- mesh = trackerMesh;
|
|
|
- emit_signal(SNAME("mesh_updated"), mesh);
|
|
|
- }
|
|
|
- };
|
|
|
- }; break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- };
|
|
|
-};
|
|
|
+ xr_server->connect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker));
|
|
|
+ xr_server->connect("tracker_updated", callable_mp(this, &XRCamera3D::_changed_tracker));
|
|
|
+ xr_server->connect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker));
|
|
|
+}
|
|
|
|
|
|
-void XRController3D::_bind_methods() {
|
|
|
- ClassDB::bind_method(D_METHOD("set_controller_id", "controller_id"), &XRController3D::set_controller_id);
|
|
|
- ClassDB::bind_method(D_METHOD("get_controller_id"), &XRController3D::get_controller_id);
|
|
|
- ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_controller_id", "get_controller_id");
|
|
|
- ClassDB::bind_method(D_METHOD("get_controller_name"), &XRController3D::get_controller_name);
|
|
|
+XRCamera3D::~XRCamera3D() {
|
|
|
+ XRServer *xr_server = XRServer::get_singleton();
|
|
|
+ ERR_FAIL_NULL(xr_server);
|
|
|
|
|
|
- // passthroughs to information about our related joystick
|
|
|
- ClassDB::bind_method(D_METHOD("get_joystick_id"), &XRController3D::get_joystick_id);
|
|
|
- ClassDB::bind_method(D_METHOD("is_button_pressed", "button"), &XRController3D::is_button_pressed);
|
|
|
- ClassDB::bind_method(D_METHOD("get_joystick_axis", "axis"), &XRController3D::get_joystick_axis);
|
|
|
+ xr_server->disconnect("tracker_added", callable_mp(this, &XRCamera3D::_changed_tracker));
|
|
|
+ xr_server->disconnect("tracker_updated", callable_mp(this, &XRCamera3D::_changed_tracker));
|
|
|
+ xr_server->disconnect("tracker_removed", callable_mp(this, &XRCamera3D::_removed_tracker));
|
|
|
+}
|
|
|
|
|
|
- ClassDB::bind_method(D_METHOD("get_is_active"), &XRController3D::get_is_active);
|
|
|
- ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRController3D::get_tracker_hand);
|
|
|
+////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
+// XRNode3D is a node that has it's transform updated by an XRPositionalTracker.
|
|
|
+// Note that trackers are only available in runtime and only after an XRInterface registers one.
|
|
|
+// So we bind by name and as long as a tracker isn't available, our node remains inactive.
|
|
|
|
|
|
- ClassDB::bind_method(D_METHOD("get_rumble"), &XRController3D::get_rumble);
|
|
|
- ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRController3D::set_rumble);
|
|
|
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
|
|
|
- ADD_PROPERTY_DEFAULT("rumble", 0.0);
|
|
|
+void XRNode3D::_bind_methods() {
|
|
|
+ ClassDB::bind_method(D_METHOD("set_tracker", "tracker_name"), &XRNode3D::set_tracker);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_tracker"), &XRNode3D::get_tracker);
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "tracker", PROPERTY_HINT_ENUM_SUGGESTION), "set_tracker", "get_tracker");
|
|
|
|
|
|
- ClassDB::bind_method(D_METHOD("get_mesh"), &XRController3D::get_mesh);
|
|
|
+ ClassDB::bind_method(D_METHOD("set_pose_name", "pose"), &XRNode3D::set_pose_name);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_pose_name"), &XRNode3D::get_pose_name);
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "pose", PROPERTY_HINT_ENUM_SUGGESTION), "set_pose_name", "get_pose_name");
|
|
|
|
|
|
- ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::INT, "button")));
|
|
|
- ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::INT, "button")));
|
|
|
- ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
|
|
|
+ ClassDB::bind_method(D_METHOD("get_is_active"), &XRNode3D::get_is_active);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_has_tracking_data"), &XRNode3D::get_has_tracking_data);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_pose"), &XRNode3D::get_pose);
|
|
|
+ ClassDB::bind_method(D_METHOD("trigger_haptic_pulse", "action_name", "frequency", "amplitude", "duration_sec", "delay_sec"), &XRNode3D::trigger_haptic_pulse);
|
|
|
};
|
|
|
|
|
|
-void XRController3D::set_controller_id(int p_controller_id) {
|
|
|
- // We don't check any bounds here, this controller may not yet be active and just be a place holder until it is.
|
|
|
- // Note that setting this to 0 means this node is not bound to a controller yet.
|
|
|
- controller_id = p_controller_id;
|
|
|
- update_configuration_warnings();
|
|
|
-};
|
|
|
+void XRNode3D::_validate_property(PropertyInfo &property) const {
|
|
|
+ XRServer *xr_server = XRServer::get_singleton();
|
|
|
+ ERR_FAIL_NULL(xr_server);
|
|
|
|
|
|
-int XRController3D::get_controller_id() const {
|
|
|
- return controller_id;
|
|
|
-};
|
|
|
+ if (property.name == "tracker") {
|
|
|
+ PackedStringArray names = xr_server->get_suggested_tracker_names();
|
|
|
+ String hint_string;
|
|
|
+ for (const String &name : names) {
|
|
|
+ hint_string += name + ",";
|
|
|
+ }
|
|
|
+ property.hint_string = hint_string;
|
|
|
+ } else if (property.name == "pose") {
|
|
|
+ PackedStringArray names = xr_server->get_suggested_pose_names(tracker_name);
|
|
|
+ String hint_string;
|
|
|
+ for (const String &name : names) {
|
|
|
+ hint_string += name + ",";
|
|
|
+ }
|
|
|
+ property.hint_string = hint_string;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-String XRController3D::get_controller_name() const {
|
|
|
- // get our XRServer
|
|
|
- XRServer *xr_server = XRServer::get_singleton();
|
|
|
- ERR_FAIL_NULL_V(xr_server, String());
|
|
|
+void XRNode3D::set_tracker(const StringName p_tracker_name) {
|
|
|
+ if (tracker.is_valid() && tracker->get_tracker_name() == p_tracker_name) {
|
|
|
+ // didn't change
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
|
|
|
- if (!tracker.is_valid()) {
|
|
|
- return String("Not connected");
|
|
|
- };
|
|
|
+ // just in case
|
|
|
+ _unbind_tracker();
|
|
|
|
|
|
- return tracker->get_tracker_name();
|
|
|
-};
|
|
|
+ // copy the name
|
|
|
+ tracker_name = p_tracker_name;
|
|
|
+ pose_name = "default";
|
|
|
|
|
|
-int XRController3D::get_joystick_id() const {
|
|
|
- // get our XRServer
|
|
|
- XRServer *xr_server = XRServer::get_singleton();
|
|
|
- ERR_FAIL_NULL_V(xr_server, 0);
|
|
|
+ // see if it's already available
|
|
|
+ _bind_tracker();
|
|
|
|
|
|
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
|
|
|
- if (!tracker.is_valid()) {
|
|
|
- // No tracker? no joystick id... (0 is our first joystick)
|
|
|
- return -1;
|
|
|
- };
|
|
|
+ update_configuration_warnings();
|
|
|
+ notify_property_list_changed();
|
|
|
+}
|
|
|
|
|
|
- return tracker->get_joy_id();
|
|
|
-};
|
|
|
+StringName XRNode3D::get_tracker() const {
|
|
|
+ return tracker_name;
|
|
|
+}
|
|
|
|
|
|
-bool XRController3D::is_button_pressed(int p_button) const {
|
|
|
- int joy_id = get_joystick_id();
|
|
|
- if (joy_id == -1) {
|
|
|
- return false;
|
|
|
- };
|
|
|
+void XRNode3D::set_pose_name(const StringName p_pose_name) {
|
|
|
+ pose_name = p_pose_name;
|
|
|
|
|
|
- return Input::get_singleton()->is_joy_button_pressed(joy_id, (JoyButton)p_button);
|
|
|
-};
|
|
|
+ // Update pose if we are bound to a tracker with a valid pose
|
|
|
+ Ref<XRPose> pose = get_pose();
|
|
|
+ if (pose.is_valid()) {
|
|
|
+ set_transform(pose->get_adjusted_transform());
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-float XRController3D::get_joystick_axis(int p_axis) const {
|
|
|
- int joy_id = get_joystick_id();
|
|
|
- if (joy_id == -1) {
|
|
|
- return 0.0;
|
|
|
- };
|
|
|
+StringName XRNode3D::get_pose_name() const {
|
|
|
+ return pose_name;
|
|
|
+}
|
|
|
|
|
|
- return Input::get_singleton()->get_joy_axis(joy_id, (JoyAxis)p_axis);
|
|
|
-};
|
|
|
+bool XRNode3D::get_is_active() const {
|
|
|
+ if (tracker.is_null()) {
|
|
|
+ return false;
|
|
|
+ } else if (!tracker->has_pose(pose_name)) {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-real_t XRController3D::get_rumble() const {
|
|
|
- // get our XRServer
|
|
|
+bool XRNode3D::get_has_tracking_data() const {
|
|
|
+ if (tracker.is_null()) {
|
|
|
+ return false;
|
|
|
+ } else if (!tracker->has_pose(pose_name)) {
|
|
|
+ return false;
|
|
|
+ } else {
|
|
|
+ return tracker->get_pose(pose_name)->get_has_tracking_data();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void XRNode3D::trigger_haptic_pulse(const String &p_action_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
|
|
|
+ // TODO need to link trackers to the interface that registered them so we can call this on the correct interface.
|
|
|
+ // For now this works fine as in 99% of the cases we only have our primary interface active
|
|
|
XRServer *xr_server = XRServer::get_singleton();
|
|
|
- ERR_FAIL_NULL_V(xr_server, 0.0);
|
|
|
+ if (xr_server != nullptr) {
|
|
|
+ Ref<XRInterface> xr_interface = xr_server->get_primary_interface();
|
|
|
+ if (xr_interface.is_valid()) {
|
|
|
+ xr_interface->trigger_haptic_pulse(p_action_name, tracker_name, p_frequency, p_amplitude, p_duration_sec, p_delay_sec);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
|
|
|
- if (!tracker.is_valid()) {
|
|
|
- return 0.0;
|
|
|
- };
|
|
|
+Ref<XRPose> XRNode3D::get_pose() {
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ return tracker->get_pose(pose_name);
|
|
|
+ } else {
|
|
|
+ return Ref<XRPose>();
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- return tracker->get_rumble();
|
|
|
-};
|
|
|
+void XRNode3D::_bind_tracker() {
|
|
|
+ ERR_FAIL_COND_MSG(tracker.is_valid(), "Unbind the current tracker first");
|
|
|
|
|
|
-void XRController3D::set_rumble(real_t p_rumble) {
|
|
|
- // get our XRServer
|
|
|
XRServer *xr_server = XRServer::get_singleton();
|
|
|
- ERR_FAIL_NULL(xr_server);
|
|
|
+ if (xr_server != nullptr) {
|
|
|
+ tracker = xr_server->get_tracker(tracker_name);
|
|
|
+ if (tracker.is_null()) {
|
|
|
+ // It is possible and valid if the tracker isn't available (yet), in this case we just exit
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ tracker->connect("pose_changed", callable_mp(this, &XRNode3D::_pose_changed));
|
|
|
+
|
|
|
+ Ref<XRPose> pose = get_pose();
|
|
|
+ if (pose.is_valid()) {
|
|
|
+ set_transform(pose->get_adjusted_transform());
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
|
|
|
+void XRNode3D::_unbind_tracker() {
|
|
|
if (tracker.is_valid()) {
|
|
|
- tracker->set_rumble(p_rumble);
|
|
|
- };
|
|
|
-};
|
|
|
+ tracker->disconnect("pose_changed", callable_mp(this, &XRNode3D::_pose_changed));
|
|
|
|
|
|
-Ref<Mesh> XRController3D::get_mesh() const {
|
|
|
- return mesh;
|
|
|
+ tracker.unref();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-bool XRController3D::get_is_active() const {
|
|
|
- return is_active;
|
|
|
-};
|
|
|
+void XRNode3D::_changed_tracker(const StringName p_tracker_name, int p_tracker_type) {
|
|
|
+ if (p_tracker_name == p_tracker_name) {
|
|
|
+ // just in case unref our current tracker
|
|
|
+ _unbind_tracker();
|
|
|
|
|
|
-XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
|
|
|
- // get our XRServer
|
|
|
+ // get our new tracker
|
|
|
+ _bind_tracker();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void XRNode3D::_removed_tracker(const StringName p_tracker_name, int p_tracker_type) {
|
|
|
+ if (p_tracker_name == p_tracker_name) {
|
|
|
+ // unref our tracker, it's no longer available
|
|
|
+ _unbind_tracker();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void XRNode3D::_pose_changed(const Ref<XRPose> &p_pose) {
|
|
|
+ if (p_pose.is_valid() && p_pose->get_name() == pose_name) {
|
|
|
+ set_transform(p_pose->get_adjusted_transform());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+XRNode3D::XRNode3D() {
|
|
|
XRServer *xr_server = XRServer::get_singleton();
|
|
|
- ERR_FAIL_NULL_V(xr_server, XRPositionalTracker::TRACKER_HAND_UNKNOWN);
|
|
|
+ ERR_FAIL_NULL(xr_server);
|
|
|
|
|
|
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, controller_id);
|
|
|
- if (!tracker.is_valid()) {
|
|
|
- return XRPositionalTracker::TRACKER_HAND_UNKNOWN;
|
|
|
- };
|
|
|
+ xr_server->connect("tracker_added", callable_mp(this, &XRNode3D::_changed_tracker));
|
|
|
+ xr_server->connect("tracker_updated", callable_mp(this, &XRNode3D::_changed_tracker));
|
|
|
+ xr_server->connect("tracker_removed", callable_mp(this, &XRNode3D::_removed_tracker));
|
|
|
+}
|
|
|
|
|
|
- return tracker->get_tracker_hand();
|
|
|
-};
|
|
|
+XRNode3D::~XRNode3D() {
|
|
|
+ _unbind_tracker();
|
|
|
+
|
|
|
+ XRServer *xr_server = XRServer::get_singleton();
|
|
|
+ ERR_FAIL_NULL(xr_server);
|
|
|
+
|
|
|
+ xr_server->disconnect("tracker_added", callable_mp(this, &XRNode3D::_changed_tracker));
|
|
|
+ xr_server->disconnect("tracker_updated", callable_mp(this, &XRNode3D::_changed_tracker));
|
|
|
+ xr_server->disconnect("tracker_removed", callable_mp(this, &XRNode3D::_removed_tracker));
|
|
|
+}
|
|
|
|
|
|
-TypedArray<String> XRController3D::get_configuration_warnings() const {
|
|
|
+TypedArray<String> XRNode3D::get_configuration_warnings() const {
|
|
|
TypedArray<String> warnings = Node::get_configuration_warnings();
|
|
|
|
|
|
if (is_visible() && is_inside_tree()) {
|
|
@@ -370,130 +422,171 @@ TypedArray<String> XRController3D::get_configuration_warnings() const {
|
|
|
warnings.push_back(TTR("XRController3D must have an XROrigin3D node as its parent."));
|
|
|
}
|
|
|
|
|
|
- if (controller_id == 0) {
|
|
|
- warnings.push_back(TTR("The controller ID must not be 0 or this controller won't be bound to an actual controller."));
|
|
|
+ if (tracker_name == "") {
|
|
|
+ warnings.push_back(TTR("No tracker name is set."));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pose_name == "") {
|
|
|
+ warnings.push_back(TTR("No pose is set."));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return warnings;
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
-void XRAnchor3D::_notification(int p_what) {
|
|
|
- switch (p_what) {
|
|
|
- case NOTIFICATION_ENTER_TREE: {
|
|
|
- set_process_internal(true);
|
|
|
- }; break;
|
|
|
- case NOTIFICATION_EXIT_TREE: {
|
|
|
- set_process_internal(false);
|
|
|
- }; break;
|
|
|
- case NOTIFICATION_INTERNAL_PROCESS: {
|
|
|
- // get our XRServer
|
|
|
- XRServer *xr_server = XRServer::get_singleton();
|
|
|
- ERR_FAIL_NULL(xr_server);
|
|
|
-
|
|
|
- // find the tracker for our anchor
|
|
|
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
|
|
|
- if (!tracker.is_valid()) {
|
|
|
- // this anchor is currently not available
|
|
|
- is_active = false;
|
|
|
- } else {
|
|
|
- is_active = true;
|
|
|
- Transform3D transform;
|
|
|
-
|
|
|
- // we'll need our world_scale
|
|
|
- real_t world_scale = xr_server->get_world_scale();
|
|
|
-
|
|
|
- // get our info from our tracker
|
|
|
- transform.basis = tracker->get_orientation();
|
|
|
- transform.origin = tracker->get_position(); // <-- already adjusted to world scale
|
|
|
-
|
|
|
- // our basis is scaled to the size of the plane the anchor is tracking
|
|
|
- // extract the size from our basis and reset the scale
|
|
|
- size = transform.basis.get_scale() * world_scale;
|
|
|
- transform.basis.orthonormalize();
|
|
|
-
|
|
|
- // apply our reference frame and set our transform
|
|
|
- set_transform(xr_server->get_reference_frame() * transform);
|
|
|
-
|
|
|
- // check for an updated mesh
|
|
|
- Ref<Mesh> trackerMesh = tracker->get_mesh();
|
|
|
- if (mesh != trackerMesh) {
|
|
|
- mesh = trackerMesh;
|
|
|
- emit_signal(SNAME("mesh_updated"), mesh);
|
|
|
- }
|
|
|
- };
|
|
|
- }; break;
|
|
|
- default:
|
|
|
- break;
|
|
|
- };
|
|
|
-};
|
|
|
-
|
|
|
-void XRAnchor3D::_bind_methods() {
|
|
|
- ClassDB::bind_method(D_METHOD("set_anchor_id", "anchor_id"), &XRAnchor3D::set_anchor_id);
|
|
|
- ClassDB::bind_method(D_METHOD("get_anchor_id"), &XRAnchor3D::get_anchor_id);
|
|
|
- ADD_PROPERTY(PropertyInfo(Variant::INT, "anchor_id", PROPERTY_HINT_RANGE, "0,32,1"), "set_anchor_id", "get_anchor_id");
|
|
|
- ClassDB::bind_method(D_METHOD("get_anchor_name"), &XRAnchor3D::get_anchor_name);
|
|
|
+void XRController3D::_bind_methods() {
|
|
|
+ // passthroughs to information about our related joystick
|
|
|
+ ClassDB::bind_method(D_METHOD("is_button_pressed", "name"), &XRController3D::is_button_pressed);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_value", "name"), &XRController3D::get_value);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_axis", "name"), &XRController3D::get_axis);
|
|
|
|
|
|
- ClassDB::bind_method(D_METHOD("get_is_active"), &XRAnchor3D::get_is_active);
|
|
|
- ClassDB::bind_method(D_METHOD("get_size"), &XRAnchor3D::get_size);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRController3D::get_tracker_hand);
|
|
|
|
|
|
- ClassDB::bind_method(D_METHOD("get_plane"), &XRAnchor3D::get_plane);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_rumble"), &XRController3D::get_rumble);
|
|
|
+ ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRController3D::set_rumble);
|
|
|
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble", PROPERTY_HINT_RANGE, "0.0,1.0,0.01"), "set_rumble", "get_rumble");
|
|
|
+ ADD_PROPERTY_DEFAULT("rumble", 0.0);
|
|
|
|
|
|
- ClassDB::bind_method(D_METHOD("get_mesh"), &XRAnchor3D::get_mesh);
|
|
|
- ADD_SIGNAL(MethodInfo("mesh_updated", PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh")));
|
|
|
+ ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::STRING, "name")));
|
|
|
+ ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name")));
|
|
|
+ ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value")));
|
|
|
+ ADD_SIGNAL(MethodInfo("input_axis_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "value")));
|
|
|
};
|
|
|
|
|
|
-void XRAnchor3D::set_anchor_id(int p_anchor_id) {
|
|
|
- // We don't check any bounds here, this anchor may not yet be active and just be a place holder until it is.
|
|
|
- // Note that setting this to 0 means this node is not bound to an anchor yet.
|
|
|
- anchor_id = p_anchor_id;
|
|
|
- update_configuration_warnings();
|
|
|
-};
|
|
|
+void XRController3D::_bind_tracker() {
|
|
|
+ XRNode3D::_bind_tracker();
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ // bind to input signals
|
|
|
+ tracker->connect("button_pressed", callable_mp(this, &XRController3D::_button_pressed));
|
|
|
+ tracker->connect("button_released", callable_mp(this, &XRController3D::_button_released));
|
|
|
+ tracker->connect("input_value_changed", callable_mp(this, &XRController3D::_input_value_changed));
|
|
|
+ tracker->connect("input_axis_changed", callable_mp(this, &XRController3D::_input_axis_changed));
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-int XRAnchor3D::get_anchor_id() const {
|
|
|
- return anchor_id;
|
|
|
-};
|
|
|
+void XRController3D::_unbind_tracker() {
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ // unbind input signals
|
|
|
+ tracker->disconnect("button_pressed", callable_mp(this, &XRController3D::_button_pressed));
|
|
|
+ tracker->disconnect("button_released", callable_mp(this, &XRController3D::_button_released));
|
|
|
+ tracker->disconnect("input_value_changed", callable_mp(this, &XRController3D::_input_value_changed));
|
|
|
+ tracker->disconnect("input_axis_changed", callable_mp(this, &XRController3D::_input_axis_changed));
|
|
|
+ }
|
|
|
|
|
|
-Vector3 XRAnchor3D::get_size() const {
|
|
|
- return size;
|
|
|
-};
|
|
|
+ XRNode3D::_unbind_tracker();
|
|
|
+}
|
|
|
|
|
|
-String XRAnchor3D::get_anchor_name() const {
|
|
|
- // get our XRServer
|
|
|
- XRServer *xr_server = XRServer::get_singleton();
|
|
|
- ERR_FAIL_NULL_V(xr_server, String());
|
|
|
+void XRController3D::_button_pressed(const String &p_name) {
|
|
|
+ // just pass it on...
|
|
|
+ emit_signal("button_pressed", p_name);
|
|
|
+}
|
|
|
|
|
|
- Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_ANCHOR, anchor_id);
|
|
|
- if (!tracker.is_valid()) {
|
|
|
- return String("Not connected");
|
|
|
- };
|
|
|
+void XRController3D::_button_released(const String &p_name) {
|
|
|
+ // just pass it on...
|
|
|
+ emit_signal("button_released", p_name);
|
|
|
+}
|
|
|
|
|
|
- return tracker->get_tracker_name();
|
|
|
-};
|
|
|
+void XRController3D::_input_value_changed(const String &p_name, float p_value) {
|
|
|
+ // just pass it on...
|
|
|
+ emit_signal("input_value_changed", p_name, p_value);
|
|
|
+}
|
|
|
|
|
|
-bool XRAnchor3D::get_is_active() const {
|
|
|
- return is_active;
|
|
|
-};
|
|
|
+void XRController3D::_input_axis_changed(const String &p_name, Vector2 p_value) {
|
|
|
+ // just pass it on...
|
|
|
+ emit_signal("input_axis_changed", p_name, p_value);
|
|
|
+}
|
|
|
|
|
|
-TypedArray<String> XRAnchor3D::get_configuration_warnings() const {
|
|
|
- TypedArray<String> warnings = Node::get_configuration_warnings();
|
|
|
+bool XRController3D::is_button_pressed(const StringName &p_name) const {
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ // Inputs should already be of the correct type, our XR runtime handles conversions between raw input and the desired type
|
|
|
+ bool pressed = tracker->get_input(p_name);
|
|
|
+ return pressed;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- if (is_visible() && is_inside_tree()) {
|
|
|
- // must be child node of XROrigin3D!
|
|
|
- XROrigin3D *origin = Object::cast_to<XROrigin3D>(get_parent());
|
|
|
- if (origin == nullptr) {
|
|
|
- warnings.push_back(TTR("XRAnchor3D must have an XROrigin3D node as its parent."));
|
|
|
- }
|
|
|
+float XRController3D::get_value(const StringName &p_name) const {
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ // Inputs should already be of the correct type, our XR runtime handles conversions between raw input and the desired type, but just in case we convert
|
|
|
+ Variant input = tracker->get_input(p_name);
|
|
|
+ switch (input.get_type()) {
|
|
|
+ case Variant::BOOL: {
|
|
|
+ bool value = input;
|
|
|
+ return value ? 1.0 : 0.0;
|
|
|
+ } break;
|
|
|
+ case Variant::FLOAT: {
|
|
|
+ float value = input;
|
|
|
+ return value;
|
|
|
+ } break;
|
|
|
+ default:
|
|
|
+ return 0.0;
|
|
|
+ };
|
|
|
+ } else {
|
|
|
+ return 0.0;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- if (anchor_id == 0) {
|
|
|
- warnings.push_back(TTR("The anchor ID must not be 0 or this anchor won't be bound to an actual anchor."));
|
|
|
+Vector2 XRController3D::get_axis(const StringName &p_name) const {
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ // Inputs should already be of the correct type, our XR runtime handles conversions between raw input and the desired type, but just in case we convert
|
|
|
+ Variant input = tracker->get_input(p_name);
|
|
|
+ switch (input.get_type()) {
|
|
|
+ case Variant::BOOL: {
|
|
|
+ bool value = input;
|
|
|
+ return Vector2(value ? 1.0 : 0.0, 0.0);
|
|
|
+ } break;
|
|
|
+ case Variant::FLOAT: {
|
|
|
+ float value = input;
|
|
|
+ return Vector2(value, 0.0);
|
|
|
+ } break;
|
|
|
+ case Variant::VECTOR2: {
|
|
|
+ Vector2 axis = input;
|
|
|
+ return axis;
|
|
|
+ }
|
|
|
+ default:
|
|
|
+ return Vector2();
|
|
|
}
|
|
|
+ } else {
|
|
|
+ return Vector2();
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- return warnings;
|
|
|
-};
|
|
|
+real_t XRController3D::get_rumble() const {
|
|
|
+ if (!tracker.is_valid()) {
|
|
|
+ return 0.0;
|
|
|
+ }
|
|
|
+
|
|
|
+ return tracker->get_rumble();
|
|
|
+}
|
|
|
+
|
|
|
+void XRController3D::set_rumble(real_t p_rumble) {
|
|
|
+ if (tracker.is_valid()) {
|
|
|
+ tracker->set_rumble(p_rumble);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+XRPositionalTracker::TrackerHand XRController3D::get_tracker_hand() const {
|
|
|
+ // get our XRServer
|
|
|
+ if (!tracker.is_valid()) {
|
|
|
+ return XRPositionalTracker::TRACKER_HAND_UNKNOWN;
|
|
|
+ }
|
|
|
+
|
|
|
+ return tracker->get_tracker_hand();
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
+
|
|
|
+void XRAnchor3D::_bind_methods() {
|
|
|
+ ClassDB::bind_method(D_METHOD("get_size"), &XRAnchor3D::get_size);
|
|
|
+ ClassDB::bind_method(D_METHOD("get_plane"), &XRAnchor3D::get_plane);
|
|
|
+}
|
|
|
+
|
|
|
+Vector3 XRAnchor3D::get_size() const {
|
|
|
+ return size;
|
|
|
+}
|
|
|
|
|
|
Plane XRAnchor3D::get_plane() const {
|
|
|
Vector3 location = get_position();
|
|
@@ -502,10 +595,6 @@ Plane XRAnchor3D::get_plane() const {
|
|
|
Plane plane(orientation.get_axis(1).normalized(), location);
|
|
|
|
|
|
return plane;
|
|
|
-};
|
|
|
-
|
|
|
-Ref<Mesh> XRAnchor3D::get_mesh() const {
|
|
|
- return mesh;
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -525,23 +614,21 @@ TypedArray<String> XROrigin3D::get_configuration_warnings() const {
|
|
|
}
|
|
|
|
|
|
return warnings;
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
void XROrigin3D::_bind_methods() {
|
|
|
ClassDB::bind_method(D_METHOD("set_world_scale", "world_scale"), &XROrigin3D::set_world_scale);
|
|
|
ClassDB::bind_method(D_METHOD("get_world_scale"), &XROrigin3D::get_world_scale);
|
|
|
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
void XROrigin3D::set_tracked_camera(XRCamera3D *p_tracked_camera) {
|
|
|
tracked_camera = p_tracked_camera;
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
-void XROrigin3D::clear_tracked_camera_if(XRCamera3D *p_tracked_camera) {
|
|
|
- if (tracked_camera == p_tracked_camera) {
|
|
|
- tracked_camera = nullptr;
|
|
|
- };
|
|
|
-};
|
|
|
+XRCamera3D *XROrigin3D::get_tracked_camera() const {
|
|
|
+ return tracked_camera;
|
|
|
+}
|
|
|
|
|
|
real_t XROrigin3D::get_world_scale() const {
|
|
|
// get our XRServer
|
|
@@ -549,7 +636,7 @@ real_t XROrigin3D::get_world_scale() const {
|
|
|
ERR_FAIL_NULL_V(xr_server, 1.0);
|
|
|
|
|
|
return xr_server->get_world_scale();
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
void XROrigin3D::set_world_scale(real_t p_world_scale) {
|
|
|
// get our XRServer
|
|
@@ -557,7 +644,7 @@ void XROrigin3D::set_world_scale(real_t p_world_scale) {
|
|
|
ERR_FAIL_NULL(xr_server);
|
|
|
|
|
|
xr_server->set_world_scale(p_world_scale);
|
|
|
-};
|
|
|
+}
|
|
|
|
|
|
void XROrigin3D::_notification(int p_what) {
|
|
|
// get our XRServer
|
|
@@ -596,4 +683,4 @@ void XROrigin3D::_notification(int p_what) {
|
|
|
interface->notification(p_what);
|
|
|
}
|
|
|
}
|
|
|
-};
|
|
|
+}
|