summaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp7
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_parser.h1
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp9
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_settings.h1
-rw-r--r--modules/mbedtls/SCsub6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs10
-rw-r--r--modules/navigation/2d/nav_mesh_generator_2d.cpp144
-rw-r--r--modules/openxr/doc_classes/OpenXRHand.xml7
-rw-r--r--modules/openxr/scene/openxr_hand.cpp37
-rw-r--r--modules/openxr/scene/openxr_hand.h14
-rw-r--r--modules/openxr/util.h20
-rw-r--r--modules/text_server_adv/text_server_adv.cpp28
-rw-r--r--modules/text_server_adv/text_server_adv.h1
-rw-r--r--modules/text_server_fb/text_server_fb.cpp4
-rw-r--r--modules/text_server_fb/text_server_fb.h1
17 files changed, 170 insertions, 126 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 6af6460b31..f67f4913c3 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3293,6 +3293,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
if (get_function_signature(p_call, is_constructor, base_type, p_call->function_name, return_type, par_types, default_arg_count, method_flags)) {
// If the method is implemented in the class hierarchy, the virtual flag will not be set for that MethodInfo and the search stops there.
// Virtual check only possible for super() calls because class hierarchy is known. Node/Objects may have scripts attached we don't know of at compile-time.
+ p_call->is_static = method_flags.has_flag(METHOD_FLAG_STATIC);
if (p_call->is_super && method_flags.has_flag(METHOD_FLAG_VIRTUAL)) {
push_error(vformat(R"*(Cannot call the parent class' virtual function "%s()" because it hasn't been defined.)*", p_call->function_name), p_call);
}
@@ -3311,7 +3312,7 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
base_type.is_meta_type = false;
}
- if (is_self && static_context && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
+ if (is_self && static_context && !p_call->is_static) {
// Get the parent function above any lambda.
GDScriptParser::FunctionNode *parent_function = parser->current_function;
while (parent_function && parent_function->source_lambda) {
@@ -3323,10 +3324,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
} else {
push_error(vformat(R"*(Cannot call non-static function "%s()" from a static variable initializer.)*", p_call->function_name), p_call);
}
- } else if (!is_self && base_type.is_meta_type && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
+ } else if (!is_self && base_type.is_meta_type && !p_call->is_static) {
base_type.is_meta_type = false; // For `to_string()`.
push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call);
- } else if (is_self && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
+ } else if (is_self && !p_call->is_static) {
mark_lambda_use_self();
}
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 13ed66710c..d706c1b101 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -648,7 +648,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Not exact arguments, but still can use method bind call.
gen->write_call_method_bind(result, self, method, arguments);
}
- } else if (codegen.is_static || (codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
+ } else if (call->is_static || codegen.is_static || (codegen.function_node && codegen.function_node->is_static) || call->function_name == "new") {
GDScriptCodeGenerator::Address self;
self.mode = GDScriptCodeGenerator::Address::CLASS;
if (is_awaited) {
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index ea67f1eaff..d047fa8e46 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -498,6 +498,7 @@ public:
Vector<ExpressionNode *> arguments;
StringName function_name;
bool is_super = false;
+ bool is_static = false;
CallNode() {
type = CALL;
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
index b0283b0c55..d11300343a 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.cpp
@@ -84,6 +84,11 @@ void EditorSceneExporterGLTFSettings::_get_property_list(List<PropertyInfo> *p_l
}
}
+void EditorSceneExporterGLTFSettings::_on_extension_property_list_changed() {
+ generate_property_list(_document);
+ emit_signal("property_list_changed");
+}
+
bool EditorSceneExporterGLTFSettings::_set_extension_setting(const String &p_name_str, const Variant &p_value) {
PackedStringArray split = String(p_name_str).split("/", true, 1);
if (!_config_name_to_extension_map.has(split[0])) {
@@ -130,6 +135,10 @@ void EditorSceneExporterGLTFSettings::generate_property_list(Ref<GLTFDocument> p
String image_format_hint_string = "None,PNG,JPEG";
// Add properties from all document extensions.
for (Ref<GLTFDocumentExtension> &extension : GLTFDocument::get_all_gltf_document_extensions()) {
+ const Callable on_prop_changed = callable_mp(this, &EditorSceneExporterGLTFSettings::_on_extension_property_list_changed);
+ if (!extension->is_connected("property_list_changed", on_prop_changed)) {
+ extension->connect("property_list_changed", on_prop_changed);
+ }
const String config_prefix = get_friendly_config_prefix(extension);
_config_name_to_extension_map[config_prefix] = extension;
// If the extension allows saving in different image formats, add to the enum.
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h
index 6032932367..e1ce674274 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_settings.h
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_settings.h
@@ -48,6 +48,7 @@ protected:
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;
+ void _on_extension_property_list_changed();
bool _set_extension_setting(const String &p_name_str, const Variant &p_value);
bool _get_extension_setting(const String &p_name_str, Variant &r_ret) const;
diff --git a/modules/mbedtls/SCsub b/modules/mbedtls/SCsub
index 4b8f65d8ff..04d26f9942 100644
--- a/modules/mbedtls/SCsub
+++ b/modules/mbedtls/SCsub
@@ -100,9 +100,9 @@ if env["builtin_mbedtls"]:
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_mbed_tls.Prepend(CPPPATH=["#thirdparty/mbedtls/include/"])
- env_mbed_tls.Append(
- CPPDEFINES=[("MBEDTLS_CONFIG_FILE", '\\"thirdparty/mbedtls/include/godot_module_mbedtls_config.h\\"')]
- )
+ config_path = "thirdparty/mbedtls/include/godot_module_mbedtls_config.h"
+ config_path = f"<{config_path}>" if env_mbed_tls["ninja"] and env_mbed_tls.msvc else f'\\"{config_path}\\"'
+ env_mbed_tls.Append(CPPDEFINES=[("MBEDTLS_CONFIG_FILE", config_path)])
env_thirdparty = env_mbed_tls.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index bf6cab11c7..d3899c809a 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -167,8 +167,8 @@ namespace GodotTools
public void ShowConfirmCreateSlnDialog()
{
- _confirmCreateSlnDialog.Title = "C# solution already exists. This will override the existing C# project file, any manual changes will be lost.".TTR();
- _confirmCreateSlnDialog.DialogText = "Create C# solution".TTR();
+ _confirmCreateSlnDialog.Title = "Create C# solution".TTR();
+ _confirmCreateSlnDialog.DialogText = "C# solution already exists. This will override the existing C# project file, any manual changes will be lost.".TTR();
EditorInterface.Singleton.PopupDialogCentered(_confirmCreateSlnDialog);
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
index ef3c9c79d4..7a88fea5f1 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/DelegateUtils.cs
@@ -207,7 +207,7 @@ namespace Godot
foreach (FieldInfo field in fields)
{
- Type fieldType = field.GetType();
+ Type fieldType = field.FieldType;
Variant.Type variantType = GD.TypeToVariantType(fieldType);
@@ -216,7 +216,7 @@ namespace Godot
static byte[] VarToBytes(in godot_variant var)
{
- NativeFuncs.godotsharp_var_to_bytes(var, false.ToGodotBool(), out var varBytes);
+ NativeFuncs.godotsharp_var_to_bytes(var, godot_bool.True, out var varBytes);
using (varBytes)
return Marshaling.ConvertNativePackedByteArrayToSystemArray(varBytes);
}
@@ -483,7 +483,7 @@ namespace Godot
if (fieldInfo != null)
{
- var variantValue = GD.BytesToVar(valueBuffer);
+ var variantValue = GD.BytesToVarWithObjects(valueBuffer);
object? managedValue = RuntimeTypeConversionHelper.ConvertToObjectOfType(
(godot_variant)variantValue.NativeVar, fieldInfo.FieldType);
fieldInfo.SetValue(recreatedTarget, managedValue);
@@ -799,7 +799,7 @@ namespace Godot
return func(variant);
if (typeof(GodotObject).IsAssignableFrom(type))
- return Convert.ChangeType(VariantUtils.ConvertTo<GodotObject>(variant), type, CultureInfo.InvariantCulture);
+ return VariantUtils.ConvertTo<GodotObject>(variant);
if (typeof(GodotObject[]).IsAssignableFrom(type))
{
@@ -818,7 +818,7 @@ namespace Godot
}
using var godotArray = NativeFuncs.godotsharp_variant_as_array(variant);
- return Convert.ChangeType(ConvertToSystemArrayOfGodotObject(godotArray, type), type, CultureInfo.InvariantCulture);
+ return ConvertToSystemArrayOfGodotObject(godotArray, type);
}
if (type.IsEnum)
diff --git a/modules/navigation/2d/nav_mesh_generator_2d.cpp b/modules/navigation/2d/nav_mesh_generator_2d.cpp
index 069cc0f4a8..0738a102eb 100644
--- a/modules/navigation/2d/nav_mesh_generator_2d.cpp
+++ b/modules/navigation/2d/nav_mesh_generator_2d.cpp
@@ -575,8 +575,6 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo
return;
}
- int tilemap_layer = 0; // only main tile map layer is supported
-
Ref<TileSet> tile_set = tilemap->get_tileset();
if (!tile_set.is_valid()) {
return;
@@ -589,77 +587,115 @@ void NavMeshGenerator2D::generator_parse_tilemap_node(const Ref<NavigationPolygo
return;
}
- const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform();
- TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer);
+ HashSet<Vector2i> cells_with_navigation_polygon;
+ HashSet<Vector2i> cells_with_collision_polygon;
- for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
- const Vector2i &cell = used_cells[used_cell_index];
+ const Transform2D tilemap_xform = p_source_geometry_data->root_node_transform * tilemap->get_global_transform();
- const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
- if (tile_data == nullptr) {
- continue;
- }
+#ifdef DEBUG_ENABLED
+ int error_print_counter = 0;
+ int error_print_max = 10;
+#endif // DEBUG_ENABLED
- // Transform flags.
- const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false);
- bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
- bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
- bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
+ for (int tilemap_layer = 0; tilemap_layer < tilemap->get_layers_count(); tilemap_layer++) {
+ TypedArray<Vector2i> used_cells = tilemap->get_used_cells(tilemap_layer);
- Transform2D tile_transform;
- tile_transform.set_origin(tilemap->map_to_local(cell));
+ for (int used_cell_index = 0; used_cell_index < used_cells.size(); used_cell_index++) {
+ const Vector2i &cell = used_cells[used_cell_index];
- const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
+ const TileData *tile_data = tilemap->get_cell_tile_data(tilemap_layer, cell, false);
+ if (tile_data == nullptr) {
+ continue;
+ }
- if (navigation_layers_count > 0) {
- Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose);
- if (navigation_polygon.is_valid()) {
- for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
- const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
- if (navigation_polygon_outline.size() == 0) {
- continue;
+ // Transform flags.
+ const int alternative_id = tilemap->get_cell_alternative_tile(tilemap_layer, cell, false);
+ bool flip_h = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
+ bool flip_v = (alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
+ bool transpose = (alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
+
+ Transform2D tile_transform;
+ tile_transform.set_origin(tilemap->map_to_local(cell));
+
+ const Transform2D tile_transform_offset = tilemap_xform * tile_transform;
+
+ if (navigation_layers_count > 0) {
+ Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(tilemap_layer, flip_h, flip_v, transpose);
+ if (navigation_polygon.is_valid()) {
+ if (cells_with_navigation_polygon.has(cell)) {
+#ifdef DEBUG_ENABLED
+ error_print_counter++;
+ if (error_print_counter <= error_print_max) {
+ WARN_PRINT(vformat("TileMap navigation mesh baking error. The TileMap cell key Vector2i(%s, %s) has navigation mesh from 2 or more different TileMap layers assigned. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y));
+ }
+#endif // DEBUG_ENABLED
+ } else {
+ cells_with_navigation_polygon.insert(cell);
+
+ for (int outline_index = 0; outline_index < navigation_polygon->get_outline_count(); outline_index++) {
+ const Vector<Vector2> &navigation_polygon_outline = navigation_polygon->get_outline(outline_index);
+ if (navigation_polygon_outline.size() == 0) {
+ continue;
+ }
+
+ Vector<Vector2> traversable_outline;
+ traversable_outline.resize(navigation_polygon_outline.size());
+
+ const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
+ Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
+
+ for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
+ traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
+ }
+
+ p_source_geometry_data->_add_traversable_outline(traversable_outline);
+ }
}
+ }
+ }
- Vector<Vector2> traversable_outline;
- traversable_outline.resize(navigation_polygon_outline.size());
-
- const Vector2 *navigation_polygon_outline_ptr = navigation_polygon_outline.ptr();
- Vector2 *traversable_outline_ptrw = traversable_outline.ptrw();
-
- for (int traversable_outline_index = 0; traversable_outline_index < traversable_outline.size(); traversable_outline_index++) {
- traversable_outline_ptrw[traversable_outline_index] = tile_transform_offset.xform(navigation_polygon_outline_ptr[traversable_outline_index]);
+ if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) {
+ if (cells_with_collision_polygon.has(cell)) {
+#ifdef DEBUG_ENABLED
+ error_print_counter++;
+ if (error_print_counter <= error_print_max) {
+ WARN_PRINT(vformat("TileMap navigation mesh baking error. The cell key Vector2i(%s, %s) has collision polygons from 2 or more different TileMap layers assigned that all match the parsed collision mask. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", cell.x, cell.y));
}
+#endif // DEBUG_ENABLED
+ } else {
+ cells_with_collision_polygon.insert(cell);
- p_source_geometry_data->_add_traversable_outline(traversable_outline);
- }
- }
- }
+ for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
+ PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
+ if (collision_polygon_points.size() == 0) {
+ continue;
+ }
- if (physics_layers_count > 0 && (parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_STATIC_COLLIDERS || parsed_geometry_type == NavigationPolygon::PARSED_GEOMETRY_BOTH) && (tile_set->get_physics_layer_collision_layer(tilemap_layer) & parsed_collision_mask)) {
- for (int collision_polygon_index = 0; collision_polygon_index < tile_data->get_collision_polygons_count(tilemap_layer); collision_polygon_index++) {
- PackedVector2Array collision_polygon_points = tile_data->get_collision_polygon_points(tilemap_layer, collision_polygon_index);
- if (collision_polygon_points.size() == 0) {
- continue;
- }
+ if (flip_h || flip_v || transpose) {
+ collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
+ }
- if (flip_h || flip_v || transpose) {
- collision_polygon_points = TileData::get_transformed_vertices(collision_polygon_points, flip_h, flip_v, transpose);
- }
+ Vector<Vector2> obstruction_outline;
+ obstruction_outline.resize(collision_polygon_points.size());
- Vector<Vector2> obstruction_outline;
- obstruction_outline.resize(collision_polygon_points.size());
+ const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
+ Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
- const Vector2 *collision_polygon_points_ptr = collision_polygon_points.ptr();
- Vector2 *obstruction_outline_ptrw = obstruction_outline.ptrw();
+ for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
+ obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
+ }
- for (int obstruction_outline_index = 0; obstruction_outline_index < obstruction_outline.size(); obstruction_outline_index++) {
- obstruction_outline_ptrw[obstruction_outline_index] = tile_transform_offset.xform(collision_polygon_points_ptr[obstruction_outline_index]);
+ p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
+ }
}
-
- p_source_geometry_data->_add_obstruction_outline(obstruction_outline);
}
}
}
+#ifdef DEBUG_ENABLED
+ if (error_print_counter > error_print_max) {
+ ERR_PRINT(vformat("TileMap navigation mesh baking error. A total of %s cells with navigation or collision polygons from 2 or more different TileMap layers overlap. This can cause unexpected navigation mesh baking results. The duplicated cell data was ignored.", error_print_counter));
+ }
+#endif // DEBUG_ENABLED
}
void NavMeshGenerator2D::generator_parse_navigationobstacle_node(const Ref<NavigationPolygon> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData2D> p_source_geometry_data, Node *p_node) {
diff --git a/modules/openxr/doc_classes/OpenXRHand.xml b/modules/openxr/doc_classes/OpenXRHand.xml
index 23d932ddd7..9cc548dd6f 100644
--- a/modules/openxr/doc_classes/OpenXRHand.xml
+++ b/modules/openxr/doc_classes/OpenXRHand.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="OpenXRHand" inherits="Node3D" deprecated="Use [XRHandModifier3D] instead." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
+<class name="OpenXRHand" inherits="SkeletonModifier3D" deprecated="Use [XRHandModifier3D] instead." xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
<brief_description>
Node supporting hand and finger tracking in OpenXR.
</brief_description>
@@ -18,14 +18,11 @@
<member name="hand" type="int" setter="set_hand" getter="get_hand" enum="OpenXRHand.Hands" default="0">
Specifies whether this node tracks the left or right hand of the player.
</member>
- <member name="hand_skeleton" type="NodePath" setter="set_hand_skeleton" getter="get_hand_skeleton" default="NodePath(&quot;&quot;)">
- Set a [Skeleton3D] node for which the pose positions will be updated.
- </member>
<member name="motion_range" type="int" setter="set_motion_range" getter="get_motion_range" enum="OpenXRHand.MotionRange" default="0">
Set the motion range (if supported) limiting the hand motion.
</member>
<member name="skeleton_rig" type="int" setter="set_skeleton_rig" getter="get_skeleton_rig" enum="OpenXRHand.SkeletonRig" default="0">
- Set the type of skeleton rig the [member hand_skeleton] is compliant with.
+ Set the type of skeleton rig the parent [Skeleton3D] is compliant with.
</member>
</members>
<constants>
diff --git a/modules/openxr/scene/openxr_hand.cpp b/modules/openxr/scene/openxr_hand.cpp
index 2a4104f6ee..f20d1f8e19 100644
--- a/modules/openxr/scene/openxr_hand.cpp
+++ b/modules/openxr/scene/openxr_hand.cpp
@@ -40,9 +40,6 @@ void OpenXRHand::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_hand", "hand"), &OpenXRHand::set_hand);
ClassDB::bind_method(D_METHOD("get_hand"), &OpenXRHand::get_hand);
- ClassDB::bind_method(D_METHOD("set_hand_skeleton", "hand_skeleton"), &OpenXRHand::set_hand_skeleton);
- ClassDB::bind_method(D_METHOD("get_hand_skeleton"), &OpenXRHand::get_hand_skeleton);
-
ClassDB::bind_method(D_METHOD("set_motion_range", "motion_range"), &OpenXRHand::set_motion_range);
ClassDB::bind_method(D_METHOD("get_motion_range"), &OpenXRHand::get_motion_range);
@@ -54,7 +51,6 @@ void OpenXRHand::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Left,Right"), "set_hand", "get_hand");
ADD_PROPERTY(PropertyInfo(Variant::INT, "motion_range", PROPERTY_HINT_ENUM, "Unobstructed,Conform to controller"), "set_motion_range", "get_motion_range");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "hand_skeleton", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Skeleton3D"), "set_hand_skeleton", "get_hand_skeleton");
ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton_rig", PROPERTY_HINT_ENUM, "OpenXR,Humanoid"), "set_skeleton_rig", "get_skeleton_rig");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_update", PROPERTY_HINT_ENUM, "Full,Rotation Only"), "set_bone_update", "get_bone_update");
@@ -90,12 +86,6 @@ OpenXRHand::Hands OpenXRHand::get_hand() const {
return hand;
}
-void OpenXRHand::set_hand_skeleton(const NodePath &p_hand_skeleton) {
- hand_skeleton = p_hand_skeleton;
-
- // TODO if inside tree call _get_bones()
-}
-
void OpenXRHand::set_motion_range(MotionRange p_motion_range) {
ERR_FAIL_INDEX(p_motion_range, MOTION_RANGE_MAX);
motion_range = p_motion_range;
@@ -107,10 +97,6 @@ OpenXRHand::MotionRange OpenXRHand::get_motion_range() const {
return motion_range;
}
-NodePath OpenXRHand::get_hand_skeleton() const {
- return hand_skeleton;
-}
-
void OpenXRHand::_set_motion_range() {
if (!hand_tracking_ext) {
return;
@@ -152,20 +138,6 @@ OpenXRHand::BoneUpdate OpenXRHand::get_bone_update() const {
return bone_update;
}
-Skeleton3D *OpenXRHand::get_skeleton() {
- if (!has_node(hand_skeleton)) {
- return nullptr;
- }
-
- Node *node = get_node(hand_skeleton);
- if (!node) {
- return nullptr;
- }
-
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(node);
- return skeleton;
-}
-
void OpenXRHand::_get_joint_data() {
// Table of bone names for different rig types.
static const String bone_names[SKELETON_RIG_MAX][XR_HAND_JOINT_COUNT_EXT] = {
@@ -290,7 +262,7 @@ void OpenXRHand::_get_joint_data() {
}
}
-void OpenXRHand::_update_skeleton() {
+void OpenXRHand::_process_modification() {
if (openxr_api == nullptr || !openxr_api->is_initialized()) {
return;
} else if (hand_tracking_ext == nullptr || !hand_tracking_ext->get_active()) {
@@ -395,21 +367,14 @@ void OpenXRHand::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
_get_joint_data();
-
- set_process_internal(true);
} break;
case NOTIFICATION_EXIT_TREE: {
- set_process_internal(false);
-
// reset
for (int i = 0; i < XR_HAND_JOINT_COUNT_EXT; i++) {
joints[i].bone = -1;
joints[i].parent_joint = -1;
}
} break;
- case NOTIFICATION_INTERNAL_PROCESS: {
- _update_skeleton();
- } break;
default: {
} break;
}
diff --git a/modules/openxr/scene/openxr_hand.h b/modules/openxr/scene/openxr_hand.h
index 4c77e7277c..fc0a994f48 100644
--- a/modules/openxr/scene/openxr_hand.h
+++ b/modules/openxr/scene/openxr_hand.h
@@ -31,16 +31,15 @@
#ifndef OPENXR_HAND_H
#define OPENXR_HAND_H
-#include "scene/3d/node_3d.h"
-#include "scene/3d/skeleton_3d.h"
+#include "scene/3d/skeleton_modifier_3d.h"
#include <openxr/openxr.h>
class OpenXRAPI;
class OpenXRHandTrackingExtension;
-class OpenXRHand : public Node3D {
- GDCLASS(OpenXRHand, Node3D);
+class OpenXRHand : public SkeletonModifier3D {
+ GDCLASS(OpenXRHand, SkeletonModifier3D);
public:
enum Hands { // Deprecated, need to change this to OpenXRInterface::Hands.
@@ -86,13 +85,13 @@ private:
void _set_motion_range();
- Skeleton3D *get_skeleton();
void _get_joint_data();
- void _update_skeleton();
protected:
static void _bind_methods();
+ virtual void _process_modification() override;
+
public:
OpenXRHand();
@@ -102,9 +101,6 @@ public:
void set_motion_range(MotionRange p_motion_range);
MotionRange get_motion_range() const;
- void set_hand_skeleton(const NodePath &p_hand_skeleton);
- NodePath get_hand_skeleton() const;
-
void set_skeleton_rig(SkeletonRig p_skeleton_rig);
SkeletonRig get_skeleton_rig() const;
diff --git a/modules/openxr/util.h b/modules/openxr/util.h
index 7488b5cf8e..4c611d6f4a 100644
--- a/modules/openxr/util.h
+++ b/modules/openxr/util.h
@@ -34,21 +34,23 @@
#define UNPACK(...) __VA_ARGS__
#define INIT_XR_FUNC_V(openxr_api, name) \
- do { \
+ if constexpr (true) { \
XrResult get_instance_proc_addr_result; \
get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \
ERR_FAIL_COND_V(XR_FAILED(get_instance_proc_addr_result), false); \
- } while (0)
+ } else \
+ ((void)0)
#define EXT_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(OpenXRAPI::get_singleton(), name)
#define OPENXR_API_INIT_XR_FUNC_V(name) INIT_XR_FUNC_V(this, name)
#define INIT_XR_FUNC(openxr_api, name) \
- do { \
+ if constexpr (true) { \
XrResult get_instance_proc_addr_result; \
get_instance_proc_addr_result = openxr_api->get_instance_proc_addr(#name, (PFN_xrVoidFunction *)&name##_ptr); \
ERR_FAIL_COND(XR_FAILED(get_instance_proc_addr_result)); \
- } while (0)
+ } else \
+ ((void)0)
#define EXT_INIT_XR_FUNC(name) INIT_XR_FUNC(OpenXRAPI::get_singleton(), name)
#define OPENXR_API_INIT_XR_FUNC(name) INIT_XR_FUNC(this, name)
@@ -59,16 +61,18 @@
#define EXT_TRY_INIT_XR_FUNC(name) TRY_INIT_XR_FUNC(OpenXRAPI::get_singleton(), name)
#define OPENXR_TRY_API_INIT_XR_FUNC(name) TRY_INIT_XR_FUNC(this, name)
#define GDEXTENSION_INIT_XR_FUNC(name) \
- do { \
+ if constexpr (true) { \
name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \
ERR_FAIL_NULL(name##_ptr); \
- } while (0)
+ } else \
+ ((void)0)
#define GDEXTENSION_INIT_XR_FUNC_V(name) \
- do { \
+ if constexpr (true) { \
name##_ptr = reinterpret_cast<PFN_##name>(get_openxr_api()->get_instance_proc_addr(#name)); \
ERR_FAIL_NULL_V(name##_ptr, false); \
- } while (0)
+ } else \
+ ((void)0)
#define EXT_PROTO_XRRESULT_FUNC1(func_name, arg1_type, arg1) \
PFN_##func_name func_name##_ptr = nullptr; \
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index f5174d7d46..cc1ceec41e 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -6976,6 +6976,34 @@ String TextServerAdvanced::_string_to_lower(const String &p_string, const String
return String::utf16(lower.ptr(), len);
}
+String TextServerAdvanced::_string_to_title(const String &p_string, const String &p_language) const {
+#ifndef ICU_STATIC_DATA
+ if (!icu_data_loaded) {
+ return p_string.capitalize();
+ }
+#endif
+
+ if (p_string.is_empty()) {
+ return p_string;
+ }
+ const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
+
+ // Convert to UTF-16.
+ Char16String utf16 = p_string.utf16();
+
+ Vector<char16_t> upper;
+ UErrorCode err = U_ZERO_ERROR;
+ int32_t len = u_strToTitle(nullptr, 0, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);
+ ERR_FAIL_COND_V_MSG(err != U_BUFFER_OVERFLOW_ERROR, p_string, u_errorName(err));
+ upper.resize(len);
+ err = U_ZERO_ERROR;
+ u_strToTitle(upper.ptrw(), len, utf16.get_data(), -1, nullptr, lang.ascii().get_data(), &err);
+ ERR_FAIL_COND_V_MSG(U_FAILURE(err), p_string, u_errorName(err));
+
+ // Convert back to UTF-32.
+ return String::utf16(upper.ptr(), len);
+}
+
PackedInt32Array TextServerAdvanced::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {
const String lang = (p_language.is_empty()) ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
// Convert to UTF-16.
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 154fe670eb..160eb27528 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -991,6 +991,7 @@ public:
MODBIND2RC(String, string_to_upper, const String &, const String &);
MODBIND2RC(String, string_to_lower, const String &, const String &);
+ MODBIND2RC(String, string_to_title, const String &, const String &);
MODBIND0(cleanup);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 302bd677fe..1a0a4ec356 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -4439,6 +4439,10 @@ String TextServerFallback::_string_to_lower(const String &p_string, const String
return p_string.to_lower();
}
+String TextServerFallback::_string_to_title(const String &p_string, const String &p_language) const {
+ return p_string.capitalize();
+}
+
PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const {
PackedInt32Array ret;
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 0db1f7318f..9fd5af8b51 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -848,6 +848,7 @@ public:
MODBIND2RC(String, string_to_upper, const String &, const String &);
MODBIND2RC(String, string_to_lower, const String &, const String &);
+ MODBIND2RC(String, string_to_title, const String &, const String &);
MODBIND0(cleanup);