diff options
Diffstat (limited to 'scene/3d')
-rw-r--r-- | scene/3d/audio_listener_3d.h | 3 | ||||
-rw-r--r-- | scene/3d/audio_stream_player_3d.cpp | 4 | ||||
-rw-r--r-- | scene/3d/collision_object_3d.cpp | 4 | ||||
-rw-r--r-- | scene/3d/cpu_particles_3d.h | 7 | ||||
-rw-r--r-- | scene/3d/gpu_particles_3d.cpp | 1 | ||||
-rw-r--r-- | scene/3d/navigation_agent_3d.cpp | 4 | ||||
-rw-r--r-- | scene/3d/navigation_region_3d.cpp | 2 | ||||
-rw-r--r-- | scene/3d/node_3d.cpp | 4 | ||||
-rw-r--r-- | scene/3d/soft_dynamic_body_3d.cpp | 88 | ||||
-rw-r--r-- | scene/3d/soft_dynamic_body_3d.h | 15 | ||||
-rw-r--r-- | scene/3d/sprite_3d.h | 6 | ||||
-rw-r--r-- | scene/3d/xr_nodes.cpp | 627 | ||||
-rw-r--r-- | scene/3d/xr_nodes.h | 110 |
13 files changed, 490 insertions, 385 deletions
diff --git a/scene/3d/audio_listener_3d.h b/scene/3d/audio_listener_3d.h index 492cacb0e9..31de3b4fb1 100644 --- a/scene/3d/audio_listener_3d.h +++ b/scene/3d/audio_listener_3d.h @@ -63,9 +63,6 @@ public: virtual Transform3D get_listener_transform() const; - void set_visible_layers(uint32_t p_layers); - uint32_t get_visible_layers() const; - AudioListener3D(); ~AudioListener3D(); }; diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp index c422070480..44a685f506 100644 --- a/scene/3d/audio_stream_player_3d.cpp +++ b/scene/3d/audio_stream_player_3d.cpp @@ -835,7 +835,7 @@ void AudioStreamPlayer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_stream_playback"), &AudioStreamPlayer3D::get_stream_playback); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), "set_stream", "get_stream"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,Inverse Square,Log,Disabled"), "set_attenuation_model", "get_attenuation_model"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "attenuation_model", PROPERTY_HINT_ENUM, "Inverse,Inverse Square,Logarithmic,Disabled"), "set_attenuation_model", "get_attenuation_model"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_db", PROPERTY_HINT_RANGE, "-80,80"), "set_unit_db", "get_unit_db"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "unit_size", PROPERTY_HINT_RANGE, "0.1,100,0.01,or_greater"), "set_unit_size", "get_unit_size"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_db", PROPERTY_HINT_RANGE, "-24,6"), "set_max_db", "get_max_db"); @@ -843,7 +843,7 @@ void AudioStreamPlayer3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "playing", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR), "_set_playing", "is_playing"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "autoplay"), "set_autoplay", "is_autoplay_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "stream_paused", PROPERTY_HINT_NONE, ""), "set_stream_paused", "get_stream_paused"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,1,or_greater,exp"), "set_max_distance", "get_max_distance"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "max_distance", PROPERTY_HINT_RANGE, "0,4096,0.01,or_greater"), "set_max_distance", "get_max_distance"); ADD_PROPERTY(PropertyInfo(Variant::INT, "max_polyphony", PROPERTY_HINT_NONE, ""), "set_max_polyphony", "get_max_polyphony"); ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bus", PROPERTY_HINT_ENUM, ""), "set_bus", "get_bus"); ADD_PROPERTY(PropertyInfo(Variant::INT, "area_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_area_mask", "get_area_mask"); diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp index 814ed5c2a7..fd891a5e13 100644 --- a/scene/3d/collision_object_3d.cpp +++ b/scene/3d/collision_object_3d.cpp @@ -648,7 +648,7 @@ void CollisionObject3D::shape_owner_clear_shapes(uint32_t p_owner) { } uint32_t CollisionObject3D::shape_find_owner(int p_shape_index) const { - ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0); + ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, UINT32_MAX); for (const KeyValue<uint32_t, ShapeData> &E : shapes) { for (int i = 0; i < E.value.shapes.size(); i++) { @@ -659,7 +659,7 @@ uint32_t CollisionObject3D::shape_find_owner(int p_shape_index) const { } //in theory it should be unreachable - return 0; + ERR_FAIL_V_MSG(UINT32_MAX, "Can't find owner for shape index " + itos(p_shape_index) + "."); } CollisionObject3D::CollisionObject3D(RID p_rid, bool p_area) { diff --git a/scene/3d/cpu_particles_3d.h b/scene/3d/cpu_particles_3d.h index 160814ead4..aca7328a27 100644 --- a/scene/3d/cpu_particles_3d.h +++ b/scene/3d/cpu_particles_3d.h @@ -209,7 +209,6 @@ public: void set_explosiveness_ratio(real_t p_ratio); void set_randomness_ratio(real_t p_ratio); void set_lifetime_randomness(double p_random); - void set_visibility_aabb(const AABB &p_aabb); void set_use_local_coordinates(bool p_enable); void set_speed_scale(double p_scale); @@ -221,7 +220,6 @@ public: real_t get_explosiveness_ratio() const; real_t get_randomness_ratio() const; double get_lifetime_randomness() const; - AABB get_visibility_aabb() const; bool get_use_local_coordinates() const; double get_speed_scale() const; @@ -234,9 +232,6 @@ public: void set_draw_order(DrawOrder p_order); DrawOrder get_draw_order() const; - void set_draw_passes(int p_count); - int get_draw_passes() const; - void set_mesh(const Ref<Mesh> &p_mesh); Ref<Mesh> get_mesh() const; @@ -275,7 +270,6 @@ public: void set_emission_points(const Vector<Vector3> &p_points); void set_emission_normals(const Vector<Vector3> &p_normals); void set_emission_colors(const Vector<Color> &p_colors); - void set_emission_point_count(int p_count); void set_emission_ring_axis(Vector3 p_axis); void set_emission_ring_height(real_t p_height); void set_emission_ring_radius(real_t p_radius); @@ -291,7 +285,6 @@ public: Vector<Vector3> get_emission_points() const; Vector<Vector3> get_emission_normals() const; Vector<Color> get_emission_colors() const; - int get_emission_point_count() const; Vector3 get_emission_ring_axis() const; real_t get_emission_ring_height() const; real_t get_emission_ring_radius() const; diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp index 32a62d8c7e..ea6242b669 100644 --- a/scene/3d/gpu_particles_3d.cpp +++ b/scene/3d/gpu_particles_3d.cpp @@ -562,6 +562,7 @@ void GPUParticles3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_transform_align"), &GPUParticles3D::get_transform_align); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "emitting"), "set_emitting", "is_emitting"); + ADD_PROPERTY_DEFAULT("emitting", true); // Workaround for doctool in headless mode, as dummy rasterizer always returns false. ADD_PROPERTY(PropertyInfo(Variant::INT, "amount", PROPERTY_HINT_RANGE, "1,1000000,1,exp"), "set_amount", "get_amount"); ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "sub_emitter", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "GPUParticles3D"), "set_sub_emitter", "get_sub_emitter"); ADD_GROUP("Time", ""); diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp index c2d5c757db..1bc7d20c19 100644 --- a/scene/3d/navigation_agent_3d.cpp +++ b/scene/3d/navigation_agent_3d.cpp @@ -192,7 +192,7 @@ Vector3 NavigationAgent3D::get_target_location() const { Vector3 NavigationAgent3D::get_next_location() { update_navigation(); if (navigation_path.size() == 0) { - ERR_FAIL_COND_V(agent_parent == nullptr, Vector3()); + ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector3(), "The agent has no parent."); return agent_parent->get_global_transform().origin; } else { return navigation_path[nav_path_index] - Vector3(0, navigation_height_offset, 0); @@ -200,7 +200,7 @@ Vector3 NavigationAgent3D::get_next_location() { } real_t NavigationAgent3D::distance_to_target() const { - ERR_FAIL_COND_V(agent_parent == nullptr, 0.0); + ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent."); return agent_parent->get_global_transform().origin.distance_to(target_location); } diff --git a/scene/3d/navigation_region_3d.cpp b/scene/3d/navigation_region_3d.cpp index 8a51a259f7..473368cf69 100644 --- a/scene/3d/navigation_region_3d.cpp +++ b/scene/3d/navigation_region_3d.cpp @@ -162,7 +162,7 @@ void _bake_navigation_mesh(void *p_user_data) { } void NavigationRegion3D::bake_navigation_mesh() { - ERR_FAIL_COND(bake_thread.is_started()); + ERR_FAIL_COND_MSG(bake_thread.is_started(), "Unable to start another bake request. The navigation mesh bake thread is already baking a navigation mesh."); BakeThreadsArgs *args = memnew(BakeThreadsArgs); args->nav_region = this; diff --git a/scene/3d/node_3d.cpp b/scene/3d/node_3d.cpp index c96204cf60..5293dd3f0a 100644 --- a/scene/3d/node_3d.cpp +++ b/scene/3d/node_3d.cpp @@ -484,14 +484,14 @@ void Node3D::_update_gizmos() { #endif } -#ifdef TOOLS_ENABLED void Node3D::set_disable_gizmos(bool p_enabled) { +#ifdef TOOLS_ENABLED data.gizmos_disabled = p_enabled; if (!p_enabled) { clear_gizmos(); } -} #endif +} void Node3D::set_disable_scale(bool p_enabled) { data.disable_scale = p_enabled; diff --git a/scene/3d/soft_dynamic_body_3d.cpp b/scene/3d/soft_dynamic_body_3d.cpp index 9fceb21790..903eedb58b 100644 --- a/scene/3d/soft_dynamic_body_3d.cpp +++ b/scene/3d/soft_dynamic_body_3d.cpp @@ -250,7 +250,7 @@ void SoftDynamicBody3D::_notification(int p_what) { RID space = get_world_3d()->get_space(); PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space); - prepare_physics_server(); + _prepare_physics_server(); } break; case NOTIFICATION_READY: { @@ -284,13 +284,13 @@ void SoftDynamicBody3D::_notification(int p_what) { case NOTIFICATION_DISABLED: { if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) { - prepare_physics_server(); + _prepare_physics_server(); } } break; case NOTIFICATION_ENABLED: { if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) { - prepare_physics_server(); + _prepare_physics_server(); } } break; @@ -378,7 +378,7 @@ void SoftDynamicBody3D::_bind_methods() { TypedArray<String> SoftDynamicBody3D::get_configuration_warnings() const { TypedArray<String> warnings = Node::get_configuration_warnings(); - if (get_mesh().is_null()) { + if (mesh.is_null()) { warnings.push_back(TTR("This body will be ignored until you set a mesh.")); } @@ -407,11 +407,17 @@ void SoftDynamicBody3D::_update_physics_server() { } void SoftDynamicBody3D::_draw_soft_mesh() { - if (get_mesh().is_null()) { + if (mesh.is_null()) { return; } - const RID mesh_rid = get_mesh()->get_rid(); + RID mesh_rid = mesh->get_rid(); + if (owned_mesh != mesh_rid) { + _become_mesh_owner(); + mesh_rid = mesh->get_rid(); + PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh_rid); + } + if (!rendering_server_handler.is_ready(mesh_rid)) { rendering_server_handler.prepare(mesh_rid, 0); @@ -430,11 +436,11 @@ void SoftDynamicBody3D::_draw_soft_mesh() { rendering_server_handler.commit_changes(); } -void SoftDynamicBody3D::prepare_physics_server() { +void SoftDynamicBody3D::_prepare_physics_server() { #ifdef TOOLS_ENABLED if (Engine::get_singleton()->is_editor_hint()) { - if (get_mesh().is_valid()) { - PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()->get_rid()); + if (mesh.is_valid()) { + PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh->get_rid()); } else { PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID()); } @@ -443,9 +449,13 @@ void SoftDynamicBody3D::prepare_physics_server() { } #endif - if (get_mesh().is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) { - become_mesh_owner(); - PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, get_mesh()->get_rid()); + if (mesh.is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) { + RID mesh_rid = mesh->get_rid(); + if (owned_mesh != mesh_rid) { + _become_mesh_owner(); + mesh_rid = mesh->get_rid(); + } + PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh_rid); RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftDynamicBody3D::_draw_soft_mesh)); } else { PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID()); @@ -455,38 +465,32 @@ void SoftDynamicBody3D::prepare_physics_server() { } } -void SoftDynamicBody3D::become_mesh_owner() { - if (mesh.is_null()) { - return; - } +void SoftDynamicBody3D::_become_mesh_owner() { + Vector<Ref<Material>> copy_materials; + copy_materials.append_array(surface_override_materials); - if (!mesh_owner) { - mesh_owner = true; + ERR_FAIL_COND(!mesh->get_surface_count()); - Vector<Ref<Material>> copy_materials; - copy_materials.append_array(surface_override_materials); + // Get current mesh array and create new mesh array with necessary flag for SoftDynamicBody + Array surface_arrays = mesh->surface_get_arrays(0); + Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0); + Dictionary surface_lods = mesh->surface_get_lods(0); + uint32_t surface_format = mesh->surface_get_format(0); - ERR_FAIL_COND(!mesh->get_surface_count()); + surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE; - // Get current mesh array and create new mesh array with necessary flag for SoftDynamicBody - Array surface_arrays = mesh->surface_get_arrays(0); - Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0); - Dictionary surface_lods = mesh->surface_get_lods(0); - uint32_t surface_format = mesh->surface_get_format(0); + Ref<ArrayMesh> soft_mesh; + soft_mesh.instantiate(); + soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format); + soft_mesh->surface_set_material(0, mesh->surface_get_material(0)); - surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE; + set_mesh(soft_mesh); - Ref<ArrayMesh> soft_mesh; - soft_mesh.instantiate(); - soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format); - soft_mesh->surface_set_material(0, mesh->surface_get_material(0)); - - set_mesh(soft_mesh); - - for (int i = copy_materials.size() - 1; 0 <= i; --i) { - set_surface_override_material(i, copy_materials[i]); - } + for (int i = copy_materials.size() - 1; 0 <= i; --i) { + set_surface_override_material(i, copy_materials[i]); } + + owned_mesh = soft_mesh->get_rid(); } void SoftDynamicBody3D::set_collision_mask(uint32_t p_mask) { @@ -548,16 +552,10 @@ void SoftDynamicBody3D::set_disable_mode(DisableMode p_mode) { return; } - bool inside_tree = is_inside_tree(); - - if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) { - prepare_physics_server(); - } - disable_mode = p_mode; - if (inside_tree && (disable_mode == DISABLE_MODE_REMOVE)) { - prepare_physics_server(); + if (mesh.is_valid() && is_inside_tree() && !is_enabled()) { + _prepare_physics_server(); } } diff --git a/scene/3d/soft_dynamic_body_3d.h b/scene/3d/soft_dynamic_body_3d.h index 5e7fbfe29e..57e116aa05 100644 --- a/scene/3d/soft_dynamic_body_3d.h +++ b/scene/3d/soft_dynamic_body_3d.h @@ -90,7 +90,7 @@ private: DisableMode disable_mode = DISABLE_MODE_REMOVE; - bool mesh_owner = false; + RID owned_mesh; uint32_t collision_mask = 1; uint32_t collision_layer = 1; NodePath parent_collision_ignore; @@ -106,6 +106,12 @@ private: void _update_pickable(); + void _update_physics_server(); + void _draw_soft_mesh(); + + void _prepare_physics_server(); + void _become_mesh_owner(); + protected: bool _set(const StringName &p_name, const Variant &p_value); bool _get(const StringName &p_name, Variant &r_ret) const; @@ -120,14 +126,7 @@ protected: TypedArray<String> get_configuration_warnings() const override; -protected: - void _update_physics_server(); - void _draw_soft_mesh(); - public: - void prepare_physics_server(); - void become_mesh_owner(); - RID get_physics_rid() const { return physics_rid; } void set_collision_mask(uint32_t p_mask); diff --git a/scene/3d/sprite_3d.h b/scene/3d/sprite_3d.h index 90c2a309e1..61448c0e32 100644 --- a/scene/3d/sprite_3d.h +++ b/scene/3d/sprite_3d.h @@ -118,12 +118,6 @@ public: void set_flip_v(bool p_flip); bool is_flipped_v() const; - void set_region_enabled(bool p_region); - bool is_region_enabled() const; - - void set_region_rect(const Rect2 &p_region_rect); - Rect2 get_region_rect() const; - void set_modulate(const Color &p_color); Color get_modulate() const; diff --git a/scene/3d/xr_nodes.cpp b/scene/3d/xr_nodes.cpp index 56edf100f6..9dbee58f0e 100644 --- a/scene/3d/xr_nodes.cpp +++ b/scene/3d/xr_nodes.cpp @@ -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); } } -}; +} diff --git a/scene/3d/xr_nodes.h b/scene/3d/xr_nodes.h index 6e54ff83d7..5e7d06093d 100644 --- a/scene/3d/xr_nodes.h +++ b/scene/3d/xr_nodes.h @@ -45,8 +45,18 @@ class XRCamera3D : public Camera3D { GDCLASS(XRCamera3D, Camera3D); protected: + // The name and pose for our HMD tracker is currently the only hardcoded bit. + // If we ever are able to support multiple HMDs we may need to make this settable. + StringName tracker_name = "head"; + StringName pose_name = "default"; + Ref<XRPositionalTracker> tracker; + void _notification(int p_what); + void _changed_tracker(const StringName p_tracker_name, int p_tracker_type); + void _removed_tracker(const StringName p_tracker_name, int p_tracker_type); + void _pose_changed(const Ref<XRPose> &p_pose); + public: TypedArray<String> get_configuration_warnings() const override; @@ -55,48 +65,88 @@ public: virtual Vector3 project_position(const Point2 &p_point, real_t p_z_depth) const override; virtual Vector<Plane> get_frustum() const override; - XRCamera3D() {} - ~XRCamera3D() {} + XRCamera3D(); + ~XRCamera3D(); }; /* - XRController3D is a helper node that automatically updates its position based on tracker data. + XRNode3D is a helper node that implements binding to a tracker. It must be a child node of our XROrigin node */ -class XRController3D : public Node3D { - GDCLASS(XRController3D, Node3D); +class XRNode3D : public Node3D { + GDCLASS(XRNode3D, Node3D); private: - int controller_id = 1; + StringName tracker_name; + StringName pose_name = "default"; bool is_active = true; - int button_states = 0; - Ref<Mesh> mesh; protected: - void _notification(int p_what); + Ref<XRPositionalTracker> tracker; + static void _bind_methods(); -public: - void set_controller_id(int p_controller_id); - int get_controller_id() const; - String get_controller_name() const; + virtual void _bind_tracker(); + virtual void _unbind_tracker(); + void _changed_tracker(const StringName p_tracker_name, int p_tracker_type); + void _removed_tracker(const StringName p_tracker_name, int p_tracker_type); - int get_joystick_id() const; - bool is_button_pressed(int p_button) const; - float get_joystick_axis(int p_axis) const; + void _pose_changed(const Ref<XRPose> &p_pose); - real_t get_rumble() const; - void set_rumble(real_t p_rumble); +public: + virtual void _validate_property(PropertyInfo &property) const override; + void set_tracker(const StringName p_tracker_name); + StringName get_tracker() const; + + void set_pose_name(const StringName p_pose); + StringName get_pose_name() const; bool get_is_active() const; - XRPositionalTracker::TrackerHand get_tracker_hand() const; + bool get_has_tracking_data() const; - Ref<Mesh> get_mesh() const; + void trigger_haptic_pulse(const String &p_action_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0); + + Ref<XRPose> get_pose(); TypedArray<String> get_configuration_warnings() const override; + XRNode3D(); + ~XRNode3D(); +}; + +/* + XRController3D is a helper node that automatically updates its position based on tracker data. + + It must be a child node of our XROrigin node +*/ + +class XRController3D : public XRNode3D { + GDCLASS(XRController3D, XRNode3D); + +private: +protected: + static void _bind_methods(); + + virtual void _bind_tracker() override; + virtual void _unbind_tracker() override; + + void _button_pressed(const String &p_name); + void _button_released(const String &p_name); + void _input_value_changed(const String &p_name, float p_value); + void _input_axis_changed(const String &p_name, Vector2 p_value); + +public: + bool is_button_pressed(const StringName &p_name) const; + float get_value(const StringName &p_name) const; + Vector2 get_axis(const StringName &p_name) const; + + real_t get_rumble() const; + void set_rumble(real_t p_rumble); + + XRPositionalTracker::TrackerHand get_tracker_hand() const; + XRController3D() {} ~XRController3D() {} }; @@ -106,33 +156,19 @@ public: It must be a child node of our XROrigin3D node */ -class XRAnchor3D : public Node3D { - GDCLASS(XRAnchor3D, Node3D); +class XRAnchor3D : public XRNode3D { + GDCLASS(XRAnchor3D, XRNode3D); private: - int anchor_id = 1; - bool is_active = true; Vector3 size; - Ref<Mesh> mesh; protected: - void _notification(int p_what); static void _bind_methods(); public: - void set_anchor_id(int p_anchor_id); - int get_anchor_id() const; - String get_anchor_name() const; - - bool get_is_active() const; Vector3 get_size() const; - Plane get_plane() const; - Ref<Mesh> get_mesh() const; - - TypedArray<String> get_configuration_warnings() const override; - XRAnchor3D() {} ~XRAnchor3D() {} }; @@ -159,7 +195,7 @@ public: TypedArray<String> get_configuration_warnings() const override; void set_tracked_camera(XRCamera3D *p_tracked_camera); - void clear_tracked_camera_if(XRCamera3D *p_tracked_camera); + XRCamera3D *get_tracked_camera() const; real_t get_world_scale() const; void set_world_scale(real_t p_world_scale); |