diff options
Diffstat (limited to 'servers')
96 files changed, 1145 insertions, 681 deletions
diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 3e3a7d2381..b5333d91c6 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -676,63 +676,6 @@ bool AudioStreamRandomizer::is_monophonic() const { return false; } -bool AudioStreamRandomizer::_get(const StringName &p_name, Variant &r_ret) const { - if (AudioStream::_get(p_name, r_ret)) { - return true; - } - Vector<String> components = String(p_name).split("/", true, 2); - if (components.size() == 2 && components[0].begins_with("stream_") && components[0].trim_prefix("stream_").is_valid_int()) { - int index = components[0].trim_prefix("stream_").to_int(); - if (index < 0 || index >= (int)audio_stream_pool.size()) { - return false; - } - - if (components[1] == "stream") { - r_ret = get_stream(index); - return true; - } else if (components[1] == "weight") { - r_ret = get_stream_probability_weight(index); - return true; - } else { - return false; - } - } - return false; -} - -bool AudioStreamRandomizer::_set(const StringName &p_name, const Variant &p_value) { - if (AudioStream::_set(p_name, p_value)) { - return true; - } - Vector<String> components = String(p_name).split("/", true, 2); - if (components.size() == 2 && components[0].begins_with("stream_") && components[0].trim_prefix("stream_").is_valid_int()) { - int index = components[0].trim_prefix("stream_").to_int(); - if (index < 0 || index >= (int)audio_stream_pool.size()) { - return false; - } - - if (components[1] == "stream") { - set_stream(index, p_value); - return true; - } else if (components[1] == "weight") { - set_stream_probability_weight(index, p_value); - return true; - } else { - return false; - } - } - return false; -} - -void AudioStreamRandomizer::_get_property_list(List<PropertyInfo> *p_list) const { - AudioStream::_get_property_list(p_list); // Define the trivial scalar properties. - p_list->push_back(PropertyInfo(Variant::NIL, "Streams", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP)); - for (int i = 0; i < audio_stream_pool.size(); i++) { - p_list->push_back(PropertyInfo(Variant::OBJECT, vformat("stream_%d/stream", i), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); - p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("stream_%d/weight", i), PROPERTY_HINT_RANGE, "0,100,0.001,or_greater")); - } -} - void AudioStreamRandomizer::_bind_methods() { ClassDB::bind_method(D_METHOD("add_stream", "index", "stream", "weight"), &AudioStreamRandomizer::add_stream, DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("move_stream", "index_from", "index_to"), &AudioStreamRandomizer::move_stream); @@ -764,9 +707,17 @@ void AudioStreamRandomizer::_bind_methods() { BIND_ENUM_CONSTANT(PLAYBACK_RANDOM_NO_REPEATS); BIND_ENUM_CONSTANT(PLAYBACK_RANDOM); BIND_ENUM_CONSTANT(PLAYBACK_SEQUENTIAL); + + PoolEntry defaults; + + base_property_helper.set_prefix("stream_"); + base_property_helper.register_property(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"), defaults.stream, &AudioStreamRandomizer::set_stream, &AudioStreamRandomizer::get_stream); + base_property_helper.register_property(PropertyInfo(Variant::FLOAT, "weight", PROPERTY_HINT_RANGE, "0,100,0.001,or_greater"), defaults.weight, &AudioStreamRandomizer::set_stream_probability_weight, &AudioStreamRandomizer::get_stream_probability_weight); } -AudioStreamRandomizer::AudioStreamRandomizer() {} +AudioStreamRandomizer::AudioStreamRandomizer() { + property_helper.setup_for_instance(base_property_helper, this); +} void AudioStreamPlaybackRandomizer::start(double p_from_pos) { playing = playback; diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index f8123fbe15..01a4a09942 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -33,6 +33,7 @@ #include "core/io/image.h" #include "core/io/resource.h" +#include "scene/property_list_helper.h" #include "servers/audio/audio_filter_sw.h" #include "servers/audio_server.h" @@ -236,9 +237,12 @@ private: struct PoolEntry { Ref<AudioStream> stream; - float weight; + float weight = 1.0; }; + static inline PropertyListHelper base_property_helper; + PropertyListHelper property_helper; + HashSet<AudioStreamPlaybackRandomizer *> playbacks; Vector<PoolEntry> audio_stream_pool; float random_pitch_scale = 1.0f; @@ -254,9 +258,11 @@ private: protected: static void _bind_methods(); - bool _set(const StringName &p_name, const Variant &p_value); - bool _get(const StringName &p_name, Variant &r_ret) const; - void _get_property_list(List<PropertyInfo> *p_list) const; + bool _set(const StringName &p_name, const Variant &p_value) { return property_helper.property_set_value(p_name, p_value); } + bool _get(const StringName &p_name, Variant &r_ret) const { return property_helper.property_get_value(p_name, r_ret); } + void _get_property_list(List<PropertyInfo> *p_list) const { property_helper.get_property_list(p_list, audio_stream_pool.size()); } + bool _property_can_revert(const StringName &p_name) const { return property_helper.property_can_revert(p_name); } + bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return property_helper.property_get_revert(p_name, r_property); } public: void add_stream(int p_index, Ref<AudioStream> p_stream, float p_weight = 1.0); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 9ceb6909fe..9600caa214 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -212,7 +212,7 @@ String DisplayServer::global_menu_get_item_submenu(const String &p_menu_root, in ERR_FAIL_NULL_V(nmenu, String()); RID rid = nmenu->get_item_submenu(_get_rid_from_name(nmenu, p_menu_root), p_idx); if (!nmenu->is_system_menu(rid)) { - for (HashMap<String, RID>::Iterator E = menu_names.begin(); E;) { + for (HashMap<String, RID>::Iterator E = menu_names.begin(); E; ++E) { if (E->value == rid) { return E->key; } @@ -697,10 +697,6 @@ void DisplayServer::release_rendering_thread() { WARN_PRINT("Rendering thread not supported by this display server."); } -void DisplayServer::make_rendering_thread() { - WARN_PRINT("Rendering thread not supported by this display server."); -} - void DisplayServer::swap_buffers() { WARN_PRINT("Swap buffers not supported by this display server."); } diff --git a/servers/display_server.h b/servers/display_server.h index f1a98c2c17..aab51644c0 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -559,7 +559,6 @@ public: virtual void force_process_and_drop_events(); virtual void release_rendering_thread(); - virtual void make_rendering_thread(); virtual void swap_buffers(); virtual void set_native_icon(const String &p_filename); diff --git a/servers/navigation/navigation_path_query_parameters_2d.cpp b/servers/navigation/navigation_path_query_parameters_2d.cpp index 78da87d677..6c1f88e349 100644 --- a/servers/navigation/navigation_path_query_parameters_2d.cpp +++ b/servers/navigation/navigation_path_query_parameters_2d.cpp @@ -119,6 +119,22 @@ BitField<NavigationPathQueryParameters2D::PathMetadataFlags> NavigationPathQuery return (int64_t)parameters.metadata_flags; } +void NavigationPathQueryParameters2D::set_simplify_path(bool p_enabled) { + parameters.simplify_path = p_enabled; +} + +bool NavigationPathQueryParameters2D::get_simplify_path() const { + return parameters.simplify_path; +} + +void NavigationPathQueryParameters2D::set_simplify_epsilon(real_t p_epsilon) { + parameters.simplify_epsilon = MAX(0.0, p_epsilon); +} + +real_t NavigationPathQueryParameters2D::get_simplify_epsilon() const { + return parameters.simplify_epsilon; +} + void NavigationPathQueryParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationPathQueryParameters2D::set_pathfinding_algorithm); ClassDB::bind_method(D_METHOD("get_pathfinding_algorithm"), &NavigationPathQueryParameters2D::get_pathfinding_algorithm); @@ -141,6 +157,12 @@ void NavigationPathQueryParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_metadata_flags", "flags"), &NavigationPathQueryParameters2D::set_metadata_flags); ClassDB::bind_method(D_METHOD("get_metadata_flags"), &NavigationPathQueryParameters2D::get_metadata_flags); + ClassDB::bind_method(D_METHOD("set_simplify_path", "enabled"), &NavigationPathQueryParameters2D::set_simplify_path); + ClassDB::bind_method(D_METHOD("get_simplify_path"), &NavigationPathQueryParameters2D::get_simplify_path); + + ClassDB::bind_method(D_METHOD("set_simplify_epsilon", "epsilon"), &NavigationPathQueryParameters2D::set_simplify_epsilon); + ClassDB::bind_method(D_METHOD("get_simplify_epsilon"), &NavigationPathQueryParameters2D::get_simplify_epsilon); + ADD_PROPERTY(PropertyInfo(Variant::RID, "map"), "set_map", "get_map"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "start_position"), "set_start_position", "get_start_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "target_position"), "set_target_position", "get_target_position"); @@ -148,6 +170,8 @@ void NavigationPathQueryParameters2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing"); ADD_PROPERTY(PropertyInfo(Variant::INT, "metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_metadata_flags", "get_metadata_flags"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simplify_path"), "set_simplify_path", "get_simplify_path"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "simplify_epsilon"), "set_simplify_epsilon", "get_simplify_epsilon"); BIND_ENUM_CONSTANT(PATHFINDING_ALGORITHM_ASTAR); diff --git a/servers/navigation/navigation_path_query_parameters_2d.h b/servers/navigation/navigation_path_query_parameters_2d.h index 48bb93aa7c..a1d5f2d109 100644 --- a/servers/navigation/navigation_path_query_parameters_2d.h +++ b/servers/navigation/navigation_path_query_parameters_2d.h @@ -82,6 +82,12 @@ public: void set_metadata_flags(BitField<NavigationPathQueryParameters2D::PathMetadataFlags> p_flags); BitField<NavigationPathQueryParameters2D::PathMetadataFlags> get_metadata_flags() const; + + void set_simplify_path(bool p_enabled); + bool get_simplify_path() const; + + void set_simplify_epsilon(real_t p_epsilon); + real_t get_simplify_epsilon() const; }; VARIANT_ENUM_CAST(NavigationPathQueryParameters2D::PathfindingAlgorithm); diff --git a/servers/navigation/navigation_path_query_parameters_3d.cpp b/servers/navigation/navigation_path_query_parameters_3d.cpp index 52333edbc1..b0a5b0ad82 100644 --- a/servers/navigation/navigation_path_query_parameters_3d.cpp +++ b/servers/navigation/navigation_path_query_parameters_3d.cpp @@ -119,6 +119,22 @@ BitField<NavigationPathQueryParameters3D::PathMetadataFlags> NavigationPathQuery return (int64_t)parameters.metadata_flags; } +void NavigationPathQueryParameters3D::set_simplify_path(bool p_enabled) { + parameters.simplify_path = p_enabled; +} + +bool NavigationPathQueryParameters3D::get_simplify_path() const { + return parameters.simplify_path; +} + +void NavigationPathQueryParameters3D::set_simplify_epsilon(real_t p_epsilon) { + parameters.simplify_epsilon = MAX(0.0, p_epsilon); +} + +real_t NavigationPathQueryParameters3D::get_simplify_epsilon() const { + return parameters.simplify_epsilon; +} + void NavigationPathQueryParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_pathfinding_algorithm", "pathfinding_algorithm"), &NavigationPathQueryParameters3D::set_pathfinding_algorithm); ClassDB::bind_method(D_METHOD("get_pathfinding_algorithm"), &NavigationPathQueryParameters3D::get_pathfinding_algorithm); @@ -141,6 +157,12 @@ void NavigationPathQueryParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_metadata_flags", "flags"), &NavigationPathQueryParameters3D::set_metadata_flags); ClassDB::bind_method(D_METHOD("get_metadata_flags"), &NavigationPathQueryParameters3D::get_metadata_flags); + ClassDB::bind_method(D_METHOD("set_simplify_path", "enabled"), &NavigationPathQueryParameters3D::set_simplify_path); + ClassDB::bind_method(D_METHOD("get_simplify_path"), &NavigationPathQueryParameters3D::get_simplify_path); + + ClassDB::bind_method(D_METHOD("set_simplify_epsilon", "epsilon"), &NavigationPathQueryParameters3D::set_simplify_epsilon); + ClassDB::bind_method(D_METHOD("get_simplify_epsilon"), &NavigationPathQueryParameters3D::get_simplify_epsilon); + ADD_PROPERTY(PropertyInfo(Variant::RID, "map"), "set_map", "get_map"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "start_position"), "set_start_position", "get_start_position"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "target_position"), "set_target_position", "get_target_position"); @@ -148,6 +170,8 @@ void NavigationPathQueryParameters3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "pathfinding_algorithm", PROPERTY_HINT_ENUM, "AStar"), "set_pathfinding_algorithm", "get_pathfinding_algorithm"); ADD_PROPERTY(PropertyInfo(Variant::INT, "path_postprocessing", PROPERTY_HINT_ENUM, "Corridorfunnel,Edgecentered"), "set_path_postprocessing", "get_path_postprocessing"); ADD_PROPERTY(PropertyInfo(Variant::INT, "metadata_flags", PROPERTY_HINT_FLAGS, "Include Types,Include RIDs,Include Owners"), "set_metadata_flags", "get_metadata_flags"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "simplify_path"), "set_simplify_path", "get_simplify_path"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "simplify_epsilon"), "set_simplify_epsilon", "get_simplify_epsilon"); BIND_ENUM_CONSTANT(PATHFINDING_ALGORITHM_ASTAR); diff --git a/servers/navigation/navigation_path_query_parameters_3d.h b/servers/navigation/navigation_path_query_parameters_3d.h index b12c2d49d5..2eb85db787 100644 --- a/servers/navigation/navigation_path_query_parameters_3d.h +++ b/servers/navigation/navigation_path_query_parameters_3d.h @@ -82,6 +82,12 @@ public: void set_metadata_flags(BitField<NavigationPathQueryParameters3D::PathMetadataFlags> p_flags); BitField<NavigationPathQueryParameters3D::PathMetadataFlags> get_metadata_flags() const; + + void set_simplify_path(bool p_enabled); + bool get_simplify_path() const; + + void set_simplify_epsilon(real_t p_epsilon); + real_t get_simplify_epsilon() const; }; VARIANT_ENUM_CAST(NavigationPathQueryParameters3D::PathfindingAlgorithm); diff --git a/servers/navigation/navigation_utilities.h b/servers/navigation/navigation_utilities.h index 04d0ab0d98..7ae22b1d3a 100644 --- a/servers/navigation/navigation_utilities.h +++ b/servers/navigation/navigation_utilities.h @@ -66,6 +66,8 @@ struct PathQueryParameters { Vector3 target_position; uint32_t navigation_layers = 1; BitField<PathMetadataFlags> metadata_flags = PATH_INCLUDE_ALL; + bool simplify_path = false; + real_t simplify_epsilon = 0.0; }; struct PathQueryResult { diff --git a/servers/navigation_server_2d.cpp b/servers/navigation_server_2d.cpp index d87ac00e32..c5ce82265b 100644 --- a/servers/navigation_server_2d.cpp +++ b/servers/navigation_server_2d.cpp @@ -165,6 +165,11 @@ void NavigationServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("bake_from_source_geometry_data_async", "navigation_polygon", "source_geometry_data", "callback"), &NavigationServer2D::bake_from_source_geometry_data_async, DEFVAL(Callable())); ClassDB::bind_method(D_METHOD("is_baking_navigation_polygon", "navigation_polygon"), &NavigationServer2D::is_baking_navigation_polygon); + ClassDB::bind_method(D_METHOD("source_geometry_parser_create"), &NavigationServer2D::source_geometry_parser_create); + ClassDB::bind_method(D_METHOD("source_geometry_parser_set_callback", "parser", "callback"), &NavigationServer2D::source_geometry_parser_set_callback); + + ClassDB::bind_method(D_METHOD("simplify_path", "path", "epsilon"), &NavigationServer2D::simplify_path); + ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer2D::free); ClassDB::bind_method(D_METHOD("set_debug_enabled", "enabled"), &NavigationServer2D::set_debug_enabled); diff --git a/servers/navigation_server_2d.h b/servers/navigation_server_2d.h index d7dc9d6526..a8d9678a6f 100644 --- a/servers/navigation_server_2d.h +++ b/servers/navigation_server_2d.h @@ -34,8 +34,8 @@ #include "core/object/class_db.h" #include "core/templates/rid.h" -#include "scene/resources/navigation_mesh_source_geometry_data_2d.h" -#include "scene/resources/navigation_polygon.h" +#include "scene/resources/2d/navigation_mesh_source_geometry_data_2d.h" +#include "scene/resources/2d/navigation_polygon.h" #include "servers/navigation/navigation_path_query_parameters_2d.h" #include "servers/navigation/navigation_path_query_result_2d.h" @@ -306,6 +306,11 @@ public: virtual void bake_from_source_geometry_data_async(const Ref<NavigationPolygon> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData2D> &p_source_geometry_data, const Callable &p_callback = Callable()) = 0; virtual bool is_baking_navigation_polygon(Ref<NavigationPolygon> p_navigation_polygon) const = 0; + virtual RID source_geometry_parser_create() = 0; + virtual void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) = 0; + + virtual Vector<Vector2> simplify_path(const Vector<Vector2> &p_path, real_t p_epsilon) = 0; + NavigationServer2D(); ~NavigationServer2D() override; diff --git a/servers/navigation_server_2d_dummy.h b/servers/navigation_server_2d_dummy.h index 94c6dfd6a7..465cfcca98 100644 --- a/servers/navigation_server_2d_dummy.h +++ b/servers/navigation_server_2d_dummy.h @@ -170,6 +170,11 @@ public: void bake_from_source_geometry_data_async(const Ref<NavigationPolygon> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData2D> &p_source_geometry_data, const Callable &p_callback = Callable()) override {} bool is_baking_navigation_polygon(Ref<NavigationPolygon> p_navigation_polygon) const override { return false; } + RID source_geometry_parser_create() override { return RID(); } + void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) override {} + + Vector<Vector2> simplify_path(const Vector<Vector2> &p_path, real_t p_epsilon) override { return Vector<Vector2>(); } + void set_debug_enabled(bool p_enabled) {} bool get_debug_enabled() const { return false; } }; diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index c12659fe7a..b21c6b60f0 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -181,10 +181,17 @@ void NavigationServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("obstacle_set_avoidance_layers", "obstacle", "layers"), &NavigationServer3D::obstacle_set_avoidance_layers); ClassDB::bind_method(D_METHOD("obstacle_get_avoidance_layers", "obstacle"), &NavigationServer3D::obstacle_get_avoidance_layers); +#ifndef _3D_DISABLED ClassDB::bind_method(D_METHOD("parse_source_geometry_data", "navigation_mesh", "source_geometry_data", "root_node", "callback"), &NavigationServer3D::parse_source_geometry_data, DEFVAL(Callable())); ClassDB::bind_method(D_METHOD("bake_from_source_geometry_data", "navigation_mesh", "source_geometry_data", "callback"), &NavigationServer3D::bake_from_source_geometry_data, DEFVAL(Callable())); ClassDB::bind_method(D_METHOD("bake_from_source_geometry_data_async", "navigation_mesh", "source_geometry_data", "callback"), &NavigationServer3D::bake_from_source_geometry_data_async, DEFVAL(Callable())); ClassDB::bind_method(D_METHOD("is_baking_navigation_mesh", "navigation_mesh"), &NavigationServer3D::is_baking_navigation_mesh); +#endif // _3D_DISABLED + + ClassDB::bind_method(D_METHOD("source_geometry_parser_create"), &NavigationServer3D::source_geometry_parser_create); + ClassDB::bind_method(D_METHOD("source_geometry_parser_set_callback", "parser", "callback"), &NavigationServer3D::source_geometry_parser_set_callback); + + ClassDB::bind_method(D_METHOD("simplify_path", "path", "epsilon"), &NavigationServer3D::simplify_path); ClassDB::bind_method(D_METHOD("free_rid", "rid"), &NavigationServer3D::free); @@ -294,7 +301,11 @@ void NavigationServer3D::set_debug_enabled(bool p_enabled) { debug_enabled = p_enabled; if (debug_dirty) { + navigation_debug_dirty = true; callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); + + avoidance_debug_dirty = true; + callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred(); } #endif // DEBUG_ENABLED } diff --git a/servers/navigation_server_3d.h b/servers/navigation_server_3d.h index 975ffdee94..17c0771732 100644 --- a/servers/navigation_server_3d.h +++ b/servers/navigation_server_3d.h @@ -34,8 +34,8 @@ #include "core/object/class_db.h" #include "core/templates/rid.h" +#include "scene/resources/3d/navigation_mesh_source_geometry_data_3d.h" #include "scene/resources/navigation_mesh.h" -#include "scene/resources/navigation_mesh_source_geometry_data_3d.h" #include "servers/navigation/navigation_path_query_parameters_3d.h" #include "servers/navigation/navigation_path_query_result_3d.h" @@ -344,10 +344,17 @@ public: virtual NavigationUtilities::PathQueryResult _query_path(const NavigationUtilities::PathQueryParameters &p_parameters) const = 0; +#ifndef _3D_DISABLED virtual void parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) = 0; virtual void bake_from_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) = 0; virtual void bake_from_source_geometry_data_async(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) = 0; virtual bool is_baking_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) const = 0; +#endif // _3D_DISABLED + + virtual RID source_geometry_parser_create() = 0; + virtual void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) = 0; + + virtual Vector<Vector3> simplify_path(const Vector<Vector3> &p_path, real_t p_epsilon) = 0; NavigationServer3D(); ~NavigationServer3D() override; diff --git a/servers/navigation_server_3d_dummy.h b/servers/navigation_server_3d_dummy.h index 9ba9b20d00..5c9e97d226 100644 --- a/servers/navigation_server_3d_dummy.h +++ b/servers/navigation_server_3d_dummy.h @@ -175,10 +175,17 @@ public: void obstacle_set_avoidance_layers(RID p_obstacle, uint32_t p_layers) override {} uint32_t obstacle_get_avoidance_layers(RID p_obstacle) const override { return 0; } +#ifndef _3D_DISABLED void parse_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, Node *p_root_node, const Callable &p_callback = Callable()) override {} void bake_from_source_geometry_data(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) override {} void bake_from_source_geometry_data_async(const Ref<NavigationMesh> &p_navigation_mesh, const Ref<NavigationMeshSourceGeometryData3D> &p_source_geometry_data, const Callable &p_callback = Callable()) override {} bool is_baking_navigation_mesh(Ref<NavigationMesh> p_navigation_mesh) const override { return false; } +#endif // _3D_DISABLED + + RID source_geometry_parser_create() override { return RID(); } + void source_geometry_parser_set_callback(RID p_parser, const Callable &p_callback) override {} + + Vector<Vector3> simplify_path(const Vector<Vector3> &p_path, real_t p_epsilon) override { return Vector<Vector3>(); } void free(RID p_object) override {} void set_active(bool p_active) override {} diff --git a/servers/physics_2d/godot_shape_2d.cpp b/servers/physics_2d/godot_shape_2d.cpp index db5e6b2353..d77b1a77e3 100644 --- a/servers/physics_2d/godot_shape_2d.cpp +++ b/servers/physics_2d/godot_shape_2d.cpp @@ -123,7 +123,7 @@ void GodotWorldBoundaryShape2D::set_data(const Variant &p_data) { ERR_FAIL_COND(arr.size() != 2); normal = arr[0]; d = arr[1]; - configure(Rect2(Vector2(-1e4, -1e4), Vector2(1e4 * 2, 1e4 * 2))); + configure(Rect2(Vector2(-1e15, -1e15), Vector2(1e15 * 2, 1e15 * 2))); } Variant GodotWorldBoundaryShape2D::get_data() const { diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp index beaa30eb84..c53c8481f4 100644 --- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp +++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp @@ -1962,7 +1962,7 @@ static void _collision_cylinder_face(const GodotShape3D *p_a, const Transform3D // Points of B, cylinder lateral surface. for (int i = 0; i < 3; i++) { - const Vector3 &point = vertex[i]; + const Vector3 point = vertex[i] - p_transform_a.origin; Vector3 axis = Plane(cyl_axis).project(point).normalized(); if (axis.dot(normal) < 0.0) { axis *= -1.0; diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp index ea389ff59c..6eb983d5e0 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -152,7 +152,7 @@ Vector3 GodotWorldBoundaryShape3D::get_moment_of_inertia(real_t p_mass) const { void GodotWorldBoundaryShape3D::_setup(const Plane &p_plane) { plane = p_plane; - configure(AABB(Vector3(-1e4, -1e4, -1e4), Vector3(1e4 * 2, 1e4 * 2, 1e4 * 2))); + configure(AABB(Vector3(-1e15, -1e15, -1e15), Vector3(1e15 * 2, 1e15 * 2, 1e15 * 2))); } void GodotWorldBoundaryShape3D::set_data(const Variant &p_data) { diff --git a/servers/physics_server_2d_wrap_mt.cpp b/servers/physics_server_2d_wrap_mt.cpp index a23bb5e701..4548bb91cb 100644 --- a/servers/physics_server_2d_wrap_mt.cpp +++ b/servers/physics_server_2d_wrap_mt.cpp @@ -33,7 +33,7 @@ #include "core/os/os.h" void PhysicsServer2DWrapMT::thread_exit() { - exit.set(); + exit = true; } void PhysicsServer2DWrapMT::thread_step(real_t p_delta) { @@ -41,25 +41,18 @@ void PhysicsServer2DWrapMT::thread_step(real_t p_delta) { step_sem.post(); } -void PhysicsServer2DWrapMT::_thread_callback(void *_instance) { - PhysicsServer2DWrapMT *vsmt = reinterpret_cast<PhysicsServer2DWrapMT *>(_instance); - - vsmt->thread_loop(); -} - void PhysicsServer2DWrapMT::thread_loop() { server_thread = Thread::get_caller_id(); physics_server_2d->init(); - exit.clear(); - step_thread_up.set(); - while (!exit.is_set()) { - // flush commands one by one, until exit is requested - command_queue.wait_and_flush(); + command_queue.set_pump_task_id(server_task_id); + while (!exit) { + WorkerThreadPool::get_singleton()->yield(); + command_queue.flush_all(); } - command_queue.flush_all(); // flush all + command_queue.flush_all(); physics_server_2d->finish(); } @@ -70,18 +63,14 @@ void PhysicsServer2DWrapMT::step(real_t p_step) { if (create_thread) { command_queue.push(this, &PhysicsServer2DWrapMT::thread_step, p_step); } else { - command_queue.flush_all(); //flush all pending from other threads + command_queue.flush_all(); // Flush all pending from other threads. physics_server_2d->step(p_step); } } void PhysicsServer2DWrapMT::sync() { if (create_thread) { - if (first_frame) { - first_frame = false; - } else { - step_sem.wait(); //must not wait if a step was not issued - } + step_sem.wait(); } physics_server_2d->sync(); } @@ -96,40 +85,34 @@ void PhysicsServer2DWrapMT::end_sync() { void PhysicsServer2DWrapMT::init() { if (create_thread) { - //OS::get_singleton()->release_rendering_thread(); - thread.start(_thread_callback, this); - while (!step_thread_up.is_set()) { - OS::get_singleton()->delay_usec(1000); - } + exit = false; + server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer2DWrapMT::thread_loop), true); + step_sem.post(); } else { physics_server_2d->init(); } } void PhysicsServer2DWrapMT::finish() { - if (thread.is_started()) { + if (create_thread) { command_queue.push(this, &PhysicsServer2DWrapMT::thread_exit); - thread.wait_to_finish(); + if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id); + server_task_id = WorkerThreadPool::INVALID_TASK_ID; + } } else { physics_server_2d->finish(); } } -PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) : - command_queue(p_create_thread) { +PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool p_create_thread) { physics_server_2d = p_contained; create_thread = p_create_thread; - - if (!p_create_thread) { - server_thread = Thread::get_caller_id(); - } else { - server_thread = 0; + if (!create_thread) { + server_thread = Thread::MAIN_ID; } - - main_thread = Thread::get_caller_id(); } PhysicsServer2DWrapMT::~PhysicsServer2DWrapMT() { memdelete(physics_server_2d); - //finish(); } diff --git a/servers/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h index 3bebe5df85..5e2b3b4086 100644 --- a/servers/physics_server_2d_wrap_mt.h +++ b/servers/physics_server_2d_wrap_mt.h @@ -32,6 +32,7 @@ #define PHYSICS_SERVER_2D_WRAP_MT_H #include "core/config/project_settings.h" +#include "core/object/worker_thread_pool.h" #include "core/os/thread.h" #include "core/templates/command_queue_mt.h" #include "core/templates/safe_refcount.h" @@ -43,30 +44,27 @@ #define SYNC_DEBUG #endif +#ifdef DEBUG_ENABLED +#define MAIN_THREAD_SYNC_WARN WARN_PRINT("Call to " + String(__FUNCTION__) + " causing PhysicsServer2D synchronizations on every frame. This significantly affects performance."); +#endif + class PhysicsServer2DWrapMT : public PhysicsServer2D { - mutable PhysicsServer2D *physics_server_2d; + mutable PhysicsServer2D *physics_server_2d = nullptr; mutable CommandQueueMT command_queue; - static void _thread_callback(void *_instance); void thread_loop(); - Thread::ID server_thread; - Thread::ID main_thread; - SafeFlag exit; - Thread thread; - SafeFlag step_thread_up; + Thread::ID server_thread = Thread::UNASSIGNED_ID; + WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID; + bool exit = false; + Semaphore step_sem; bool create_thread = false; - Semaphore step_sem; void thread_step(real_t p_delta); void thread_exit(); - bool first_frame = true; - - Mutex alloc_mutex; - public: #define ServerName PhysicsServer2D #define ServerNameWrapMT PhysicsServer2DWrapMT @@ -94,7 +92,7 @@ public: //these work well, but should be used from the main thread only bool shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + ERR_FAIL_COND_V(!Thread::is_main_thread(), false); return physics_server_2d->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count); } @@ -109,18 +107,18 @@ public: // this function only works on physics process, errors and returns null otherwise PhysicsDirectSpaceState2D *space_get_direct_state(RID p_space) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + ERR_FAIL_COND_V(!Thread::is_main_thread(), nullptr); return physics_server_2d->space_get_direct_state(p_space); } FUNC2(space_set_debug_contacts, RID, int); virtual Vector<Vector2> space_get_contacts(RID p_space) const override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector<Vector2>()); + ERR_FAIL_COND_V(!Thread::is_main_thread(), Vector<Vector2>()); return physics_server_2d->space_get_contacts(p_space); } virtual int space_get_contact_count(RID p_space) const override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0); + ERR_FAIL_COND_V(!Thread::is_main_thread(), 0); return physics_server_2d->space_get_contact_count(p_space); } @@ -261,13 +259,13 @@ public: FUNC2(body_set_pickable, RID, bool); bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + ERR_FAIL_COND_V(!Thread::is_main_thread(), false); return physics_server_2d->body_test_motion(p_body, p_parameters, r_result); } // this function only works on physics process, errors and returns null otherwise PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + ERR_FAIL_COND_V(!Thread::is_main_thread(), nullptr); return physics_server_2d->body_get_direct_state(p_body); } @@ -338,4 +336,8 @@ public: #endif #undef SYNC_DEBUG +#ifdef DEBUG_ENABLED +#undef MAIN_THREAD_SYNC_WARN +#endif + #endif // PHYSICS_SERVER_2D_WRAP_MT_H diff --git a/servers/physics_server_3d_wrap_mt.cpp b/servers/physics_server_3d_wrap_mt.cpp index feb17cad84..f8f60281a7 100644 --- a/servers/physics_server_3d_wrap_mt.cpp +++ b/servers/physics_server_3d_wrap_mt.cpp @@ -41,22 +41,15 @@ void PhysicsServer3DWrapMT::thread_step(real_t p_delta) { step_sem.post(); } -void PhysicsServer3DWrapMT::_thread_callback(void *_instance) { - PhysicsServer3DWrapMT *vsmt = reinterpret_cast<PhysicsServer3DWrapMT *>(_instance); - - vsmt->thread_loop(); -} - void PhysicsServer3DWrapMT::thread_loop() { server_thread = Thread::get_caller_id(); physics_server_3d->init(); - exit = false; - step_thread_up = true; + command_queue.set_pump_task_id(server_task_id); while (!exit) { - // flush commands one by one, until exit is requested - command_queue.wait_and_flush(); + WorkerThreadPool::get_singleton()->yield(); + command_queue.flush_all(); } command_queue.flush_all(); // flush all @@ -70,18 +63,14 @@ void PhysicsServer3DWrapMT::step(real_t p_step) { if (create_thread) { command_queue.push(this, &PhysicsServer3DWrapMT::thread_step, p_step); } else { - command_queue.flush_all(); //flush all pending from other threads + command_queue.flush_all(); // Flush all pending from other threads. physics_server_3d->step(p_step); } } void PhysicsServer3DWrapMT::sync() { if (create_thread) { - if (first_frame) { - first_frame = false; - } else { - step_sem.wait(); //must not wait if a step was not issued - } + step_sem.wait(); } physics_server_3d->sync(); } @@ -96,40 +85,34 @@ void PhysicsServer3DWrapMT::end_sync() { void PhysicsServer3DWrapMT::init() { if (create_thread) { - //OS::get_singleton()->release_rendering_thread(); - thread.start(_thread_callback, this); - while (!step_thread_up) { - OS::get_singleton()->delay_usec(1000); - } + exit = false; + server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &PhysicsServer3DWrapMT::thread_loop), true); + step_sem.post(); } else { physics_server_3d->init(); } } void PhysicsServer3DWrapMT::finish() { - if (thread.is_started()) { + if (create_thread) { command_queue.push(this, &PhysicsServer3DWrapMT::thread_exit); - thread.wait_to_finish(); + if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id); + server_task_id = WorkerThreadPool::INVALID_TASK_ID; + } } else { physics_server_3d->finish(); } } -PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) : - command_queue(p_create_thread) { +PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool p_create_thread) { physics_server_3d = p_contained; create_thread = p_create_thread; - - if (!p_create_thread) { - server_thread = Thread::get_caller_id(); - } else { - server_thread = 0; + if (!create_thread) { + server_thread = Thread::MAIN_ID; } - - main_thread = Thread::get_caller_id(); } PhysicsServer3DWrapMT::~PhysicsServer3DWrapMT() { memdelete(physics_server_3d); - //finish(); } diff --git a/servers/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h index fc8930977d..22f3ee0e45 100644 --- a/servers/physics_server_3d_wrap_mt.h +++ b/servers/physics_server_3d_wrap_mt.h @@ -32,6 +32,7 @@ #define PHYSICS_SERVER_3D_WRAP_MT_H #include "core/config/project_settings.h" +#include "core/object/worker_thread_pool.h" #include "core/os/thread.h" #include "core/templates/command_queue_mt.h" #include "servers/physics_server_3d.h" @@ -42,30 +43,27 @@ #define SYNC_DEBUG #endif +#ifdef DEBUG_ENABLED +#define MAIN_THREAD_SYNC_WARN WARN_PRINT("Call to " + String(__FUNCTION__) + " causing PhysicsServer3D synchronizations on every frame. This significantly affects performance."); +#endif + class PhysicsServer3DWrapMT : public PhysicsServer3D { - mutable PhysicsServer3D *physics_server_3d; + mutable PhysicsServer3D *physics_server_3d = nullptr; mutable CommandQueueMT command_queue; - static void _thread_callback(void *_instance); void thread_loop(); - Thread::ID server_thread; - Thread::ID main_thread; - volatile bool exit = false; - Thread thread; - volatile bool step_thread_up = false; + Thread::ID server_thread = Thread::UNASSIGNED_ID; + WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID; + bool exit = false; + Semaphore step_sem; bool create_thread = false; - Semaphore step_sem; void thread_step(real_t p_delta); void thread_exit(); - bool first_frame = true; - - Mutex alloc_mutex; - public: #define ServerName PhysicsServer3D #define ServerNameWrapMT PhysicsServer3DWrapMT @@ -98,7 +96,7 @@ public: #if 0 //these work well, but should be used from the main thread only bool shape_collide(RID p_shape_A, const Transform &p_xform_A, const Vector3 &p_motion_A, RID p_shape_B, const Transform &p_xform_B, const Vector3 &p_motion_B, Vector3 *r_results, int p_result_max, int &r_result_count) { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + ERR_FAIL_COND_V(!Thread::is_main_thread(), false); return physics_server_3d->shape_collide(p_shape_A, p_xform_A, p_motion_A, p_shape_B, p_xform_B, p_motion_B, r_results, p_result_max, r_result_count); } #endif @@ -113,18 +111,18 @@ public: // this function only works on physics process, errors and returns null otherwise PhysicsDirectSpaceState3D *space_get_direct_state(RID p_space) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + ERR_FAIL_COND_V(!Thread::is_main_thread(), nullptr); return physics_server_3d->space_get_direct_state(p_space); } FUNC2(space_set_debug_contacts, RID, int); virtual Vector<Vector3> space_get_contacts(RID p_space) const override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), Vector<Vector3>()); + ERR_FAIL_COND_V(!Thread::is_main_thread(), Vector<Vector3>()); return physics_server_3d->space_get_contacts(p_space); } virtual int space_get_contact_count(RID p_space) const override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), 0); + ERR_FAIL_COND_V(!Thread::is_main_thread(), 0); return physics_server_3d->space_get_contact_count(p_space); } @@ -260,13 +258,13 @@ public: FUNC2(body_set_ray_pickable, RID, bool); bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); + ERR_FAIL_COND_V(!Thread::is_main_thread(), false); return physics_server_3d->body_test_motion(p_body, p_parameters, r_result); } // this function only works on physics process, errors and returns null otherwise PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override { - ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), nullptr); + ERR_FAIL_COND_V(!Thread::is_main_thread(), nullptr); return physics_server_3d->body_get_direct_state(p_body); } @@ -411,4 +409,8 @@ public: #endif #undef SYNC_DEBUG +#ifdef DEBUG_ENABLED +#undef MAIN_THREAD_SYNC_WARN +#endif + #endif // PHYSICS_SERVER_3D_WRAP_MT_H diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index c03c0b7a40..1a75614a4c 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -94,6 +94,7 @@ #include "physics_server_3d_wrap_mt.h" #include "servers/extensions/physics_server_3d_extension.h" #include "xr/xr_body_tracker.h" +#include "xr/xr_controller_tracker.h" #include "xr/xr_face_tracker.h" #include "xr/xr_hand_tracker.h" #include "xr/xr_interface.h" @@ -325,12 +326,14 @@ void register_server_types() { GDREGISTER_ABSTRACT_CLASS(XRInterface); GDREGISTER_CLASS(XRBodyTracker); + GDREGISTER_CLASS(XRControllerTracker); GDREGISTER_CLASS(XRFaceTracker); GDREGISTER_CLASS(XRHandTracker); GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions. GDREGISTER_CLASS(XRPose); GDREGISTER_CLASS(XRPositionalTracker); GDREGISTER_CLASS(XRServer); + GDREGISTER_ABSTRACT_CLASS(XRTracker); #endif // _3D_DISABLED GDREGISTER_ABSTRACT_CLASS(NavigationServer3D); diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h index a76305cdaa..0a9602b603 100644 --- a/servers/rendering/dummy/storage/light_storage.h +++ b/servers/rendering/dummy/storage/light_storage.h @@ -91,6 +91,7 @@ public: void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {} void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {} void light_instance_mark_visible(RID p_light_instance) override {} + virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override { return false; } /* PROBE API */ virtual RID reflection_probe_allocate() override { return RID(); } diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index e32164ea98..34f9069649 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -332,7 +332,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 child_item_count = ci->ysort_children_count + 1; child_items = (Item **)alloca(child_item_count * sizeof(Item *)); - ci->ysort_xform = final_xform.affine_inverse(); + ci->ysort_xform = ci->xform_curr.affine_inverse(); ci->ysort_pos = Vector2(); ci->ysort_modulate = Color(1, 1, 1, 1); ci->ysort_index = 0; @@ -1970,6 +1970,8 @@ void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) { RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_NULL(occluder); + + occluder->sdf_collision = p_enable; } void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) { diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index abbe04b5b2..a363b03dd8 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -533,7 +533,7 @@ void CopyEffects::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuff RD::get_singleton()->draw_list_draw(draw_list, true); } -void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview, bool p_alpha_to_one, bool p_linear, bool p_normal) { +void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview, bool p_alpha_to_one, bool p_linear, bool p_normal, const Rect2 &p_src_rect) { UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton(); ERR_FAIL_NULL(uniform_set_cache); MaterialStorage *material_storage = MaterialStorage::get_singleton(); @@ -568,6 +568,14 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_NORMAL; } + if (p_src_rect != Rect2()) { + copy_to_fb.push_constant.section[0] = p_src_rect.position.x; + copy_to_fb.push_constant.section[1] = p_src_rect.position.y; + copy_to_fb.push_constant.section[2] = p_src_rect.size.x; + copy_to_fb.push_constant.section[3] = p_src_rect.size.y; + copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_USE_SRC_SECTION; + } + // setup our uniforms RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); @@ -583,7 +591,7 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, p_rect); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); if (p_secondary.is_valid()) { @@ -982,7 +990,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, p_region); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer))); RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); RD::get_singleton()->draw_list_set_push_constant(draw_list, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h index d18971a676..014f78e2b9 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.h +++ b/servers/rendering/renderer_rd/effects/copy_effects.h @@ -191,6 +191,7 @@ private: COPY_TO_FB_FLAG_ALPHA_TO_ONE = (1 << 5), COPY_TO_FB_FLAG_LINEAR = (1 << 6), COPY_TO_FB_FLAG_NORMAL = (1 << 7), + COPY_TO_FB_FLAG_USE_SRC_SECTION = (1 << 8), }; struct CopyToFbPushConstant { @@ -329,7 +330,7 @@ public: void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false); void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far); - void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false, bool p_normal = false); + void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false, bool p_normal = false, const Rect2 &p_src_rect = Rect2()); void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false); void copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_source_rd_texture, bool p_linear = false); void copy_raster(RID p_source_texture, RID p_dest_framebuffer); diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp index a57a65fd5a..017ad41fdc 100644 --- a/servers/rendering/renderer_rd/effects/debug_effects.cpp +++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp @@ -282,7 +282,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj // And draw our frustum. RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect); RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); @@ -326,7 +326,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj rect.size.x *= atlas_rect_norm.size.x; rect.size.y *= atlas_rect_norm.size.y; - draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); + draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect); pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); diff --git a/servers/rendering/renderer_rd/effects/fsr2.cpp b/servers/rendering/renderer_rd/effects/fsr2.cpp index bebbf51d51..925352a7d1 100644 --- a/servers/rendering/renderer_rd/effects/fsr2.cpp +++ b/servers/rendering/renderer_rd/effects/fsr2.cpp @@ -527,6 +527,7 @@ FSR2Effect::FSR2Effect() { "\n#define FFX_GLSL 1\n" "\n#define FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS 1\n" "\n#define FFX_FSR2_OPTION_HDR_COLOR_INPUT 1\n" + "\n#define FFX_FSR2_OPTION_INVERTED_DEPTH 1\n" "\n#define FFX_FSR2_OPTION_GODOT_REACTIVE_MASK_CLAMP 1\n" "\n#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS 1\n"; @@ -808,7 +809,7 @@ FSR2Effect::~FSR2Effect() { FSR2Context *FSR2Effect::create_context(Size2i p_internal_size, Size2i p_target_size) { FSR2Context *context = memnew(RendererRD::FSR2Context); - context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE; + context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE | FFX_FSR2_ENABLE_DEPTH_INVERTED; context->fsr_desc.maxRenderSize.width = p_internal_size.x; context->fsr_desc.maxRenderSize.height = p_internal_size.y; context->fsr_desc.displaySize.width = p_target_size.x; diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp index bdd687d9f4..3db82c8fbd 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.cpp +++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp @@ -483,8 +483,12 @@ void SSEffects::downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uin downsample_uniform_set = uniform_set_cache->get_cache_vec(shader, 2, u_depths); } - float depth_linearize_mul = -p_projection.columns[3][2] * 0.5; - float depth_linearize_add = p_projection.columns[2][2]; + Projection correction; + correction.set_depth_correction(false); + Projection temp = correction * p_projection; + + float depth_linearize_mul = -temp.columns[3][2]; + float depth_linearize_add = temp.columns[2][2]; if (depth_linearize_mul * depth_linearize_add < 0) { depth_linearize_add = -depth_linearize_add; } diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index 78214ede0b..c7752f8a86 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -3407,7 +3407,7 @@ void GI::init(SkyRD *p_sky) { RD::PipelineDepthStencilState ds; ds.enable_depth_test = true; ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + ds.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; voxel_gi_debug_shader_version_pipelines[i].setup(voxel_gi_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); } @@ -3575,7 +3575,7 @@ void GI::init(SkyRD *p_sky) { RD::PipelineDepthStencilState ds; ds.enable_depth_test = true; ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + ds.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; for (int i = 0; i < SDFGIShader::PROBE_DEBUG_MAX; i++) { // TODO check if version is enabled @@ -3810,8 +3810,13 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor rbgi->scene_data_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SceneData)); } + Projection correction; + correction.set_depth_correction(false); + for (uint32_t v = 0; v < p_view_count; v++) { - RendererRD::MaterialStorage::store_camera(p_projections[v].inverse(), scene_data.inv_projection[v]); + Projection temp = correction * p_projections[v]; + + RendererRD::MaterialStorage::store_camera(temp.inverse(), scene_data.inv_projection[v]); scene_data.eye_offset[v][0] = p_eye_offsets[v].x; scene_data.eye_offset[v][1] = p_eye_offsets[v].y; scene_data.eye_offset[v][2] = p_eye_offsets[v].z; diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index 41609dc74d..b5d31f5414 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -141,7 +141,7 @@ void SkyRD::SkyShaderData::set_code(const String &p_code) { for (int i = 0; i < SKY_VERSION_MAX; i++) { RD::PipelineDepthStencilState depth_stencil_state; depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) { RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i); @@ -1174,6 +1174,7 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con } Projection correction; + correction.set_depth_correction(false, true); correction.add_jitter_offset(p_jitter); sky_scene_state.view_count = p_view_count; @@ -1184,10 +1185,12 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con for (uint32_t i = 0; i < p_view_count; i++) { Projection view_inv_projection = (correction * p_view_projections[i]).inverse(); if (p_view_count > 1) { + // Reprojection is used when we need to have things in combined space. RendererRD::MaterialStorage::store_camera(p_cam_projection * view_inv_projection, sky_scene_state.ubo.combined_reprojection[i]); } else { + // This is unused so just reset to identity. Projection ident; - RendererRD::MaterialStorage::store_camera(correction, sky_scene_state.ubo.combined_reprojection[i]); + RendererRD::MaterialStorage::store_camera(ident, sky_scene_state.ubo.combined_reprojection[i]); } RendererRD::MaterialStorage::store_camera(view_inv_projection, sky_scene_state.ubo.view_inv_projections[i]); @@ -1469,7 +1472,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p Vector<Color> clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors, 0.0); _render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier); RD::get_singleton()->draw_list_end(); } @@ -1488,7 +1491,7 @@ void SkyRD::update_res_buffers(Ref<RenderSceneBuffersRD> p_render_buffers, RID p Vector<Color> clear_colors; clear_colors.push_back(Color(0.0, 0.0, 0.0)); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors, 0.0); _render_sky(draw_list, p_time, framebuffer, pipeline, material->uniform_set, texture_uniform_set, projection, sky_transform, sky_scene_state.cam_transform.origin, p_luminance_multiplier); RD::get_singleton()->draw_list_end(); } diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index d78f3ba05b..c7ab7ea462 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -1132,6 +1132,7 @@ void RenderForwardClustered::_update_sdfgi(RenderDataRD *p_render_data) { } if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { + RENDER_TIMESTAMP("Render SDFGI"); Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); float exposure_normalization = 1.0; @@ -1403,7 +1404,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } } - //cube shadows are rendered in their own way + RENDER_TIMESTAMP("Render OmniLight Shadows"); + // Cube shadows are rendered in their own way. for (const int &index : p_render_data->cube_shadows) { _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); } @@ -1411,7 +1413,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo if (p_render_data->directional_shadows.size()) { //open the pass for directional shadows light_storage->update_directional_shadow_atlas(); - RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE); + RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0); RD::get_singleton()->draw_list_end(); } } @@ -1459,6 +1461,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo // drawcalls per eye/view. It will all sync up at the barrier. if (p_use_ssao || p_use_ssil) { + RENDER_TIMESTAMP("Prepare Depth for SSAO/SSIL"); // Convert our depth buffer data to linear data in for (uint32_t v = 0; v < rb->get_view_count(); v++) { ss_effects->downsample_depth(rb, v, p_render_data->scene_data->view_projection[v]); @@ -1474,6 +1477,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } } + RENDER_TIMESTAMP("Pre Opaque Render"); + if (current_cluster_builder) { // Note: when rendering stereoscopic (multiview) we are using our combined frustum projection to create // our cluster data. We use reprojection in the shader to adjust for our left/right eye. @@ -1506,6 +1511,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } if (rb_data.is_valid()) { + RENDER_TIMESTAMP("Update Volumetric Fog"); bool directional_shadows = RendererRD::LightStorage::get_singleton()->has_directional_shadows(directional_light_count); _update_volumetric_fog(rb, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes); } @@ -1924,7 +1930,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } if (needs_pre_resolve) { //pre clear the depth framebuffer, as AMD (and maybe others?) use compute for it, and barrier other compute shaders. - RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pass_clear); + RD::get_singleton()->draw_list_begin(depth_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pass_clear, 0.0); RD::get_singleton()->draw_list_end(); //start compute processes here, so they run at the same time as depth pre-pass _post_prepass_render(p_render_data, using_sdfgi || using_voxelgi); @@ -1967,6 +1973,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co WARN_PRINT_ONCE("Pre opaque rendering effects can't access resolved depth buffers."); } + RENDER_TIMESTAMP("Process Pre Opaque Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_OPAQUE, p_render_data); } @@ -1978,6 +1985,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, normal_roughness_views, rb_data.is_valid() && rb_data->has_voxelgi() ? rb_data->get_voxelgi() : RID()); + RENDER_TIMESTAMP("Render Opaque Pass"); + RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count; @@ -1988,8 +1997,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass); - RENDER_TIMESTAMP("Render Opaque Pass"); - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, samplers, true); { @@ -2014,7 +2021,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co uint32_t opaque_color_pass_flags = using_motion_pass ? (color_pass_flags & ~COLOR_PASS_FLAG_MOTION_VECTORS) : color_pass_flags; RID opaque_framebuffer = using_motion_pass ? rb_data->get_color_pass_fb(opaque_color_pass_flags) : color_framebuffer; RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, opaque_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count, 0, spec_constant_base_flags); - _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0); + _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0); } RD::get_singleton()->draw_command_end_label(); @@ -2053,6 +2060,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } + RENDER_TIMESTAMP("Process Post Opaque Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_OPAQUE, p_render_data); } @@ -2113,6 +2121,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } { + RENDER_TIMESTAMP("Process Post Sky Compositor Effects"); // Don't need to check for depth or color resolve here, we've already triggered it. _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_SKY, p_render_data); } @@ -2190,6 +2199,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } + RENDER_TIMESTAMP("Process Pre Transparent Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); } @@ -2234,6 +2244,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); { + RENDER_TIMESTAMP("Process Post Transparent Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_TRANSPARENT, p_render_data); } @@ -2629,7 +2640,7 @@ void RenderForwardClustered::_render_shadow_end() { for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from); - _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect); + _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect); } RD::get_singleton()->draw_command_end_label(); @@ -2729,7 +2740,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } @@ -2779,7 +2790,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance Color(0, 0, 0, 0), Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); const int uv_offset_count = 9; static const Vector2 uv_offsets[uv_offset_count] = { @@ -2885,7 +2896,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu } RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, 0, true, false, rp_uniform_set, false); - _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2()); + _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, Rect2()); } RD::get_singleton()->draw_command_end_label(); @@ -4265,7 +4276,7 @@ RenderForwardClustered::RenderForwardClustered() { sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 12af8822b4..1f12d92754 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -379,7 +379,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { template <PassMode p_pass_mode, uint32_t p_color_pass_flags = 0> _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); void _update_instance_data_buffer(RenderListType p_render_list); void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index 0b504eca0a..209fabeddf 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -260,7 +260,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { if (depth_test != DEPTH_TEST_DISABLED) { depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; } bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable")); @@ -827,7 +827,7 @@ void fragment() { sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } } diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 2f307c62f3..5715d94d95 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -614,7 +614,7 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) { if (p_render_data->directional_shadows.size()) { //open the pass for directional shadows light_storage->update_directional_shadow_atlas(); - RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE); + RD::get_singleton()->draw_list_begin(light_storage->direction_shadow_get_fb(), RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0); RD::get_singleton()->draw_list_end(); } } @@ -777,7 +777,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) { // can't do blit subpass because we're scaling using_subpass_post_process = false; - } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) { + } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes) || environment_get_background(p_render_data->environment) == RS::ENV_BG_CANVAS)) { // can't do blit subpass because we're using post processes using_subpass_post_process = false; } @@ -984,7 +984,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0); RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); if (copy_canvas) { @@ -1385,7 +1385,7 @@ void RenderForwardMobile::_render_shadow_end() { for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from); - _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect); + _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect); } RD::get_singleton()->draw_command_end_label(); @@ -1437,7 +1437,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c Color(0, 0, 0, 0), Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } @@ -1483,7 +1483,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *> Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); const int uv_offset_count = 9; static const Vector2 uv_offsets[uv_offset_count] = { diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 5c02204627..f29503e5ec 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -350,7 +350,7 @@ private: template <PassMode p_pass_mode> _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); - void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); RenderList render_list[RENDER_LIST_MAX]; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 95ba76a707..a2f112669c 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -271,7 +271,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { if (depth_test != DEPTH_TEST_DISABLED) { depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; } @@ -731,7 +731,7 @@ void fragment() { sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 6f56711151..fa8cf9c028 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -1931,7 +1931,7 @@ void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstan while (instance) { OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder); - if (!co || co->sdf_index_array.is_null()) { + if (!co || co->sdf_index_array.is_null() || !instance->sdf_collision) { instance = instance->next; continue; } diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index e61bb9eae8..6cb03871c9 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1157,6 +1157,7 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render render_data.lights = ∅ render_data.reflection_probes = ∅ render_data.voxel_gi_instances = ∅ + render_data.lightmaps = ∅ } if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED || diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl index fe770ac065..48c1b0a3f6 100644 --- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl @@ -32,9 +32,9 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh; float get_depth_at_pos(vec2 uv) { float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + depth = -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); } return depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl index 947aa793d9..2010b58474 100644 --- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl @@ -53,9 +53,9 @@ layout(set = 2, binding = 0) uniform sampler2D original_weight; float get_depth_at_pos(vec2 uv) { float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + depth = -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); } return depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl index 7192e596eb..26ee06aa03 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl @@ -21,6 +21,7 @@ #define FLAG_ALPHA_TO_ONE (1 << 5) #define FLAG_LINEAR (1 << 6) #define FLAG_NORMAL (1 << 7) +#define FLAG_USE_SRC_SECTION (1 << 8) #ifdef USE_MULTIVIEW layout(location = 0) out vec3 uv_interp; @@ -54,6 +55,10 @@ void main() { if (bool(params.flags & FLAG_FLIP_Y)) { uv_interp.y = 1.0 - uv_interp.y; } + + if (bool(params.flags & FLAG_USE_SRC_SECTION)) { + uv_interp.xy = params.section.xy + uv_interp.xy * params.section.zw; + } } #[fragment] diff --git a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl index e77d0de719..3fb93dda35 100644 --- a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl @@ -77,8 +77,8 @@ void main() { float depth_fix = 1.0 / dot(normal, unorm); depth = 2.0 * depth - 1.0; - float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - depth = (linear_depth * depth_fix) / params.z_far; - + float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); + // linear_depth equal to view space depth + depth = (params.z_far - linear_depth * depth_fix) / params.z_far; gl_FragDepth = depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl index 51caa67d3c..d9e21b8cd1 100644 --- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl @@ -98,9 +98,9 @@ void main() { // unproject our Z value so we can use it directly. depth = depth * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0; + depth = -(depth * (params.camera_z_far - params.camera_z_near) - (params.camera_z_far + params.camera_z_near)) / 2.0; } else { - depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near)); + depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near + depth * (params.camera_z_far - params.camera_z_near)); } depth = -depth; } diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl index 80ed34cda1..480172f9dc 100644 --- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl @@ -174,9 +174,9 @@ vec3 reconstruct_position(ivec2 screen_pos) { pos.z = pos.z * 2.0 - 1.0; if (params.orthogonal) { - pos.z = ((pos.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + pos.z = -(pos.z * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - pos.z * (params.z_far - params.z_near)); + pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + pos.z * (params.z_far - params.z_near)); } pos.z = -pos.z; diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl index 4e5b11aed8..35457a2482 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl @@ -25,7 +25,7 @@ params; void main() { vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0)); uv_interp = base_arr[gl_VertexIndex]; - gl_Position = vec4(uv_interp, 1.0, 1.0); + gl_Position = vec4(uv_interp, 0.0, 1.0); } #[fragment] @@ -158,7 +158,7 @@ vec3 interleaved_gradient_noise(vec2 pos) { vec4 volumetric_fog_process(vec2 screen_uv) { #ifdef USE_MULTIVIEW - vec4 reprojected = sky_scene_data.combined_reprojection[ViewIndex] * (vec4(screen_uv * 2.0 - 1.0, 1.0, 1.0) * sky_scene_data.z_far); + vec4 reprojected = sky_scene_data.combined_reprojection[ViewIndex] * vec4(screen_uv * 2.0 - 1.0, 0.0, 1.0); // Unproject at the far plane vec3 fog_pos = vec3(reprojected.xy / reprojected.w, 1.0) * 0.5 + 0.5; #else vec3 fog_pos = vec3(screen_uv, 1.0); @@ -187,9 +187,11 @@ void main() { vec3 cube_normal; #ifdef USE_MULTIVIEW // In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject. - vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 1.0, 1.0); + vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 0.0, 1.0); // unproject at the far plane vec4 unprojected = sky_scene_data.view_inv_projections[ViewIndex] * unproject; cube_normal = unprojected.xyz / unprojected.w; + + // Unproject will give us the position between the eyes, need to re-offset cube_normal += sky_scene_data.view_eye_offsets[ViewIndex].xyz; #else cube_normal.z = -1.0; diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl index 57b9a4c320..d0cfe6a3b8 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -416,7 +416,7 @@ void main() { } float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r; - float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * INV_FOG_FADE); + float shadow = exp(min(0.0, (pssm_coord.z - depth)) * z_range * INV_FOG_FADE); shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance @@ -519,7 +519,7 @@ void main() { float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; - shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE)); + shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (pos.z - depth)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE)); } total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g) * omni_lights.data[light_index].volumetric_fog_energy; } @@ -597,7 +597,7 @@ void main() { float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; - shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE)); + shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (pos.z - depth)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE)); } total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g) * spot_lights.data[light_index].volumetric_fog_energy; } diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 6eae64c04e..359d7799e5 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -487,8 +487,8 @@ void vertex_shader(vec3 vertex_input, #ifdef MODE_RENDER_DEPTH if (scene_data.pancake_shadows) { - if (gl_Position.z <= 0.00001) { - gl_Position.z = 0.00001; + if (gl_Position.z >= 0.9999) { + gl_Position.z = 0.9999; } } #endif diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 259edc63a0..c26313092b 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -475,8 +475,8 @@ void main() { #ifdef MODE_RENDER_DEPTH if (scene_data.pancake_shadows) { - if (gl_Position.z <= 0.00001) { - gl_Position.z = 0.00001; + if (gl_Position.z >= 0.9999) { + gl_Position.z = 0.9999; } } #endif // MODE_RENDER_DEPTH diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index e9722bad1f..47e6fe5873 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -454,7 +454,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { vec3 v0 = abs(basis_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); vec3 tangent = normalize(cross(v0, basis_normal)); vec3 bitangent = normalize(cross(tangent, basis_normal)); - float z_norm = shadow_len * omni_lights.data[idx].inv_radius; + float z_norm = 1.0 - shadow_len * omni_lights.data[idx].inv_radius; tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; @@ -479,7 +479,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), pos.xy, 0.0).r; - if (d < z_norm) { + if (d > z_norm) { blocker_average += d; blocker_count += 1.0; } @@ -488,11 +488,11 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { if (blocker_count > 0.0) { //blockers found, do soft shadow blocker_average /= blocker_count; - float penumbra = (z_norm - blocker_average) / blocker_average; + float penumbra = (z_norm + blocker_average) / blocker_average; tangent *= penumbra; bitangent *= penumbra; - z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; + z_norm += omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; shadow = 0.0; for (uint i = 0; i < sc_penumbra_shadow_samples; i++) { @@ -536,6 +536,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { vec2 pos = shadow_sample.xy / shadow_sample.z; float depth = shadow_len - omni_lights.data[idx].shadow_bias; depth *= omni_lights.data[idx].inv_radius; + depth = 1.0 - depth; shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth), omni_lights.data[idx].shadow_opacity); } @@ -706,7 +707,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { vec4 v = vec4(vertex + normal_bias, 1.0); vec4 splane = (spot_lights.data[idx].shadow_matrix * v); - splane.z -= spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius); + splane.z += spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius); splane /= splane.w; float shadow; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index cf8c29e624..d1ff9fc362 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -668,7 +668,9 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light->directional_blend_splits; for (int j = 0; j < 4; j++) { Rect2 atlas_rect = light_instance->shadow_transform[j].atlas_rect; - Projection matrix = light_instance->shadow_transform[j].camera; + Projection correction; + correction.set_depth_correction(false, true, false); + Projection matrix = correction * light_instance->shadow_transform[j].camera; float split = light_instance->shadow_transform[MIN(limit, j)].split; Projection bias; @@ -967,7 +969,9 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged Projection bias; bias.set_light_bias(); - Projection cm = light_instance->shadow_transform[0].camera; + Projection correction; + correction.set_depth_correction(false, true, false); + Projection cm = correction * light_instance->shadow_transform[0].camera; Projection shadow_mtx = bias * cm * modelview; RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrix); diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index b3d6bf5254..f152cc5dae 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -590,6 +590,29 @@ public: virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override; virtual void light_instance_mark_visible(RID p_light_instance) override; + virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override { + const LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); + ERR_FAIL_NULL_V(light_instance, false); + const Light *light = light_owner.get_or_null(light_instance->light); + ERR_FAIL_NULL_V(light, false); + + if (!light->shadow) { + return false; + } + + if (!light->distance_fade) { + return true; + } + + real_t distance = p_position.distance_to(light_instance->transform.origin); + + if (distance > light->distance_fade_shadow + light->distance_fade_length) { + return false; + } + + return true; + } + _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->light; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index e78b8de4db..f7b28e7a1e 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -257,7 +257,6 @@ void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) } bool ParticlesStorage::particles_get_emitting(RID p_particles) { - ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, false); @@ -608,10 +607,6 @@ void ParticlesStorage::particles_request_process(RID p_particles) { } AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) { - if (RSG::threaded) { - WARN_PRINT_ONCE("Calling this function with threaded rendering enabled stalls the renderer, use with care."); - } - const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, AABB()); @@ -1388,6 +1383,11 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) { } } void ParticlesStorage::update_particles() { + if (!particle_update_list.first()) { + return; + } + + RENDER_TIMESTAMP("Update GPUParticles"); uint32_t frame = RSG::rasterizer->get_frame_number(); bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0; while (particle_update_list.first()) { @@ -1637,7 +1637,6 @@ Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const { } bool ParticlesStorage::particles_is_inactive(RID p_particles) const { - ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_NULL_V(particles, false); return !particles->emitting && particles->inactive; diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index c5d74d395f..b7934cb3de 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -130,9 +130,10 @@ void RenderSceneBuffersRD::cleanup() { named_textures.clear(); // Clear weight_buffer / blur textures. - for (const WeightBuffers &weight_buffer : weight_buffers) { + for (WeightBuffers &weight_buffer : weight_buffers) { if (weight_buffer.weight.is_valid()) { RD::get_singleton()->free(weight_buffer.weight); + weight_buffer.weight = RID(); } } } diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index f3ce432495..af30a32866 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2965,7 +2965,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const dd.emission_rect[3] = 0; } - Color modulate = decal->modulate; + Color modulate = decal->modulate.srgb_to_linear(); dd.modulate[0] = modulate.r; dd.modulate[1] = modulate.g; dd.modulate[2] = modulate.b; @@ -3820,7 +3820,10 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons if (RendererSceneRenderRD::get_singleton()->_render_buffers_can_be_storage()) { copy_effects->copy_to_rect(rt->color, rt->backbuffer_mipmap0, region, false, false, false, !rt->use_hdr, true); } else { - copy_effects->copy_to_fb_rect(rt->color, rt->backbuffer_fb, region, false, false, false, false, RID(), false, true); + Rect2 src_rect = Rect2(region); + src_rect.position /= Size2(rt->size); + src_rect.size /= Size2(rt->size); + copy_effects->copy_to_fb_rect(rt->color, rt->backbuffer_fb, region, false, false, false, false, RID(), false, true, false, false, src_rect); } if (!p_gen_mipmaps) { diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index aa69cd8539..96c0479ac3 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1029,7 +1029,6 @@ inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_NULL(instance); - ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); if (p_aabb != AABB()) { // Set custom AABB @@ -1720,6 +1719,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { idata.base_rid = p_instance->base; idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1; idata.visibility_index = p_instance->visibility_index; + idata.occlusion_timeout = 0; for (Instance *E : p_instance->visibility_dependencies) { Instance *dep_instance = E; @@ -2775,7 +2775,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul #define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check<false>(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0) #define VIS_PARENT_CHECK (_visibility_parent_check(cull_data, idata)) #define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check) -#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near)) +#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near, cull_data.scenario->instance_data[i].occlusion_timeout)) if (!HIDDEN_BY_VISIBILITY_CHECKS) { if ((LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) || (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_ALL_CULLING)) { @@ -3028,6 +3028,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c light_culler->prepare_camera(p_camera_data->main_transform, p_camera_data->main_projection); Scenario *scenario = scenario_owner.get_or_null(p_scenario); + Vector3 camera_position = p_camera_data->main_transform.origin; ERR_FAIL_COND(p_render_buffers.is_null()); @@ -3037,7 +3038,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c if (p_reflection_probe.is_null()) { //no rendering code here, this is only to set up what needs to be done, request regions, etc. - scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not) + scene_render->sdfgi_update(p_render_buffers, p_environment, camera_position); //update conditions for SDFGI (whether its used or not) } RENDER_TIMESTAMP("Update Visibility Dependencies"); @@ -3050,7 +3051,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c VisibilityCullData visibility_cull_data; visibility_cull_data.scenario = scenario; visibility_cull_data.viewport_mask = scenario->viewport_visibility_masks[p_viewport]; - visibility_cull_data.camera_position = p_camera_data->main_transform.origin; + visibility_cull_data.camera_position = camera_position; for (int i = scenario->instance_visibility.get_bin_count() - 1; i > 0; i--) { // We skip bin 0 visibility_cull_data.cull_offset = scenario->instance_visibility.get_bin_start(i); @@ -3219,16 +3220,20 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c } } - // Positional Shadowss + // Positional Shadows for (uint32_t i = 0; i < (uint32_t)scene_cull_result.lights.size(); i++) { Instance *ins = scene_cull_result.lights[i]; - if (!p_shadow_atlas.is_valid() || !RSG::light_storage->light_has_shadow(ins->base)) { + if (!p_shadow_atlas.is_valid()) { continue; } InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data); + if (!RSG::light_storage->light_instance_is_shadow_visible_at_position(light->instance, camera_position)) { + continue; + } + float coverage = 0.f; { //compute coverage @@ -3567,43 +3572,47 @@ void RendererSceneCull::render_probes() { bool busy = false; - while (ref_probe) { - SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); - RID base = ref_probe->self()->owner->base; + if (ref_probe) { + RENDER_TIMESTAMP("Render ReflectionProbes"); - switch (RSG::light_storage->reflection_probe_get_update_mode(base)) { - case RS::REFLECTION_PROBE_UPDATE_ONCE: { - if (busy) { //already rendering something - break; - } + while (ref_probe) { + SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); + RID base = ref_probe->self()->owner->base; - bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); - if (done) { - done_list.push_back(ref_probe); - } else { - ref_probe->self()->render_step++; - } + switch (RSG::light_storage->reflection_probe_get_update_mode(base)) { + case RS::REFLECTION_PROBE_UPDATE_ONCE: { + if (busy) { // Already rendering something. + break; + } - busy = true; //do not render another one of this kind - } break; - case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { - int step = 0; - bool done = false; - while (!done) { - done = _render_reflection_probe_step(ref_probe->self()->owner, step); - step++; - } + bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); + if (done) { + done_list.push_back(ref_probe); + } else { + ref_probe->self()->render_step++; + } - done_list.push_back(ref_probe); - } break; - } + busy = true; // Do not render another one of this kind. + } break; + case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { + int step = 0; + bool done = false; + while (!done) { + done = _render_reflection_probe_step(ref_probe->self()->owner, step); + step++; + } - ref_probe = next; - } + done_list.push_back(ref_probe); + } break; + } - // Now remove from our list - for (SelfList<InstanceReflectionProbeData> *rp : done_list) { - reflection_probe_render_list.remove(rp); + ref_probe = next; + } + + // Now remove from our list + for (SelfList<InstanceReflectionProbeData> *rp : done_list) { + reflection_probe_render_list.remove(rp); + } } /* VOXEL GIS */ @@ -4252,6 +4261,7 @@ RendererSceneCull::RendererSceneCull() { indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame"); thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances"); thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)WorkerThreadPool::get_singleton()->get_thread_count()); //make sure there is at least one thread per CPU + RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = GLOBAL_GET("rendering/occlusion_culling/jitter_projection"); dummy_occlusion_culling = memnew(RendererSceneOcclusionCull); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 341ba0e3b0..0039d14475 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -286,6 +286,13 @@ public: Instance *instance = nullptr; int32_t parent_array_index = -1; int32_t visibility_index = -1; + + // Each time occlusion culling determines an instance is visible, + // set this to occlusion_frame plus some delay. + // Once the timeout is reached, allow the instance to be occlusion culled. + // This creates a delay for occlusion culling, which prevents flickering + // when jittering the raster occlusion projection. + uint64_t occlusion_timeout = 0; }; struct InstanceVisibilityData { diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp index c4f0177c73..1f0239411a 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.cpp +++ b/servers/rendering/renderer_scene_occlusion_cull.cpp @@ -43,6 +43,8 @@ const Vector3 RendererSceneOcclusionCull::HZBuffer::corners[8] = { Vector3(1, 1, 1) }; +bool RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = false; + bool RendererSceneOcclusionCull::HZBuffer::is_empty() const { return sizes.is_empty(); } @@ -66,6 +68,8 @@ void RendererSceneOcclusionCull::HZBuffer::clear() { } void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) { + occlusion_buffer_size = p_size; + if (p_size == Size2i()) { clear(); return; @@ -124,6 +128,9 @@ void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) { } void RendererSceneOcclusionCull::HZBuffer::update_mips() { + // Keep this up to date as a local to be used for occlusion timers. + occlusion_frame = Engine::get_singleton()->get_frames_drawn(); + if (sizes.is_empty()) { return; } diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index 149d7b1cdb..5adba5dc6a 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -53,14 +53,10 @@ public: PackedByteArray debug_data; float debug_tex_range = 0.0f; - public: - bool is_empty() const; - virtual void clear(); - virtual void resize(const Size2i &p_size); - - void update_mips(); + uint64_t occlusion_frame = 0; + Size2i occlusion_buffer_size; - _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const { + _FORCE_INLINE_ bool _is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const { if (is_empty()) { return false; } @@ -154,7 +150,47 @@ public: return !visible; } + public: + static bool occlusion_jitter_enabled; + + bool is_empty() const; + virtual void clear(); + virtual void resize(const Size2i &p_size); + + void update_mips(); + + // Thin wrapper around _is_occluded(), + // allowing occlusion timers to delay the disappearance + // of objects to prevent flickering when using jittering. + _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near, uint64_t &r_occlusion_timeout) const { + bool occluded = _is_occluded(p_bounds, p_cam_position, p_cam_inv_transform, p_cam_projection, p_near); + + // Special case, temporal jitter disabled, + // so we don't use occlusion timers. + if (!occlusion_jitter_enabled) { + return occluded; + } + + if (!occluded) { +//#define DEBUG_RASTER_OCCLUSION_JITTER +#ifdef DEBUG_RASTER_OCCLUSION_JITTER + r_occlusion_timeout = occlusion_frame + 1; +#else + r_occlusion_timeout = occlusion_frame + 9; +#endif + } else if (r_occlusion_timeout) { + // Regular timeout, allow occlusion culling + // to proceed as normal after the delay. + if (occlusion_frame >= r_occlusion_timeout) { + r_occlusion_timeout = 0; + } + } + + return occluded && !r_occlusion_timeout; + } + RID get_debug_texture(); + const Size2i &get_occlusion_buffer_size() const { return occlusion_buffer_size; } virtual ~HZBuffer(){}; }; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index bafabf16b8..31d5a9074c 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -802,8 +802,6 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { } else #endif // _3D_DISABLED { - RSG::texture_storage->render_target_set_override(vp->render_target, RID(), RID(), RID()); - RSG::scene->set_debug_draw_mode(vp->debug_draw); // render standard mono camera @@ -1062,6 +1060,13 @@ void RendererViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpda viewport->update_mode = p_mode; } +RS::ViewportUpdateMode RendererViewport::viewport_get_update_mode(RID p_viewport) const { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_NULL_V(viewport, RS::VIEWPORT_UPDATE_DISABLED); + + return viewport->update_mode; +} + RID RendererViewport::viewport_get_render_target(RID p_viewport) const { const Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_NULL_V(viewport, RID()); @@ -1191,6 +1196,9 @@ void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canva void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) { Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_NULL(viewport); + if (viewport->transparent_bg == p_enabled) { + return; + } RSG::texture_storage->render_target_set_transparent(viewport->render_target, p_enabled); viewport->transparent_bg = p_enabled; diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index 90c29618b3..5107398c54 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -236,6 +236,7 @@ public: void viewport_set_texture_mipmap_bias(RID p_viewport, float p_mipmap_bias); void viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode); + RS::ViewportUpdateMode viewport_get_update_mode(RID p_viewport) const; void viewport_set_vflip(RID p_viewport, bool p_enable); void viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 7dfff0b76f..962531c866 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -1350,6 +1350,9 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye thread_local LocalVector<RDD::BufferTextureCopyRegion> command_buffer_texture_copy_regions_vector; command_buffer_texture_copy_regions_vector.clear(); + uint32_t block_w = 0, block_h = 0; + get_compressed_image_format_block_dimensions(tex->format, block_w, block_h); + uint32_t w = tex->width; uint32_t h = tex->height; uint32_t d = tex->depth; @@ -1365,8 +1368,8 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye copy_region.texture_region_size.z = d; command_buffer_texture_copy_regions_vector.push_back(copy_region); - w = MAX(1u, w >> 1); - h = MAX(1u, h >> 1); + w = MAX(block_w, w >> 1); + h = MAX(block_h, h >> 1); d = MAX(1u, d >> 1); } @@ -1395,8 +1398,6 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye for (uint32_t i = 0; i < tex->mipmaps; i++) { uint32_t width = 0, height = 0, depth = 0; uint32_t tight_mip_size = get_image_format_required_size(tex->format, w, h, d, 1, &width, &height, &depth); - uint32_t block_w = 0, block_h = 0; - get_compressed_image_format_block_dimensions(tex->format, block_w, block_h); uint32_t tight_row_pitch = tight_mip_size / ((height / block_h) * depth); // Copy row-by-row to erase padding due to alignments. @@ -1408,8 +1409,8 @@ Vector<uint8_t> RenderingDevice::texture_get_data(RID p_texture, uint32_t p_laye wp += tight_row_pitch; } - w = MAX(1u, w >> 1); - h = MAX(1u, h >> 1); + w = MAX(block_w, w >> 1); + h = MAX(block_h, h >> 1); d = MAX(1u, d >> 1); read_ptr += mip_layouts[i].size; write_ptr += tight_mip_size; @@ -5089,7 +5090,8 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ draw_list = nullptr; compute_list = nullptr; - if (main_instance) { + bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable"); + if (main_instance && project_pipeline_cache_enable) { // Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache. pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s", OS::get_singleton()->get_current_rendering_method(), @@ -5223,8 +5225,12 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r case DRIVER_RESOURCE_LOGICAL_DEVICE: case DRIVER_RESOURCE_PHYSICAL_DEVICE: case DRIVER_RESOURCE_TOPMOST_OBJECT: + break; case DRIVER_RESOURCE_COMMAND_QUEUE: + driver_id = main_queue.id; + break; case DRIVER_RESOURCE_QUEUE_FAMILY: + driver_id = main_queue_family.id; break; case DRIVER_RESOURCE_TEXTURE: case DRIVER_RESOURCE_TEXTURE_VIEW: @@ -5232,19 +5238,19 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r Texture *tex = texture_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(tex, 0); - driver_id = tex->driver_id; + driver_id = tex->driver_id.id; } break; case DRIVER_RESOURCE_SAMPLER: { RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(sampler_driver_id, 0); - driver_id = *sampler_driver_id; + driver_id = (*sampler_driver_id).id; } break; case DRIVER_RESOURCE_UNIFORM_SET: { UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(uniform_set, 0); - driver_id = uniform_set->driver_id; + driver_id = uniform_set->driver_id.id; } break; case DRIVER_RESOURCE_BUFFER: { Buffer *buffer = nullptr; @@ -5261,19 +5267,19 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r } ERR_FAIL_NULL_V(buffer, 0); - driver_id = buffer->driver_id; + driver_id = buffer->driver_id.id; } break; case DRIVER_RESOURCE_COMPUTE_PIPELINE: { ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(compute_pipeline, 0); - driver_id = compute_pipeline->driver_id; + driver_id = compute_pipeline->driver_id.id; } break; case DRIVER_RESOURCE_RENDER_PIPELINE: { RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(render_pipeline, 0); - driver_id = render_pipeline->driver_id; + driver_id = render_pipeline->driver_id.id; } break; default: { ERR_FAIL_V(0); @@ -5549,6 +5555,7 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("compute_list_set_push_constant", "compute_list", "buffer", "size_bytes"), &RenderingDevice::_compute_list_set_push_constant); ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set); ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch); + ClassDB::bind_method(D_METHOD("compute_list_dispatch_indirect", "compute_list", "buffer", "offset"), &RenderingDevice::compute_list_dispatch_indirect); ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier); ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end); @@ -6394,11 +6401,11 @@ Vector<int64_t> RenderingDevice::_draw_list_switch_to_next_pass_split(uint32_t p #endif void RenderingDevice::_draw_list_set_push_constant(DrawListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) { - ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size); + ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size()); draw_list_set_push_constant(p_list, p_data.ptr(), p_data_size); } void RenderingDevice::_compute_list_set_push_constant(ComputeListID p_list, const Vector<uint8_t> &p_data, uint32_t p_data_size) { - ERR_FAIL_COND((uint32_t)p_data.size() > p_data_size); + ERR_FAIL_COND(p_data_size > (uint32_t)p_data.size()); compute_list_set_push_constant(p_list, p_data.ptr(), p_data_size); } diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index 09a0412941..e9464ba321 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -128,7 +128,7 @@ public: #define DEFINE_ID(m_name) \ struct m_name##ID : public ID { \ - _ALWAYS_INLINE_ operator bool() const { return id != 0; } \ + _ALWAYS_INLINE_ explicit operator bool() const { return id != 0; } \ _ALWAYS_INLINE_ m_name##ID &operator=(m_name##ID p_other) { \ id = p_other.id; \ return *this; \ diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp index 4b85d1c2bf..adac7ee3eb 100644 --- a/servers/rendering/rendering_device_graph.cpp +++ b/servers/rendering/rendering_device_graph.cpp @@ -261,7 +261,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr } if (resource_tracker->parent->usage == RESOURCE_USAGE_NONE) { - if (resource_tracker->parent->texture_driver_id != 0) { + if (resource_tracker->parent->texture_driver_id.id != 0) { // If the resource is a texture, we transition it entirely to the layout determined by the first slice that uses it. _add_texture_barrier_to_command(resource_tracker->parent->texture_driver_id, RDD::BarrierAccessBits(0), new_usage_access, RDG::RESOURCE_USAGE_NONE, new_resource_usage, resource_tracker->parent->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); } @@ -324,7 +324,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr ERR_FAIL_MSG("Texture slices that overlap can't be used in the same command."); } else { // Delete the slice from the dirty list and revert it to the usage of the parent. - if (current_tracker->texture_driver_id != 0) { + if (current_tracker->texture_driver_id.id != 0) { _add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->parent->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); // Merge the area of the slice with the current tracking area of the command and indicate it's a write usage as well. @@ -383,7 +383,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr while (current_tracker != nullptr) { current_tracker->reset_if_outdated(tracking_frame); - if (current_tracker->texture_driver_id != 0) { + if (current_tracker->texture_driver_id.id != 0) { // Transition all slices to the layout of the parent resource. _add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); } diff --git a/servers/rendering/rendering_light_culler.cpp b/servers/rendering/rendering_light_culler.cpp index fdf0d73654..0889898f0b 100644 --- a/servers/rendering/rendering_light_culler.cpp +++ b/servers/rendering/rendering_light_culler.cpp @@ -427,15 +427,19 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan uint8_t *entry = &data.LUT_entries[lookup][0]; int n_edges = data.LUT_entry_sizes[lookup] - 1; + const Vector3 &pt2 = p_light_source.pos; + for (int e = 0; e < n_edges; e++) { int i0 = entry[e]; int i1 = entry[e + 1]; const Vector3 &pt0 = data.frustum_points[i0]; const Vector3 &pt1 = data.frustum_points[i1]; - // Create plane from 3 points. - Plane p(pt0, pt1, p_light_source.pos); - r_cull_planes.add_cull_plane(p); + if (!_is_colinear_tri(pt0, pt1, pt2)) { + // Create plane from 3 points. + Plane p(pt0, pt1, pt2); + r_cull_planes.add_cull_plane(p); + } } // Last to 0 edge. @@ -446,9 +450,11 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan const Vector3 &pt0 = data.frustum_points[i0]; const Vector3 &pt1 = data.frustum_points[i1]; - // Create plane from 3 points. - Plane p(pt0, pt1, p_light_source.pos); - r_cull_planes.add_cull_plane(p); + if (!_is_colinear_tri(pt0, pt1, pt2)) { + // Create plane from 3 points. + Plane p(pt0, pt1, pt2); + r_cull_planes.add_cull_plane(p); + } } #ifdef LIGHT_CULLER_DEBUG_LOGGING diff --git a/servers/rendering/rendering_light_culler.h b/servers/rendering/rendering_light_culler.h index 602543850a..0bf975430b 100644 --- a/servers/rendering/rendering_light_culler.h +++ b/servers/rendering/rendering_light_culler.h @@ -163,6 +163,39 @@ private: bool _prepare_light(const RendererSceneCull::Instance &p_instance, int32_t p_directional_light_id = -1); + // Avoid adding extra culling planes derived from near colinear triangles. + // The normals derived from these will be inaccurate, and can lead to false + // culling of objects that should be within the light volume. + bool _is_colinear_tri(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c) const { + // Lengths of sides a, b and c. + float la = (p_b - p_a).length(); + float lb = (p_c - p_b).length(); + float lc = (p_c - p_a).length(); + + // Get longest side into lc. + if (lb < la) { + SWAP(la, lb); + } + if (lc < lb) { + SWAP(lb, lc); + } + + // Prevent divide by zero. + if (lc > 0.00001f) { + // If the summed length of the smaller two + // sides is close to the length of the longest side, + // the points are colinear, and the triangle is near degenerate. + float ld = ((la + lb) - lc) / lc; + + // ld will be close to zero for colinear tris. + return ld < 0.00001f; + } + + // Don't create planes from tiny triangles, + // they won't be accurate. + return true; + } + // Internal version uses LightSource. bool _add_light_camera_planes(LightCullPlanes &r_cull_planes, const LightSource &p_light_source); diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index f614070f68..7e5ccee0e3 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -69,9 +69,6 @@ void RenderingServerDefault::request_frame_drawn_callback(const Callable &p_call } void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { - //needs to be done before changes is reset to 0, to not force the editor to redraw - RS::get_singleton()->emit_signal(SNAME("frame_pre_draw")); - changes = 0; RSG::rasterizer->begin_frame(frame_step); @@ -80,6 +77,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { uint64_t time_usec = OS::get_singleton()->get_ticks_usec(); + RENDER_TIMESTAMP("Prepare Render Frame"); RSG::scene->update(); //update scenes stuff before updating instances frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0; @@ -219,16 +217,9 @@ void RenderingServerDefault::_finish() { void RenderingServerDefault::init() { if (create_thread) { - print_verbose("RenderingServerWrapMT: Creating render thread"); + print_verbose("RenderingServerWrapMT: Starting render thread"); DisplayServer::get_singleton()->release_rendering_thread(); - if (create_thread) { - thread.start(_thread_callback, this); - print_verbose("RenderingServerWrapMT: Starting render thread"); - } - while (!draw_thread_up.is_set()) { - OS::get_singleton()->delay_usec(1000); - } - print_verbose("RenderingServerWrapMT: Finished render thread"); + server_task_id = WorkerThreadPool::get_singleton()->add_task(callable_mp(this, &RenderingServerDefault::_thread_loop), true); } else { _init(); } @@ -237,8 +228,9 @@ void RenderingServerDefault::init() { void RenderingServerDefault::finish() { if (create_thread) { command_queue.push(this, &RenderingServerDefault::_thread_exit); - if (thread.is_started()) { - thread.wait_to_finish(); + if (server_task_id != WorkerThreadPool::INVALID_TASK_ID) { + WorkerThreadPool::get_singleton()->wait_for_task_completion(server_task_id); + server_task_id = WorkerThreadPool::INVALID_TASK_ID; } } else { _finish(); @@ -336,38 +328,29 @@ Size2i RenderingServerDefault::get_maximum_viewport_size() const { } void RenderingServerDefault::_thread_exit() { - exit.set(); + exit = true; } void RenderingServerDefault::_thread_draw(bool p_swap_buffers, double frame_step) { _draw(p_swap_buffers, frame_step); } -void RenderingServerDefault::_thread_flush() { -} - -void RenderingServerDefault::_thread_callback(void *_instance) { - RenderingServerDefault *vsmt = reinterpret_cast<RenderingServerDefault *>(_instance); - - vsmt->_thread_loop(); -} - void RenderingServerDefault::_thread_loop() { server_thread = Thread::get_caller_id(); - DisplayServer::get_singleton()->make_rendering_thread(); - + DisplayServer::get_singleton()->gl_window_make_current(DisplayServer::MAIN_WINDOW_ID); // Move GL to this thread. _init(); - draw_thread_up.set(); - while (!exit.is_set()) { - // flush commands one by one, until exit is requested - command_queue.wait_and_flush(); + command_queue.set_pump_task_id(server_task_id); + while (!exit) { + WorkerThreadPool::get_singleton()->yield(); + command_queue.flush_all(); } - command_queue.flush_all(); // flush all + command_queue.flush_all(); _finish(); + DisplayServer::get_singleton()->release_rendering_thread(); } /* INTERPOLATION */ @@ -383,15 +366,15 @@ void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) { /* EVENT QUEUING */ void RenderingServerDefault::sync() { - if (create_thread) { - command_queue.push_and_sync(this, &RenderingServerDefault::_thread_flush); - } else { - command_queue.flush_all(); //flush all pending from other threads + if (!create_thread) { + command_queue.flush_all(); // Flush all pending from other threads. } } void RenderingServerDefault::draw(bool p_swap_buffers, double frame_step) { ERR_FAIL_COND_MSG(!Thread::is_main_thread(), "Manually triggering the draw function from the RenderingServer can only be done on the main thread. Call this function from the main thread or use call_deferred()."); + // Needs to be done before changes is reset to 0, to not force the editor to redraw. + RS::get_singleton()->emit_signal(SNAME("frame_pre_draw")); if (create_thread) { command_queue.push(this, &RenderingServerDefault::_thread_draw, p_swap_buffers, frame_step); } else { @@ -403,21 +386,14 @@ void RenderingServerDefault::_call_on_render_thread(const Callable &p_callable) p_callable.call(); } -RenderingServerDefault::RenderingServerDefault(bool p_create_thread) : - command_queue(p_create_thread) { +RenderingServerDefault::RenderingServerDefault(bool p_create_thread) { RenderingServer::init(); -#ifdef THREADS_ENABLED create_thread = p_create_thread; if (!create_thread) { - server_thread = Thread::get_caller_id(); - } else { - server_thread = 0; + server_thread = Thread::MAIN_ID; } -#else - create_thread = false; - server_thread = Thread::get_main_id(); -#endif + RSG::threaded = create_thread; RSG::canvas = memnew(RendererCanvasCull); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 139624c777..f94323f198 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -31,6 +31,7 @@ #ifndef RENDERING_SERVER_DEFAULT_H #define RENDERING_SERVER_DEFAULT_H +#include "core/object/worker_thread_pool.h" #include "core/os/thread.h" #include "core/templates/command_queue_mt.h" #include "core/templates/hash_map.h" @@ -75,22 +76,17 @@ class RenderingServerDefault : public RenderingServer { mutable CommandQueueMT command_queue; - static void _thread_callback(void *_instance); void _thread_loop(); - Thread::ID server_thread = 0; - SafeFlag exit; - Thread thread; - SafeFlag draw_thread_up; - bool create_thread; + Thread::ID server_thread = Thread::UNASSIGNED_ID; + WorkerThreadPool::TaskID server_task_id = WorkerThreadPool::INVALID_TASK_ID; + bool exit = false; + bool create_thread = false; void _thread_draw(bool p_swap_buffers, double frame_step); - void _thread_flush(); void _thread_exit(); - Mutex alloc_mutex; - void _draw(bool p_swap_buffers, double frame_step); void _init(); void _finish(); @@ -127,6 +123,10 @@ public: #define SYNC_DEBUG #endif +#ifdef DEBUG_ENABLED +#define MAIN_THREAD_SYNC_WARN WARN_PRINT("Call to " + String(__FUNCTION__) + " causing RenderingServer synchronizations on every frame. This significantly affects performance."); +#endif + #include "servers/server_wrap_mt_common.h" /* TEXTURE API */ @@ -625,6 +625,7 @@ public: FUNC2(viewport_set_texture_mipmap_bias, RID, float) FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode) + FUNC1RC(ViewportUpdateMode, viewport_get_update_mode, RID) FUNC1RC(RID, viewport_get_render_target, RID) FUNC1RC(RID, viewport_get_texture, RID) @@ -1012,6 +1013,9 @@ public: #undef ServerName #undef WRITE_ACTION #undef SYNC_DEBUG +#ifdef DEBUG_ENABLED +#undef MAIN_THREAD_SYNC_WARN +#endif virtual uint64_t get_rendering_info(RenderingInfo p_info) override; virtual RenderingDevice::DeviceType get_video_adapter_type() const override; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index fef1a205d6..99b3f54379 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -5029,6 +5029,10 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Vector<Expression> expression; //Vector<TokenType> operators; +#ifdef DEBUG_ENABLED + bool check_position_write = check_warnings && HAS_WARNING(ShaderWarning::MAGIC_POSITION_WRITE_FLAG); + check_position_write = check_position_write && String(shader_type_identifier) == "spatial" && current_function == "vertex"; +#endif while (true) { Node *expr = nullptr; @@ -5589,6 +5593,24 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons _set_error(vformat(RTR("Can't use function as identifier: '%s'."), String(identifier))); return nullptr; } +#ifdef DEBUG_ENABLED + if (check_position_write && ident_type == IDENTIFIER_BUILTIN_VAR) { + if (String(identifier) == "POSITION") { + // Check if the user wrote "POSITION = vec4(VERTEX," and warn if they did. + TkPos prev_pos = _get_tkpos(); + if (_get_token().type == TK_OP_ASSIGN && + _get_token().type == TK_TYPE_VEC4 && + _get_token().type == TK_PARENTHESIS_OPEN && + _get_token().text == "VERTEX" && + _get_token().type == TK_COMMA) { + _add_line_warning(ShaderWarning::MAGIC_POSITION_WRITE); + } + + // Reset the position so compiling can continue as normal. + _set_tkpos(prev_pos); + } + } +#endif if (is_const) { last_type = IDENTIFIER_CONSTANT; } else { @@ -8361,7 +8383,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f } } #endif // DEBUG_ENABLED - if (String(shader_type_identifier) != "spatial") { + if (shader_type_identifier != StringName() && String(shader_type_identifier) != "spatial") { _set_error(vformat(RTR("Uniform instances are not yet implemented for '%s' shaders."), shader_type_identifier)); return ERR_PARSE_ERROR; } @@ -8848,7 +8870,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f _set_error(RTR("'hint_normal_roughness_texture' is only available when using the Forward+ backend.")); return ERR_PARSE_ERROR; } - if (String(shader_type_identifier) != "spatial") { + if (shader_type_identifier != StringName() && String(shader_type_identifier) != "spatial") { _set_error(vformat(RTR("'hint_normal_roughness_texture' is not supported in '%s' shaders."), shader_type_identifier)); return ERR_PARSE_ERROR; } @@ -8857,7 +8879,7 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f new_hint = ShaderNode::Uniform::HINT_DEPTH_TEXTURE; --texture_uniforms; --texture_binding; - if (String(shader_type_identifier) != "spatial") { + if (shader_type_identifier != StringName() && String(shader_type_identifier) != "spatial") { _set_error(vformat(RTR("'hint_depth_texture' is not supported in '%s' shaders."), shader_type_identifier)); return ERR_PARSE_ERROR; } diff --git a/servers/rendering/shader_warnings.cpp b/servers/rendering/shader_warnings.cpp index dce8f6cff1..3b99f6c2bf 100644 --- a/servers/rendering/shader_warnings.cpp +++ b/servers/rendering/shader_warnings.cpp @@ -65,6 +65,8 @@ String ShaderWarning::get_message() const { return subject; case DEVICE_LIMIT_EXCEEDED: return vformat(RTR("The total size of the %s for this shader on this device has been exceeded (%d/%d). The shader may not work correctly."), subject, (int)extra_args[0], (int)extra_args[1]); + case MAGIC_POSITION_WRITE: + return vformat(RTR("You are attempting to assign the VERTEX position in model space to the vertex POSITION in clip space. The definition of clip space changed in version 4.3, so if this code was written prior to 4.3, it will not continue to work. Consider specifying the clip space z-component directly i.e. use `vec4(VERTEX.xy, 1.0, 1.0)`.")); default: break; } @@ -92,6 +94,7 @@ String ShaderWarning::get_name_from_code(Code p_code) { "UNUSED_LOCAL_VARIABLE", "FORMATTING_ERROR", "DEVICE_LIMIT_EXCEEDED", + "MAGIC_POSITION_WRITE", }; static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names."); @@ -122,6 +125,7 @@ static void init_code_to_flags_map() { code_to_flags_map->insert(ShaderWarning::UNUSED_LOCAL_VARIABLE, ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG); code_to_flags_map->insert(ShaderWarning::FORMATTING_ERROR, ShaderWarning::FORMATTING_ERROR_FLAG); code_to_flags_map->insert(ShaderWarning::DEVICE_LIMIT_EXCEEDED, ShaderWarning::DEVICE_LIMIT_EXCEEDED_FLAG); + code_to_flags_map->insert(ShaderWarning::MAGIC_POSITION_WRITE, ShaderWarning::MAGIC_POSITION_WRITE_FLAG); } ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const HashMap<Code, bool> &p_map) { diff --git a/servers/rendering/shader_warnings.h b/servers/rendering/shader_warnings.h index ed28ebdd2b..69d684850f 100644 --- a/servers/rendering/shader_warnings.h +++ b/servers/rendering/shader_warnings.h @@ -51,6 +51,7 @@ public: UNUSED_LOCAL_VARIABLE, FORMATTING_ERROR, DEVICE_LIMIT_EXCEEDED, + MAGIC_POSITION_WRITE, WARNING_MAX, }; @@ -65,6 +66,7 @@ public: UNUSED_LOCAL_VARIABLE_FLAG = 64U, FORMATTING_ERROR_FLAG = 128U, DEVICE_LIMIT_EXCEEDED_FLAG = 256U, + MAGIC_POSITION_WRITE_FLAG = 512U, }; private: diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h index d439598f3d..6a0adfa596 100644 --- a/servers/rendering/storage/light_storage.h +++ b/servers/rendering/storage/light_storage.h @@ -98,6 +98,7 @@ public: virtual bool light_instances_can_render_shadow_cube() const { return true; } + virtual bool light_instance_is_shadow_visible_at_position(RID p_light, const Vector3 &p_position) const = 0; /* PROBE API */ diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 994f6ad8b4..bbe6b1ad0d 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -83,25 +83,16 @@ static PackedInt64Array to_int_array(const Vector<ObjectID> &ids) { } PackedInt64Array RenderingServer::_instances_cull_aabb_bind(const AABB &p_aabb, RID p_scenario) const { - if (RSG::threaded) { - WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); - } Vector<ObjectID> ids = instances_cull_aabb(p_aabb, p_scenario); return to_int_array(ids); } PackedInt64Array RenderingServer::_instances_cull_ray_bind(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { - if (RSG::threaded) { - WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); - } Vector<ObjectID> ids = instances_cull_ray(p_from, p_to, p_scenario); return to_int_array(ids); } PackedInt64Array RenderingServer::_instances_cull_convex_bind(const TypedArray<Plane> &p_convex, RID p_scenario) const { - if (RSG::threaded) { - WARN_PRINT_ONCE("Using this function with a threaded renderer hurts performance, as it causes a server stall."); - } Vector<Plane> planes; for (int i = 0; i < p_convex.size(); ++i) { const Variant &v = p_convex[i]; @@ -2783,6 +2774,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_fsr_sharpness", "viewport", "sharpness"), &RenderingServer::viewport_set_fsr_sharpness); ClassDB::bind_method(D_METHOD("viewport_set_texture_mipmap_bias", "viewport", "mipmap_bias"), &RenderingServer::viewport_set_texture_mipmap_bias); ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &RenderingServer::viewport_set_update_mode); + ClassDB::bind_method(D_METHOD("viewport_get_update_mode", "viewport"), &RenderingServer::viewport_get_update_mode); ClassDB::bind_method(D_METHOD("viewport_set_clear_mode", "viewport", "clear_mode"), &RenderingServer::viewport_set_clear_mode); ClassDB::bind_method(D_METHOD("viewport_get_render_target", "viewport"), &RenderingServer::viewport_get_render_target); ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &RenderingServer::viewport_get_texture); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index a3a77bc57b..8f0150f180 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -873,6 +873,7 @@ public: }; virtual void viewport_set_update_mode(RID p_viewport, ViewportUpdateMode p_mode) = 0; + virtual ViewportUpdateMode viewport_get_update_mode(RID p_viewport) const = 0; enum ViewportClearMode { VIEWPORT_CLEAR_ALWAYS, diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h index 1a73c97fc7..40867490ca 100644 --- a/servers/server_wrap_mt_common.h +++ b/servers/server_wrap_mt_common.h @@ -31,12 +31,22 @@ #ifndef SERVER_WRAP_MT_COMMON_H #define SERVER_WRAP_MT_COMMON_H +#ifdef DEBIG_ENABLED +#define MAIN_THREAD_SYNC_CHECK \ + if (unlikely(Thread::is_main_thread() && Engine::get_singleton()->notify_frame_server_synced())) { \ + MAIN_THREAD_SYNC_WARN \ + } +#else +#define MAIN_THREAD_SYNC_CHECK +#endif + #define FUNC0R(m_r, m_type) \ virtual m_r m_type() override { \ if (Thread::get_caller_id() != server_thread) { \ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -68,6 +78,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -102,6 +113,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(); \ @@ -113,6 +125,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(); \ @@ -128,6 +141,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -141,6 +155,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -154,6 +169,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1); \ @@ -165,6 +181,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1); \ @@ -199,6 +216,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -212,6 +230,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -225,6 +244,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2); \ @@ -236,6 +256,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2); \ @@ -270,6 +291,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -283,6 +305,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -296,6 +319,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3); \ @@ -307,6 +331,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3); \ @@ -341,6 +366,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -354,6 +380,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -367,6 +394,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4); \ @@ -378,6 +406,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4); \ @@ -412,6 +441,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -425,6 +455,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -438,6 +469,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5); \ @@ -449,6 +481,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5); \ @@ -483,6 +516,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -496,6 +530,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -509,6 +544,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6); \ @@ -520,6 +556,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6); \ @@ -554,6 +591,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -567,6 +605,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -580,6 +619,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ @@ -591,6 +631,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6, p7); \ @@ -625,6 +666,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -638,6 +680,7 @@ m_r ret; \ command_queue.push_and_ret(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8, &ret); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ return ret; \ } else { \ command_queue.flush_if_pending(); \ @@ -651,6 +694,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ @@ -662,6 +706,7 @@ if (Thread::get_caller_id() != server_thread) { \ command_queue.push_and_sync(server_name, &ServerName::m_type, p1, p2, p3, p4, p5, p6, p7, p8); \ SYNC_DEBUG \ + MAIN_THREAD_SYNC_CHECK \ } else { \ command_queue.flush_if_pending(); \ server_name->m_type(p1, p2, p3, p4, p5, p6, p7, p8); \ diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index eb9f1c1484..8f9797805f 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -285,7 +285,7 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_get_line_breaks_adv, "shaped", "width", "start", "once", "break_flags"); GDVIRTUAL_BIND(_shaped_text_get_line_breaks, "shaped", "width", "start", "break_flags"); - GDVIRTUAL_BIND(_shaped_text_get_word_breaks, "shaped", "grapheme_flags"); + GDVIRTUAL_BIND(_shaped_text_get_word_breaks, "shaped", "grapheme_flags", "skip_grapheme_flags"); GDVIRTUAL_BIND(_shaped_text_get_trim_pos, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_ellipsis_pos, "shaped"); @@ -341,6 +341,7 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_string_to_upper, "string", "language"); GDVIRTUAL_BIND(_string_to_lower, "string", "language"); + GDVIRTUAL_BIND(_string_to_title, "string", "language"); GDVIRTUAL_BIND(_parse_structured_text, "parser_type", "args", "text"); @@ -1255,12 +1256,12 @@ PackedInt32Array TextServerExtension::shaped_text_get_line_breaks(const RID &p_s return TextServer::shaped_text_get_line_breaks(p_shaped, p_width, p_start, p_break_flags); } -PackedInt32Array TextServerExtension::shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags) const { +PackedInt32Array TextServerExtension::shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags, BitField<TextServer::GraphemeFlag> p_skip_grapheme_flags) const { PackedInt32Array ret; - if (GDVIRTUAL_CALL(_shaped_text_get_word_breaks, p_shaped, p_grapheme_flags, ret)) { + if (GDVIRTUAL_CALL(_shaped_text_get_word_breaks, p_shaped, p_grapheme_flags, p_skip_grapheme_flags, ret)) { return ret; } - return TextServer::shaped_text_get_word_breaks(p_shaped, p_grapheme_flags); + return TextServer::shaped_text_get_word_breaks(p_shaped, p_grapheme_flags, p_skip_grapheme_flags); } int64_t TextServerExtension::shaped_text_get_trim_pos(const RID &p_shaped) const { @@ -1507,6 +1508,14 @@ String TextServerExtension::string_to_upper(const String &p_string, const String return p_string; } +String TextServerExtension::string_to_title(const String &p_string, const String &p_language) const { + String ret; + if (GDVIRTUAL_CALL(_string_to_title, p_string, p_language, ret)) { + return ret; + } + return p_string; +} + String TextServerExtension::string_to_lower(const String &p_string, const String &p_language) const { String ret; if (GDVIRTUAL_CALL(_string_to_lower, p_string, p_language, ret)) { diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 84d68de4fa..f447f0f5bd 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -472,10 +472,10 @@ public: virtual PackedInt32Array shaped_text_get_line_breaks_adv(const RID &p_shaped, const PackedFloat32Array &p_width, int64_t p_start = 0, bool p_once = true, BitField<TextServer::LineBreakFlag> p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override; virtual PackedInt32Array shaped_text_get_line_breaks(const RID &p_shaped, double p_width, int64_t p_start = 0, BitField<TextServer::LineBreakFlag> p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override; - virtual PackedInt32Array shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const override; + virtual PackedInt32Array shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION, BitField<TextServer::GraphemeFlag> p_skip_grapheme_flags = GRAPHEME_IS_VIRTUAL) const override; GDVIRTUAL5RC(PackedInt32Array, _shaped_text_get_line_breaks_adv, RID, const PackedFloat32Array &, int64_t, bool, BitField<TextServer::LineBreakFlag>); GDVIRTUAL4RC(PackedInt32Array, _shaped_text_get_line_breaks, RID, double, int64_t, BitField<TextServer::LineBreakFlag>); - GDVIRTUAL2RC(PackedInt32Array, _shaped_text_get_word_breaks, RID, BitField<TextServer::GraphemeFlag>); + GDVIRTUAL3RC(PackedInt32Array, _shaped_text_get_word_breaks, RID, BitField<TextServer::GraphemeFlag>, BitField<TextServer::GraphemeFlag>); virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override; virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override; @@ -566,8 +566,10 @@ public: virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + virtual String string_to_title(const String &p_string, const String &p_language = "") const override; GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &); GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &); + GDVIRTUAL2RC(String, _string_to_title, const String &, const String &); TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &); diff --git a/servers/text_server.compat.inc b/servers/text_server.compat.inc new file mode 100644 index 0000000000..0ff35721a3 --- /dev/null +++ b/servers/text_server.compat.inc @@ -0,0 +1,41 @@ +/**************************************************************************/ +/* text_server.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +PackedInt32Array TextServer::_shaped_text_get_word_breaks_bind_compat_90732(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags) const { + return shaped_text_get_word_breaks(p_shaped, p_grapheme_flags, 0); +} + +void TextServer::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("shaped_text_get_word_breaks", "shaped", "grapheme_flags"), &TextServer::_shaped_text_get_word_breaks_bind_compat_90732, DEFVAL(GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION)); +} + +#endif diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 078ee27753..562f2df411 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -29,6 +29,8 @@ /**************************************************************************/ #include "servers/text_server.h" +#include "text_server.compat.inc" + #include "core/variant/typed_array.h" #include "servers/rendering_server.h" @@ -435,7 +437,7 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_get_range", "shaped"), &TextServer::shaped_text_get_range); ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); - ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped", "grapheme_flags"), &TextServer::shaped_text_get_word_breaks, DEFVAL(GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION)); + ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped", "grapheme_flags", "skip_grapheme_flags"), &TextServer::shaped_text_get_word_breaks, DEFVAL(GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION), DEFVAL(GRAPHEME_IS_VIRTUAL)); ClassDB::bind_method(D_METHOD("shaped_text_get_trim_pos", "shaped"), &TextServer::shaped_text_get_trim_pos); ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_pos", "shaped"), &TextServer::shaped_text_get_ellipsis_pos); @@ -491,6 +493,7 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL("")); ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL("")); + ClassDB::bind_method(D_METHOD("string_to_title", "string", "language"), &TextServer::string_to_title, DEFVAL("")); ClassDB::bind_method(D_METHOD("parse_structured_text", "parser_type", "args", "text"), &TextServer::parse_structured_text); @@ -1093,7 +1096,7 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do return lines; } -PackedInt32Array TextServer::shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags) const { +PackedInt32Array TextServer::shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags, BitField<TextServer::GraphemeFlag> p_skip_grapheme_flags) const { PackedInt32Array words; const_cast<TextServer *>(this)->shaped_text_update_justification_ops(p_shaped); @@ -1106,10 +1109,11 @@ PackedInt32Array TextServer::shaped_text_get_word_breaks(const RID &p_shaped, Bi for (int i = 0; i < l_size; i++) { if (l_gl[i].count > 0) { - if ((l_gl[i].flags & p_grapheme_flags) != 0) { - if (word_start != l_gl[i].start) { + if ((l_gl[i].flags & p_grapheme_flags) != 0 && (l_gl[i].flags & p_skip_grapheme_flags) == 0) { + int next = (i == 0) ? l_gl[i].start : l_gl[i - 1].end; + if (word_start < next) { words.push_back(word_start); - words.push_back(l_gl[i].start); + words.push_back(next); } word_start = l_gl[i].end; } diff --git a/servers/text_server.h b/servers/text_server.h index 4a16ae64e8..775dbb5508 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -226,6 +226,11 @@ protected: static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + PackedInt32Array _shaped_text_get_word_breaks_bind_compat_90732(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const; + static void _bind_compatibility_methods(); +#endif + public: virtual bool has_feature(Feature p_feature) const = 0; virtual String get_name() const = 0; @@ -483,7 +488,7 @@ public: virtual PackedInt32Array shaped_text_get_line_breaks_adv(const RID &p_shaped, const PackedFloat32Array &p_width, int64_t p_start = 0, bool p_once = true, BitField<TextServer::LineBreakFlag> p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; virtual PackedInt32Array shaped_text_get_line_breaks(const RID &p_shaped, double p_width, int64_t p_start = 0, BitField<TextServer::LineBreakFlag> p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; - virtual PackedInt32Array shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const; + virtual PackedInt32Array shaped_text_get_word_breaks(const RID &p_shaped, BitField<TextServer::GraphemeFlag> p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION, BitField<TextServer::GraphemeFlag> p_skip_grapheme_flags = GRAPHEME_IS_VIRTUAL) const; virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const = 0; virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const = 0; @@ -546,6 +551,7 @@ public: // Other string operations. virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0; virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0; + virtual String string_to_title(const String &p_string, const String &p_language = "") const = 0; TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; diff --git a/servers/xr/xr_body_tracker.cpp b/servers/xr/xr_body_tracker.cpp index cd58c14348..9c82b80911 100644 --- a/servers/xr/xr_body_tracker.cpp +++ b/servers/xr/xr_body_tracker.cpp @@ -134,6 +134,14 @@ void XRBodyTracker::_bind_methods() { BIND_BITFIELD_FLAG(JOINT_FLAG_POSITION_TRACKED); } +void XRBodyTracker::set_tracker_type(XRServer::TrackerType p_type) { + ERR_FAIL_COND_MSG(p_type != XRServer::TRACKER_BODY, "XRBodyTracker must be of type TRACKER_BODY."); +} + +void XRBodyTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { + ERR_FAIL_COND_MSG(p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN, "XRBodyTracker cannot specify hand."); +} + void XRBodyTracker::set_has_tracking_data(bool p_has_tracking_data) { has_tracking_data = p_has_tracking_data; } @@ -169,3 +177,7 @@ Transform3D XRBodyTracker::get_joint_transform(Joint p_joint) const { ERR_FAIL_INDEX_V(p_joint, JOINT_MAX, Transform3D()); return joint_transforms[p_joint]; } + +XRBodyTracker::XRBodyTracker() { + type = XRServer::TRACKER_BODY; +} diff --git a/servers/xr/xr_body_tracker.h b/servers/xr/xr_body_tracker.h index 659aa39df1..544de8ca8b 100644 --- a/servers/xr/xr_body_tracker.h +++ b/servers/xr/xr_body_tracker.h @@ -31,10 +31,10 @@ #ifndef XR_BODY_TRACKER_H #define XR_BODY_TRACKER_H -#include "core/object/ref_counted.h" +#include "servers/xr/xr_positional_tracker.h" -class XRBodyTracker : public RefCounted { - GDCLASS(XRBodyTracker, RefCounted); +class XRBodyTracker : public XRPositionalTracker { + GDCLASS(XRBodyTracker, XRPositionalTracker); _THREAD_SAFE_CLASS_ public: @@ -140,6 +140,9 @@ public: JOINT_FLAG_POSITION_TRACKED = 8, }; + void set_tracker_type(XRServer::TrackerType p_type) override; + void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) override; + void set_has_tracking_data(bool p_has_tracking_data); bool get_has_tracking_data() const; @@ -152,6 +155,8 @@ public: void set_joint_transform(Joint p_joint, const Transform3D &p_transform); Transform3D get_joint_transform(Joint p_joint) const; + XRBodyTracker(); + protected: static void _bind_methods(); diff --git a/servers/xr/xr_controller_tracker.cpp b/servers/xr/xr_controller_tracker.cpp new file mode 100644 index 0000000000..df85e86b7e --- /dev/null +++ b/servers/xr/xr_controller_tracker.cpp @@ -0,0 +1,39 @@ +/**************************************************************************/ +/* xr_controller_tracker.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "xr_controller_tracker.h" + +#include "core/input/input.h" + +void XRControllerTracker::_bind_methods(){}; + +XRControllerTracker::XRControllerTracker() { + type = XRServer::TRACKER_CONTROLLER; +} diff --git a/servers/xr/xr_controller_tracker.h b/servers/xr/xr_controller_tracker.h new file mode 100644 index 0000000000..a443cc1fd8 --- /dev/null +++ b/servers/xr/xr_controller_tracker.h @@ -0,0 +1,52 @@ +/**************************************************************************/ +/* xr_controller_tracker.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef XR_CONTROLLER_TRACKER_H +#define XR_CONTROLLER_TRACKER_H + +#include "core/os/thread_safe.h" +#include "servers/xr/xr_positional_tracker.h" + +/** + The controller tracker object as an object that represents the position and orientation of a controller. +*/ + +class XRControllerTracker : public XRPositionalTracker { + GDCLASS(XRControllerTracker, XRPositionalTracker); + _THREAD_SAFE_CLASS_ + +protected: + static void _bind_methods(); + +public: + XRControllerTracker(); +}; + +#endif // XR_CONTROLLER_TRACKER_H diff --git a/servers/xr/xr_face_tracker.cpp b/servers/xr/xr_face_tracker.cpp index a38ccfd527..7015cd0805 100644 --- a/servers/xr/xr_face_tracker.cpp +++ b/servers/xr/xr_face_tracker.cpp @@ -187,6 +187,10 @@ void XRFaceTracker::_bind_methods() { ADD_PROPERTY_DEFAULT("blend_shapes", PackedFloat32Array()); // To prevent ludicrously large default values. } +void XRFaceTracker::set_tracker_type(XRServer::TrackerType p_type) { + ERR_FAIL_COND_MSG(p_type != XRServer::TRACKER_FACE, "XRFaceTracker must be of type TRACKER_FACE."); +} + float XRFaceTracker::get_blend_shape(BlendShapeEntry p_blend_shape) const { // Fail if the blend shape index is out of range. ERR_FAIL_INDEX_V(p_blend_shape, FT_MAX, 0.0f); @@ -220,3 +224,7 @@ void XRFaceTracker::set_blend_shapes(const PackedFloat32Array &p_blend_shapes) { // Copy the blend shape values into the blend shape array. memcpy(blend_shape_values, p_blend_shapes.ptr(), sizeof(blend_shape_values)); } + +XRFaceTracker::XRFaceTracker() { + type = XRServer::TRACKER_FACE; +} diff --git a/servers/xr/xr_face_tracker.h b/servers/xr/xr_face_tracker.h index b9f553cba6..a753a7abdc 100644 --- a/servers/xr/xr_face_tracker.h +++ b/servers/xr/xr_face_tracker.h @@ -31,7 +31,7 @@ #ifndef XR_FACE_TRACKER_H #define XR_FACE_TRACKER_H -#include "core/object/ref_counted.h" +#include "servers/xr/xr_tracker.h" /** The XRFaceTracker class provides face blend shape weights. @@ -41,8 +41,8 @@ and Meta Movement standards. */ -class XRFaceTracker : public RefCounted { - GDCLASS(XRFaceTracker, RefCounted); +class XRFaceTracker : public XRTracker { + GDCLASS(XRFaceTracker, XRTracker); _THREAD_SAFE_CLASS_ public: @@ -195,12 +195,16 @@ public: FT_MAX // Maximum blend shape. }; + void set_tracker_type(XRServer::TrackerType p_type) override; + float get_blend_shape(BlendShapeEntry p_blend_shape) const; void set_blend_shape(BlendShapeEntry p_blend_shape, float p_value); PackedFloat32Array get_blend_shapes() const; void set_blend_shapes(const PackedFloat32Array &p_blend_shapes); + XRFaceTracker(); + protected: static void _bind_methods(); diff --git a/servers/xr/xr_hand_tracker.cpp b/servers/xr/xr_hand_tracker.cpp index 8cc2d5f7d2..cb0fbfb35f 100644 --- a/servers/xr/xr_hand_tracker.cpp +++ b/servers/xr/xr_hand_tracker.cpp @@ -30,6 +30,8 @@ #include "xr_hand_tracker.h" +#include "xr_body_tracker.h" + void XRHandTracker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hand", "hand"), &XRHandTracker::set_hand); ClassDB::bind_method(D_METHOD("get_hand"), &XRHandTracker::get_hand); @@ -55,7 +57,6 @@ void XRHandTracker::_bind_methods() { ClassDB::bind_method(D_METHOD("set_hand_joint_angular_velocity", "joint", "angular_velocity"), &XRHandTracker::set_hand_joint_angular_velocity); ClassDB::bind_method(D_METHOD("get_hand_joint_angular_velocity", "joint"), &XRHandTracker::get_hand_joint_angular_velocity); - ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "has_tracking_data", PROPERTY_HINT_NONE), "set_has_tracking_data", "get_has_tracking_data"); ADD_PROPERTY(PropertyInfo(Variant::INT, "hand_tracking_source", PROPERTY_HINT_ENUM, "Unknown,Unobstructed,Controller"), "set_hand_tracking_source", "get_hand_tracking_source"); @@ -104,8 +105,49 @@ void XRHandTracker::_bind_methods() { BIND_BITFIELD_FLAG(HAND_JOINT_FLAG_ANGULAR_VELOCITY_VALID); } +void XRHandTracker::set_tracker_type(XRServer::TrackerType p_type) { + ERR_FAIL_COND_MSG(p_type != XRServer::TRACKER_HAND, "XRHandTracker must be of type TRACKER_HAND."); +} + +void XRHandTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { + ERR_FAIL_INDEX(p_hand, TRACKER_HAND_MAX); + + switch (p_hand) { + case TRACKER_HAND_LEFT: + tracker_hand = TRACKER_HAND_LEFT; + hand = HAND_LEFT; + break; + + case TRACKER_HAND_RIGHT: + tracker_hand = TRACKER_HAND_RIGHT; + hand = HAND_RIGHT; + break; + + case TRACKER_HAND_UNKNOWN: + default: + ERR_FAIL_MSG("XRHandTracker must specify hand"); + break; + } +} + void XRHandTracker::set_hand(XRHandTracker::Hand p_hand) { - hand = p_hand; + ERR_FAIL_INDEX(p_hand, HAND_MAX); + + switch (p_hand) { + case HAND_LEFT: + tracker_hand = TRACKER_HAND_LEFT; + hand = HAND_LEFT; + break; + + case HAND_RIGHT: + tracker_hand = TRACKER_HAND_RIGHT; + hand = HAND_RIGHT; + break; + + default: + ERR_FAIL_MSG("XRHandTracker must specify hand"); + break; + } } XRHandTracker::Hand XRHandTracker::get_hand() const { @@ -177,3 +219,7 @@ Vector3 XRHandTracker::get_hand_joint_angular_velocity(XRHandTracker::HandJoint ERR_FAIL_INDEX_V(p_joint, HAND_JOINT_MAX, Vector3()); return hand_joint_angular_velocities[p_joint]; } + +XRHandTracker::XRHandTracker() { + type = XRServer::TRACKER_HAND; +} diff --git a/servers/xr/xr_hand_tracker.h b/servers/xr/xr_hand_tracker.h index 648f02d1f8..8ef3c229c3 100644 --- a/servers/xr/xr_hand_tracker.h +++ b/servers/xr/xr_hand_tracker.h @@ -31,10 +31,10 @@ #ifndef XR_HAND_TRACKER_H #define XR_HAND_TRACKER_H -#include "core/object/ref_counted.h" +#include "servers/xr/xr_positional_tracker.h" -class XRHandTracker : public RefCounted { - GDCLASS(XRHandTracker, RefCounted); +class XRHandTracker : public XRPositionalTracker { + GDCLASS(XRHandTracker, XRPositionalTracker); _THREAD_SAFE_CLASS_ public: @@ -90,6 +90,9 @@ public: HAND_JOINT_FLAG_ANGULAR_VELOCITY_VALID = 32, }; + void set_tracker_type(XRServer::TrackerType p_type) override; + void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) override; + void set_hand(Hand p_hand); Hand get_hand() const; @@ -114,6 +117,8 @@ public: void set_hand_joint_angular_velocity(HandJoint p_joint, const Vector3 &p_velocity); Vector3 get_hand_joint_angular_velocity(HandJoint p_joint) const; + XRHandTracker(); + protected: static void _bind_methods(); diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index 6c15e4c1b0..b479237730 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -31,23 +31,13 @@ #include "xr_positional_tracker.h" #include "core/input/input.h" +#include "xr_controller_tracker.h" void XRPositionalTracker::_bind_methods() { BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN); BIND_ENUM_CONSTANT(TRACKER_HAND_LEFT); BIND_ENUM_CONSTANT(TRACKER_HAND_RIGHT); - - ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRPositionalTracker::get_tracker_type); - ClassDB::bind_method(D_METHOD("set_tracker_type", "type"), &XRPositionalTracker::set_tracker_type); - ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_tracker_type", "get_tracker_type"); - - ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRPositionalTracker::get_tracker_name); - ClassDB::bind_method(D_METHOD("set_tracker_name", "name"), &XRPositionalTracker::set_tracker_name); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_tracker_name", "get_tracker_name"); - - ClassDB::bind_method(D_METHOD("get_tracker_desc"), &XRPositionalTracker::get_tracker_desc); - ClassDB::bind_method(D_METHOD("set_tracker_desc", "description"), &XRPositionalTracker::set_tracker_desc); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_tracker_desc", "get_tracker_desc"); + BIND_ENUM_CONSTANT(TRACKER_HAND_MAX); ClassDB::bind_method(D_METHOD("get_tracker_profile"), &XRPositionalTracker::get_tracker_profile); ClassDB::bind_method(D_METHOD("set_tracker_profile", "profile"), &XRPositionalTracker::set_tracker_profile); @@ -73,34 +63,6 @@ void XRPositionalTracker::_bind_methods() { ADD_SIGNAL(MethodInfo("profile_changed", PropertyInfo(Variant::STRING, "role"))); }; -void XRPositionalTracker::set_tracker_type(XRServer::TrackerType p_type) { - if (type != p_type) { - type = p_type; - hand = XRPositionalTracker::TRACKER_HAND_UNKNOWN; - }; -}; - -XRServer::TrackerType XRPositionalTracker::get_tracker_type() const { - return type; -}; - -void XRPositionalTracker::set_tracker_name(const StringName &p_name) { - // Note: this should not be changed after the tracker is registered with the XRServer! - name = p_name; -}; - -StringName XRPositionalTracker::get_tracker_name() const { - return name; -}; - -void XRPositionalTracker::set_tracker_desc(const String &p_desc) { - description = p_desc; -} - -String XRPositionalTracker::get_tracker_desc() const { - return description; -} - void XRPositionalTracker::set_tracker_profile(const String &p_profile) { if (profile != p_profile) { profile = p_profile; @@ -114,19 +76,12 @@ String XRPositionalTracker::get_tracker_profile() const { } XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const { - return hand; + return tracker_hand; }; void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) { - XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL(xr_server); - - if (hand != p_hand) { - // we can only set this if we've previously set this to be a controller!! - ERR_FAIL_COND((type != XRServer::TRACKER_CONTROLLER) && (p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN)); - - hand = p_hand; - }; + ERR_FAIL_INDEX(p_hand, TRACKER_HAND_MAX); + tracker_hand = p_hand; }; bool XRPositionalTracker::has_pose(const StringName &p_action_name) const { @@ -177,6 +132,11 @@ void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transf } Variant XRPositionalTracker::get_input(const StringName &p_action_name) const { + // Complain if this method is called on a XRPositionalTracker instance. + if (!dynamic_cast<const XRControllerTracker *>(this)) { + WARN_DEPRECATED_MSG(R"*(The "get_input()" method is deprecated, use "XRControllerTracker" instead.)*"); + } + if (inputs.has(p_action_name)) { return inputs[p_action_name]; } else { @@ -185,10 +145,13 @@ Variant XRPositionalTracker::get_input(const StringName &p_action_name) const { } void XRPositionalTracker::set_input(const StringName &p_action_name, const Variant &p_value) { - bool changed = false; + // Complain if this method is called on a XRPositionalTracker instance. + if (!dynamic_cast<XRControllerTracker *>(this)) { + WARN_DEPRECATED_MSG(R"*(The "set_input()" method is deprecated, use "XRControllerTracker" instead.)*"); + } // XR inputs - + bool changed; if (inputs.has(p_action_name)) { changed = inputs[p_action_name] != p_value; } else { @@ -227,9 +190,3 @@ void XRPositionalTracker::set_input(const StringName &p_action_name, const Varia } } } - -XRPositionalTracker::XRPositionalTracker() { - type = XRServer::TRACKER_UNKNOWN; - name = "Unknown"; - hand = TRACKER_HAND_UNKNOWN; -}; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index d8939b4582..9e4e4d1cc3 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -34,6 +34,7 @@ #include "core/os/thread_safe.h" #include "scene/resources/mesh.h" #include "servers/xr/xr_pose.h" +#include "servers/xr/xr_tracker.h" #include "servers/xr_server.h" /** @@ -42,41 +43,33 @@ This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking. */ -class XRPositionalTracker : public RefCounted { - GDCLASS(XRPositionalTracker, RefCounted); +class XRPositionalTracker : public XRTracker { + GDCLASS(XRPositionalTracker, XRTracker); _THREAD_SAFE_CLASS_ public: enum TrackerHand { TRACKER_HAND_UNKNOWN, /* unknown or not applicable */ TRACKER_HAND_LEFT, /* controller is the left hand controller */ - TRACKER_HAND_RIGHT /* controller is the right hand controller */ + TRACKER_HAND_RIGHT, /* controller is the right hand controller */ + TRACKER_HAND_MAX }; -private: - XRServer::TrackerType type; // type of tracker - StringName name; // (unique) name of the tracker - String description; // description of the tracker +protected: String profile; // this is interface dependent, for OpenXR this will be the interaction profile bound for to the tracker - TrackerHand hand; // if known, the hand this tracker is held in + TrackerHand tracker_hand = TRACKER_HAND_UNKNOWN; // if known, the hand this tracker is held in HashMap<StringName, Ref<XRPose>> poses; HashMap<StringName, Variant> inputs; -protected: static void _bind_methods(); public: - void set_tracker_type(XRServer::TrackerType p_type); - XRServer::TrackerType get_tracker_type() const; - void set_tracker_name(const StringName &p_name); - StringName get_tracker_name() const; - void set_tracker_desc(const String &p_desc); - String get_tracker_desc() const; void set_tracker_profile(const String &p_profile); String get_tracker_profile() const; + XRPositionalTracker::TrackerHand get_tracker_hand() const; - void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand); + virtual void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand); bool has_pose(const StringName &p_action_name) const; Ref<XRPose> get_pose(const StringName &p_action_name) const; @@ -85,9 +78,6 @@ public: Variant get_input(const StringName &p_action_name) const; void set_input(const StringName &p_action_name, const Variant &p_value); - - XRPositionalTracker(); - ~XRPositionalTracker() {} }; VARIANT_ENUM_CAST(XRPositionalTracker::TrackerHand); diff --git a/servers/xr/xr_tracker.cpp b/servers/xr/xr_tracker.cpp new file mode 100644 index 0000000000..0b917a5dc3 --- /dev/null +++ b/servers/xr/xr_tracker.cpp @@ -0,0 +1,70 @@ +/**************************************************************************/ +/* xr_tracker.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#include "xr_tracker.h" + +void XRTracker::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRTracker::get_tracker_type); + ClassDB::bind_method(D_METHOD("set_tracker_type", "type"), &XRTracker::set_tracker_type); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_tracker_type", "get_tracker_type"); + + ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRTracker::get_tracker_name); + ClassDB::bind_method(D_METHOD("set_tracker_name", "name"), &XRTracker::set_tracker_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_tracker_name", "get_tracker_name"); + + ClassDB::bind_method(D_METHOD("get_tracker_desc"), &XRTracker::get_tracker_desc); + ClassDB::bind_method(D_METHOD("set_tracker_desc", "description"), &XRTracker::set_tracker_desc); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_tracker_desc", "get_tracker_desc"); +}; + +void XRTracker::set_tracker_type(XRServer::TrackerType p_type) { + type = p_type; +}; + +XRServer::TrackerType XRTracker::get_tracker_type() const { + return type; +}; + +void XRTracker::set_tracker_name(const StringName &p_name) { + // Note: this should not be changed after the tracker is registered with the XRServer! + name = p_name; +}; + +StringName XRTracker::get_tracker_name() const { + return name; +}; + +void XRTracker::set_tracker_desc(const String &p_desc) { + description = p_desc; +} + +String XRTracker::get_tracker_desc() const { + return description; +} diff --git a/servers/xr/xr_tracker.h b/servers/xr/xr_tracker.h new file mode 100644 index 0000000000..3348e164d8 --- /dev/null +++ b/servers/xr/xr_tracker.h @@ -0,0 +1,61 @@ +/**************************************************************************/ +/* xr_tracker.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef XR_TRACKER_H +#define XR_TRACKER_H + +#include "core/os/thread_safe.h" +#include "servers/xr_server.h" + +/** + The XR tracker object is a common base for all different types of XR trackers. +*/ + +class XRTracker : public RefCounted { + GDCLASS(XRTracker, RefCounted); + _THREAD_SAFE_CLASS_ + +protected: + XRServer::TrackerType type = XRServer::TRACKER_UNKNOWN; // type of tracker + StringName name = "Unknown"; // (unique) name of the tracker + String description; // description of the tracker + + static void _bind_methods(); + +public: + virtual void set_tracker_type(XRServer::TrackerType p_type); + XRServer::TrackerType get_tracker_type() const; + void set_tracker_name(const StringName &p_name); + StringName get_tracker_name() const; + void set_tracker_desc(const String &p_desc); + String get_tracker_desc() const; +}; + +#endif // XR_TRACKER_H diff --git a/servers/xr_server.compat.inc b/servers/xr_server.compat.inc new file mode 100644 index 0000000000..967666fa6f --- /dev/null +++ b/servers/xr_server.compat.inc @@ -0,0 +1,51 @@ +/**************************************************************************/ +/* xr_server.compat.inc */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/**************************************************************************/ + +#ifndef DISABLE_DEPRECATED + +void XRServer::_add_tracker_bind_compat_90645(const Ref<XRPositionalTracker> &p_tracker) { + add_tracker(p_tracker); +} + +void XRServer::_remove_tracker_bind_compat_90645(const Ref<XRPositionalTracker> &p_tracker) { + remove_tracker(p_tracker); +} + +Ref<XRPositionalTracker> XRServer::_get_tracker_bind_compat_90645(const StringName &p_name) const { + return get_tracker(p_name); +} + +void XRServer::_bind_compatibility_methods() { + ClassDB::bind_compatibility_method(D_METHOD("add_tracker", "tracker"), &XRServer::_add_tracker_bind_compat_90645); + ClassDB::bind_compatibility_method(D_METHOD("remove_tracker", "tracker"), &XRServer::_remove_tracker_bind_compat_90645); + ClassDB::bind_compatibility_method(D_METHOD("get_tracker", "name"), &XRServer::_get_tracker_bind_compat_90645); +} + +#endif // DISABLE_DEPRECATED diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index af14ba4a00..f1105a650d 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -35,6 +35,7 @@ #include "xr/xr_hand_tracker.h" #include "xr/xr_interface.h" #include "xr/xr_positional_tracker.h" +#include "xr_server.compat.inc" XRServer::XRMode XRServer::xr_mode = XRMODE_DEFAULT; @@ -77,21 +78,6 @@ void XRServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_trackers", "tracker_types"), &XRServer::get_trackers); ClassDB::bind_method(D_METHOD("get_tracker", "tracker_name"), &XRServer::get_tracker); - ClassDB::bind_method(D_METHOD("add_hand_tracker", "tracker_name", "hand_tracker"), &XRServer::add_hand_tracker); - ClassDB::bind_method(D_METHOD("remove_hand_tracker", "tracker_name"), &XRServer::remove_hand_tracker); - ClassDB::bind_method(D_METHOD("get_hand_trackers"), &XRServer::get_hand_trackers); - ClassDB::bind_method(D_METHOD("get_hand_tracker", "tracker_name"), &XRServer::get_hand_tracker); - - ClassDB::bind_method(D_METHOD("add_face_tracker", "tracker_name", "face_tracker"), &XRServer::add_face_tracker); - ClassDB::bind_method(D_METHOD("remove_face_tracker", "tracker_name"), &XRServer::remove_face_tracker); - ClassDB::bind_method(D_METHOD("get_face_trackers"), &XRServer::get_face_trackers); - ClassDB::bind_method(D_METHOD("get_face_tracker", "tracker_name"), &XRServer::get_face_tracker); - - ClassDB::bind_method(D_METHOD("add_body_tracker", "tracker_name", "body_tracker"), &XRServer::add_body_tracker); - ClassDB::bind_method(D_METHOD("remove_body_tracker", "tracker_name"), &XRServer::remove_body_tracker); - ClassDB::bind_method(D_METHOD("get_body_trackers"), &XRServer::get_body_trackers); - ClassDB::bind_method(D_METHOD("get_body_tracker", "tracker_name"), &XRServer::get_body_tracker); - ClassDB::bind_method(D_METHOD("get_primary_interface"), &XRServer::get_primary_interface); ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface); @@ -101,6 +87,9 @@ void XRServer::_bind_methods() { BIND_ENUM_CONSTANT(TRACKER_CONTROLLER); BIND_ENUM_CONSTANT(TRACKER_BASESTATION); BIND_ENUM_CONSTANT(TRACKER_ANCHOR); + BIND_ENUM_CONSTANT(TRACKER_HAND); + BIND_ENUM_CONSTANT(TRACKER_BODY); + BIND_ENUM_CONSTANT(TRACKER_FACE); BIND_ENUM_CONSTANT(TRACKER_ANY_KNOWN); BIND_ENUM_CONSTANT(TRACKER_UNKNOWN); BIND_ENUM_CONSTANT(TRACKER_ANY); @@ -115,18 +104,6 @@ void XRServer::_bind_methods() { ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); ADD_SIGNAL(MethodInfo("tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); - - ADD_SIGNAL(MethodInfo("hand_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "hand_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRHandTracker"))); - ADD_SIGNAL(MethodInfo("hand_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "hand_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRHandTracker"))); - ADD_SIGNAL(MethodInfo("hand_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); - - ADD_SIGNAL(MethodInfo("face_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "face_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRFaceTracker"))); - ADD_SIGNAL(MethodInfo("face_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "face_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRFaceTracker"))); - ADD_SIGNAL(MethodInfo("face_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); - - ADD_SIGNAL(MethodInfo("body_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "body_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRBodyTracker"))); - ADD_SIGNAL(MethodInfo("body_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "body_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRBodyTracker"))); - ADD_SIGNAL(MethodInfo("body_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); }; double XRServer::get_world_scale() const { @@ -281,7 +258,7 @@ void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface } }; -void XRServer::add_tracker(Ref<XRPositionalTracker> p_tracker) { +void XRServer::add_tracker(const Ref<XRTracker> &p_tracker) { ERR_FAIL_COND(p_tracker.is_null()); StringName tracker_name = p_tracker->get_tracker_name(); @@ -297,7 +274,7 @@ void XRServer::add_tracker(Ref<XRPositionalTracker> p_tracker) { } }; -void XRServer::remove_tracker(Ref<XRPositionalTracker> p_tracker) { +void XRServer::remove_tracker(const Ref<XRTracker> &p_tracker) { ERR_FAIL_COND(p_tracker.is_null()); StringName tracker_name = p_tracker->get_tracker_name(); @@ -323,12 +300,12 @@ Dictionary XRServer::get_trackers(int p_tracker_types) { return res; } -Ref<XRPositionalTracker> XRServer::get_tracker(const StringName &p_name) const { +Ref<XRTracker> XRServer::get_tracker(const StringName &p_name) const { if (trackers.has(p_name)) { return trackers[p_name]; } else { // tracker hasn't been registered yet, which is fine, no need to spam the error log... - return Ref<XRPositionalTracker>(); + return Ref<XRTracker>(); } }; @@ -382,120 +359,6 @@ PackedStringArray XRServer::get_suggested_pose_names(const StringName &p_tracker return arr; } -void XRServer::add_hand_tracker(const StringName &p_tracker_name, Ref<XRHandTracker> p_hand_tracker) { - ERR_FAIL_COND(p_hand_tracker.is_null()); - - if (!hand_trackers.has(p_tracker_name)) { - // We don't have a tracker with this name, we're going to add it. - hand_trackers[p_tracker_name] = p_hand_tracker; - emit_signal(SNAME("hand_tracker_added"), p_tracker_name, p_hand_tracker); - } else if (hand_trackers[p_tracker_name] != p_hand_tracker) { - // We already have a tracker with this name, we're going to replace it. - hand_trackers[p_tracker_name] = p_hand_tracker; - emit_signal(SNAME("hand_tracker_updated"), p_tracker_name, p_hand_tracker); - } -} - -void XRServer::remove_hand_tracker(const StringName &p_tracker_name) { - // Skip if no hand tracker is found. - if (!hand_trackers.has(p_tracker_name)) { - return; - } - - // Send the removed signal, then remove the hand tracker. - emit_signal(SNAME("hand_tracker_removed"), p_tracker_name); - hand_trackers.erase(p_tracker_name); -} - -Dictionary XRServer::get_hand_trackers() const { - return hand_trackers; -} - -Ref<XRHandTracker> XRServer::get_hand_tracker(const StringName &p_tracker_name) const { - // Skip if no tracker is found. - if (!hand_trackers.has(p_tracker_name)) { - return Ref<XRHandTracker>(); - } - - return hand_trackers[p_tracker_name]; -} - -void XRServer::add_face_tracker(const StringName &p_tracker_name, Ref<XRFaceTracker> p_face_tracker) { - ERR_FAIL_COND(p_face_tracker.is_null()); - - if (!face_trackers.has(p_tracker_name)) { - // We don't have a tracker with this name, we're going to add it. - face_trackers[p_tracker_name] = p_face_tracker; - emit_signal(SNAME("face_tracker_added"), p_tracker_name, p_face_tracker); - } else if (face_trackers[p_tracker_name] != p_face_tracker) { - // We already have a tracker with this name, we're going to replace it. - face_trackers[p_tracker_name] = p_face_tracker; - emit_signal(SNAME("face_tracker_updated"), p_tracker_name, p_face_tracker); - } -} - -void XRServer::remove_face_tracker(const StringName &p_tracker_name) { - // Skip if no face tracker is found. - if (!face_trackers.has(p_tracker_name)) { - return; - } - - // Send the removed signal, then remove the face tracker. - emit_signal(SNAME("face_tracker_removed"), p_tracker_name); - face_trackers.erase(p_tracker_name); -} - -Dictionary XRServer::get_face_trackers() const { - return face_trackers; -} - -Ref<XRFaceTracker> XRServer::get_face_tracker(const StringName &p_tracker_name) const { - // Skip if no tracker is found. - if (!face_trackers.has(p_tracker_name)) { - return Ref<XRFaceTracker>(); - } - - return face_trackers[p_tracker_name]; -} - -void XRServer::add_body_tracker(const StringName &p_tracker_name, Ref<XRBodyTracker> p_body_tracker) { - ERR_FAIL_COND(p_body_tracker.is_null()); - - if (!body_trackers.has(p_tracker_name)) { - // We don't have a tracker with this name, we're going to add it. - body_trackers[p_tracker_name] = p_body_tracker; - emit_signal(SNAME("body_tracker_added"), p_tracker_name, p_body_tracker); - } else if (body_trackers[p_tracker_name] != p_body_tracker) { - // We already have a tracker with this name, we're going to replace it. - body_trackers[p_tracker_name] = p_body_tracker; - emit_signal(SNAME("body_tracker_updated"), p_tracker_name, p_body_tracker); - } -} - -void XRServer::remove_body_tracker(const StringName &p_tracker_name) { - // Skip if no face tracker is found. - if (!body_trackers.has(p_tracker_name)) { - return; - } - - // Send the removed signal, then remove the face tracker. - emit_signal(SNAME("body_tracker_removed"), p_tracker_name); - body_trackers.erase(p_tracker_name); -} - -Dictionary XRServer::get_body_trackers() const { - return body_trackers; -} - -Ref<XRBodyTracker> XRServer::get_body_tracker(const StringName &p_tracker_name) const { - // Skip if no tracker is found. - if (!body_trackers.has(p_tracker_name)) { - return Ref<XRBodyTracker>(); - } - - return body_trackers[p_tracker_name]; -} - void XRServer::_process() { // called from our main game loop before we handle physics and game logic // note that we can have multiple interfaces active if we have interfaces that purely handle tracking @@ -545,14 +408,8 @@ XRServer::XRServer() { XRServer::~XRServer() { primary_interface.unref(); - while (interfaces.size() > 0) { - interfaces.remove_at(0); - } - - // TODO pretty sure there is a clear function or something... - while (trackers.size() > 0) { - trackers.erase(trackers.get_key_at_index(0)); - } + interfaces.clear(); + trackers.clear(); singleton = nullptr; }; diff --git a/servers/xr_server.h b/servers/xr_server.h index 6aaa34b21d..717728171a 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -38,10 +38,8 @@ #include "core/variant/variant.h" class XRInterface; +class XRTracker; class XRPositionalTracker; -class XRHandTracker; -class XRFaceTracker; -class XRBodyTracker; /** The XR server is a singleton object that gives access to the various @@ -71,6 +69,9 @@ public: TRACKER_CONTROLLER = 0x02, /* tracks a controller */ TRACKER_BASESTATION = 0x04, /* tracks location of a base station */ TRACKER_ANCHOR = 0x08, /* tracks an anchor point, used in AR to track a real live location */ + TRACKER_HAND = 0x10, /* tracks a hand */ + TRACKER_BODY = 0x20, /* tracks a body */ + TRACKER_FACE = 0x40, /* tracks a face */ TRACKER_UNKNOWN = 0x80, /* unknown tracker */ TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */ @@ -88,9 +89,6 @@ private: Vector<Ref<XRInterface>> interfaces; Dictionary trackers; - Dictionary hand_trackers; - Dictionary face_trackers; - Dictionary body_trackers; Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ @@ -103,6 +101,13 @@ protected: static void _bind_methods(); +#ifndef DISABLE_DEPRECATED + static void _bind_compatibility_methods(); + void _add_tracker_bind_compat_90645(const Ref<XRPositionalTracker> &p_tracker); + void _remove_tracker_bind_compat_90645(const Ref<XRPositionalTracker> &p_tracker); + Ref<XRPositionalTracker> _get_tracker_bind_compat_90645(const StringName &p_name) const; +#endif + public: static XRMode get_xr_mode(); static void set_xr_mode(XRMode p_mode); @@ -174,13 +179,13 @@ public: void set_primary_interface(const Ref<XRInterface> &p_primary_interface); /* - Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc. + Our trackers are objects that expose tracked information about physical objects such as controller, anchor points, faces, hands etc. They are created and managed by our active AR/VR interfaces. */ - void add_tracker(Ref<XRPositionalTracker> p_tracker); - void remove_tracker(Ref<XRPositionalTracker> p_tracker); + void add_tracker(const Ref<XRTracker> &p_tracker); + void remove_tracker(const Ref<XRTracker> &p_tracker); Dictionary get_trackers(int p_tracker_types); - Ref<XRPositionalTracker> get_tracker(const StringName &p_name) const; + Ref<XRTracker> get_tracker(const StringName &p_name) const; /* We don't know which trackers and actions will existing during runtime but we can request suggested names from our interfaces to help our IDE UI. @@ -189,30 +194,6 @@ public: PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const; // Q: Should we add get_suggested_input_names and get_suggested_haptic_names even though we don't use them for the IDE? - /* - Hand trackers are objects that expose the tracked joints of a hand. - */ - void add_hand_tracker(const StringName &p_tracker_name, Ref<XRHandTracker> p_hand_tracker); - void remove_hand_tracker(const StringName &p_tracker_name); - Dictionary get_hand_trackers() const; - Ref<XRHandTracker> get_hand_tracker(const StringName &p_tracker_name) const; - - /* - Face trackers are objects that expose the tracked blend shapes of a face. - */ - void add_face_tracker(const StringName &p_tracker_name, Ref<XRFaceTracker> p_face_tracker); - void remove_face_tracker(const StringName &p_tracker_name); - Dictionary get_face_trackers() const; - Ref<XRFaceTracker> get_face_tracker(const StringName &p_tracker_name) const; - - /* - Body trackers are objects that expose the tracked joints of a body. - */ - void add_body_tracker(const StringName &p_tracker_name, Ref<XRBodyTracker> p_face_tracker); - void remove_body_tracker(const StringName &p_tracker_name); - Dictionary get_body_trackers() const; - Ref<XRBodyTracker> get_body_tracker(const StringName &p_tracker_name) const; - // Process is called before we handle our physics process and game process. This is where our interfaces will update controller data and such. void _process(); |
