summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/bmp/image_loader_bmp.cpp2
-rw-r--r--modules/bullet/SCsub11
-rw-r--r--modules/bullet/bullet_physics_server.cpp370
-rw-r--r--modules/bullet/bullet_physics_server.h2
-rw-r--r--modules/bullet/rigid_body_bullet.cpp12
-rw-r--r--modules/bullet/shape_bullet.cpp24
-rw-r--r--modules/bullet/shape_bullet.h6
-rw-r--r--modules/bullet/soft_body_bullet.cpp67
-rw-r--r--modules/bullet/soft_body_bullet.h8
-rw-r--r--modules/bullet/space_bullet.cpp10
-rw-r--r--modules/csg/csg.cpp54
-rw-r--r--modules/csg/csg.h2
-rw-r--r--modules/csg/csg_shape.cpp454
-rw-r--r--modules/csg/csg_shape.h18
-rw-r--r--modules/csg/doc_classes/CSGBox3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGCombiner3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGCylinder3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGMesh3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGPolygon3D.xml17
-rw-r--r--modules/csg/doc_classes/CSGPrimitive3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGSphere3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGTorus3D.xml4
-rw-r--r--modules/enet/doc_classes/ENetConnection.xml6
-rw-r--r--modules/enet/doc_classes/ENetMultiplayerPeer.xml6
-rw-r--r--modules/enet/doc_classes/ENetPacketPeer.xml1
-rw-r--r--modules/enet/enet_multiplayer_peer.cpp41
-rw-r--r--modules/enet/enet_multiplayer_peer.h40
-rw-r--r--modules/etcpak/image_compress_etcpak.cpp4
-rw-r--r--modules/fbx/data/fbx_mesh_data.cpp7
-rw-r--r--modules/fbx/data/fbx_mesh_data.h6
-rw-r--r--modules/fbx/data/fbx_skeleton.cpp6
-rw-r--r--modules/fbx/doc_classes/EditorSceneImporterFBX.xml4
-rw-r--r--modules/fbx/editor_scene_importer_fbx.cpp40
-rw-r--r--modules/fbx/tools/validation_tools.h6
-rw-r--r--modules/gdnative/SCsub2
-rw-r--r--modules/gdnative/config.py5
-rw-r--r--modules/gdnative/doc_classes/GDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml6
-rw-r--r--modules/gdnative/doc_classes/NativeScript.xml4
-rw-r--r--modules/gdnative/doc_classes/PluginScript.xml2
-rw-r--r--modules/gdnative/doc_classes/VideoStreamGDNative.xml2
-rw-r--r--modules/gdnative/doc_classes/WebRTCDataChannelGDNative.xml13
-rw-r--r--modules/gdnative/doc_classes/WebRTCPeerConnectionGDNative.xml13
-rw-r--r--modules/gdnative/gdnative_api.json574
-rw-r--r--modules/gdnative/gdnative_builders.py2
-rw-r--r--modules/gdnative/gdnative_library_editor_plugin.cpp18
-rw-r--r--modules/gdnative/include/nativescript/godot_nativescript.h2
-rw-r--r--modules/gdnative/include/net/godot_net.h122
-rw-r--r--modules/gdnative/include/net/godot_webrtc.h123
-rw-r--r--modules/gdnative/include/text/godot_text.h283
-rw-r--r--modules/gdnative/nativescript/api_generator.cpp4
-rw-r--r--modules/gdnative/nativescript/nativescript.cpp124
-rw-r--r--modules/gdnative/net/SCsub12
-rw-r--r--modules/gdnative/net/multiplayer_peer_gdnative.cpp136
-rw-r--r--modules/gdnative/net/multiplayer_peer_gdnative.h79
-rw-r--r--modules/gdnative/net/packet_peer_gdnative.cpp72
-rw-r--r--modules/gdnative/net/register_types.cpp43
-rw-r--r--modules/gdnative/net/register_types.h37
-rw-r--r--modules/gdnative/net/stream_peer_gdnative.h60
-rw-r--r--modules/gdnative/register_types.cpp3
-rw-r--r--modules/gdnative/text/SCsub6
-rw-r--r--modules/gdnative/text/config.py6
-rw-r--r--modules/gdnative/text/register_types.cpp36
-rw-r--r--modules/gdnative/text/text_server_gdnative.cpp1086
-rw-r--r--modules/gdnative/text/text_server_gdnative.h254
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml17
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml4
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp8
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h4
-rw-r--r--modules/gdscript/gdscript.cpp163
-rw-r--r--modules/gdscript/gdscript.h1
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp321
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp68
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h7
-rw-r--r--modules/gdscript/gdscript_cache.cpp20
-rw-r--r--modules/gdscript/gdscript_cache.h1
-rw-r--r--modules/gdscript/gdscript_codegen.h1
-rw-r--r--modules/gdscript/gdscript_compiler.cpp163
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp8
-rw-r--r--modules/gdscript/gdscript_editor.cpp88
-rw-r--r--modules/gdscript/gdscript_function.cpp8
-rw-r--r--modules/gdscript/gdscript_function.h1
-rw-r--r--modules/gdscript/gdscript_parser.cpp308
-rw-r--r--modules/gdscript/gdscript_parser.h11
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp12
-rw-r--r--modules/gdscript/gdscript_vm.cpp39
-rw-r--r--modules/gdscript/gdscript_warning.cpp4
-rw-r--r--modules/gdscript/gdscript_warning.h1
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp9
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.h2
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp25
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.h3
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp7
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.h1
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp7
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp91
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h4
-rw-r--r--modules/gdscript/language_server/lsp.hpp32
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp21
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/constant_name_shadows_builtin_type.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/constant_name_shadows_builtin_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_name_shadows_builtin_type.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_name_shadows_builtin_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/missing_argument.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/missing_argument.out (renamed from modules/gdscript/tests/scripts/parser/errors/missing_argument.out)0
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/variable_name_shadows_builtin_type.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/variable_name_shadows_builtin_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/as.gd16
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/as.out8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/constants_from_parent.gd16
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/constants_from_parent.out4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_from_parent.gd14
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_from_parent.out4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_value_from_parent.gd14
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_value_from_parent.out4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd14
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_functions.gd16
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_functions.out3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_inline.gd46
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/property_inline.out10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/static_method_builtin_type.gd2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/static_method_builtin_type.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/subscript_self.gd8
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/subscript_self.out3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd10
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_in_if.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_in_if.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_in_var.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_in_var.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/brace_syntax.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/brace_syntax.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/invalid_escape_sequence.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/invalid_escape_sequence.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/invalid_ternary_operator.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/invalid_ternary_operator.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_argument.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_colon.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/redefine_keyword.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/redefine_keyword.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/subscript_without_index.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/subscript_without_index.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/vcs_conflict_marker.gd13
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/vcs_conflict_marker.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.gd34
-rw-r--r--modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out14
-rw-r--r--modules/gdscript/tests/scripts/parser/features/array.gd16
-rw-r--r--modules/gdscript/tests/scripts/parser/features/array.out11
-rw-r--r--modules/gdscript/tests/scripts/parser/features/basic_expression_matching.gd27
-rw-r--r--modules/gdscript/tests/scripts/parser/features/basic_expression_matching.out10
-rw-r--r--modules/gdscript/tests/scripts/parser/features/bitwise_operators.gd50
-rw-r--r--modules/gdscript/tests/scripts/parser/features/bitwise_operators.out14
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class.gd25
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class.out3
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class_inheritance.gd33
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class_inheritance.out10
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class_name.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class_name.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/concatenation.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/concatenation.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/constants.gd11
-rw-r--r--modules/gdscript/tests/scripts/parser/features/constants.out33
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary.gd37
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary.out14
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.gd9
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.gd12
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd20
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dollar_node_paths.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/enum.gd14
-rw-r--r--modules/gdscript/tests/scripts/parser/features/enum.out6
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable.gd18
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable.out8
-rw-r--r--modules/gdscript/tests/scripts/parser/features/float_notation.gd24
-rw-r--r--modules/gdscript/tests/scripts/parser/features/float_notation.out19
-rw-r--r--modules/gdscript/tests/scripts/parser/features/for_range.gd39
-rw-r--r--modules/gdscript/tests/scripts/parser/features/for_range.out58
-rw-r--r--modules/gdscript/tests/scripts/parser/features/function_default_parameter_type_inference.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/function_default_parameter_type_inference.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/function_many_parameters.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/function_many_parameters.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/in.gd14
-rw-r--r--modules/gdscript/tests/scripts/parser/features/in.out11
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_callable.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_callable.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_capture_callable.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_capture_callable.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_named_callable.gd10
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_named_callable.out3
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match.gd18
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_arrays.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_arrays.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.gd10
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_if.gd14
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_if.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_strings.gd15
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_strings.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_vector.gd17
-rw-r--r--modules/gdscript/tests/scripts/parser/features/multiline_vector.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_arithmetic.gd22
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_arithmetic.out82
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_array.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_array.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_dictionary.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_dictionary.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_function_calls.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_if.gd57
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_if.out21
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_match.gd79
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_match.out22
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_parentheses.gd65
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_parentheses.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/number_separators.gd12
-rw-r--r--modules/gdscript/tests/scripts/parser/features/number_separators.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/operator_assign.gd8
-rw-r--r--modules/gdscript/tests/scripts/parser/features/operator_assign.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd37
-rw-r--r--modules/gdscript/tests/scripts/parser/features/property_setter_getter.out19
-rw-r--r--modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.gd22
-rw-r--r--modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.out10
-rw-r--r--modules/gdscript/tests/scripts/parser/features/signal_declaration.gd20
-rw-r--r--modules/gdscript/tests/scripts/parser/features/signal_declaration.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/single_line_declaration.gd11
-rw-r--r--modules/gdscript/tests/scripts/parser/features/single_line_declaration.out3
-rw-r--r--modules/gdscript/tests/scripts/parser/features/space_indentation.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/space_indentation.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/features/static_typing.gd13
-rw-r--r--modules/gdscript/tests/scripts/parser/features/static_typing.out21
-rw-r--r--modules/gdscript/tests/scripts/parser/features/string_formatting.gd18
-rw-r--r--modules/gdscript/tests/scripts/parser/features/string_formatting.out11
-rw-r--r--modules/gdscript/tests/scripts/parser/features/super.gd60
-rw-r--r--modules/gdscript/tests/scripts/parser/features/super.out13
-rw-r--r--modules/gdscript/tests/scripts/parser/features/truthiness.gd30
-rw-r--r--modules/gdscript/tests/scripts/parser/features/truthiness.out65
-rw-r--r--modules/gdscript/tests/scripts/parser/features/typed_arrays.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/typed_arrays.out3
-rw-r--r--modules/gdscript/tests/scripts/parser/features/variable_declaration.gd22
-rw-r--r--modules/gdscript/tests/scripts/parser/features/variable_declaration.out6
-rw-r--r--modules/gdscript/tests/scripts/parser/features/while.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/while.out6
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/assert_always_true.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/assert_always_true.out13
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.gd8
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/empty_file.notest.gd1
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/empty_file.notest.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/empty_file_comment.notest.gd1
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/empty_file_comment.notest.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/empty_file_newline.notest.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/empty_file_newline.notest.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment.notest.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment.notest.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.gd8
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/integer_division.gd10
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/integer_division.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.gd9
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.out6
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.gd5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out1
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.gd8
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out9
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.gd8
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out9
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out9
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd9
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out21
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.gd7
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unused_argument.gd12
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unused_argument.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/void_assignment.out5
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd13
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out5
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd138
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out35
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd138
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out35
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd138
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out35
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd138
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out35
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/lua_assign.gd4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/lua_assign.out2
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/property_with_operator_assignment.gd11
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/property_with_operator_assignment.out8
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/recursion.gd19
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/recursion.out125
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.gd42
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.out34
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp4
-rw-r--r--modules/glslang/SCsub53
-rw-r--r--modules/gltf/config.py5
-rw-r--r--modules/gltf/doc_classes/EditorSceneImporterGLTF.xml4
-rw-r--r--modules/gltf/doc_classes/GLTFAccessor.xml4
-rw-r--r--modules/gltf/doc_classes/GLTFAnimation.xml4
-rw-r--r--modules/gltf/doc_classes/GLTFBufferView.xml4
-rw-r--r--modules/gltf/doc_classes/GLTFCamera.xml12
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml28
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml73
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml (renamed from modules/gdnative/doc_classes/PacketPeerGDNative.xml)6
-rw-r--r--modules/gltf/doc_classes/GLTFLight.xml22
-rw-r--r--modules/gltf/doc_classes/GLTFMesh.xml6
-rw-r--r--modules/gltf/doc_classes/GLTFNode.xml8
-rw-r--r--modules/gltf/doc_classes/GLTFSkeleton.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFSkin.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFSpecGloss.xml4
-rw-r--r--modules/gltf/doc_classes/GLTFState.xml2
-rw-r--r--modules/gltf/doc_classes/GLTFTexture.xml4
-rw-r--r--modules/gltf/doc_classes/PackedSceneGLTF.xml43
-rw-r--r--modules/gltf/editor_scene_exporter_gltf_plugin.cpp16
-rw-r--r--modules/gltf/editor_scene_exporter_gltf_plugin.h5
-rw-r--r--modules/gltf/editor_scene_importer_gltf.cpp118
-rw-r--r--modules/gltf/editor_scene_importer_gltf.h35
-rw-r--r--modules/gltf/gltf_accessor.cpp2
-rw-r--r--modules/gltf/gltf_accessor.h5
-rw-r--r--modules/gltf/gltf_animation.h2
-rw-r--r--modules/gltf/gltf_buffer_view.cpp2
-rw-r--r--modules/gltf/gltf_camera.cpp12
-rw-r--r--modules/gltf/gltf_camera.h12
-rw-r--r--modules/gltf/gltf_document.cpp1391
-rw-r--r--modules/gltf/gltf_document.h97
-rw-r--r--modules/gltf/gltf_document_extension.cpp (renamed from modules/gdnative/net/stream_peer_gdnative.cpp)77
-rw-r--r--modules/gltf/gltf_document_extension.h (renamed from modules/gdnative/net/packet_peer_gdnative.h)44
-rw-r--r--modules/gltf/gltf_document_extension_convert_importer_mesh.cpp (renamed from modules/gdnative/net/webrtc_gdnative.cpp)71
-rw-r--r--modules/gltf/gltf_document_extension_convert_importer_mesh.h (renamed from modules/stb_vorbis/register_types.cpp)41
-rw-r--r--modules/gltf/gltf_light.cpp14
-rw-r--r--modules/gltf/gltf_light.h14
-rw-r--r--modules/gltf/gltf_mesh.cpp6
-rw-r--r--modules/gltf/gltf_mesh.h9
-rw-r--r--modules/gltf/gltf_node.cpp14
-rw-r--r--modules/gltf/gltf_node.h7
-rw-r--r--modules/gltf/gltf_state.h7
-rw-r--r--modules/gltf/register_types.cpp5
-rw-r--r--modules/gridmap/grid_map.cpp111
-rw-r--r--modules/gridmap/grid_map_editor_plugin.cpp54
-rw-r--r--modules/gridmap/grid_map_editor_plugin.h4
-rw-r--r--modules/hdr/image_loader_hdr.cpp4
-rw-r--r--modules/lightmapper_rd/SCsub3
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp48
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.h11
-rw-r--r--modules/lightmapper_rd/lm_common_inc.glsl30
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl86
-rw-r--r--modules/minimp3/audio_stream_mp3.cpp2
-rw-r--r--modules/minimp3/doc_classes/AudioStreamMP3.xml4
-rw-r--r--modules/mobile_vr/doc_classes/MobileVRInterface.xml4
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp30
-rw-r--r--modules/mobile_vr/mobile_vr_interface.h46
-rw-r--r--modules/mobile_vr/register_types.cpp17
-rw-r--r--modules/mono/csharp_script.cpp68
-rw-r--r--modules/mono/csharp_script.h2
-rw-r--r--modules/mono/doc_classes/CSharpScript.xml2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs1
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs8
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs6
-rw-r--r--modules/mono/editor/bindings_generator.cpp2
-rw-r--r--modules/mono/editor/code_completion.cpp4
-rw-r--r--modules/mono/editor/editor_internal_calls.cpp7
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs94
-rw-r--r--modules/mono/godotsharp_dirs.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp8
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h4
-rw-r--r--modules/mono/utils/mono_reg_utils.cpp2
-rw-r--r--modules/mono/utils/path_utils.cpp1
-rw-r--r--modules/navigation/godot_navigation_server.cpp82
-rw-r--r--modules/navigation/nav_map.cpp16
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp2
-rw-r--r--modules/ogg/config.py11
-rw-r--r--modules/ogg/doc_classes/OGGPacketSequence.xml30
-rw-r--r--modules/ogg/doc_classes/OGGPacketSequencePlayback.xml (renamed from modules/gdnative/doc_classes/StreamPeerGDNative.xml)6
-rw-r--r--modules/ogg/ogg_packet_sequence.cpp220
-rw-r--r--modules/ogg/ogg_packet_sequence.h128
-rw-r--r--modules/ogg/register_types.cpp7
-rw-r--r--modules/opensimplex/doc_classes/NoiseTexture.xml4
-rw-r--r--modules/opensimplex/doc_classes/OpenSimplexNoise.xml2
-rw-r--r--modules/raycast/SCsub18
-rw-r--r--modules/raycast/godot_update_embree.py12
-rw-r--r--modules/raycast/lightmap_raycaster.cpp9
-rw-r--r--modules/raycast/lightmap_raycaster.h2
-rw-r--r--modules/raycast/raycast_occlusion_cull.cpp209
-rw-r--r--modules/raycast/raycast_occlusion_cull.h31
-rw-r--r--modules/raycast/register_types.cpp5
-rw-r--r--modules/raycast/static_raycaster.cpp137
-rw-r--r--modules/raycast/static_raycaster.h (renamed from modules/gdnative/text/register_types.h)39
-rw-r--r--modules/regex/doc_classes/RegEx.xml2
-rw-r--r--modules/regex/doc_classes/RegExMatch.xml2
-rw-r--r--modules/stb_vorbis/SCsub27
-rw-r--r--modules/stb_vorbis/audio_stream_ogg_vorbis.cpp278
-rw-r--r--modules/stb_vorbis/config.py16
-rw-r--r--modules/stb_vorbis/register_types.h37
-rw-r--r--modules/text_server_adv/SCsub1
-rw-r--r--modules/text_server_adv/config.py10
-rw-r--r--modules/text_server_adv/doc_classes/TextServerAdvanced.xml10
-rw-r--r--modules/text_server_adv/register_types.cpp7
-rw-r--r--modules/text_server_adv/script_iterator.cpp20
-rw-r--r--modules/text_server_adv/script_iterator.h2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp1096
-rw-r--r--modules/text_server_adv/text_server_adv.h136
-rw-r--r--modules/text_server_fb/config.py10
-rw-r--r--modules/text_server_fb/doc_classes/TextServerFallback.xml10
-rw-r--r--modules/text_server_fb/register_types.cpp7
-rw-r--r--modules/text_server_fb/text_server_fb.cpp755
-rw-r--r--modules/text_server_fb/text_server_fb.h98
-rw-r--r--modules/theora/doc_classes/VideoStreamTheora.xml2
-rw-r--r--modules/theora/video_stream_theora.cpp2
-rw-r--r--modules/upnp/doc_classes/UPNP.xml32
-rw-r--r--modules/vhacd/register_types.cpp69
-rw-r--r--modules/visual_script/config.py1
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml22
-rw-r--r--modules/visual_script/doc_classes/VisualScriptClassConstant.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptComment.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptComposeArray.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCondition.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstant.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptConstructor.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCustomNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptCustomNodes.xml37
-rw-r--r--modules/visual_script/doc_classes/VisualScriptDeconstruct.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEmitSignal.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptExpression.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunction.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionCall.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptFunctionState.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIndexGet.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIndexSet.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptInputAction.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptIterator.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLists.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVar.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptMathConstant.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptNode.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptOperator.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPreload.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertyGet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptPropertySet.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptResourcePath.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptReturn.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneNode.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSceneTree.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelect.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSelf.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSequence.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSubCall.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptSwitch.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptTypeCast.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableGet.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptVariableSet.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptWhile.xml4
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYield.xml2
-rw-r--r--modules/visual_script/doc_classes/VisualScriptYieldSignal.xml2
-rw-r--r--modules/visual_script/register_types.cpp2
-rw-r--r--modules/visual_script/visual_script.cpp32
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp15
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.h1
-rw-r--r--modules/visual_script/visual_script_editor.cpp66
-rw-r--r--modules/visual_script/visual_script_editor.h6
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp2
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp2
-rw-r--r--modules/vorbis/SCsub3
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp435
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.h (renamed from modules/stb_vorbis/audio_stream_ogg_vorbis.h)54
-rw-r--r--modules/vorbis/config.py11
-rw-r--r--modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml (renamed from modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml)12
-rw-r--r--modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml (renamed from modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml)6
-rw-r--r--modules/vorbis/register_types.cpp15
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.cpp (renamed from modules/stb_vorbis/resource_importer_ogg_vorbis.cpp)116
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.h (renamed from modules/stb_vorbis/resource_importer_ogg_vorbis.h)20
-rw-r--r--modules/webm/doc_classes/VideoStreamWebm.xml2
-rw-r--r--modules/webm/video_stream_webm.cpp2
-rw-r--r--modules/webrtc/SCsub5
-rw-r--r--modules/webrtc/config.py2
-rw-r--r--modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml106
-rw-r--r--modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml7
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnection.xml3
-rw-r--r--modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml71
-rw-r--r--modules/webrtc/register_types.cpp26
-rw-r--r--modules/webrtc/webrtc_data_channel_extension.cpp215
-rw-r--r--modules/webrtc/webrtc_data_channel_extension.h (renamed from modules/webrtc/webrtc_data_channel_gdnative.h)53
-rw-r--r--modules/webrtc/webrtc_data_channel_gdnative.cpp143
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.cpp70
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.h10
-rw-r--r--modules/webrtc/webrtc_peer_connection.cpp24
-rw-r--r--modules/webrtc/webrtc_peer_connection.h7
-rw-r--r--modules/webrtc/webrtc_peer_connection_extension.cpp131
-rw-r--r--modules/webrtc/webrtc_peer_connection_extension.h (renamed from modules/webrtc/webrtc_peer_connection_gdnative.h)47
-rw-r--r--modules/webrtc/webrtc_peer_connection_gdnative.cpp121
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.h3
-rw-r--r--modules/websocket/doc_classes/WebSocketClient.xml3
-rw-r--r--modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml7
-rw-r--r--modules/websocket/doc_classes/WebSocketPeer.xml2
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml3
-rw-r--r--modules/websocket/editor_debugger_server_websocket.cpp14
-rw-r--r--modules/websocket/editor_debugger_server_websocket.h2
-rw-r--r--modules/websocket/websocket_client.cpp2
-rw-r--r--modules/websocket/websocket_multiplayer_peer.cpp45
-rw-r--r--modules/websocket/websocket_multiplayer_peer.h7
-rw-r--r--modules/websocket/websocket_server.cpp8
-rw-r--r--modules/websocket/wsl_server.cpp12
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml2
-rw-r--r--modules/webxr/register_types.cpp21
-rw-r--r--modules/webxr/webxr_interface_js.cpp2
-rw-r--r--modules/webxr/webxr_interface_js.h2
-rw-r--r--modules/xatlas_unwrap/register_types.cpp2
638 files changed, 10334 insertions, 7735 deletions
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index 171895ed24..bd8342e1aa 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -91,11 +91,13 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
// the data width in case of 8/4/1 bit images
const uint32_t w = bits_per_pixel >= 24 ? width : width_bytes;
const uint8_t *line = p_buffer + (line_width * (height - 1));
+ const uint8_t *end_buffer = p_buffer + p_header.bmp_file_header.bmp_file_size - p_header.bmp_file_header.bmp_file_offset;
for (uint64_t i = 0; i < height; i++) {
const uint8_t *line_ptr = line;
for (unsigned int j = 0; j < w; j++) {
+ ERR_FAIL_COND_V(line_ptr >= end_buffer, ERR_FILE_CORRUPT);
switch (bits_per_pixel) {
case 1: {
uint8_t color_index = *line_ptr;
diff --git a/modules/bullet/SCsub b/modules/bullet/SCsub
index ba57de303e..09509abc44 100644
--- a/modules/bullet/SCsub
+++ b/modules/bullet/SCsub
@@ -10,7 +10,7 @@ env_bullet = env_modules.Clone()
thirdparty_obj = []
if env["builtin_bullet"]:
- # Build only version 2 for now (as of 2.89)
+ # Build only "Bullet2" API (not "Bullet3" folders).
# Sync file list with relevant upstream CMakeLists.txt for each folder.
if env["float"] == "64":
env.Append(CPPDEFINES=["BT_USE_DOUBLE_PRECISION=1"])
@@ -189,6 +189,7 @@ if env["builtin_bullet"]:
"LinearMath/btGeometryUtil.cpp",
"LinearMath/btPolarDecomposition.cpp",
"LinearMath/btQuickprof.cpp",
+ "LinearMath/btReducedVector.cpp",
"LinearMath/btSerializer.cpp",
"LinearMath/btSerializer64.cpp",
"LinearMath/btThreads.cpp",
@@ -200,15 +201,11 @@ if env["builtin_bullet"]:
thirdparty_sources = [thirdparty_dir + file for file in bullet2_src]
- # Treat Bullet headers as system headers to avoid raising warnings. Not supported on MSVC.
- if not env.msvc:
- env_bullet.Append(CPPFLAGS=["-isystem", Dir(thirdparty_dir).path])
- else:
- env_bullet.Prepend(CPPPATH=[thirdparty_dir])
+ env_bullet.Prepend(CPPPATH=[thirdparty_dir])
if env["target"] == "debug" or env["target"] == "release_debug":
env_bullet.Append(CPPDEFINES=["DEBUG"])
- env_bullet.Append(CPPDEFINES=["BT_USE_OLD_DAMPING_METHOD"])
+ env_bullet.Append(CPPDEFINES=["BT_USE_OLD_DAMPING_METHOD", "BT_THREADSAFE"])
env_thirdparty = env_bullet.Clone()
env_thirdparty.disable_warnings()
diff --git a/modules/bullet/bullet_physics_server.cpp b/modules/bullet/bullet_physics_server.cpp
index fc876a81cf..bb2db49c87 100644
--- a/modules/bullet/bullet_physics_server.cpp
+++ b/modules/bullet/bullet_physics_server.cpp
@@ -87,8 +87,8 @@ RID BulletPhysicsServer3D::shape_create(ShapeType p_shape) {
ShapeBullet *shape = nullptr;
switch (p_shape) {
- case SHAPE_PLANE: {
- shape = bulletnew(PlaneShapeBullet);
+ case SHAPE_WORLD_BOUNDARY: {
+ shape = bulletnew(WorldBoundaryShapeBullet);
} break;
case SHAPE_SPHERE: {
shape = bulletnew(SphereShapeBullet);
@@ -124,7 +124,7 @@ RID BulletPhysicsServer3D::shape_create(ShapeType p_shape) {
}
void BulletPhysicsServer3D::shape_set_data(RID p_shape, const Variant &p_data) {
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND(!shape);
shape->set_data(p_data);
}
@@ -134,25 +134,25 @@ void BulletPhysicsServer3D::shape_set_custom_solver_bias(RID p_shape, real_t p_b
}
PhysicsServer3D::ShapeType BulletPhysicsServer3D::shape_get_type(RID p_shape) const {
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND_V(!shape, PhysicsServer3D::SHAPE_CUSTOM);
return shape->get_type();
}
Variant BulletPhysicsServer3D::shape_get_data(RID p_shape) const {
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND_V(!shape, Variant());
return shape->get_data();
}
void BulletPhysicsServer3D::shape_set_margin(RID p_shape, real_t p_margin) {
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND(!shape);
shape->set_margin(p_margin);
}
real_t BulletPhysicsServer3D::shape_get_margin(RID p_shape) const {
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND_V(!shape, 0.0);
return shape->get_margin();
}
@@ -168,7 +168,7 @@ RID BulletPhysicsServer3D::space_create() {
}
void BulletPhysicsServer3D::space_set_active(RID p_space, bool p_active) {
- SpaceBullet *space = space_owner.getornull(p_space);
+ SpaceBullet *space = space_owner.get_or_null(p_space);
ERR_FAIL_COND(!space);
if (space_is_active(p_space) == p_active) {
@@ -185,47 +185,47 @@ void BulletPhysicsServer3D::space_set_active(RID p_space, bool p_active) {
}
bool BulletPhysicsServer3D::space_is_active(RID p_space) const {
- SpaceBullet *space = space_owner.getornull(p_space);
+ SpaceBullet *space = space_owner.get_or_null(p_space);
ERR_FAIL_COND_V(!space, false);
return -1 != active_spaces.find(space);
}
void BulletPhysicsServer3D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) {
- SpaceBullet *space = space_owner.getornull(p_space);
+ SpaceBullet *space = space_owner.get_or_null(p_space);
ERR_FAIL_COND(!space);
space->set_param(p_param, p_value);
}
real_t BulletPhysicsServer3D::space_get_param(RID p_space, SpaceParameter p_param) const {
- SpaceBullet *space = space_owner.getornull(p_space);
+ SpaceBullet *space = space_owner.get_or_null(p_space);
ERR_FAIL_COND_V(!space, 0);
return space->get_param(p_param);
}
PhysicsDirectSpaceState3D *BulletPhysicsServer3D::space_get_direct_state(RID p_space) {
- SpaceBullet *space = space_owner.getornull(p_space);
+ SpaceBullet *space = space_owner.get_or_null(p_space);
ERR_FAIL_COND_V(!space, nullptr);
return space->get_direct_state();
}
void BulletPhysicsServer3D::space_set_debug_contacts(RID p_space, int p_max_contacts) {
- SpaceBullet *space = space_owner.getornull(p_space);
+ SpaceBullet *space = space_owner.get_or_null(p_space);
ERR_FAIL_COND(!space);
space->set_debug_contacts(p_max_contacts);
}
Vector<Vector3> BulletPhysicsServer3D::space_get_contacts(RID p_space) const {
- SpaceBullet *space = space_owner.getornull(p_space);
+ SpaceBullet *space = space_owner.get_or_null(p_space);
ERR_FAIL_COND_V(!space, Vector<Vector3>());
return space->get_debug_contacts();
}
int BulletPhysicsServer3D::space_get_contact_count(RID p_space) const {
- SpaceBullet *space = space_owner.getornull(p_space);
+ SpaceBullet *space = space_owner.get_or_null(p_space);
ERR_FAIL_COND_V(!space, 0);
return space->get_debug_contact_count();
@@ -239,91 +239,91 @@ RID BulletPhysicsServer3D::area_create() {
}
void BulletPhysicsServer3D::area_set_space(RID p_area, RID p_space) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
SpaceBullet *space = nullptr;
if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
+ space = space_owner.get_or_null(p_space);
ERR_FAIL_COND(!space);
}
area->set_space(space);
}
RID BulletPhysicsServer3D::area_get_space(RID p_area) const {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
return area->get_space()->get_self();
}
void BulletPhysicsServer3D::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_spOv_mode(p_mode);
}
PhysicsServer3D::AreaSpaceOverrideMode BulletPhysicsServer3D::area_get_space_override_mode(RID p_area) const {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND_V(!area, PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED);
return area->get_spOv_mode();
}
void BulletPhysicsServer3D::area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform, bool p_disabled) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND(!shape);
area->add_shape(shape, p_transform, p_disabled);
}
void BulletPhysicsServer3D::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND(!shape);
area->set_shape(p_shape_idx, shape);
}
void BulletPhysicsServer3D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_shape_transform(p_shape_idx, p_transform);
}
int BulletPhysicsServer3D::area_get_shape_count(RID p_area) const {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND_V(!area, 0);
return area->get_shape_count();
}
RID BulletPhysicsServer3D::area_get_shape(RID p_area, int p_shape_idx) const {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND_V(!area, RID());
return area->get_shape(p_shape_idx)->get_self();
}
Transform3D BulletPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND_V(!area, Transform3D());
return area->get_shape_transform(p_shape_idx);
}
void BulletPhysicsServer3D::area_remove_shape(RID p_area, int p_shape_idx) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
return area->remove_shape_full(p_shape_idx);
}
void BulletPhysicsServer3D::area_clear_shapes(RID p_area) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
for (int i = area->get_shape_count(); 0 < i; --i) {
@@ -332,7 +332,7 @@ void BulletPhysicsServer3D::area_clear_shapes(RID p_area) {
}
void BulletPhysicsServer3D::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_shape_disabled(p_shape_idx, p_disabled);
@@ -342,7 +342,7 @@ void BulletPhysicsServer3D::area_attach_object_instance_id(RID p_area, ObjectID
if (space_owner.owns(p_area)) {
return;
}
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_instance_id(p_id);
}
@@ -351,19 +351,19 @@ ObjectID BulletPhysicsServer3D::area_get_object_instance_id(RID p_area) const {
if (space_owner.owns(p_area)) {
return ObjectID();
}
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND_V(!area, ObjectID());
return area->get_instance_id();
}
void BulletPhysicsServer3D::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) {
if (space_owner.owns(p_area)) {
- SpaceBullet *space = space_owner.getornull(p_area);
+ SpaceBullet *space = space_owner.get_or_null(p_area);
if (space) {
space->set_param(p_param, p_value);
}
} else {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_param(p_param, p_value);
@@ -372,10 +372,10 @@ void BulletPhysicsServer3D::area_set_param(RID p_area, AreaParameter p_param, co
Variant BulletPhysicsServer3D::area_get_param(RID p_area, AreaParameter p_param) const {
if (space_owner.owns(p_area)) {
- SpaceBullet *space = space_owner.getornull(p_area);
+ SpaceBullet *space = space_owner.get_or_null(p_area);
return space->get_param(p_param);
} else {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND_V(!area, Variant());
return area->get_param(p_param);
@@ -383,52 +383,52 @@ Variant BulletPhysicsServer3D::area_get_param(RID p_area, AreaParameter p_param)
}
void BulletPhysicsServer3D::area_set_transform(RID p_area, const Transform3D &p_transform) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_transform(p_transform);
}
Transform3D BulletPhysicsServer3D::area_get_transform(RID p_area) const {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND_V(!area, Transform3D());
return area->get_transform();
}
void BulletPhysicsServer3D::area_set_collision_mask(RID p_area, uint32_t p_mask) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_collision_mask(p_mask);
}
void BulletPhysicsServer3D::area_set_collision_layer(RID p_area, uint32_t p_layer) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_collision_layer(p_layer);
}
void BulletPhysicsServer3D::area_set_monitorable(RID p_area, bool p_monitorable) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_monitorable(p_monitorable);
}
void BulletPhysicsServer3D::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_event_callback(CollisionObjectBullet::TYPE_RIGID_BODY, p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
void BulletPhysicsServer3D::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_event_callback(CollisionObjectBullet::TYPE_AREA, p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method);
}
void BulletPhysicsServer3D::area_set_ray_pickable(RID p_area, bool p_enable) {
- AreaBullet *area = area_owner.getornull(p_area);
+ AreaBullet *area = area_owner.get_or_null(p_area);
ERR_FAIL_COND(!area);
area->set_ray_pickable(p_enable);
}
@@ -445,12 +445,12 @@ RID BulletPhysicsServer3D::body_create(BodyMode p_mode, bool p_init_sleeping) {
}
void BulletPhysicsServer3D::body_set_space(RID p_body, RID p_space) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
SpaceBullet *space = nullptr;
if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
+ space = space_owner.get_or_null(p_space);
ERR_FAIL_COND(!space);
}
@@ -462,7 +462,7 @@ void BulletPhysicsServer3D::body_set_space(RID p_body, RID p_space) {
}
RID BulletPhysicsServer3D::body_get_space(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, RID());
SpaceBullet *space = body->get_space();
@@ -473,52 +473,52 @@ RID BulletPhysicsServer3D::body_get_space(RID p_body) const {
}
void BulletPhysicsServer3D::body_set_mode(RID p_body, PhysicsServer3D::BodyMode p_mode) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_mode(p_mode);
}
PhysicsServer3D::BodyMode BulletPhysicsServer3D::body_get_mode(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, BODY_MODE_STATIC);
return body->get_mode();
}
void BulletPhysicsServer3D::body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform, bool p_disabled) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND(!shape);
body->add_shape(shape, p_transform, p_disabled);
}
void BulletPhysicsServer3D::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- ShapeBullet *shape = shape_owner.getornull(p_shape);
+ ShapeBullet *shape = shape_owner.get_or_null(p_shape);
ERR_FAIL_COND(!shape);
body->set_shape(p_shape_idx, shape);
}
void BulletPhysicsServer3D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_shape_transform(p_shape_idx, p_transform);
}
int BulletPhysicsServer3D::body_get_shape_count(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_shape_count();
}
RID BulletPhysicsServer3D::body_get_shape(RID p_body, int p_shape_idx) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, RID());
ShapeBullet *shape = body->get_shape(p_shape_idx);
@@ -528,27 +528,27 @@ RID BulletPhysicsServer3D::body_get_shape(RID p_body, int p_shape_idx) const {
}
Transform3D BulletPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, Transform3D());
return body->get_shape_transform(p_shape_idx);
}
void BulletPhysicsServer3D::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_shape_disabled(p_shape_idx, p_disabled);
}
void BulletPhysicsServer3D::body_remove_shape(RID p_body, int p_shape_idx) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->remove_shape_full(p_shape_idx);
}
void BulletPhysicsServer3D::body_clear_shapes(RID p_body) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->remove_all_shapes();
@@ -569,42 +569,42 @@ ObjectID BulletPhysicsServer3D::body_get_object_instance_id(RID p_body) const {
}
void BulletPhysicsServer3D::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_continuous_collision_detection(p_enable);
}
bool BulletPhysicsServer3D::body_is_continuous_collision_detection_enabled(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, false);
return body->is_continuous_collision_detection_enabled();
}
void BulletPhysicsServer3D::body_set_collision_layer(RID p_body, uint32_t p_layer) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_collision_layer(p_layer);
}
uint32_t BulletPhysicsServer3D::body_get_collision_layer(RID p_body) const {
- const RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ const RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_collision_layer();
}
void BulletPhysicsServer3D::body_set_collision_mask(RID p_body, uint32_t p_mask) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_collision_mask(p_mask);
}
uint32_t BulletPhysicsServer3D::body_get_collision_mask(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_collision_mask();
@@ -620,21 +620,21 @@ uint32_t BulletPhysicsServer3D::body_get_user_flags(RID p_body) const {
}
void BulletPhysicsServer3D::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_param(p_param, p_value);
}
real_t BulletPhysicsServer3D::body_get_param(RID p_body, BodyParameter p_param) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_param(p_param);
}
void BulletPhysicsServer3D::body_set_kinematic_safe_margin(RID p_body, real_t p_margin) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
if (body->get_kinematic_utilities()) {
@@ -643,7 +643,7 @@ void BulletPhysicsServer3D::body_set_kinematic_safe_margin(RID p_body, real_t p_
}
real_t BulletPhysicsServer3D::body_get_kinematic_safe_margin(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
if (body->get_kinematic_utilities()) {
@@ -654,90 +654,90 @@ real_t BulletPhysicsServer3D::body_get_kinematic_safe_margin(RID p_body) const {
}
void BulletPhysicsServer3D::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_state(p_state, p_variant);
}
Variant BulletPhysicsServer3D::body_get_state(RID p_body, BodyState p_state) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, Variant());
return body->get_state(p_state);
}
void BulletPhysicsServer3D::body_set_applied_force(RID p_body, const Vector3 &p_force) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_applied_force(p_force);
}
Vector3 BulletPhysicsServer3D::body_get_applied_force(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, Vector3());
return body->get_applied_force();
}
void BulletPhysicsServer3D::body_set_applied_torque(RID p_body, const Vector3 &p_torque) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_applied_torque(p_torque);
}
Vector3 BulletPhysicsServer3D::body_get_applied_torque(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, Vector3());
return body->get_applied_torque();
}
void BulletPhysicsServer3D::body_add_central_force(RID p_body, const Vector3 &p_force) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->apply_central_force(p_force);
}
void BulletPhysicsServer3D::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->apply_force(p_force, p_position);
}
void BulletPhysicsServer3D::body_add_torque(RID p_body, const Vector3 &p_torque) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->apply_torque(p_torque);
}
void BulletPhysicsServer3D::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->apply_central_impulse(p_impulse);
}
void BulletPhysicsServer3D::body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->apply_impulse(p_impulse, p_position);
}
void BulletPhysicsServer3D::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->apply_torque_impulse(p_impulse);
}
void BulletPhysicsServer3D::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
Vector3 v = body->get_linear_velocity();
@@ -748,39 +748,39 @@ void BulletPhysicsServer3D::body_set_axis_velocity(RID p_body, const Vector3 &p_
}
void BulletPhysicsServer3D::body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_axis_lock(p_axis, p_lock);
}
bool BulletPhysicsServer3D::body_is_axis_locked(RID p_body, BodyAxis p_axis) const {
- const RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ const RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->is_axis_locked(p_axis);
}
void BulletPhysicsServer3D::body_add_collision_exception(RID p_body, RID p_body_b) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- RigidBodyBullet *other_body = rigid_body_owner.getornull(p_body_b);
+ RigidBodyBullet *other_body = rigid_body_owner.get_or_null(p_body_b);
ERR_FAIL_COND(!other_body);
body->add_collision_exception(other_body);
}
void BulletPhysicsServer3D::body_remove_collision_exception(RID p_body, RID p_body_b) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- RigidBodyBullet *other_body = rigid_body_owner.getornull(p_body_b);
+ RigidBodyBullet *other_body = rigid_body_owner.get_or_null(p_body_b);
ERR_FAIL_COND(!other_body);
body->remove_collision_exception(other_body);
}
void BulletPhysicsServer3D::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
for (int i = 0; i < body->get_exceptions().size(); i++) {
p_exceptions->push_back(body->get_exceptions()[i]);
@@ -788,14 +788,14 @@ void BulletPhysicsServer3D::body_get_collision_exceptions(RID p_body, List<RID>
}
void BulletPhysicsServer3D::body_set_max_contacts_reported(RID p_body, int p_contacts) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_max_collisions_detection(p_contacts);
}
int BulletPhysicsServer3D::body_get_max_contacts_reported(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_max_collisions_detection();
@@ -811,39 +811,39 @@ real_t BulletPhysicsServer3D::body_get_contacts_reported_depth_threshold(RID p_b
}
void BulletPhysicsServer3D::body_set_omit_force_integration(RID p_body, bool p_omit) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_omit_forces_integration(p_omit);
}
bool BulletPhysicsServer3D::body_is_omitting_force_integration(RID p_body) const {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, false);
return body->get_omit_forces_integration();
}
void BulletPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_force_integration_callback(p_callable, p_udata);
}
void BulletPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_ray_pickable(p_enable);
}
PhysicsDirectBodyState3D *BulletPhysicsServer3D::body_get_direct_state(RID p_body) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, nullptr);
return BulletPhysicsDirectBodyState3D::get_singleton(body);
}
bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result, bool p_exclude_raycast_shapes, const Set<RID> &p_exclude) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, false);
ERR_FAIL_COND_V(!body->get_space(), false);
@@ -851,7 +851,7 @@ bool BulletPhysicsServer3D::body_test_motion(RID p_body, const Transform3D &p_fr
}
int BulletPhysicsServer3D::body_test_ray_separation(RID p_body, const Transform3D &p_transform, bool p_infinite_inertia, Vector3 &r_recover_motion, SeparationResult *r_results, int p_result_max, real_t p_margin) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_body);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
ERR_FAIL_COND_V(!body->get_space(), 0);
@@ -869,19 +869,19 @@ RID BulletPhysicsServer3D::soft_body_create(bool p_init_sleeping) {
}
void BulletPhysicsServer3D::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->update_rendering_server(p_rendering_server_handler);
}
void BulletPhysicsServer3D::soft_body_set_space(RID p_body, RID p_space) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
SpaceBullet *space = nullptr;
if (p_space.is_valid()) {
- space = space_owner.getornull(p_space);
+ space = space_owner.get_or_null(p_space);
ERR_FAIL_COND(!space);
}
@@ -893,7 +893,7 @@ void BulletPhysicsServer3D::soft_body_set_space(RID p_body, RID p_space) {
}
RID BulletPhysicsServer3D::soft_body_get_space(RID p_body) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, RID());
SpaceBullet *space = body->get_space();
@@ -903,8 +903,8 @@ RID BulletPhysicsServer3D::soft_body_get_space(RID p_body) const {
return space->get_self();
}
-void BulletPhysicsServer3D::soft_body_set_mesh(RID p_body, const REF &p_mesh) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+void BulletPhysicsServer3D::soft_body_set_mesh(RID p_body, RID p_mesh) {
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_soft_mesh(p_mesh);
@@ -918,40 +918,40 @@ AABB BulletPhysicsServer::soft_body_get_bounds(RID p_body) const {
}
void BulletPhysicsServer3D::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_collision_layer(p_layer);
}
uint32_t BulletPhysicsServer3D::soft_body_get_collision_layer(RID p_body) const {
- const SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ const SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_collision_layer();
}
void BulletPhysicsServer3D::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_collision_mask(p_mask);
}
uint32_t BulletPhysicsServer3D::soft_body_get_collision_mask(RID p_body) const {
- const SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ const SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0);
return body->get_collision_mask();
}
void BulletPhysicsServer3D::soft_body_add_collision_exception(RID p_body, RID p_body_b) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- CollisionObjectBullet *other_body = rigid_body_owner.getornull(p_body_b);
+ CollisionObjectBullet *other_body = rigid_body_owner.get_or_null(p_body_b);
if (!other_body) {
- other_body = soft_body_owner.getornull(p_body_b);
+ other_body = soft_body_owner.get_or_null(p_body_b);
}
ERR_FAIL_COND(!other_body);
@@ -959,12 +959,12 @@ void BulletPhysicsServer3D::soft_body_add_collision_exception(RID p_body, RID p_
}
void BulletPhysicsServer3D::soft_body_remove_collision_exception(RID p_body, RID p_body_b) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
- CollisionObjectBullet *other_body = rigid_body_owner.getornull(p_body_b);
+ CollisionObjectBullet *other_body = rigid_body_owner.get_or_null(p_body_b);
if (!other_body) {
- other_body = soft_body_owner.getornull(p_body_b);
+ other_body = soft_body_owner.get_or_null(p_body_b);
}
ERR_FAIL_COND(!other_body);
@@ -972,7 +972,7 @@ void BulletPhysicsServer3D::soft_body_remove_collision_exception(RID p_body, RID
}
void BulletPhysicsServer3D::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
for (int i = 0; i < body->get_exceptions().size(); i++) {
p_exceptions->push_back(body->get_exceptions()[i]);
@@ -991,98 +991,98 @@ Variant BulletPhysicsServer3D::soft_body_get_state(RID p_body, BodyState p_state
}
void BulletPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform3D &p_transform) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_soft_transform(p_transform);
}
void BulletPhysicsServer3D::soft_body_set_ray_pickable(RID p_body, bool p_enable) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_ray_pickable(p_enable);
}
void BulletPhysicsServer3D::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_simulation_precision(p_simulation_precision);
}
int BulletPhysicsServer3D::soft_body_get_simulation_precision(RID p_body) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_simulation_precision();
}
void BulletPhysicsServer3D::soft_body_set_total_mass(RID p_body, real_t p_total_mass) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_total_mass(p_total_mass);
}
real_t BulletPhysicsServer3D::soft_body_get_total_mass(RID p_body) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_total_mass();
}
void BulletPhysicsServer3D::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_linear_stiffness(p_stiffness);
}
real_t BulletPhysicsServer3D::soft_body_get_linear_stiffness(RID p_body) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_linear_stiffness();
}
void BulletPhysicsServer3D::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_pressure_coefficient(p_pressure_coefficient);
}
real_t BulletPhysicsServer3D::soft_body_get_pressure_coefficient(RID p_body) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_pressure_coefficient();
}
void BulletPhysicsServer3D::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_damping_coefficient(p_damping_coefficient);
}
real_t BulletPhysicsServer3D::soft_body_get_damping_coefficient(RID p_body) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_damping_coefficient();
}
void BulletPhysicsServer3D::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_drag_coefficient(p_drag_coefficient);
}
real_t BulletPhysicsServer3D::soft_body_get_drag_coefficient(RID p_body) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_drag_coefficient();
}
void BulletPhysicsServer3D::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_node_position(p_point_index, p_global_position);
}
Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, int p_point_index) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, Vector3(0., 0., 0.));
Vector3 pos;
body->get_node_position(p_point_index, pos);
@@ -1090,25 +1090,25 @@ Vector3 BulletPhysicsServer3D::soft_body_get_point_global_position(RID p_body, i
}
void BulletPhysicsServer3D::soft_body_remove_all_pinned_points(RID p_body) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->reset_all_node_mass();
}
void BulletPhysicsServer3D::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND(!body);
body->set_node_mass(p_point_index, p_pin ? 0 : 1);
}
bool BulletPhysicsServer3D::soft_body_is_point_pinned(RID p_body, int p_point_index) const {
- SoftBodyBullet *body = soft_body_owner.getornull(p_body);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_body);
ERR_FAIL_COND_V(!body, 0.f);
return body->get_node_mass(p_point_index);
}
PhysicsServer3D::JointType BulletPhysicsServer3D::joint_get_type(RID p_joint) const {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, JOINT_PIN);
return joint->get_type();
}
@@ -1123,28 +1123,28 @@ int BulletPhysicsServer3D::joint_get_solver_priority(RID p_joint) const {
}
void BulletPhysicsServer3D::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
joint->disable_collisions_between_bodies(p_disable);
}
bool BulletPhysicsServer3D::joint_is_disabled_collisions_between_bodies(RID p_joint) const {
- JointBullet *joint(joint_owner.getornull(p_joint));
+ JointBullet *joint(joint_owner.get_or_null(p_joint));
ERR_FAIL_COND_V(!joint, false);
return joint->is_disabled_collisions_between_bodies();
}
RID BulletPhysicsServer3D::joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) {
- RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
+ RigidBodyBullet *body_A = rigid_body_owner.get_or_null(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
- body_B = rigid_body_owner.getornull(p_body_B);
+ body_B = rigid_body_owner.get_or_null(p_body_B);
JointAssertSpace(body_B, "B", RID());
JointAssertSameSpace(body_A, body_B, RID());
}
@@ -1158,7 +1158,7 @@ RID BulletPhysicsServer3D::joint_create_pin(RID p_body_A, const Vector3 &p_local
}
void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
@@ -1166,7 +1166,7 @@ void BulletPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_par
}
real_t BulletPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, 0);
PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
@@ -1174,7 +1174,7 @@ real_t BulletPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_p
}
void BulletPhysicsServer3D::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
@@ -1182,7 +1182,7 @@ void BulletPhysicsServer3D::pin_joint_set_local_a(RID p_joint, const Vector3 &p_
}
Vector3 BulletPhysicsServer3D::pin_joint_get_local_a(RID p_joint) const {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, Vector3());
ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
@@ -1190,7 +1190,7 @@ Vector3 BulletPhysicsServer3D::pin_joint_get_local_a(RID p_joint) const {
}
void BulletPhysicsServer3D::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_PIN);
PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
@@ -1198,7 +1198,7 @@ void BulletPhysicsServer3D::pin_joint_set_local_b(RID p_joint, const Vector3 &p_
}
Vector3 BulletPhysicsServer3D::pin_joint_get_local_b(RID p_joint) const {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, Vector3());
ERR_FAIL_COND_V(joint->get_type() != JOINT_PIN, Vector3());
PinJointBullet *pin_joint = static_cast<PinJointBullet *>(joint);
@@ -1206,13 +1206,13 @@ Vector3 BulletPhysicsServer3D::pin_joint_get_local_b(RID p_joint) const {
}
RID BulletPhysicsServer3D::joint_create_hinge(RID p_body_A, const Transform3D &p_hinge_A, RID p_body_B, const Transform3D &p_hinge_B) {
- RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
+ RigidBodyBullet *body_A = rigid_body_owner.get_or_null(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
- body_B = rigid_body_owner.getornull(p_body_B);
+ body_B = rigid_body_owner.get_or_null(p_body_B);
JointAssertSpace(body_B, "B", RID());
JointAssertSameSpace(body_A, body_B, RID());
}
@@ -1226,13 +1226,13 @@ RID BulletPhysicsServer3D::joint_create_hinge(RID p_body_A, const Transform3D &p
}
RID BulletPhysicsServer3D::joint_create_hinge_simple(RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) {
- RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
+ RigidBodyBullet *body_A = rigid_body_owner.get_or_null(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
- body_B = rigid_body_owner.getornull(p_body_B);
+ body_B = rigid_body_owner.get_or_null(p_body_B);
JointAssertSpace(body_B, "B", RID());
JointAssertSameSpace(body_A, body_B, RID());
}
@@ -1246,7 +1246,7 @@ RID BulletPhysicsServer3D::joint_create_hinge_simple(RID p_body_A, const Vector3
}
void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint);
@@ -1254,7 +1254,7 @@ void BulletPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p
}
real_t BulletPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, 0);
HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint);
@@ -1262,7 +1262,7 @@ real_t BulletPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam
}
void BulletPhysicsServer3D::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_HINGE);
HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint);
@@ -1270,7 +1270,7 @@ void BulletPhysicsServer3D::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_f
}
bool BulletPhysicsServer3D::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, false);
ERR_FAIL_COND_V(joint->get_type() != JOINT_HINGE, false);
HingeJointBullet *hinge_joint = static_cast<HingeJointBullet *>(joint);
@@ -1278,13 +1278,13 @@ bool BulletPhysicsServer3D::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_f
}
RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) {
- RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
+ RigidBodyBullet *body_A = rigid_body_owner.get_or_null(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
- body_B = rigid_body_owner.getornull(p_body_B);
+ body_B = rigid_body_owner.get_or_null(p_body_B);
JointAssertSpace(body_B, "B", RID());
JointAssertSameSpace(body_A, body_B, RID());
}
@@ -1298,7 +1298,7 @@ RID BulletPhysicsServer3D::joint_create_slider(RID p_body_A, const Transform3D &
}
void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_SLIDER);
SliderJointBullet *slider_joint = static_cast<SliderJointBullet *>(joint);
@@ -1306,7 +1306,7 @@ void BulletPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam
}
real_t BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_SLIDER, 0);
SliderJointBullet *slider_joint = static_cast<SliderJointBullet *>(joint);
@@ -1314,13 +1314,13 @@ real_t BulletPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointPar
}
RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) {
- RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
+ RigidBodyBullet *body_A = rigid_body_owner.get_or_null(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
- body_B = rigid_body_owner.getornull(p_body_B);
+ body_B = rigid_body_owner.get_or_null(p_body_B);
JointAssertSpace(body_B, "B", RID());
JointAssertSameSpace(body_A, body_B, RID());
}
@@ -1332,7 +1332,7 @@ RID BulletPhysicsServer3D::joint_create_cone_twist(RID p_body_A, const Transform
}
void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_CONE_TWIST);
ConeTwistJointBullet *coneTwist_joint = static_cast<ConeTwistJointBullet *>(joint);
@@ -1340,7 +1340,7 @@ void BulletPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJoi
}
real_t BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, 0.);
ERR_FAIL_COND_V(joint->get_type() != JOINT_CONE_TWIST, 0.);
ConeTwistJointBullet *coneTwist_joint = static_cast<ConeTwistJointBullet *>(joint);
@@ -1348,13 +1348,13 @@ real_t BulletPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJ
}
RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) {
- RigidBodyBullet *body_A = rigid_body_owner.getornull(p_body_A);
+ RigidBodyBullet *body_A = rigid_body_owner.get_or_null(p_body_A);
ERR_FAIL_COND_V(!body_A, RID());
JointAssertSpace(body_A, "A", RID());
RigidBodyBullet *body_B = nullptr;
if (p_body_B.is_valid()) {
- body_B = rigid_body_owner.getornull(p_body_B);
+ body_B = rigid_body_owner.get_or_null(p_body_B);
JointAssertSpace(body_B, "B", RID());
JointAssertSameSpace(body_A, body_B, RID());
}
@@ -1368,7 +1368,7 @@ RID BulletPhysicsServer3D::joint_create_generic_6dof(RID p_body_A, const Transfo
}
void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
@@ -1376,7 +1376,7 @@ void BulletPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::A
}
real_t BulletPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, 0);
ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, 0);
Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
@@ -1384,7 +1384,7 @@ real_t BulletPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3:
}
void BulletPhysicsServer3D::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND(!joint);
ERR_FAIL_COND(joint->get_type() != JOINT_6DOF);
Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
@@ -1392,7 +1392,7 @@ void BulletPhysicsServer3D::generic_6dof_joint_set_flag(RID p_joint, Vector3::Ax
}
bool BulletPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) {
- JointBullet *joint = joint_owner.getornull(p_joint);
+ JointBullet *joint = joint_owner.get_or_null(p_joint);
ERR_FAIL_COND_V(!joint, false);
ERR_FAIL_COND_V(joint->get_type() != JOINT_6DOF, false);
Generic6DOFJointBullet *generic_6dof_joint = static_cast<Generic6DOFJointBullet *>(joint);
@@ -1401,17 +1401,17 @@ bool BulletPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Ax
void BulletPhysicsServer3D::free(RID p_rid) {
if (shape_owner.owns(p_rid)) {
- ShapeBullet *shape = shape_owner.getornull(p_rid);
+ ShapeBullet *shape = shape_owner.get_or_null(p_rid);
// Notify the shape is configured
- for (Map<ShapeOwnerBullet *, int>::Element *element = shape->get_owners().front(); element; element = element->next()) {
- static_cast<ShapeOwnerBullet *>(element->key())->remove_shape_full(shape);
+ for (const KeyValue<ShapeOwnerBullet *, int> &element : shape->get_owners()) {
+ static_cast<ShapeOwnerBullet *>(element.key)->remove_shape_full(shape);
}
shape_owner.free(p_rid);
bulletdelete(shape);
} else if (rigid_body_owner.owns(p_rid)) {
- RigidBodyBullet *body = rigid_body_owner.getornull(p_rid);
+ RigidBodyBullet *body = rigid_body_owner.get_or_null(p_rid);
body->set_space(nullptr);
@@ -1421,7 +1421,7 @@ void BulletPhysicsServer3D::free(RID p_rid) {
bulletdelete(body);
} else if (soft_body_owner.owns(p_rid)) {
- SoftBodyBullet *body = soft_body_owner.getornull(p_rid);
+ SoftBodyBullet *body = soft_body_owner.get_or_null(p_rid);
body->set_space(nullptr);
@@ -1429,7 +1429,7 @@ void BulletPhysicsServer3D::free(RID p_rid) {
bulletdelete(body);
} else if (area_owner.owns(p_rid)) {
- AreaBullet *area = area_owner.getornull(p_rid);
+ AreaBullet *area = area_owner.get_or_null(p_rid);
area->set_space(nullptr);
@@ -1439,13 +1439,13 @@ void BulletPhysicsServer3D::free(RID p_rid) {
bulletdelete(area);
} else if (joint_owner.owns(p_rid)) {
- JointBullet *joint = joint_owner.getornull(p_rid);
+ JointBullet *joint = joint_owner.get_or_null(p_rid);
joint->destroy_internal_constraint();
joint_owner.free(p_rid);
bulletdelete(joint);
} else if (space_owner.owns(p_rid)) {
- SpaceBullet *space = space_owner.getornull(p_rid);
+ SpaceBullet *space = space_owner.get_or_null(p_rid);
space->remove_all_collision_objects();
@@ -1493,38 +1493,38 @@ int BulletPhysicsServer3D::get_process_info(ProcessInfo p_info) {
SpaceBullet *BulletPhysicsServer3D::get_space(RID p_rid) const {
ERR_FAIL_COND_V_MSG(space_owner.owns(p_rid) == false, nullptr, "The RID is not valid.");
- return space_owner.getornull(p_rid);
+ return space_owner.get_or_null(p_rid);
}
ShapeBullet *BulletPhysicsServer3D::get_shape(RID p_rid) const {
ERR_FAIL_COND_V_MSG(shape_owner.owns(p_rid) == false, nullptr, "The RID is not valid.");
- return shape_owner.getornull(p_rid);
+ return shape_owner.get_or_null(p_rid);
}
CollisionObjectBullet *BulletPhysicsServer3D::get_collision_object(RID p_object) const {
if (rigid_body_owner.owns(p_object)) {
- return rigid_body_owner.getornull(p_object);
+ return rigid_body_owner.get_or_null(p_object);
}
if (area_owner.owns(p_object)) {
- return area_owner.getornull(p_object);
+ return area_owner.get_or_null(p_object);
}
if (soft_body_owner.owns(p_object)) {
- return soft_body_owner.getornull(p_object);
+ return soft_body_owner.get_or_null(p_object);
}
ERR_FAIL_V_MSG(nullptr, "The RID is no valid.");
}
RigidCollisionObjectBullet *BulletPhysicsServer3D::get_rigid_collision_object(RID p_object) const {
if (rigid_body_owner.owns(p_object)) {
- return rigid_body_owner.getornull(p_object);
+ return rigid_body_owner.get_or_null(p_object);
}
if (area_owner.owns(p_object)) {
- return area_owner.getornull(p_object);
+ return area_owner.get_or_null(p_object);
}
ERR_FAIL_V_MSG(nullptr, "The RID is no valid.");
}
JointBullet *BulletPhysicsServer3D::get_joint(RID p_rid) const {
ERR_FAIL_COND_V_MSG(joint_owner.owns(p_rid) == false, nullptr, "The RID is not valid.");
- return joint_owner.getornull(p_rid);
+ return joint_owner.get_or_null(p_rid);
}
diff --git a/modules/bullet/bullet_physics_server.h b/modules/bullet/bullet_physics_server.h
index 7f0934e679..7c146de0c3 100644
--- a/modules/bullet/bullet_physics_server.h
+++ b/modules/bullet/bullet_physics_server.h
@@ -265,7 +265,7 @@ public:
virtual void soft_body_set_space(RID p_body, RID p_space) override;
virtual RID soft_body_get_space(RID p_body) const override;
- virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override;
+ virtual void soft_body_set_mesh(RID p_body, RID p_mesh) override;
virtual AABB soft_body_get_bounds(RID p_body) const override;
diff --git a/modules/bullet/rigid_body_bullet.cpp b/modules/bullet/rigid_body_bullet.cpp
index 0d2cd1f5a0..7b20fad28c 100644
--- a/modules/bullet/rigid_body_bullet.cpp
+++ b/modules/bullet/rigid_body_bullet.cpp
@@ -303,6 +303,7 @@ RigidBodyBullet::~RigidBodyBullet() {
void RigidBodyBullet::init_kinematic_utilities() {
kinematic_utilities = memnew(KinematicUtilities(this));
+ reload_kinematic_shapes();
}
void RigidBodyBullet::destroy_kinematic_utilities() {
@@ -529,26 +530,23 @@ void RigidBodyBullet::set_mode(PhysicsServer3D::BodyMode p_mode) {
can_integrate_forces = false;
destroy_kinematic_utilities();
// The mode change is relevant to its mass
+ mode = p_mode;
switch (p_mode) {
case PhysicsServer3D::BODY_MODE_KINEMATIC:
- mode = PhysicsServer3D::BODY_MODE_KINEMATIC;
reload_axis_lock();
_internal_set_mass(0);
init_kinematic_utilities();
break;
case PhysicsServer3D::BODY_MODE_STATIC:
- mode = PhysicsServer3D::BODY_MODE_STATIC;
reload_axis_lock();
_internal_set_mass(0);
break;
case PhysicsServer3D::BODY_MODE_DYNAMIC:
- mode = PhysicsServer3D::BODY_MODE_DYNAMIC;
reload_axis_lock();
_internal_set_mass(0 == mass ? 1 : mass);
scratch_space_override_modificator();
break;
- case PhysicsServer3D::MODE_DYNAMIC_LOCKED:
- mode = PhysicsServer3D::MODE_DYNAMIC_LOCKED;
+ case PhysicsServer3D::MODE_DYNAMIC_LINEAR:
reload_axis_lock();
_internal_set_mass(0 == mass ? 1 : mass);
scratch_space_override_modificator();
@@ -721,7 +719,7 @@ bool RigidBodyBullet::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {
void RigidBodyBullet::reload_axis_lock() {
btBody->setLinearFactor(btVector3(btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)), btScalar(!is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z))));
- if (PhysicsServer3D::MODE_DYNAMIC_LOCKED == mode) {
+ if (PhysicsServer3D::MODE_DYNAMIC_LINEAR == mode) {
/// When character angular is always locked
btBody->setAngularFactor(btVector3(0., 0., 0.));
} else {
@@ -1016,7 +1014,7 @@ void RigidBodyBullet::_internal_set_mass(real_t p_mass) {
// Rigidbody is dynamic if and only if mass is non Zero, otherwise static
const bool isDynamic = p_mass != 0.f;
if (isDynamic) {
- if (PhysicsServer3D::BODY_MODE_DYNAMIC != mode && PhysicsServer3D::MODE_DYNAMIC_LOCKED != mode) {
+ if (PhysicsServer3D::BODY_MODE_DYNAMIC != mode && PhysicsServer3D::MODE_DYNAMIC_LINEAR != mode) {
return;
}
diff --git a/modules/bullet/shape_bullet.cpp b/modules/bullet/shape_bullet.cpp
index 40e785d699..ec039ba842 100644
--- a/modules/bullet/shape_bullet.cpp
+++ b/modules/bullet/shape_bullet.cpp
@@ -63,8 +63,8 @@ btCollisionShape *ShapeBullet::prepare(btCollisionShape *p_btShape) const {
}
void ShapeBullet::notifyShapeChanged() {
- for (Map<ShapeOwnerBullet *, int>::Element *E = owners.front(); E; E = E->next()) {
- ShapeOwnerBullet *owner = static_cast<ShapeOwnerBullet *>(E->key());
+ for (const KeyValue<ShapeOwnerBullet *, int> &E : owners) {
+ ShapeOwnerBullet *owner = static_cast<ShapeOwnerBullet *>(E.key);
owner->shape_changed(owner->find_shape(this));
}
}
@@ -110,7 +110,7 @@ btEmptyShape *ShapeBullet::create_shape_empty() {
return bulletnew(btEmptyShape);
}
-btStaticPlaneShape *ShapeBullet::create_shape_plane(const btVector3 &planeNormal, btScalar planeConstant) {
+btStaticPlaneShape *ShapeBullet::create_shape_world_boundary(const btVector3 &planeNormal, btScalar planeConstant) {
return bulletnew(btStaticPlaneShape(planeNormal, planeConstant));
}
@@ -164,32 +164,32 @@ btRayShape *ShapeBullet::create_shape_ray(real_t p_length, bool p_slips_on_slope
return r;
}
-/* PLANE */
+/* World boundary */
-PlaneShapeBullet::PlaneShapeBullet() :
+WorldBoundaryShapeBullet::WorldBoundaryShapeBullet() :
ShapeBullet() {}
-void PlaneShapeBullet::set_data(const Variant &p_data) {
+void WorldBoundaryShapeBullet::set_data(const Variant &p_data) {
setup(p_data);
}
-Variant PlaneShapeBullet::get_data() const {
+Variant WorldBoundaryShapeBullet::get_data() const {
return plane;
}
-PhysicsServer3D::ShapeType PlaneShapeBullet::get_type() const {
- return PhysicsServer3D::SHAPE_PLANE;
+PhysicsServer3D::ShapeType WorldBoundaryShapeBullet::get_type() const {
+ return PhysicsServer3D::SHAPE_WORLD_BOUNDARY;
}
-void PlaneShapeBullet::setup(const Plane &p_plane) {
+void WorldBoundaryShapeBullet::setup(const Plane &p_plane) {
plane = p_plane;
notifyShapeChanged();
}
-btCollisionShape *PlaneShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
+btCollisionShape *WorldBoundaryShapeBullet::create_bt_shape(const btVector3 &p_implicit_scale, real_t p_extra_edge) {
btVector3 btPlaneNormal;
G_TO_B(plane.normal, btPlaneNormal);
- return prepare(PlaneShapeBullet::create_shape_plane(btPlaneNormal, plane.d));
+ return prepare(WorldBoundaryShapeBullet::create_shape_world_boundary(btPlaneNormal, plane.d));
}
/* Sphere */
diff --git a/modules/bullet/shape_bullet.h b/modules/bullet/shape_bullet.h
index 5080d13d99..0822399b5e 100644
--- a/modules/bullet/shape_bullet.h
+++ b/modules/bullet/shape_bullet.h
@@ -81,7 +81,7 @@ public:
public:
static class btEmptyShape *create_shape_empty();
- static class btStaticPlaneShape *create_shape_plane(const btVector3 &planeNormal, btScalar planeConstant);
+ static class btStaticPlaneShape *create_shape_world_boundary(const btVector3 &planeNormal, btScalar planeConstant);
static class btSphereShape *create_shape_sphere(btScalar radius);
static class btBoxShape *create_shape_box(const btVector3 &boxHalfExtents);
static class btCapsuleShape *create_shape_capsule(btScalar radius, btScalar height);
@@ -93,11 +93,11 @@ public:
static class btRayShape *create_shape_ray(real_t p_length, bool p_slips_on_slope);
};
-class PlaneShapeBullet : public ShapeBullet {
+class WorldBoundaryShapeBullet : public ShapeBullet {
Plane plane;
public:
- PlaneShapeBullet();
+ WorldBoundaryShapeBullet();
virtual void set_data(const Variant &p_data);
virtual Variant get_data() const;
diff --git a/modules/bullet/soft_body_bullet.cpp b/modules/bullet/soft_body_bullet.cpp
index bbbb0e7851..81b832fb42 100644
--- a/modules/bullet/soft_body_bullet.cpp
+++ b/modules/bullet/soft_body_bullet.cpp
@@ -32,9 +32,10 @@
#include "bullet_types_converter.h"
#include "bullet_utilities.h"
-#include "scene/3d/soft_body_3d.h"
#include "space_bullet.h"
+#include "servers/rendering_server.h"
+
SoftBodyBullet::SoftBodyBullet() :
CollisionObjectBullet(CollisionObjectBullet::TYPE_SOFT_BODY) {}
@@ -70,7 +71,7 @@ void SoftBodyBullet::update_rendering_server(RenderingServerHandler *p_rendering
return;
}
- /// Update visual server vertices
+ /// Update rendering server vertices
const btSoftBody::tNodeArray &nodes(bt_soft_body->m_nodes);
const int nodes_count = nodes.size();
@@ -105,24 +106,26 @@ void SoftBodyBullet::update_rendering_server(RenderingServerHandler *p_rendering
p_rendering_server_handler->set_aabb(aabb);
}
-void SoftBodyBullet::set_soft_mesh(const Ref<Mesh> &p_mesh) {
- if (p_mesh.is_null()) {
- soft_mesh.unref();
- } else {
- soft_mesh = p_mesh;
- }
+void SoftBodyBullet::set_soft_mesh(RID p_mesh) {
+ destroy_soft_body();
+
+ soft_mesh = p_mesh;
if (soft_mesh.is_null()) {
- destroy_soft_body();
return;
}
- Array arrays = soft_mesh->surface_get_arrays(0);
- ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & RS::ARRAY_FORMAT_INDEX));
- set_trimesh_body_shape(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]);
+ Array arrays = RenderingServer::get_singleton()->mesh_surface_get_arrays(soft_mesh, 0);
+
+ bool success = set_trimesh_body_shape(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]);
+ if (!success) {
+ destroy_soft_body();
+ }
}
void SoftBodyBullet::destroy_soft_body() {
+ soft_mesh = RID();
+
if (!bt_soft_body) {
return;
}
@@ -187,22 +190,24 @@ void SoftBodyBullet::get_node_position(int p_node_index, Vector3 &r_position) co
}
}
-void SoftBodyBullet::set_node_mass(int node_index, btScalar p_mass) {
+void SoftBodyBullet::set_node_mass(int p_node_index, btScalar p_mass) {
if (0 >= p_mass) {
- pin_node(node_index);
+ pin_node(p_node_index);
} else {
- unpin_node(node_index);
+ unpin_node(p_node_index);
}
if (bt_soft_body) {
- bt_soft_body->setMass(node_index, p_mass);
+ ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size());
+ bt_soft_body->setMass(p_node_index, p_mass);
}
}
-btScalar SoftBodyBullet::get_node_mass(int node_index) const {
+btScalar SoftBodyBullet::get_node_mass(int p_node_index) const {
if (bt_soft_body) {
- return bt_soft_body->getMass(node_index);
+ ERR_FAIL_INDEX_V(p_node_index, bt_soft_body->m_nodes.size(), 1);
+ return bt_soft_body->getMass(p_node_index);
} else {
- return -1 == search_node_pinned(node_index) ? 1 : 0;
+ return -1 == search_node_pinned(p_node_index) ? 1 : 0;
}
}
@@ -289,15 +294,15 @@ void SoftBodyBullet::set_drag_coefficient(real_t p_val) {
}
}
-void SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector3> p_vertices) {
- /// Assert the current soft body is destroyed
- destroy_soft_body();
+bool SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector3> p_vertices) {
+ ERR_FAIL_COND_V(p_indices.is_empty(), false);
+ ERR_FAIL_COND_V(p_vertices.is_empty(), false);
- /// Parse visual server indices to physical indices.
- /// Merge all overlapping vertices and create a map of physical vertices to visual server
+ /// Parse rendering server indices to physical indices.
+ /// Merge all overlapping vertices and create a map of physical vertices to rendering server
{
- /// This is the map of visual server indices to physics indices (So it's the inverse of idices_map), Thanks to it I don't need make a heavy search in the indices_map
+ /// This is the map of rendering server indices to physics indices (So it's the inverse of idices_map), Thanks to it I don't need make a heavy search in the indices_map
Vector<int> vs_indices_to_physics_table;
{ // Map vertices
@@ -363,6 +368,8 @@ void SoftBodyBullet::set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector
bt_soft_body = btSoftBodyHelpers::CreateFromTriMesh(fake_world_info, &bt_vertices[0], &bt_triangles[0], triangles_size, false);
setup_soft_body();
}
+
+ return true;
}
void SoftBodyBullet::setup_soft_body() {
@@ -413,17 +420,25 @@ void SoftBodyBullet::setup_soft_body() {
// Set pinned nodes
for (int i = pinned_nodes.size() - 1; 0 <= i; --i) {
- bt_soft_body->setMass(pinned_nodes[i], 0);
+ const int node_index = pinned_nodes[i];
+ ERR_CONTINUE(0 > node_index || bt_soft_body->m_nodes.size() <= node_index);
+ bt_soft_body->setMass(node_index, 0);
}
}
void SoftBodyBullet::pin_node(int p_node_index) {
+ if (bt_soft_body) {
+ ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size());
+ }
if (-1 == search_node_pinned(p_node_index)) {
pinned_nodes.push_back(p_node_index);
}
}
void SoftBodyBullet::unpin_node(int p_node_index) {
+ if (bt_soft_body) {
+ ERR_FAIL_INDEX(p_node_index, bt_soft_body->m_nodes.size());
+ }
const int id = search_node_pinned(p_node_index);
if (-1 != id) {
pinned_nodes.remove(id);
diff --git a/modules/bullet/soft_body_bullet.h b/modules/bullet/soft_body_bullet.h
index 63708b57a7..84da56ae69 100644
--- a/modules/bullet/soft_body_bullet.h
+++ b/modules/bullet/soft_body_bullet.h
@@ -32,7 +32,6 @@
#define SOFT_BODY_BULLET_H
#include "collision_object_bullet.h"
-#include "scene/resources/material.h" // TODO remove this please
#ifdef None
/// This is required to remove the macro None defined by x11 compiler because this word "None" is used internally by Bullet
@@ -42,7 +41,6 @@
#include "BulletSoftBody/btSoftBodyHelpers.h"
#include "collision_object_bullet.h"
-#include "scene/resources/mesh.h"
#include "servers/physics_server_3d.h"
#ifdef x11_None
@@ -64,7 +62,7 @@ private:
btSoftBody::Material *mat0 = nullptr; // This is just a copy of pointer managed by btSoftBody
bool isScratched = false;
- Ref<Mesh> soft_mesh;
+ RID soft_mesh;
int simulation_precision = 5;
real_t total_mass = 1.;
@@ -100,7 +98,7 @@ public:
void update_rendering_server(RenderingServerHandler *p_rendering_server_handler);
- void set_soft_mesh(const Ref<Mesh> &p_mesh);
+ void set_soft_mesh(RID p_mesh);
void destroy_soft_body();
// Special function. This function has bad performance
@@ -139,7 +137,7 @@ public:
_FORCE_INLINE_ real_t get_drag_coefficient() const { return drag_coefficient; }
private:
- void set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector3> p_vertices);
+ bool set_trimesh_body_shape(Vector<int> p_indices, Vector<Vector3> p_vertices);
void setup_soft_body();
void pin_node(int p_node_index);
diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp
index a9a811c445..66d7370bd7 100644
--- a/modules/bullet/space_bullet.cpp
+++ b/modules/bullet/space_bullet.cpp
@@ -122,7 +122,7 @@ int BulletPhysicsDirectSpaceState::intersect_shape(const RID &p_shape, const Tra
return 0;
}
- ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape);
+ ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get_or_null(p_shape);
ERR_FAIL_COND_V(!shape, 0);
btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale_abs(), p_margin);
@@ -158,7 +158,7 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf
btVector3 bt_motion;
G_TO_B(p_motion, bt_motion);
- ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape);
+ ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get_or_null(p_shape);
ERR_FAIL_COND_V(!shape, false);
btCollisionShape *btShape = shape->create_bt_shape(p_xform.basis.get_scale(), p_margin);
@@ -219,7 +219,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform3D
return false;
}
- ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape);
+ ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get_or_null(p_shape);
ERR_FAIL_COND_V(!shape, false);
btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin);
@@ -251,7 +251,7 @@ bool BulletPhysicsDirectSpaceState::collide_shape(RID p_shape, const Transform3D
}
bool BulletPhysicsDirectSpaceState::rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) {
- ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->getornull(p_shape);
+ ShapeBullet *shape = space->get_physics_server()->get_shape_owner()->get_or_null(p_shape);
ERR_FAIL_COND_V(!shape, false);
btCollisionShape *btShape = shape->create_bt_shape(p_shape_xform.basis.get_scale_abs(), p_margin);
@@ -947,7 +947,6 @@ bool SpaceBullet::test_body_motion(RigidBodyBullet *p_body, const Transform3D &p
if (!p_body->get_kinematic_utilities()) {
p_body->init_kinematic_utilities();
- p_body->reload_kinematic_shapes();
}
btVector3 initial_recover_motion(0, 0, 0);
@@ -1089,7 +1088,6 @@ int SpaceBullet::test_ray_separation(RigidBodyBullet *p_body, const Transform3D
if (!p_body->get_kinematic_utilities()) {
p_body->init_kinematic_utilities();
- p_body->reload_kinematic_shapes();
}
btVector3 recover_motion(0, 0, 0);
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index cb82b65307..5ffe644495 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -37,16 +37,16 @@
// Static helper functions.
inline static bool is_snapable(const Vector3 &p_point1, const Vector3 &p_point2, real_t p_distance) {
- return (p_point1 - p_point2).length_squared() < p_distance * p_distance;
+ return p_point2.distance_squared_to(p_point1) < p_distance * p_distance;
}
-inline static Vector2 interpolate_segment_uv(const Vector2 p_segement_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) {
- float segment_length = (p_segement_points[1] - p_segement_points[0]).length();
- if (p_segement_points[0].is_equal_approx(p_segement_points[1])) {
+inline static Vector2 interpolate_segment_uv(const Vector2 p_segment_points[2], const Vector2 p_uvs[2], const Vector2 &p_interpolation_point) {
+ if (p_segment_points[0].is_equal_approx(p_segment_points[1])) {
return p_uvs[0];
}
- float distance = (p_interpolation_point - p_segement_points[0]).length();
+ float segment_length = p_segment_points[0].distance_to(p_segment_points[1]);
+ float distance = p_segment_points[0].distance_to(p_interpolation_point);
float fraction = distance / segment_length;
return p_uvs[0].lerp(p_uvs[1], fraction);
@@ -162,7 +162,7 @@ inline static bool is_triangle_degenerate(const Vector2 p_vertices[3], real_t p_
return det < p_vertex_snap2;
}
-inline static bool are_segements_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) {
+inline static bool are_segments_parallel(const Vector2 p_segment1_points[2], const Vector2 p_segment2_points[2], float p_vertex_snap2) {
Vector2 segment1 = p_segment1_points[1] - p_segment1_points[0];
Vector2 segment2 = p_segment2_points[1] - p_segment2_points[0];
real_t segment1_length2 = segment1.dot(segment1);
@@ -258,8 +258,8 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<
}
materials.resize(material_map.size());
- for (Map<Ref<Material>, int>::Element *E = material_map.front(); E; E = E->next()) {
- materials.write[E->get()] = E->key();
+ for (const KeyValue<Ref<Material>, int> &E : material_map) {
+ materials.write[E.value] = E.key;
}
_regen_face_aabbs();
@@ -408,7 +408,7 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_b
} break;
- case OPERATION_SUBSTRACTION: {
+ case OPERATION_SUBTRACTION: {
int face_count = 0;
for (int i = 0; i < mesh_merge.faces.size(); i++) {
@@ -457,8 +457,8 @@ void CSGBrushOperation::merge_brushes(Operation p_operation, const CSGBrush &p_b
// Update the list of materials.
r_merged_brush.materials.resize(mesh_merge.materials.size());
- for (const Map<Ref<Material>, int>::Element *E = mesh_merge.materials.front(); E; E = E->next()) {
- r_merged_brush.materials.write[E->get()] = E->key();
+ for (const KeyValue<Ref<Material>, int> &E : mesh_merge.materials) {
+ r_merged_brush.materials.write[E.value] = E.key;
}
}
@@ -517,7 +517,7 @@ int CSGBrushOperation::MeshMerge::_create_bvh(FaceBVH *facebvhptr, FaceBVH **fac
int index = r_max_alloc++;
FaceBVH *_new = &facebvhptr[index];
_new->aabb = aabb;
- _new->center = aabb.position + aabb.size * 0.5;
+ _new->center = aabb.get_center();
_new->face = -1;
_new->left = left;
_new->right = right;
@@ -596,7 +596,7 @@ bool CSGBrushOperation::MeshMerge::_bvh_inside(FaceBVH *facebvhptr, int p_max_de
_add_distance(intersectionsA, intersectionsB, current_face.from_b, 0);
}
} else if (ray_intersects_triangle(face_center, face_normal, current_points, CMP_EPSILON, intersection_point)) {
- real_t distance = (intersection_point - face_center).length();
+ real_t distance = face_center.distance_to(intersection_point);
_add_distance(intersectionsA, intersectionsB, current_face.from_b, distance);
}
}
@@ -678,7 +678,7 @@ void CSGBrushOperation::MeshMerge::mark_inside_faces() {
facebvh[i].aabb.position = points[faces[i].points[0]];
facebvh[i].aabb.expand_to(points[faces[i].points[1]]);
facebvh[i].aabb.expand_to(points[faces[i].points[2]]);
- facebvh[i].center = facebvh[i].aabb.position + facebvh[i].aabb.size * 0.5;
+ facebvh[i].center = facebvh[i].aabb.get_center();
facebvh[i].aabb.grow_by(vertex_snap);
facebvh[i].next = -1;
@@ -781,7 +781,7 @@ void CSGBrushOperation::MeshMerge::add_face(const Vector3 p_points[], const Vect
int CSGBrushOperation::Build2DFaces::_get_point_idx(const Vector2 &p_point) {
for (int vertex_idx = 0; vertex_idx < vertices.size(); ++vertex_idx) {
- if ((p_point - vertices[vertex_idx].point).length_squared() < vertex_snap2) {
+ if (vertices[vertex_idx].point.distance_squared_to(p_point) < vertex_snap2) {
return vertex_idx;
}
}
@@ -911,7 +911,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
vertices[outer_edge_idx[1]].point,
vertices[p_segment_indices[closest_idx]].point
};
- if (are_segements_parallel(edge1, edge2, vertex_snap2)) {
+ if (are_segments_parallel(edge1, edge2, vertex_snap2)) {
if (!degenerate_points.find(outer_edge_idx[0])) {
degenerate_points.push_back(outer_edge_idx[0]);
}
@@ -961,7 +961,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
// Check if point is existing face vertex.
bool existing = false;
for (int i = 0; i < 3; ++i) {
- if ((point_2D - face_vertices[i].point).length_squared() < vertex_snap2) {
+ if (face_vertices[i].point.distance_squared_to(point_2D) < vertex_snap2) {
existing = true;
break;
}
@@ -978,7 +978,7 @@ void CSGBrushOperation::Build2DFaces::_merge_faces(const Vector<int> &p_segment_
};
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(point_2D, edge_points);
- if ((closest_point - point_2D).length_squared() < vertex_snap2) {
+ if (point_2D.distance_squared_to(closest_point) < vertex_snap2) {
int opposite_vertex_idx = face.vertex_idx[(face_edge_idx + 2) % 3];
// If new vertex snaps to degenerate vertex, just delete this face.
@@ -1041,7 +1041,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
bool on_edge = false;
for (int edge_point_idx = 0; edge_point_idx < 2; ++edge_point_idx) {
intersection_point = Geometry2D::get_closest_point_to_segment(p_segment_points[edge_point_idx], edge_points);
- if ((intersection_point - p_segment_points[edge_point_idx]).length_squared() < vertex_snap2) {
+ if (p_segment_points[edge_point_idx].distance_squared_to(intersection_point) < vertex_snap2) {
on_edge = true;
break;
}
@@ -1050,13 +1050,13 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
// Else check if the segment intersects the edge.
if (on_edge || Geometry2D::segment_intersects_segment(p_segment_points[0], p_segment_points[1], edge_points[0], edge_points[1], &intersection_point)) {
// Check if intersection point is an edge point.
- if ((intersection_point - edge_points[0]).length_squared() < vertex_snap2 ||
- (intersection_point - edge_points[1]).length_squared() < vertex_snap2) {
+ if ((edge_points[0].distance_squared_to(intersection_point) < vertex_snap2) ||
+ (edge_points[1].distance_squared_to(intersection_point) < vertex_snap2)) {
continue;
}
// Check if edge exists, by checking if the intersecting segment is parallel to the edge.
- if (are_segements_parallel(p_segment_points, edge_points, vertex_snap2)) {
+ if (are_segments_parallel(p_segment_points, edge_points, vertex_snap2)) {
continue;
}
@@ -1078,7 +1078,7 @@ void CSGBrushOperation::Build2DFaces::_find_edge_intersections(const Vector2 p_s
// If opposite point is on the segment, add its index to segment indices too.
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(vertices[opposite_vertex_idx].point, p_segment_points);
- if ((closest_point - vertices[opposite_vertex_idx].point).length_squared() < vertex_snap2) {
+ if (vertices[opposite_vertex_idx].point.distance_squared_to(closest_point) < vertex_snap2) {
_add_vertex_idx_sorted(r_segment_indices, opposite_vertex_idx);
}
@@ -1132,7 +1132,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
// Check if point is existing face vertex.
for (int i = 0; i < 3; ++i) {
- if ((p_point - face_vertices[i].point).length_squared() < vertex_snap2) {
+ if (face_vertices[i].point.distance_squared_to(p_point) < vertex_snap2) {
return face.vertex_idx[i];
}
}
@@ -1150,7 +1150,7 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
};
Vector2 closest_point = Geometry2D::get_closest_point_to_segment(p_point, edge_points);
- if ((closest_point - p_point).length_squared() < vertex_snap2) {
+ if (p_point.distance_squared_to(closest_point) < vertex_snap2) {
on_edge = true;
// Add the point as a new vertex.
@@ -1172,8 +1172,8 @@ int CSGBrushOperation::Build2DFaces::_insert_point(const Vector2 &p_point) {
Vector2 split_edge1[2] = { vertices[new_vertex_idx].point, edge_points[0] };
Vector2 split_edge2[2] = { vertices[new_vertex_idx].point, edge_points[1] };
Vector2 new_edge[2] = { vertices[new_vertex_idx].point, vertices[opposite_vertex_idx].point };
- if (are_segements_parallel(split_edge1, new_edge, vertex_snap2) &&
- are_segements_parallel(split_edge2, new_edge, vertex_snap2)) {
+ if (are_segments_parallel(split_edge1, new_edge, vertex_snap2) &&
+ are_segments_parallel(split_edge2, new_edge, vertex_snap2)) {
break;
}
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index c872860486..b1fe933268 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -67,7 +67,7 @@ struct CSGBrushOperation {
enum Operation {
OPERATION_UNION,
OPERATION_INTERSECTION,
- OPERATION_SUBSTRACTION,
+ OPERATION_SUBTRACTION,
};
void merge_brushes(Operation p_operation, const CSGBrush &p_brush_a, const CSGBrush &p_brush_b, CSGBrush &r_merged_brush, float p_vertex_snap);
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index bf11cc7f68..14e7896295 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -192,7 +192,7 @@ CSGBrush *CSGShape3D::_get_brush() {
bop.merge_brushes(CSGBrushOperation::OPERATION_INTERSECTION, *n, *nn2, *nn, snap);
break;
case CSGShape3D::OPERATION_SUBTRACTION:
- bop.merge_brushes(CSGBrushOperation::OPERATION_SUBSTRACTION, *n, *nn2, *nn, snap);
+ bop.merge_brushes(CSGBrushOperation::OPERATION_SUBTRACTION, *n, *nn2, *nn, snap);
break;
}
memdelete(n);
@@ -280,7 +280,7 @@ void CSGShape3D::mikktSetTSpaceDefault(const SMikkTSpaceContext *pContext, const
}
void CSGShape3D::_update_shape() {
- if (parent) {
+ if (parent || !is_inside_tree()) {
return;
}
@@ -1732,6 +1732,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
int extrusion_face_count = shape_sides * 2;
int end_count = 0;
int shape_face_count = shape_faces.size() / 3;
+ real_t curve_length = 1.0;
switch (mode) {
case MODE_DEPTH:
extrusions = 1;
@@ -1744,7 +1745,12 @@ CSGBrush *CSGPolygon3D::_build_brush() {
}
break;
case MODE_PATH: {
- extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval);
+ curve_length = curve->get_baked_length();
+ if (path_interval_type == PATH_INTERVAL_DISTANCE) {
+ extrusions = MAX(1, Math::ceil(curve_length / path_interval)) + 1;
+ } else {
+ extrusions = Math::ceil(1.0 * curve->get_point_count() / path_interval);
+ }
if (!path_joined) {
end_count = 2;
extrusions -= 1;
@@ -1767,212 +1773,245 @@ CSGBrush *CSGPolygon3D::_build_brush() {
smooth.resize(face_count);
materials.resize(face_count);
invert.resize(face_count);
+ int faces_removed = 0;
- Vector3 *facesw = faces.ptrw();
- Vector2 *uvsw = uvs.ptrw();
- bool *smoothw = smooth.ptrw();
- Ref<Material> *materialsw = materials.ptrw();
- bool *invertw = invert.ptrw();
-
- int face = 0;
- Transform3D base_xform;
- Transform3D current_xform;
- Transform3D previous_xform;
- double u_step = 1.0 / extrusions;
- double v_step = 1.0 / shape_sides;
- double spin_step = Math::deg2rad(spin_degrees / spin_sides);
- double extrusion_step = 1.0 / extrusions;
- if (mode == MODE_PATH) {
- if (path_joined) {
- extrusion_step = 1.0 / (extrusions - 1);
- }
- extrusion_step *= curve->get_baked_length();
- }
+ {
+ Vector3 *facesw = faces.ptrw();
+ Vector2 *uvsw = uvs.ptrw();
+ bool *smoothw = smooth.ptrw();
+ Ref<Material> *materialsw = materials.ptrw();
+ bool *invertw = invert.ptrw();
- if (mode == MODE_PATH) {
- if (!path_local) {
- base_xform = path->get_global_transform();
+ int face = 0;
+ Transform3D base_xform;
+ Transform3D current_xform;
+ Transform3D previous_xform;
+ Transform3D previous_previous_xform;
+ double u_step = 1.0 / extrusions;
+ if (path_u_distance > 0.0) {
+ u_step *= curve_length / path_u_distance;
+ }
+ double v_step = 1.0 / shape_sides;
+ double spin_step = Math::deg2rad(spin_degrees / spin_sides);
+ double extrusion_step = 1.0 / extrusions;
+ if (mode == MODE_PATH) {
+ if (path_joined) {
+ extrusion_step = 1.0 / (extrusions - 1);
+ }
+ extrusion_step *= curve_length;
}
- Vector3 current_point = curve->interpolate_baked(0);
- Vector3 next_point = curve->interpolate_baked(extrusion_step);
- Vector3 current_up = Vector3(0, 1, 0);
- Vector3 direction = next_point - current_point;
+ if (mode == MODE_PATH) {
+ if (!path_local) {
+ base_xform = path->get_global_transform();
+ }
- if (path_joined) {
- Vector3 last_point = curve->interpolate_baked(curve->get_baked_length());
- direction = next_point - last_point;
- }
+ Vector3 current_point = curve->interpolate_baked(0);
+ Vector3 next_point = curve->interpolate_baked(extrusion_step);
+ Vector3 current_up = Vector3(0, 1, 0);
+ Vector3 direction = next_point - current_point;
+
+ if (path_joined) {
+ Vector3 last_point = curve->interpolate_baked(curve->get_baked_length());
+ direction = next_point - last_point;
+ }
- switch (path_rotation) {
- case PATH_ROTATION_POLYGON:
- direction = Vector3(0, 0, -1);
- break;
- case PATH_ROTATION_PATH:
- break;
- case PATH_ROTATION_PATH_FOLLOW:
- current_up = curve->interpolate_baked_up_vector(0);
- break;
+ switch (path_rotation) {
+ case PATH_ROTATION_POLYGON:
+ direction = Vector3(0, 0, -1);
+ break;
+ case PATH_ROTATION_PATH:
+ break;
+ case PATH_ROTATION_PATH_FOLLOW:
+ current_up = curve->interpolate_baked_up_vector(0);
+ break;
+ }
+
+ Transform3D facing = Transform3D().looking_at(direction, current_up);
+ current_xform = base_xform.translated(current_point) * facing;
}
- Transform3D facing = Transform3D().looking_at(direction, current_up);
- current_xform = base_xform.translated(current_point) * facing;
- }
+ // Create the mesh.
+ if (end_count > 0) {
+ // Add front end face.
+ for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
+ for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
+ // We need to reverse the rotation of the shape face vertices.
+ int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx];
+ Point2 p = shape_polygon[index];
+ Point2 uv = (p - shape_rect.position) / shape_rect.size;
+
+ // Use the left side of the bottom half of the y-inverted texture.
+ uv.x = uv.x / 2;
+ uv.y = 1 - (uv.y / 2);
+
+ facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
+ uvsw[face * 3 + face_vertex_idx] = uv;
+ }
- // Create the mesh.
- if (end_count > 0) {
- // Add front end face.
- for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
- for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
- // We need to reverse the rotation of the shape face vertices.
- int index = shape_faces[face_idx * 3 + 2 - face_vertex_idx];
- Point2 p = shape_polygon[index];
- Point2 uv = (p - shape_rect.position) / shape_rect.size;
-
- // Use the left side of the bottom half of the y-inverted texture.
- uv.x = uv.x / 2;
- uv.y = 1 - (uv.y / 2);
-
- facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
- uvsw[face * 3 + face_vertex_idx] = uv;
+ smoothw[face] = false;
+ materialsw[face] = material;
+ invertw[face] = invert_faces;
+ face++;
}
-
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_faces;
- face++;
}
- }
- // Add extrusion faces.
- for (int x0 = 0; x0 < extrusions; x0++) {
- previous_xform = current_xform;
-
- switch (mode) {
- case MODE_DEPTH: {
- current_xform.translate(Vector3(0, 0, -depth));
- } break;
- case MODE_SPIN: {
- current_xform.rotate(Vector3(0, 1, 0), spin_step);
- } break;
- case MODE_PATH: {
- double previous_offset = x0 * extrusion_step;
- double current_offset = (x0 + 1) * extrusion_step;
- double next_offset = (x0 + 2) * extrusion_step;
- if (x0 == extrusions - 1) {
- if (path_joined) {
- current_offset = 0;
- next_offset = extrusion_step;
+ real_t angle_simplify_dot = Math::cos(Math::deg2rad(path_simplify_angle));
+ Vector3 previous_simplify_dir = Vector3(0, 0, 0);
+ int faces_combined = 0;
+
+ // Add extrusion faces.
+ for (int x0 = 0; x0 < extrusions; x0++) {
+ previous_previous_xform = previous_xform;
+ previous_xform = current_xform;
+
+ switch (mode) {
+ case MODE_DEPTH: {
+ current_xform.translate(Vector3(0, 0, -depth));
+ } break;
+ case MODE_SPIN: {
+ current_xform.rotate(Vector3(0, 1, 0), spin_step);
+ } break;
+ case MODE_PATH: {
+ double previous_offset = x0 * extrusion_step;
+ double current_offset = (x0 + 1) * extrusion_step;
+ double next_offset = (x0 + 2) * extrusion_step;
+ if (x0 == extrusions - 1) {
+ if (path_joined) {
+ current_offset = 0;
+ next_offset = extrusion_step;
+ } else {
+ next_offset = current_offset;
+ }
+ }
+
+ Vector3 previous_point = curve->interpolate_baked(previous_offset);
+ Vector3 current_point = curve->interpolate_baked(current_offset);
+ Vector3 next_point = curve->interpolate_baked(next_offset);
+ Vector3 current_up = Vector3(0, 1, 0);
+ Vector3 direction = next_point - previous_point;
+ Vector3 current_dir = (current_point - previous_point).normalized();
+
+ // If the angles are similar, remove the previous face and replace it with this one.
+ if (path_simplify_angle > 0.0 && x0 > 0 && previous_simplify_dir.dot(current_dir) > angle_simplify_dot) {
+ faces_combined += 1;
+ previous_xform = previous_previous_xform;
+ face -= extrusion_face_count;
+ faces_removed += extrusion_face_count;
} else {
- next_offset = current_offset;
+ faces_combined = 0;
+ previous_simplify_dir = current_dir;
}
- }
- Vector3 previous_point = curve->interpolate_baked(previous_offset);
- Vector3 current_point = curve->interpolate_baked(current_offset);
- Vector3 next_point = curve->interpolate_baked(next_offset);
- Vector3 current_up = Vector3(0, 1, 0);
- Vector3 direction = next_point - previous_point;
+ switch (path_rotation) {
+ case PATH_ROTATION_POLYGON:
+ direction = Vector3(0, 0, -1);
+ break;
+ case PATH_ROTATION_PATH:
+ break;
+ case PATH_ROTATION_PATH_FOLLOW:
+ current_up = curve->interpolate_baked_up_vector(current_offset);
+ break;
+ }
- switch (path_rotation) {
- case PATH_ROTATION_POLYGON:
- direction = Vector3(0, 0, -1);
- break;
- case PATH_ROTATION_PATH:
- break;
- case PATH_ROTATION_PATH_FOLLOW:
- current_up = curve->interpolate_baked_up_vector(current_offset);
- break;
- }
+ Transform3D facing = Transform3D().looking_at(direction, current_up);
+ current_xform = base_xform.translated(current_point) * facing;
+ } break;
+ }
- Transform3D facing = Transform3D().looking_at(direction, current_up);
- current_xform = base_xform.translated(current_point) * facing;
- } break;
- }
+ double u0 = (x0 - faces_combined) * u_step;
+ double u1 = ((x0 + 1) * u_step);
+ if (mode == MODE_PATH && !path_continuous_u) {
+ u0 = 0.0;
+ u1 = 1.0;
+ }
- double u0 = x0 * u_step;
- double u1 = ((x0 + 1) * u_step);
- if (mode == MODE_PATH && !path_continuous_u) {
- u0 = 0.0;
- u1 = 1.0;
- }
+ for (int y0 = 0; y0 < shape_sides; y0++) {
+ int y1 = (y0 + 1) % shape_sides;
+ // Use the top half of the texture.
+ double v0 = (y0 * v_step) / 2;
+ double v1 = ((y0 + 1) * v_step) / 2;
- for (int y0 = 0; y0 < shape_sides; y0++) {
- int y1 = (y0 + 1) % shape_sides;
- // Use the top half of the texture.
- double v0 = (y0 * v_step) / 2;
- double v1 = ((y0 + 1) * v_step) / 2;
-
- Vector3 v[4] = {
- previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
- current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
- current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
- previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
- };
-
- Vector2 u[4] = {
- Vector2(u0, v0),
- Vector2(u1, v0),
- Vector2(u1, v1),
- Vector2(u0, v1),
- };
-
- // Face 1
- facesw[face * 3 + 0] = v[0];
- facesw[face * 3 + 1] = v[1];
- facesw[face * 3 + 2] = v[2];
-
- uvsw[face * 3 + 0] = u[0];
- uvsw[face * 3 + 1] = u[1];
- uvsw[face * 3 + 2] = u[2];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_faces;
- materialsw[face] = material;
-
- face++;
-
- // Face 2
- facesw[face * 3 + 0] = v[2];
- facesw[face * 3 + 1] = v[3];
- facesw[face * 3 + 2] = v[0];
-
- uvsw[face * 3 + 0] = u[2];
- uvsw[face * 3 + 1] = u[3];
- uvsw[face * 3 + 2] = u[0];
-
- smoothw[face] = smooth_faces;
- invertw[face] = invert_faces;
- materialsw[face] = material;
-
- face++;
- }
- }
+ Vector3 v[4] = {
+ previous_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
+ current_xform.xform(Vector3(shape_polygon[y0].x, shape_polygon[y0].y, 0)),
+ current_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
+ previous_xform.xform(Vector3(shape_polygon[y1].x, shape_polygon[y1].y, 0)),
+ };
+
+ Vector2 u[4] = {
+ Vector2(u0, v0),
+ Vector2(u1, v0),
+ Vector2(u1, v1),
+ Vector2(u0, v1),
+ };
+
+ // Face 1
+ facesw[face * 3 + 0] = v[0];
+ facesw[face * 3 + 1] = v[1];
+ facesw[face * 3 + 2] = v[2];
+
+ uvsw[face * 3 + 0] = u[0];
+ uvsw[face * 3 + 1] = u[1];
+ uvsw[face * 3 + 2] = u[2];
+
+ smoothw[face] = smooth_faces;
+ invertw[face] = invert_faces;
+ materialsw[face] = material;
+
+ face++;
+
+ // Face 2
+ facesw[face * 3 + 0] = v[2];
+ facesw[face * 3 + 1] = v[3];
+ facesw[face * 3 + 2] = v[0];
- if (end_count > 1) {
- // Add back end face.
- for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
- for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
- int index = shape_faces[face_idx * 3 + face_vertex_idx];
- Point2 p = shape_polygon[index];
- Point2 uv = (p - shape_rect.position) / shape_rect.size;
+ uvsw[face * 3 + 0] = u[2];
+ uvsw[face * 3 + 1] = u[3];
+ uvsw[face * 3 + 2] = u[0];
- // Use the x-inverted ride side of the bottom half of the y-inverted texture.
- uv.x = 1 - uv.x / 2;
- uv.y = 1 - (uv.y / 2);
+ smoothw[face] = smooth_faces;
+ invertw[face] = invert_faces;
+ materialsw[face] = material;
- facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
- uvsw[face * 3 + face_vertex_idx] = uv;
+ face++;
}
+ }
- smoothw[face] = false;
- materialsw[face] = material;
- invertw[face] = invert_faces;
- face++;
+ if (end_count > 1) {
+ // Add back end face.
+ for (int face_idx = 0; face_idx < shape_face_count; face_idx++) {
+ for (int face_vertex_idx = 0; face_vertex_idx < 3; face_vertex_idx++) {
+ int index = shape_faces[face_idx * 3 + face_vertex_idx];
+ Point2 p = shape_polygon[index];
+ Point2 uv = (p - shape_rect.position) / shape_rect.size;
+
+ // Use the x-inverted ride side of the bottom half of the y-inverted texture.
+ uv.x = 1 - uv.x / 2;
+ uv.y = 1 - (uv.y / 2);
+
+ facesw[face * 3 + face_vertex_idx] = current_xform.xform(Vector3(p.x, p.y, 0));
+ uvsw[face * 3 + face_vertex_idx] = uv;
+ }
+
+ smoothw[face] = false;
+ materialsw[face] = material;
+ invertw[face] = invert_faces;
+ face++;
+ }
}
+
+ face_count -= faces_removed;
+ ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly.");
}
- ERR_FAIL_COND_V_MSG(face != face_count, brush, "Bug: Failed to create the CSGPolygon mesh correctly.");
+ if (faces_removed > 0) {
+ faces.resize(face_count * 3);
+ uvs.resize(face_count * 3);
+ smooth.resize(face_count);
+ materials.resize(face_count);
+ invert.resize(face_count);
+ }
brush->build_from_faces(faces, uvs, smooth, materials, invert);
@@ -2031,9 +2070,15 @@ void CSGPolygon3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path_node", "path"), &CSGPolygon3D::set_path_node);
ClassDB::bind_method(D_METHOD("get_path_node"), &CSGPolygon3D::get_path_node);
+ ClassDB::bind_method(D_METHOD("set_path_interval_type", "interval_type"), &CSGPolygon3D::set_path_interval_type);
+ ClassDB::bind_method(D_METHOD("get_path_interval_type"), &CSGPolygon3D::get_path_interval_type);
+
ClassDB::bind_method(D_METHOD("set_path_interval", "interval"), &CSGPolygon3D::set_path_interval);
ClassDB::bind_method(D_METHOD("get_path_interval"), &CSGPolygon3D::get_path_interval);
+ ClassDB::bind_method(D_METHOD("set_path_simplify_angle", "degrees"), &CSGPolygon3D::set_path_simplify_angle);
+ ClassDB::bind_method(D_METHOD("get_path_simplify_angle"), &CSGPolygon3D::get_path_simplify_angle);
+
ClassDB::bind_method(D_METHOD("set_path_rotation", "path_rotation"), &CSGPolygon3D::set_path_rotation);
ClassDB::bind_method(D_METHOD("get_path_rotation"), &CSGPolygon3D::get_path_rotation);
@@ -2043,6 +2088,9 @@ void CSGPolygon3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_path_continuous_u", "enable"), &CSGPolygon3D::set_path_continuous_u);
ClassDB::bind_method(D_METHOD("is_path_continuous_u"), &CSGPolygon3D::is_path_continuous_u);
+ ClassDB::bind_method(D_METHOD("set_path_u_distance", "distance"), &CSGPolygon3D::set_path_u_distance);
+ ClassDB::bind_method(D_METHOD("get_path_u_distance"), &CSGPolygon3D::get_path_u_distance);
+
ClassDB::bind_method(D_METHOD("set_path_joined", "enable"), &CSGPolygon3D::set_path_joined);
ClassDB::bind_method(D_METHOD("is_path_joined"), &CSGPolygon3D::is_path_joined);
@@ -2061,10 +2109,13 @@ void CSGPolygon3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "spin_degrees", PROPERTY_HINT_RANGE, "1,360,0.1"), "set_spin_degrees", "get_spin_degrees");
ADD_PROPERTY(PropertyInfo(Variant::INT, "spin_sides", PROPERTY_HINT_RANGE, "3,64,1"), "set_spin_sides", "get_spin_sides");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "path_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Path3D"), "set_path_node", "get_path_node");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.1,1.0,0.05,exp"), "set_path_interval", "get_path_interval");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "path_interval_type", PROPERTY_HINT_ENUM, "Distance,Subdivide"), "set_path_interval_type", "get_path_interval_type");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_interval", PROPERTY_HINT_RANGE, "0.01,1.0,0.01,exp,or_greater"), "set_path_interval", "get_path_interval");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_simplify_angle", PROPERTY_HINT_RANGE, "0.0,180.0,0.1,exp"), "set_path_simplify_angle", "get_path_simplify_angle");
ADD_PROPERTY(PropertyInfo(Variant::INT, "path_rotation", PROPERTY_HINT_ENUM, "Polygon,Path,PathFollow"), "set_path_rotation", "get_path_rotation");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_local"), "set_path_local", "is_path_local");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_continuous_u"), "set_path_continuous_u", "is_path_continuous_u");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "path_u_distance", PROPERTY_HINT_RANGE, "0.0,10.0,0.01,or_greater"), "set_path_u_distance", "get_path_u_distance");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "path_joined"), "set_path_joined", "is_path_joined");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_faces"), "set_smooth_faces", "get_smooth_faces");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "BaseMaterial3D,ShaderMaterial"), "set_material", "get_material");
@@ -2076,6 +2127,9 @@ void CSGPolygon3D::_bind_methods() {
BIND_ENUM_CONSTANT(PATH_ROTATION_POLYGON);
BIND_ENUM_CONSTANT(PATH_ROTATION_PATH);
BIND_ENUM_CONSTANT(PATH_ROTATION_PATH_FOLLOW);
+
+ BIND_ENUM_CONSTANT(PATH_INTERVAL_DISTANCE);
+ BIND_ENUM_CONSTANT(PATH_INTERVAL_SUBDIVIDE);
}
void CSGPolygon3D::set_polygon(const Vector<Vector2> &p_polygon) {
@@ -2119,6 +2173,16 @@ bool CSGPolygon3D::is_path_continuous_u() const {
return path_continuous_u;
}
+void CSGPolygon3D::set_path_u_distance(real_t p_path_u_distance) {
+ path_u_distance = p_path_u_distance;
+ _make_dirty();
+ update_gizmos();
+}
+
+real_t CSGPolygon3D::get_path_u_distance() const {
+ return path_u_distance;
+}
+
void CSGPolygon3D::set_spin_degrees(const float p_spin_degrees) {
ERR_FAIL_COND(p_spin_degrees < 0.01 || p_spin_degrees > 360);
spin_degrees = p_spin_degrees;
@@ -2151,8 +2215,17 @@ NodePath CSGPolygon3D::get_path_node() const {
return path_node;
}
+void CSGPolygon3D::set_path_interval_type(PathIntervalType p_interval_type) {
+ path_interval_type = p_interval_type;
+ _make_dirty();
+ update_gizmos();
+}
+
+CSGPolygon3D::PathIntervalType CSGPolygon3D::get_path_interval_type() const {
+ return path_interval_type;
+}
+
void CSGPolygon3D::set_path_interval(float p_interval) {
- ERR_FAIL_COND_MSG(p_interval <= 0 || p_interval > 1, "Path interval must be greater than 0 and less than or equal to 1.0.");
path_interval = p_interval;
_make_dirty();
update_gizmos();
@@ -2162,6 +2235,16 @@ float CSGPolygon3D::get_path_interval() const {
return path_interval;
}
+void CSGPolygon3D::set_path_simplify_angle(float p_angle) {
+ path_simplify_angle = p_angle;
+ _make_dirty();
+ update_gizmos();
+}
+
+float CSGPolygon3D::get_path_simplify_angle() const {
+ return path_simplify_angle;
+}
+
void CSGPolygon3D::set_path_rotation(PathRotation p_rotation) {
path_rotation = p_rotation;
_make_dirty();
@@ -2229,10 +2312,13 @@ CSGPolygon3D::CSGPolygon3D() {
spin_degrees = 360;
spin_sides = 8;
smooth_faces = false;
+ path_interval_type = PATH_INTERVAL_DISTANCE;
path_interval = 1.0;
+ path_simplify_angle = 0.0;
path_rotation = PATH_ROTATION_PATH_FOLLOW;
path_local = false;
path_continuous_u = true;
+ path_u_distance = 1.0;
path_joined = false;
path = nullptr;
}
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index 5cf371665e..c85cce776b 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -336,6 +336,11 @@ public:
MODE_PATH
};
+ enum PathIntervalType {
+ PATH_INTERVAL_DISTANCE,
+ PATH_INTERVAL_SUBDIVIDE
+ };
+
enum PathRotation {
PATH_ROTATION_POLYGON,
PATH_ROTATION_PATH,
@@ -356,7 +361,9 @@ private:
int spin_sides;
NodePath path_node;
+ PathIntervalType path_interval_type;
float path_interval;
+ float path_simplify_angle;
PathRotation path_rotation;
bool path_local;
@@ -364,6 +371,7 @@ private:
bool smooth_faces;
bool path_continuous_u;
+ real_t path_u_distance;
bool path_joined;
bool _is_editable_3d_polygon() const;
@@ -396,9 +404,15 @@ public:
void set_path_node(const NodePath &p_path);
NodePath get_path_node() const;
+ void set_path_interval_type(PathIntervalType p_interval_type);
+ PathIntervalType get_path_interval_type() const;
+
void set_path_interval(float p_interval);
float get_path_interval() const;
+ void set_path_simplify_angle(float p_angle);
+ float get_path_simplify_angle() const;
+
void set_path_rotation(PathRotation p_rotation);
PathRotation get_path_rotation() const;
@@ -408,6 +422,9 @@ public:
void set_path_continuous_u(bool p_enable);
bool is_path_continuous_u() const;
+ void set_path_u_distance(real_t p_path_u_distance);
+ real_t get_path_u_distance() const;
+
void set_path_joined(bool p_enable);
bool is_path_joined() const;
@@ -422,5 +439,6 @@ public:
VARIANT_ENUM_CAST(CSGPolygon3D::Mode)
VARIANT_ENUM_CAST(CSGPolygon3D::PathRotation)
+VARIANT_ENUM_CAST(CSGPolygon3D::PathIntervalType)
#endif // CSG_SHAPE_H
diff --git a/modules/csg/doc_classes/CSGBox3D.xml b/modules/csg/doc_classes/CSGBox3D.xml
index 5bb1c4e75b..d64e58ae4d 100644
--- a/modules/csg/doc_classes/CSGBox3D.xml
+++ b/modules/csg/doc_classes/CSGBox3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="material" type="Material" setter="set_material" getter="get_material">
The material used to render the box.
@@ -18,6 +16,4 @@
The box's width, height and depth.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGCombiner3D.xml b/modules/csg/doc_classes/CSGCombiner3D.xml
index b55111eee4..422c5d35b7 100644
--- a/modules/csg/doc_classes/CSGCombiner3D.xml
+++ b/modules/csg/doc_classes/CSGCombiner3D.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGCylinder3D.xml b/modules/csg/doc_classes/CSGCylinder3D.xml
index bfd2a5d5f2..40e989bfb3 100644
--- a/modules/csg/doc_classes/CSGCylinder3D.xml
+++ b/modules/csg/doc_classes/CSGCylinder3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="cone" type="bool" setter="set_cone" getter="is_cone" default="false">
If [code]true[/code] a cone is created, the [member radius] will only apply to one side.
@@ -30,6 +28,4 @@
If [code]true[/code] the normals of the cylinder are set to give a smooth effect making the cylinder seem rounded. If [code]false[/code] the cylinder will have a flat shaded look.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGMesh3D.xml b/modules/csg/doc_classes/CSGMesh3D.xml
index 5fa8427843..2810343139 100644
--- a/modules/csg/doc_classes/CSGMesh3D.xml
+++ b/modules/csg/doc_classes/CSGMesh3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="material" type="Material" setter="set_material" getter="get_material">
The [Material] used in drawing the CSG shape.
@@ -19,6 +17,4 @@
[b]Note:[/b] When using an [ArrayMesh], avoid meshes with vertex normals unless a flat shader is required. By default, CSGMesh will ignore the mesh's vertex normals and use a smooth shader calculated using the faces' normals. If a flat shader is required, ensure that all faces' vertex normals are parallel.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGPolygon3D.xml b/modules/csg/doc_classes/CSGPolygon3D.xml
index 5309cde956..ecbb7962d1 100644
--- a/modules/csg/doc_classes/CSGPolygon3D.xml
+++ b/modules/csg/doc_classes/CSGPolygon3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="depth" type="float" setter="set_depth" getter="get_depth" default="1.0">
When [member mode] is [constant MODE_DEPTH], the depth of the extrusion.
@@ -26,6 +24,9 @@
<member name="path_interval" type="float" setter="set_path_interval" getter="get_path_interval">
When [member mode] is [constant MODE_PATH], the path interval or ratio of path points to extrusions.
</member>
+ <member name="path_interval_type" type="int" setter="set_path_interval_type" getter="get_path_interval_type" enum="CSGPolygon3D.PathIntervalType">
+ When [member mode] is [constant MODE_PATH], this will determine if the interval should be by distance ([constant PATH_INTERVAL_DISTANCE]) or subdivision fractions ([constant PATH_INTERVAL_SUBDIVIDE]).
+ </member>
<member name="path_joined" type="bool" setter="set_path_joined" getter="is_path_joined">
When [member mode] is [constant MODE_PATH], if [code]true[/code] the ends of the path are joined, by adding an extrusion between the last and first points of the path.
</member>
@@ -38,6 +39,12 @@
<member name="path_rotation" type="int" setter="set_path_rotation" getter="get_path_rotation" enum="CSGPolygon3D.PathRotation">
When [member mode] is [constant MODE_PATH], the [enum PathRotation] method used to rotate the [member polygon] as it is extruded.
</member>
+ <member name="path_simplify_angle" type="float" setter="set_path_simplify_angle" getter="get_path_simplify_angle">
+ When [member mode] is [constant MODE_PATH], extrusions that are less than this angle, will be merged together to reduce polygon count.
+ </member>
+ <member name="path_u_distance" type="float" setter="set_path_u_distance" getter="get_path_u_distance">
+ When [member mode] is [constant MODE_PATH], this is the distance along the path, in meters, the texture coordinates will tile. When set to 0, texture coordinates will match geometry exactly with no tiling.
+ </member>
<member name="polygon" type="PackedVector2Array" setter="set_polygon" getter="get_polygon" default="PackedVector2Array(0, 0, 0, 1, 1, 1, 1, 0)">
The point array that defines the 2D polygon that is extruded.
</member>
@@ -72,5 +79,11 @@
<constant name="PATH_ROTATION_PATH_FOLLOW" value="2" enum="PathRotation">
The [member polygon] shape follows the path and its rotations around the path axis.
</constant>
+ <constant name="PATH_INTERVAL_DISTANCE" value="0" enum="PathIntervalType">
+ When [member mode] is set to [constant MODE_PATH], [member path_interval] will determine the distance, in meters, each interval of the path will extrude.
+ </constant>
+ <constant name="PATH_INTERVAL_SUBDIVIDE" value="1" enum="PathIntervalType">
+ When [member mode] is set to [constant MODE_PATH], [member path_interval] will subdivide the polygons along the path.
+ </constant>
</constants>
</class>
diff --git a/modules/csg/doc_classes/CSGPrimitive3D.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml
index 31b7360fac..8f4c8b9451 100644
--- a/modules/csg/doc_classes/CSGPrimitive3D.xml
+++ b/modules/csg/doc_classes/CSGPrimitive3D.xml
@@ -8,13 +8,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false">
Invert the faces of the mesh.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGSphere3D.xml b/modules/csg/doc_classes/CSGSphere3D.xml
index 4d5b3be099..b8dfb4cf5f 100644
--- a/modules/csg/doc_classes/CSGSphere3D.xml
+++ b/modules/csg/doc_classes/CSGSphere3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="material" type="Material" setter="set_material" getter="get_material">
The material used to render the sphere.
@@ -27,6 +25,4 @@
If [code]true[/code] the normals of the sphere are set to give a smooth effect making the sphere seem rounded. If [code]false[/code] the sphere will have a flat shaded look.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/csg/doc_classes/CSGTorus3D.xml b/modules/csg/doc_classes/CSGTorus3D.xml
index abe3eab913..91ee63a4c9 100644
--- a/modules/csg/doc_classes/CSGTorus3D.xml
+++ b/modules/csg/doc_classes/CSGTorus3D.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="inner_radius" type="float" setter="set_inner_radius" getter="get_inner_radius" default="2.0">
The inner radius of the torus.
@@ -30,6 +28,4 @@
If [code]true[/code] the normals of the torus are set to give a smooth effect making the torus seem rounded. If [code]false[/code] the torus will have a flat shaded look.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/enet/doc_classes/ENetConnection.xml b/modules/enet/doc_classes/ENetConnection.xml
index 00469ab44c..fcdf282a7d 100644
--- a/modules/enet/doc_classes/ENetConnection.xml
+++ b/modules/enet/doc_classes/ENetConnection.xml
@@ -51,7 +51,7 @@
<argument index="3" name="data" type="int" default="0" />
<description>
Initiates a connection to a foreign [code]address[/code] using the specified [code]port[/code] and allocting the requested [code]channels[/code]. Optional [code]data[/code] can be passed during connection in the form of a 32 bit integer.
- Note: You must call either [method create_host] or [method create_host_bound] before calling this method.
+ [b]Note:[/b] You must call either [method create_host] or [method create_host_bound] before calling this method.
</description>
</method>
<method name="create_host">
@@ -121,7 +121,7 @@
<return type="Array" />
<description>
Returns the list of peers associated with this host.
- Note: This list might include some peers that are not fully connected or are still being disconnected.
+ [b]Note:[/b] This list might include some peers that are not fully connected or are still being disconnected.
</description>
</method>
<method name="pop_statistic">
@@ -136,7 +136,7 @@
<argument index="0" name="refuse" type="bool" />
<description>
Configures the DTLS server to automatically drop new connections.
- Note: This method is only relevant after calling [method dtls_server_setup].
+ [b]Note:[/b] This method is only relevant after calling [method dtls_server_setup].
</description>
</method>
<method name="service">
diff --git a/modules/enet/doc_classes/ENetMultiplayerPeer.xml b/modules/enet/doc_classes/ENetMultiplayerPeer.xml
index 43e1d40e47..22136c3944 100644
--- a/modules/enet/doc_classes/ENetMultiplayerPeer.xml
+++ b/modules/enet/doc_classes/ENetMultiplayerPeer.xml
@@ -18,7 +18,7 @@
<argument index="1" name="host" type="ENetConnection" />
<description>
Add a new remote peer with the given [code]peer_id[/code] connected to the given [code]host[/code].
- Note: The [code]host[/code] must have exactly one peer in the [constant ENetPacketPeer.STATE_CONNECTED] state.
+ [b]Note:[/b] The [code]host[/code] must have exactly one peer in the [constant ENetPacketPeer.STATE_CONNECTED] state.
</description>
</method>
<method name="close_connection">
@@ -77,12 +77,8 @@
<member name="host" type="ENetConnection" setter="" getter="get_host">
The underlying [ENetConnection] created after [method create_client] and [method create_server].
</member>
- <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" />
<member name="server_relay" type="bool" setter="set_server_relay_enabled" getter="is_server_relay_enabled" default="true">
Enable or disable the server feature that notifies clients of other peers' connection/disconnection, and relays messages between them. When this option is [code]false[/code], clients won't be automatically notified of other peers and won't be able to send them packets through the server.
</member>
- <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" />
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/enet/doc_classes/ENetPacketPeer.xml b/modules/enet/doc_classes/ENetPacketPeer.xml
index 8f0693fb01..4116ba17f2 100644
--- a/modules/enet/doc_classes/ENetPacketPeer.xml
+++ b/modules/enet/doc_classes/ENetPacketPeer.xml
@@ -6,6 +6,7 @@
<description>
A PacketPeer implementation representing a peer of an [ENetConnection].
This class cannot be instantiated directly but can be retrieved during [method ENetConnection.service] or via [method ENetConnection.get_peers].
+ [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
<link title="API documentation on the ENet website">http://enet.bespin.org/usergroup0.html</link>
diff --git a/modules/enet/enet_multiplayer_peer.cpp b/modules/enet/enet_multiplayer_peer.cpp
index afd31207f6..2cfae60ad2 100644
--- a/modules/enet/enet_multiplayer_peer.cpp
+++ b/modules/enet/enet_multiplayer_peer.cpp
@@ -33,22 +33,6 @@
#include "core/io/marshalls.h"
#include "core/os/os.h"
-void ENetMultiplayerPeer::set_transfer_channel(int p_channel) {
- transfer_channel = p_channel;
-}
-
-int ENetMultiplayerPeer::get_transfer_channel() const {
- return transfer_channel;
-}
-
-void ENetMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) {
- transfer_mode = p_mode;
-}
-
-Multiplayer::TransferMode ENetMultiplayerPeer::get_transfer_mode() const {
- return transfer_mode;
-}
-
void ENetMultiplayerPeer::set_target_peer(int p_peer) {
target_peer = p_peer;
}
@@ -62,6 +46,7 @@ int ENetMultiplayerPeer::get_packet_peer() const {
Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_max_channels, int p_in_bandwidth, int p_out_bandwidth) {
ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
+ set_refuse_new_connections(false);
Ref<ENetConnection> host;
host.instantiate();
Error err = host->create_host_bound(bind_ip, p_port, p_max_clients, 0, p_max_channels > 0 ? p_max_channels + SYSCH_MAX : 0, p_out_bandwidth);
@@ -70,7 +55,6 @@ Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_ma
}
active_mode = MODE_SERVER;
- refuse_connections = false;
unique_id = 1;
connection_status = CONNECTION_CONNECTED;
hosts[0] = host;
@@ -79,6 +63,7 @@ Error ENetMultiplayerPeer::create_server(int p_port, int p_max_clients, int p_ma
Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, int p_channel_count, int p_in_bandwidth, int p_out_bandwidth, int p_local_port) {
ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
+ set_refuse_new_connections(false);
Ref<ENetConnection> host;
host.instantiate();
Error err;
@@ -102,7 +87,6 @@ Error ENetMultiplayerPeer::create_client(const String &p_address, int p_port, in
// Need to wait for CONNECT event.
connection_status = CONNECTION_CONNECTING;
active_mode = MODE_CLIENT;
- refuse_connections = false;
peers[1] = peer;
hosts[0] = host;
@@ -113,7 +97,6 @@ Error ENetMultiplayerPeer::create_mesh(int p_id) {
ERR_FAIL_COND_V_MSG(p_id <= 0, ERR_INVALID_PARAMETER, "The unique ID must be greater then 0");
ERR_FAIL_COND_V_MSG(_is_active(), ERR_ALREADY_IN_USE, "The multiplayer instance is already active.");
active_mode = MODE_MESH;
- refuse_connections = false;
unique_id = p_id;
connection_status = CONNECTION_CONNECTED;
return OK;
@@ -145,7 +128,7 @@ bool ENetMultiplayerPeer::_poll_server() {
}
switch (ret) {
case ENetConnection::EVENT_CONNECT: {
- if (refuse_connections) {
+ if (is_refusing_new_connections()) {
event.peer->reset();
return false;
}
@@ -173,7 +156,7 @@ bool ENetMultiplayerPeer::_poll_server() {
emit_signal(SNAME("peer_disconnected"), id);
peers.erase(id);
- if (!server_relay) {
+ if (server_relay) {
_notify_peers(id, false);
}
return false;
@@ -423,6 +406,7 @@ void ENetMultiplayerPeer::close_connection(uint32_t wait_usec) {
hosts.clear();
unique_id = 0;
connection_status = CONNECTION_DISCONNECTED;
+ set_refuse_new_connections(false);
}
int ENetMultiplayerPeer::get_available_packet_count() const {
@@ -451,15 +435,16 @@ Error ENetMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size
int packet_flags = 0;
int channel = SYSCH_RELIABLE;
+ int transfer_channel = get_transfer_channel();
if (transfer_channel > 0) {
channel = SYSCH_MAX + transfer_channel - 1;
} else {
- switch (transfer_mode) {
+ switch (get_transfer_mode()) {
case Multiplayer::TRANSFER_MODE_UNRELIABLE: {
packet_flags = ENET_PACKET_FLAG_UNSEQUENCED;
channel = SYSCH_UNRELIABLE;
} break;
- case Multiplayer::TRANSFER_MODE_ORDERED: {
+ case Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED: {
packet_flags = 0;
channel = SYSCH_UNRELIABLE;
} break;
@@ -545,19 +530,15 @@ int ENetMultiplayerPeer::get_unique_id() const {
return unique_id;
}
-void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enable) {
- refuse_connections = p_enable;
+void ENetMultiplayerPeer::set_refuse_new_connections(bool p_enabled) {
#ifdef GODOT_ENET
if (_is_active()) {
for (KeyValue<int, Ref<ENetConnection>> &E : hosts) {
- E.value->refuse_new_connections(p_enable);
+ E.value->refuse_new_connections(p_enabled);
}
}
#endif
-}
-
-bool ENetMultiplayerPeer::is_refusing_new_connections() const {
- return refuse_connections;
+ MultiplayerPeer::set_refuse_new_connections(p_enabled);
}
void ENetMultiplayerPeer::set_server_relay_enabled(bool p_enabled) {
diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h
index b5316b8292..7a60e2359c 100644
--- a/modules/enet/enet_multiplayer_peer.h
+++ b/modules/enet/enet_multiplayer_peer.h
@@ -65,10 +65,7 @@ private:
uint32_t unique_id = 0;
int target_peer = 0;
- int transfer_channel = 0;
- Multiplayer::TransferMode transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE;
- bool refuse_connections = false;
bool server_relay = true;
ConnectionStatus connection_status = CONNECTION_DISCONNECTED;
@@ -101,40 +98,31 @@ protected:
static void _bind_methods();
public:
- virtual void set_transfer_channel(int p_channel) override;
- virtual int get_transfer_channel() const override;
-
- virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) override;
- virtual Multiplayer::TransferMode get_transfer_mode() const override;
virtual void set_target_peer(int p_peer) override;
-
virtual int get_packet_peer() const override;
- Error create_server(int p_port, int p_max_clients = 32, int p_max_channels = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0);
- Error create_client(const String &p_address, int p_port, int p_channel_count = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0);
- Error create_mesh(int p_id);
- Error add_mesh_peer(int p_id, Ref<ENetConnection> p_host);
-
- void close_connection(uint32_t wait_usec = 100);
-
- void disconnect_peer(int p_peer, bool now = false);
-
virtual void poll() override;
-
virtual bool is_server() const override;
+ // Overriden so we can instrument the DTLSServer when needed.
+ virtual void set_refuse_new_connections(bool p_enabled) override;
- virtual int get_available_packet_count() const override;
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override; ///< buffer is GONE after next get_packet
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
+ virtual ConnectionStatus get_connection_status() const override;
+
+ virtual int get_unique_id() const override;
virtual int get_max_packet_size() const override;
+ virtual int get_available_packet_count() const override;
+ virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
+ virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual ConnectionStatus get_connection_status() const override;
+ Error create_server(int p_port, int p_max_clients = 32, int p_max_channels = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0);
+ Error create_client(const String &p_address, int p_port, int p_channel_count = 0, int p_in_bandwidth = 0, int p_out_bandwidth = 0, int p_local_port = 0);
+ Error create_mesh(int p_id);
+ Error add_mesh_peer(int p_id, Ref<ENetConnection> p_host);
- virtual void set_refuse_new_connections(bool p_enable) override;
- virtual bool is_refusing_new_connections() const override;
+ void close_connection(uint32_t wait_usec = 100);
- virtual int get_unique_id() const override;
+ void disconnect_peer(int p_peer, bool now = false);
void set_bind_ip(const IPAddress &p_ip);
void set_server_relay_enabled(bool p_enabled);
diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp
index abc3c26188..aff7538fb6 100644
--- a/modules/etcpak/image_compress_etcpak.cpp
+++ b/modules/etcpak/image_compress_etcpak.cpp
@@ -165,9 +165,9 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua
if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC1) {
CompressEtc1RgbDither(src_mip_read, dest_mip_write, blocks, mip_w);
} else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2 || p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_RA_AS_RG) {
- CompressEtc2Rgb(src_mip_read, dest_mip_write, blocks, mip_w);
+ CompressEtc2Rgb(src_mip_read, dest_mip_write, blocks, mip_w, true);
} else if (p_compresstype == EtcpakType::ETCPAK_TYPE_ETC2_ALPHA) {
- CompressEtc2Rgba(src_mip_read, dest_mip_write, blocks, mip_w);
+ CompressEtc2Rgba(src_mip_read, dest_mip_write, blocks, mip_w, true);
} else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT1) {
CompressDxt1Dither(src_mip_read, dest_mip_write, blocks, mip_w);
} else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5 || p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5_RA_AS_RG) {
diff --git a/modules/fbx/data/fbx_mesh_data.cpp b/modules/fbx/data/fbx_mesh_data.cpp
index dcea476275..7343bf87af 100644
--- a/modules/fbx/data/fbx_mesh_data.cpp
+++ b/modules/fbx/data/fbx_mesh_data.cpp
@@ -31,6 +31,7 @@
#include "fbx_mesh_data.h"
#include "core/templates/local_vector.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh.h"
#include "scene/resources/surface_tool.h"
@@ -101,7 +102,7 @@ HashMap<int, Vector2> collect_uv(const Vector<VertexData<Vector2>> *p_data, Hash
return collection;
}
-EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
+ImporterMeshInstance3D *FBXMeshData::create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression) {
mesh_geometry = p_mesh_geometry;
// todo: make this just use a uint64_t FBX ID this is a copy of our original materials unfortunately.
const std::vector<const FBXDocParser::Material *> &material_lookup = model->GetMaterials();
@@ -344,7 +345,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
}
// Phase 6. Compose the mesh and return it.
- Ref<EditorSceneImporterMesh> mesh;
+ Ref<ImporterMesh> mesh;
mesh.instantiate();
// Add blend shape info.
@@ -380,7 +381,7 @@ EditorSceneImporterMeshNode3D *FBXMeshData::create_fbx_mesh(const ImportState &s
in_mesh_surface_id += 1;
}
- EditorSceneImporterMeshNode3D *godot_mesh = memnew(EditorSceneImporterMeshNode3D);
+ ImporterMeshInstance3D *godot_mesh = memnew(ImporterMeshInstance3D);
godot_mesh->set_mesh(mesh);
const String name = ImportUtils::FBXNodeToName(model->Name());
godot_mesh->set_name(name); // hurry up compiling >.<
diff --git a/modules/fbx/data/fbx_mesh_data.h b/modules/fbx/data/fbx_mesh_data.h
index 24db4a5469..eec7f38cd6 100644
--- a/modules/fbx/data/fbx_mesh_data.h
+++ b/modules/fbx/data/fbx_mesh_data.h
@@ -35,7 +35,7 @@
#include "core/templates/local_vector.h"
#include "core/templates/ordered_hash_map.h"
#include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/resources/surface_tool.h"
@@ -98,7 +98,7 @@ struct FBXMeshData : RefCounted {
// translate fbx mesh data from document context to FBX Mesh Geometry Context
bool valid_weight_indexes = false;
- EditorSceneImporterMeshNode3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression);
+ ImporterMeshInstance3D *create_fbx_mesh(const ImportState &state, const FBXDocParser::MeshGeometry *p_mesh_geometry, const FBXDocParser::Model *model, bool use_compression);
void gen_weight_info(Ref<SurfaceTool> st, int vertex_id) const;
@@ -107,7 +107,7 @@ struct FBXMeshData : RefCounted {
int max_weight_count = 0;
uint64_t armature_id = 0;
bool valid_armature_id = false;
- EditorSceneImporterMeshNode3D *godot_mesh_instance = nullptr;
+ ImporterMeshInstance3D *godot_mesh_instance = nullptr;
private:
void sanitize_vertex_weights(const ImportState &state);
diff --git a/modules/fbx/data/fbx_skeleton.cpp b/modules/fbx/data/fbx_skeleton.cpp
index 1ac4922acf..3dc163964c 100644
--- a/modules/fbx/data/fbx_skeleton.cpp
+++ b/modules/fbx/data/fbx_skeleton.cpp
@@ -98,9 +98,9 @@ void FBXSkeleton::init_skeleton(const ImportState &state) {
ERR_FAIL_COND_MSG(skeleton->get_bone_count() != bone_count, "Not all bones got added, is the file corrupted?");
- for (Map<int, Ref<FBXBone>>::Element *bone_element = bone_map.front(); bone_element; bone_element = bone_element->next()) {
- const Ref<FBXBone> bone = bone_element->value();
- int bone_index = bone_element->key();
+ for (const KeyValue<int, Ref<FBXBone>> &bone_element : bone_map) {
+ const Ref<FBXBone> bone = bone_element.value;
+ int bone_index = bone_element.key;
print_verbose("working on bone: " + itos(bone_index) + " bone name:" + bone->bone_name);
skeleton->set_bone_rest(bone->godot_bone_id, get_unscaled_transform(bone->node->pivot_transform->LocalTransform, state.scale));
diff --git a/modules/fbx/doc_classes/EditorSceneImporterFBX.xml b/modules/fbx/doc_classes/EditorSceneImporterFBX.xml
index da1a68c27c..6f83871772 100644
--- a/modules/fbx/doc_classes/EditorSceneImporterFBX.xml
+++ b/modules/fbx/doc_classes/EditorSceneImporterFBX.xml
@@ -29,8 +29,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/fbx/editor_scene_importer_fbx.cpp b/modules/fbx/editor_scene_importer_fbx.cpp
index e3f36ef3e3..e4de204cf1 100644
--- a/modules/fbx/editor_scene_importer_fbx.cpp
+++ b/modules/fbx/editor_scene_importer_fbx.cpp
@@ -40,9 +40,9 @@
#include "editor/editor_log.h"
#include "editor/editor_node.h"
#include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/main/node.h"
#include "scene/resources/material.h"
@@ -567,8 +567,8 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
// this means that the nodes from maya kLocators will be preserved as bones
// in the same rig without having to match this across skeletons and merge by detection
// we can just merge and undo any parent transforms
- for (Map<uint64_t, Ref<FBXBone>>::Element *bone_element = state.fbx_bone_map.front(); bone_element; bone_element = bone_element->next()) {
- Ref<FBXBone> bone = bone_element->value();
+ for (KeyValue<uint64_t, Ref<FBXBone>> &bone_element : state.fbx_bone_map) {
+ Ref<FBXBone> bone = bone_element.value;
Ref<FBXSkeleton> fbx_skeleton_inst;
uint64_t armature_id = bone->armature_id;
@@ -609,8 +609,8 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
}
// setup skeleton instances if required :)
- for (Map<uint64_t, Ref<FBXSkeleton>>::Element *skeleton_node = state.skeleton_map.front(); skeleton_node; skeleton_node = skeleton_node->next()) {
- Ref<FBXSkeleton> &skeleton = skeleton_node->value();
+ for (KeyValue<uint64_t, Ref<FBXSkeleton>> &skeleton_node : state.skeleton_map) {
+ Ref<FBXSkeleton> &skeleton = skeleton_node.value;
skeleton->init_skeleton(state);
ERR_CONTINUE_MSG(skeleton->fbx_node.is_null(), "invalid fbx target map, missing skeleton");
@@ -627,7 +627,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
node_element;
node_element = node_element->next()) {
Ref<FBXNode> fbx_node = node_element->get();
- EditorSceneImporterMeshNode3D *mesh_node = nullptr;
+ ImporterMeshInstance3D *mesh_node = nullptr;
Ref<FBXMeshData> mesh_data_precached;
// check for valid geometry
@@ -699,9 +699,9 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
}
}
- for (Map<uint64_t, Ref<FBXMeshData>>::Element *mesh_data = state.renderer_mesh_data.front(); mesh_data; mesh_data = mesh_data->next()) {
- const uint64_t mesh_id = mesh_data->key();
- Ref<FBXMeshData> mesh = mesh_data->value();
+ for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) {
+ const uint64_t mesh_id = mesh_data.key;
+ Ref<FBXMeshData> mesh = mesh_data.value;
const FBXDocParser::MeshGeometry *mesh_geometry = p_document->GetObject(mesh_id)->Get<FBXDocParser::MeshGeometry>();
@@ -765,10 +765,10 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
}
// mesh data iteration for populating skeleton mapping
- for (Map<uint64_t, Ref<FBXMeshData>>::Element *mesh_data = state.renderer_mesh_data.front(); mesh_data; mesh_data = mesh_data->next()) {
- Ref<FBXMeshData> mesh = mesh_data->value();
- const uint64_t mesh_id = mesh_data->key();
- EditorSceneImporterMeshNode3D *mesh_instance = mesh->godot_mesh_instance;
+ for (KeyValue<uint64_t, Ref<FBXMeshData>> &mesh_data : state.renderer_mesh_data) {
+ Ref<FBXMeshData> mesh = mesh_data.value;
+ const uint64_t mesh_id = mesh_data.key;
+ ImporterMeshInstance3D *mesh_instance = mesh->godot_mesh_instance;
const int mesh_weights = mesh->max_weight_count;
Ref<FBXSkeleton> skeleton;
const bool valid_armature = mesh->valid_armature_id;
@@ -1004,13 +1004,13 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
// target id, [ track name, [time index, vector] ]
//std::map<uint64_t, std::map<StringName, FBXTrack > > AnimCurveNodes;
- for (Map<uint64_t, Map<StringName, FBXTrack>>::Element *track = AnimCurveNodes.front(); track; track = track->next()) {
+ for (KeyValue<uint64_t, Map<StringName, FBXTrack>> &track : AnimCurveNodes) {
// 5 tracks
// current track index
// track count is 5
// track count is 5.
// next track id is 5.
- const uint64_t target_id = track->key();
+ const uint64_t target_id = track.key;
int track_idx = animation->add_track(Animation::TYPE_TRANSFORM3D);
// animation->track_set_path(track_idx, node_path);
@@ -1072,7 +1072,7 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
const FBXDocParser::Model *model = target_node->fbx_model;
const FBXDocParser::PropertyTable *props = dynamic_cast<const FBXDocParser::PropertyTable *>(model);
- Map<StringName, FBXTrack> &track_data = track->value();
+ Map<StringName, FBXTrack> &track_data = track.value;
FBXTrack &translation_keys = track_data[StringName("T")];
FBXTrack &rotation_keys = track_data[StringName("R")];
FBXTrack &scale_keys = track_data[StringName("S")];
@@ -1259,15 +1259,15 @@ Node3D *EditorSceneImporterFBX::_generate_scene(
state.fbx_target_map.clear();
state.fbx_node_list.clear();
- for (Map<uint64_t, Ref<FBXBone>>::Element *element = state.fbx_bone_map.front(); element; element = element->next()) {
- Ref<FBXBone> bone = element->value();
+ for (KeyValue<uint64_t, Ref<FBXBone>> &element : state.fbx_bone_map) {
+ Ref<FBXBone> bone = element.value;
bone->parent_bone.unref();
bone->node.unref();
bone->fbx_skeleton.unref();
}
- for (Map<uint64_t, Ref<FBXSkeleton>>::Element *element = state.skeleton_map.front(); element; element = element->next()) {
- Ref<FBXSkeleton> skel = element->value();
+ for (KeyValue<uint64_t, Ref<FBXSkeleton>> &element : state.skeleton_map) {
+ Ref<FBXSkeleton> skel = element.value;
skel->fbx_node.unref();
skel->skeleton_bones.clear();
}
diff --git a/modules/fbx/tools/validation_tools.h b/modules/fbx/tools/validation_tools.h
index 906a721045..12d644ee94 100644
--- a/modules/fbx/tools/validation_tools.h
+++ b/modules/fbx/tools/validation_tools.h
@@ -53,9 +53,9 @@ protected:
String csv_header = "file_path, error message, extra data\n";
massive_log_file += csv_header;
- for (Map<String, LocalVector<String>>::Element *element = validation_entries.front(); element; element = element->next()) {
- for (unsigned int x = 0; x < element->value().size(); x++) {
- const String &line_entry = element->key() + ", " + element->value()[x].c_escape() + "\n";
+ for (const KeyValue<String, LocalVector<String>> &element : validation_entries) {
+ for (unsigned int x = 0; x < element.value.size(); x++) {
+ const String &line_entry = element.key + ", " + element.value[x].c_escape() + "\n";
massive_log_file += line_entry;
}
}
diff --git a/modules/gdnative/SCsub b/modules/gdnative/SCsub
index 21ee39f3ed..f7f21a433e 100644
--- a/modules/gdnative/SCsub
+++ b/modules/gdnative/SCsub
@@ -16,10 +16,8 @@ env_gdnative.Prepend(CPPPATH=["#modules/gdnative/include/"])
Export("env_gdnative")
-SConscript("net/SCsub")
SConscript("pluginscript/SCsub")
SConscript("videodecoder/SCsub")
-SConscript("text/SCsub")
import gdnative_builders
diff --git a/modules/gdnative/config.py b/modules/gdnative/config.py
index fa985501b5..026a84a70f 100644
--- a/modules/gdnative/config.py
+++ b/modules/gdnative/config.py
@@ -10,14 +10,9 @@ def get_doc_classes():
return [
"GDNative",
"GDNativeLibrary",
- "MultiplayerPeerGDNative",
"NativeScript",
- "PacketPeerGDNative",
"PluginScript",
- "StreamPeerGDNative",
"VideoStreamGDNative",
- "WebRTCPeerConnectionGDNative",
- "WebRTCDataChannelGDNative",
]
diff --git a/modules/gdnative/doc_classes/GDNative.xml b/modules/gdnative/doc_classes/GDNative.xml
index e4c5d34a2c..4bc149b119 100644
--- a/modules/gdnative/doc_classes/GDNative.xml
+++ b/modules/gdnative/doc_classes/GDNative.xml
@@ -30,6 +30,4 @@
<member name="library" type="GDNativeLibrary" setter="set_library" getter="get_library">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
index 94eae3cd06..6b3bd714b9 100644
--- a/modules/gdnative/doc_classes/GDNativeLibrary.xml
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -7,8 +7,8 @@
A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as XRInterfaceGDNative. The library must be compiled for each platform and architecture that the project will run on.
</description>
<tutorials>
- <link title="GDNative C example">https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link>
- <link title="GDNative C++ example">https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-cpp-example.html</link>
+ <link title="GDNative C example">https://docs.godotengine.org/en/latest/tutorials/scripting/gdnative/gdnative_c_example.html</link>
+ <link title="GDNative C++ example">https://docs.godotengine.org/en/latest/tutorials/scripting/gdnative/gdnative_cpp_example.html</link>
</tutorials>
<methods>
<method name="get_current_dependencies" qualifiers="const">
@@ -45,6 +45,4 @@
On platforms that require statically linking libraries (currently only iOS), each library must have a different [code]symbol_prefix[/code].
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gdnative/doc_classes/NativeScript.xml b/modules/gdnative/doc_classes/NativeScript.xml
index 397d12a3a9..221374a7a4 100644
--- a/modules/gdnative/doc_classes/NativeScript.xml
+++ b/modules/gdnative/doc_classes/NativeScript.xml
@@ -38,7 +38,7 @@
<return type="Variant" />
<description>
Constructs a new object of the base type with a script of this type already attached.
- [i]Note[/i]: Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension.
+ [b]Note:[/b] Any arguments passed to this function will be ignored and not passed to the native constructor function. This will change with in a future API extension.
</description>
</method>
</methods>
@@ -52,6 +52,4 @@
<member name="script_class_name" type="String" setter="set_script_class_name" getter="get_script_class_name" default="&quot;&quot;">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gdnative/doc_classes/PluginScript.xml b/modules/gdnative/doc_classes/PluginScript.xml
index 8e28187482..ec80ade394 100644
--- a/modules/gdnative/doc_classes/PluginScript.xml
+++ b/modules/gdnative/doc_classes/PluginScript.xml
@@ -14,6 +14,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/gdnative/doc_classes/VideoStreamGDNative.xml b/modules/gdnative/doc_classes/VideoStreamGDNative.xml
index 8b1a3210df..dc64e8fc18 100644
--- a/modules/gdnative/doc_classes/VideoStreamGDNative.xml
+++ b/modules/gdnative/doc_classes/VideoStreamGDNative.xml
@@ -24,6 +24,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/gdnative/doc_classes/WebRTCDataChannelGDNative.xml b/modules/gdnative/doc_classes/WebRTCDataChannelGDNative.xml
deleted file mode 100644
index f32a4f0a23..0000000000
--- a/modules/gdnative/doc_classes/WebRTCDataChannelGDNative.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebRTCDataChannelGDNative" inherits="WebRTCDataChannel" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/modules/gdnative/doc_classes/WebRTCPeerConnectionGDNative.xml b/modules/gdnative/doc_classes/WebRTCPeerConnectionGDNative.xml
deleted file mode 100644
index 82f8633bb6..0000000000
--- a/modules/gdnative/doc_classes/WebRTCPeerConnectionGDNative.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="WebRTCPeerConnectionGDNative" inherits="WebRTCPeerConnection" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
-</class>
diff --git a/modules/gdnative/gdnative_api.json b/modules/gdnative/gdnative_api.json
index 66d2dc267d..cf1c7dc01f 100644
--- a/modules/gdnative/gdnative_api.json
+++ b/modules/gdnative/gdnative_api.json
@@ -5103,580 +5103,6 @@
]
}
]
- },
- {
- "name": "net",
- "type": "NET",
- "version": {
- "major": 4,
- "minor": 0
- },
- "next": null,
- "api": [
- {
- "name": "godot_net_bind_stream_peer",
- "return_type": "void",
- "arguments": [
- [
- "godot_object *",
- "p_obj"
- ],
- [
- "const godot_net_stream_peer *",
- "p_interface"
- ]
- ]
- },
- {
- "name": "godot_net_bind_packet_peer",
- "return_type": "void",
- "arguments": [
- [
- "godot_object *",
- "p_obj"
- ],
- [
- "const godot_net_packet_peer *",
- "p_interface"
- ]
- ]
- },
- {
- "name": "godot_net_bind_multiplayer_peer",
- "return_type": "void",
- "arguments": [
- [
- "godot_object *",
- "p_obj"
- ],
- [
- "const godot_net_multiplayer_peer *",
- "p_interface"
- ]
- ]
- },
- {
- "name": "godot_net_set_webrtc_library",
- "return_type": "godot_error",
- "arguments": [
- [
- "const godot_net_webrtc_library *",
- "p_library"
- ]
- ]
- },
- {
- "name": "godot_net_bind_webrtc_peer_connection",
- "return_type": "void",
- "arguments": [
- [
- "godot_object *",
- "p_obj"
- ],
- [
- "const godot_net_webrtc_peer_connection *",
- "p_interface"
- ]
- ]
- },
- {
- "name": "godot_net_bind_webrtc_data_channel",
- "return_type": "void",
- "arguments": [
- [
- "godot_object *",
- "p_obj"
- ],
- [
- "const godot_net_webrtc_data_channel *",
- "p_interface"
- ]
- ]
- }
- ]
- },
- {
- "name": "text",
- "type": "TEXT",
- "version": {
- "major": 1,
- "minor": 0
- },
- "next": null,
- "api": [
- {
- "name": "godot_text_register_interface",
- "return_type": "void",
- "arguments": [
- [
- "const godot_text_interface_gdnative *",
- "p_interface"
- ],
- [
- "const godot_string *",
- "p_name"
- ],
- [
- "uint32_t",
- "p_features"
- ]
- ]
- },
- {
- "name": "godot_glyph_new",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "r_dest"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_range",
- "return_type": "godot_vector2i",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_range",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "const godot_vector2i *",
- "p_range"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_count",
- "return_type": "godot_int",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_count",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "godot_int",
- "p_count"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_repeat",
- "return_type": "godot_int",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_repeat",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "godot_int",
- "p_repeat"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_flags",
- "return_type": "godot_int",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_flags",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "godot_int",
- "p_flags"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_offset",
- "return_type": "godot_vector2",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_offset",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "const godot_vector2 *",
- "p_offset"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_advance",
- "return_type": "godot_real_t",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_advance",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "godot_real_t",
- "p_advance"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_font",
- "return_type": "godot_rid",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_font",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "godot_rid *",
- "p_font"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_font_size",
- "return_type": "godot_int",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_font_size",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "godot_int",
- "p_size"
- ]
- ]
- },
- {
- "name": "godot_glyph_get_index",
- "return_type": "godot_int",
- "arguments": [
- [
- "const godot_glyph *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_glyph_set_index",
- "return_type": "void",
- "arguments": [
- [
- "godot_glyph *",
- "p_self"
- ],
- [
- "godot_int",
- "p_index"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_new",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "r_dest"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_new_copy",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "r_dest"
- ],
- [
- "const godot_packed_glyph_array *",
- "p_src"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_is_empty",
- "return_type": "godot_bool",
- "arguments": [
- [
- "const godot_packed_glyph_array *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_append",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_glyph *",
- "p_data"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_append_array",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_packed_glyph_array *",
- "p_array"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_insert",
- "return_type": "godot_error",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_int",
- "p_idx"
- ],
- [
- "const godot_glyph *",
- "p_data"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_has",
- "return_type": "godot_bool",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_glyph *",
- "p_value"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_sort",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_reverse",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_push_back",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_glyph *",
- "p_data"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_remove",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_int",
- "p_idx"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_resize",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_int",
- "p_size"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_ptr",
- "return_type": "const godot_glyph *",
- "arguments": [
- [
- "const godot_packed_glyph_array *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_ptrw",
- "return_type": "godot_glyph *",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_set",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_int",
- "p_idx"
- ],
- [
- "const godot_glyph *",
- "p_data"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_get",
- "return_type": "godot_glyph",
- "arguments": [
- [
- "const godot_packed_glyph_array *",
- "p_self"
- ],
- [
- "const godot_int",
- "p_idx"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_size",
- "return_type": "godot_int",
- "arguments": [
- [
- "const godot_packed_glyph_array *",
- "p_self"
- ]
- ]
- },
- {
- "name": "godot_packed_glyph_array_destroy",
- "return_type": "void",
- "arguments": [
- [
- "godot_packed_glyph_array *",
- "p_self"
- ]
- ]
- }
- ]
}
]
}
diff --git a/modules/gdnative/gdnative_builders.py b/modules/gdnative/gdnative_builders.py
index 181fd71b82..6c96e23426 100644
--- a/modules/gdnative/gdnative_builders.py
+++ b/modules/gdnative/gdnative_builders.py
@@ -20,10 +20,8 @@ def _build_gdnative_api_struct_header(api):
"#include <gdnative/gdnative.h>",
"#include <android/godot_android.h>",
"#include <nativescript/godot_nativescript.h>",
- "#include <net/godot_net.h>",
"#include <pluginscript/godot_pluginscript.h>",
"#include <videodecoder/godot_videodecoder.h>",
- "#include <text/godot_text.h>",
"",
"#ifdef __cplusplus",
'extern "C" {',
diff --git a/modules/gdnative/gdnative_library_editor_plugin.cpp b/modules/gdnative/gdnative_library_editor_plugin.cpp
index f965bcd014..9dad13a615 100644
--- a/modules/gdnative/gdnative_library_editor_plugin.cpp
+++ b/modules/gdnative/gdnative_library_editor_plugin.cpp
@@ -38,9 +38,9 @@ void GDNativeLibraryEditor::edit(Ref<GDNativeLibrary> p_library) {
library = p_library;
Ref<ConfigFile> config = p_library->get_config_file();
- for (Map<String, NativePlatformConfig>::Element *E = platforms.front(); E; E = E->next()) {
- for (List<String>::Element *it = E->value().entries.front(); it; it = it->next()) {
- String target = E->key() + "." + it->get();
+ for (KeyValue<String, NativePlatformConfig> &E : platforms) {
+ for (List<String>::Element *it = E.value.entries.front(); it; it = it->next()) {
+ String target = E.key + "." + it->get();
TargetConfig ecfg;
ecfg.library = config->get_value("entry", target, "");
ecfg.dependencies = config->get_value("dependencies", target, Array());
@@ -245,9 +245,9 @@ void GDNativeLibraryEditor::_translate_to_config_file() {
config->erase_section("entry");
config->erase_section("dependencies");
- for (Map<String, NativePlatformConfig>::Element *E = platforms.front(); E; E = E->next()) {
- for (List<String>::Element *it = E->value().entries.front(); it; it = it->next()) {
- String target = E->key() + "." + it->get();
+ for (KeyValue<String, NativePlatformConfig> &E : platforms) {
+ for (List<String>::Element *it = E.value.entries.front(); it; it = it->next()) {
+ String target = E.key + "." + it->get();
if (entry_configs[target].library.is_empty() && entry_configs[target].dependencies.is_empty()) {
continue;
}
@@ -341,9 +341,9 @@ GDNativeLibraryEditor::GDNativeLibraryEditor() {
filter_list->set_hide_on_checkable_item_selection(false);
int idx = 0;
- for (Map<String, NativePlatformConfig>::Element *E = platforms.front(); E; E = E->next()) {
- filter_list->add_check_item(E->get().name, idx);
- filter_list->set_item_metadata(idx, E->key());
+ for (const KeyValue<String, NativePlatformConfig> &E : platforms) {
+ filter_list->add_check_item(E.value.name, idx);
+ filter_list->set_item_metadata(idx, E.key);
filter_list->set_item_checked(idx, true);
idx += 1;
}
diff --git a/modules/gdnative/include/nativescript/godot_nativescript.h b/modules/gdnative/include/nativescript/godot_nativescript.h
index 09eac2492f..5390d30c9f 100644
--- a/modules/gdnative/include/nativescript/godot_nativescript.h
+++ b/modules/gdnative/include/nativescript/godot_nativescript.h
@@ -39,7 +39,7 @@ extern "C" {
typedef enum {
GODOT_METHOD_RPC_MODE_DISABLED,
- GODOT_METHOD_RPC_MODE_ANY,
+ GODOT_METHOD_RPC_MODE_ANY_PEER,
GODOT_METHOD_RPC_MODE_AUTHORITY,
} godot_nativescript_method_rpc_mode;
diff --git a/modules/gdnative/include/net/godot_net.h b/modules/gdnative/include/net/godot_net.h
deleted file mode 100644
index 3fb7b9e1cc..0000000000
--- a/modules/gdnative/include/net/godot_net.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*************************************************************************/
-/* godot_net.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 GODOT_NATIVENET_H
-#define GODOT_NATIVENET_H
-
-#include <gdnative/gdnative.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-// For future versions of the API we should only add new functions at the end of the structure and use the
-// version info to detect whether a call is available
-
-// Use these to populate version in your plugin
-#define GODOT_NET_API_MAJOR 3
-#define GODOT_NET_API_MINOR 1
-
-typedef struct {
- godot_gdnative_api_version version; /* version of our API */
- godot_object *data; /* User reference */
-
- /* This is StreamPeer */
- godot_error (*get_data)(void *user, uint8_t *p_buffer, int p_bytes);
- godot_error (*get_partial_data)(void *user, uint8_t *p_buffer, int p_bytes, int *r_received);
- godot_error (*put_data)(void *user, const uint8_t *p_data, int p_bytes);
- godot_error (*put_partial_data)(void *user, const uint8_t *p_data, int p_bytes, int *r_sent);
-
- int (*get_available_bytes)(const void *user);
-
- void *next; /* For extension? */
-} godot_net_stream_peer;
-
-/* Binds a StreamPeerGDNative to the provided interface */
-void godot_net_bind_stream_peer(godot_object *p_obj, const godot_net_stream_peer *p_interface);
-
-typedef struct {
- godot_gdnative_api_version version; /* version of our API */
-
- godot_object *data; /* User reference */
-
- /* This is PacketPeer */
- godot_error (*get_packet)(void *, const uint8_t **, int *);
- godot_error (*put_packet)(void *, const uint8_t *, int);
- godot_int (*get_available_packet_count)(const void *);
- godot_int (*get_max_packet_size)(const void *);
-
- void *next; /* For extension? */
-} godot_net_packet_peer;
-
-/* Binds a PacketPeerGDNative to the provided interface */
-void GDAPI godot_net_bind_packet_peer(godot_object *p_obj, const godot_net_packet_peer *);
-
-typedef struct {
- godot_gdnative_api_version version; /* version of our API */
-
- godot_object *data; /* User reference */
-
- /* This is PacketPeer */
- godot_error (*get_packet)(void *, const uint8_t **, int *);
- godot_error (*put_packet)(void *, const uint8_t *, int);
- godot_int (*get_available_packet_count)(const void *);
- godot_int (*get_max_packet_size)(const void *);
-
- /* This is MultiplayerPeer */
- void (*set_transfer_channel)(void *, godot_int);
- godot_int (*get_transfer_channel)(void *);
- void (*set_transfer_mode)(void *, godot_int);
- godot_int (*get_transfer_mode)(const void *);
- // 0 = broadcast, 1 = server, <0 = all but abs(value)
- void (*set_target_peer)(void *, godot_int);
- godot_int (*get_packet_peer)(const void *);
- godot_bool (*is_server)(const void *);
- void (*poll)(void *);
- // Must be > 0, 1 is for server
- int32_t (*get_unique_id)(const void *);
- void (*set_refuse_new_connections)(void *, godot_bool);
- godot_bool (*is_refusing_new_connections)(const void *);
- godot_int (*get_connection_status)(const void *);
-
- void *next; /* For extension? Or maybe not... */
-} godot_net_multiplayer_peer;
-
-/* Binds a MultiplayerPeerGDNative to the provided interface */
-void GDAPI godot_net_bind_multiplayer_peer(godot_object *p_obj, const godot_net_multiplayer_peer *);
-
-#ifdef __cplusplus
-}
-#endif
-
-// WebRTC Bindings
-#include "net/godot_webrtc.h"
-
-#endif /* GODOT_NATIVENET_H */
diff --git a/modules/gdnative/include/net/godot_webrtc.h b/modules/gdnative/include/net/godot_webrtc.h
deleted file mode 100644
index 52006e56ec..0000000000
--- a/modules/gdnative/include/net/godot_webrtc.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*************************************************************************/
-/* godot_webrtc.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 GODOT_NATIVEWEBRTC_H
-#define GODOT_NATIVEWEBRTC_H
-
-#include <gdnative/gdnative.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GODOT_NET_WEBRTC_API_MAJOR 4
-#define GODOT_NET_WEBRTC_API_MINOR 0
-
-/* Library Interface (used to set default GDNative WebRTC implementation */
-typedef struct {
- godot_gdnative_api_version version; /* version of our API */
-
- /* Called when the library is unset as default interface via godot_net_set_webrtc_library */
- void (*unregistered)();
-
- /* Used by WebRTCPeerConnection create when GDNative is the default implementation. */
- /* Takes a pointer to WebRTCPeerConnectionGDNative, should bind and return OK, failure if binding was unsuccessful. */
- godot_error (*create_peer_connection)(godot_object *);
-
- void *next; /* For extension */
-} godot_net_webrtc_library;
-
-/* WebRTCPeerConnection interface */
-typedef struct {
- godot_gdnative_api_version version; /* version of our API */
-
- godot_object *data; /* User reference */
-
- /* This is WebRTCPeerConnection */
- godot_int (*get_connection_state)(const void *);
-
- godot_error (*initialize)(void *, const godot_dictionary *);
- godot_object *(*create_data_channel)(void *, const char *p_channel_name, const godot_dictionary *);
- godot_error (*create_offer)(void *);
- godot_error (*create_answer)(void *); /* unused for now, should be done automatically on set_local_description */
- godot_error (*set_remote_description)(void *, const char *, const char *);
- godot_error (*set_local_description)(void *, const char *, const char *);
- godot_error (*add_ice_candidate)(void *, const char *, int, const char *);
- godot_error (*poll)(void *);
- void (*close)(void *);
-
- void *next; /* For extension? */
-} godot_net_webrtc_peer_connection;
-
-/* WebRTCDataChannel interface */
-typedef struct {
- godot_gdnative_api_version version; /* version of our API */
-
- godot_object *data; /* User reference */
-
- /* This is PacketPeer */
- godot_error (*get_packet)(void *, const uint8_t **, int *);
- godot_error (*put_packet)(void *, const uint8_t *, int);
- godot_int (*get_available_packet_count)(const void *);
- godot_int (*get_max_packet_size)(const void *);
-
- /* This is WebRTCDataChannel */
- void (*set_write_mode)(void *, godot_int);
- godot_int (*get_write_mode)(const void *);
- bool (*was_string_packet)(const void *);
-
- godot_int (*get_ready_state)(const void *);
- const char *(*get_label)(const void *);
- bool (*is_ordered)(const void *);
- int (*get_id)(const void *);
- int (*get_max_packet_life_time)(const void *);
- int (*get_max_retransmits)(const void *);
- const char *(*get_protocol)(const void *);
- bool (*is_negotiated)(const void *);
- int (*get_buffered_amount)(const void *);
-
- godot_error (*poll)(void *);
- void (*close)(void *);
-
- void *next; /* For extension? */
-} godot_net_webrtc_data_channel;
-
-/* Set the default GDNative library */
-godot_error GDAPI godot_net_set_webrtc_library(const godot_net_webrtc_library *);
-/* Binds a WebRTCPeerConnectionGDNative to the provided interface */
-void GDAPI godot_net_bind_webrtc_peer_connection(godot_object *p_obj, const godot_net_webrtc_peer_connection *);
-/* Binds a WebRTCDataChannelGDNative to the provided interface */
-void GDAPI godot_net_bind_webrtc_data_channel(godot_object *p_obj, const godot_net_webrtc_data_channel *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/modules/gdnative/include/text/godot_text.h b/modules/gdnative/include/text/godot_text.h
deleted file mode 100644
index 940cfd11f8..0000000000
--- a/modules/gdnative/include/text/godot_text.h
+++ /dev/null
@@ -1,283 +0,0 @@
-/*************************************************************************/
-/* godot_text.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 GODOT_NATIVETEXT_H
-#define GODOT_NATIVETEXT_H
-
-#include <gdnative/gdnative.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GODOT_TEXT_API_MAJOR 1
-#define GODOT_TEXT_API_MINOR 0
-
-#define GODOT_GLYPH_SIZE 40
-
-#ifndef GODOT_TEXT_API_GODOT_GLYPH_TYPE_DEFINED
-#define GODOT_TEXT_API_GODOT_GLYPH_TYPE_DEFINED
-typedef struct {
- uint8_t _dont_touch_that[GODOT_GLYPH_SIZE];
-} godot_glyph;
-#endif
-
-#define GODOT_PACKED_GLYPH_ARRAY_SIZE (2 * sizeof(void *))
-
-#ifndef GODOT_TEXT_API_GODOT_PACKED_GLYPH_ARRAY_TYPE_DEFINED
-#define GODOT_TEXT_API_GODOT_PACKED_GLYPH_ARRAY_TYPE_DEFINED
-typedef struct {
- uint8_t _dont_touch_that[GODOT_PACKED_GLYPH_ARRAY_SIZE];
-} godot_packed_glyph_array;
-#endif
-
-typedef struct {
- godot_gdnative_api_version version;
-
- void *(*constructor)(godot_object *);
- void (*destructor)(void *);
-
- godot_string (*get_name)(const void *);
- godot_bool (*has_feature)(const void *, godot_int);
-
- void (*free)(void *, godot_rid *);
- bool (*has)(void *, godot_rid *);
-
- bool (*load_support_data)(void *, const godot_string *);
- godot_string (*get_support_data_filename)(const void *);
- godot_string (*get_support_data_info)(const void *);
- bool (*save_support_data)(void *, const godot_string *);
-
- bool (*is_locale_right_to_left)(void *, const godot_string *);
- int32_t (*name_to_tag)(const void *, const godot_string *);
- godot_string (*tag_to_name)(const void *, int32_t);
-
- godot_rid (*create_font)(void *);
- void (*font_set_data)(void *, godot_rid *, const godot_packed_byte_array *);
- void (*font_set_data_ptr)(void *, godot_rid *, const uint8_t *, size_t);
- void (*font_set_antialiased)(void *, godot_rid *, bool);
- bool (*font_is_antialiased)(const void *, godot_rid *);
- void (*font_set_multichannel_signed_distance_field)(void *, godot_rid *, bool);
- bool (*font_is_multichannel_signed_distance_field)(const void *, godot_rid *);
- void (*font_set_msdf_pixel_range)(void *, godot_rid *, godot_int);
- godot_int (*font_get_msdf_pixel_range)(const void *, godot_rid *);
- void (*font_set_msdf_size)(void *, godot_rid *, godot_int);
- godot_int (*font_get_msdf_size)(const void *, godot_rid *);
- void (*font_set_fixed_size)(void *, godot_rid *, godot_int);
- godot_int (*font_get_fixed_size)(const void *, godot_rid *);
- void (*font_set_force_autohinter)(void *, godot_rid *, bool);
- bool (*font_is_force_autohinter)(const void *, godot_rid *);
- void (*font_set_hinting)(void *, godot_rid *, godot_int);
- godot_int (*font_get_hinting)(const void *, godot_rid *);
- void (*font_set_variation_coordinates)(void *, godot_rid *, const godot_dictionary *);
- godot_dictionary (*font_get_variation_coordinates)(const void *, godot_rid *);
- void (*font_set_oversampling)(void *, godot_rid *, godot_real_t);
- godot_real_t (*font_get_oversampling)(const void *, godot_rid *);
- godot_array (*font_get_size_cache_list)(const void *, godot_rid *);
- void (*font_clear_size_cache)(void *, godot_rid *);
- void (*font_remove_size_cache)(void *, godot_rid *, const godot_vector2i *);
- void (*font_set_ascent)(void *, godot_rid *, godot_int, godot_real_t);
- godot_real_t (*font_get_ascent)(const void *, godot_rid *, godot_int);
- void (*font_set_descent)(void *, godot_rid *, godot_int, godot_real_t);
- godot_real_t (*font_get_descent)(const void *, godot_rid *, godot_int);
- void (*font_set_underline_position)(void *, godot_rid *, godot_int, godot_real_t);
- godot_real_t (*font_get_underline_position)(const void *, godot_rid *, godot_int);
- void (*font_set_underline_thickness)(void *, godot_rid *, godot_int, godot_real_t);
- godot_real_t (*font_get_underline_thickness)(const void *, godot_rid *, godot_int);
- void (*font_set_scale)(void *, godot_rid *, godot_int, godot_real_t);
- godot_real_t (*font_get_scale)(const void *, godot_rid *, godot_int);
- void (*font_set_spacing)(void *, godot_rid *, godot_int, godot_int, godot_int);
- godot_int (*font_get_spacing)(const void *, godot_rid *, godot_int, godot_int);
- godot_int (*font_get_texture_count)(const void *, godot_rid *, const godot_vector2i *);
- void (*font_clear_textures)(void *, godot_rid *, const godot_vector2i *);
- void (*font_remove_texture)(void *, godot_rid *, const godot_vector2i *, godot_int);
- void (*font_set_texture_image)(void *, godot_rid *, const godot_vector2i *, godot_int, const godot_object *);
- godot_object *(*font_get_texture_image)(const void *, godot_rid *, const godot_vector2i *, godot_int);
- void (*font_set_texture_offsets)(void *, godot_rid *, const godot_vector2i *, godot_int, const godot_packed_int32_array *);
- godot_packed_int32_array (*font_get_texture_offsets)(const void *, godot_rid *, const godot_vector2i *, godot_int);
- godot_array (*font_get_glyph_list)(const void *, godot_rid *, const godot_vector2i *);
- void (*font_clear_glyphs)(void *, godot_rid *, const godot_vector2i *);
- void (*font_remove_glyph)(void *, godot_rid *, const godot_vector2i *, int32_t);
- godot_vector2 (*font_get_glyph_advance)(const void *, godot_rid *, godot_int, int32_t);
- void (*font_set_glyph_advance)(void *, godot_rid *, godot_int, int32_t, const godot_vector2 *);
- godot_vector2 (*font_get_glyph_offset)(const void *, godot_rid *, const godot_vector2i *, int32_t);
- void (*font_set_glyph_offset)(void *, godot_rid *, const godot_vector2i *, int32_t, const godot_vector2 *);
- godot_vector2 (*font_get_glyph_size)(const void *, godot_rid *, const godot_vector2i *, int32_t);
- void (*font_set_glyph_size)(void *, godot_rid *, const godot_vector2i *, int32_t, const godot_vector2 *);
- godot_rect2 (*font_get_glyph_uv_rect)(const void *, godot_rid *, const godot_vector2i *, int32_t);
- void (*font_set_glyph_uv_rect)(void *, godot_rid *, const godot_vector2i *, int32_t, const godot_rect2 *);
- godot_int (*font_get_glyph_texture_idx)(const void *, godot_rid *, const godot_vector2i *, int32_t);
- void (*font_set_glyph_texture_idx)(void *, godot_rid *, const godot_vector2i *, int32_t, godot_int);
- bool (*font_get_glyph_contours)(const void *, godot_rid *, godot_int, int32_t, godot_packed_vector3_array *, godot_packed_int32_array *, bool *);
- godot_array (*font_get_kerning_list)(const void *, godot_rid *, godot_int);
- void (*font_clear_kerning_map)(void *, godot_rid *, godot_int);
- void (*font_remove_kerning)(void *, godot_rid *, godot_int, const godot_vector2i *);
- void (*font_set_kerning)(void *, godot_rid *, godot_int, const godot_vector2i *, const godot_vector2 *);
- godot_vector2 (*font_get_kerning)(const void *, godot_rid *, godot_int, const godot_vector2i *);
- int32_t (*font_get_glyph_index)(const void *, godot_rid *, godot_int, char32_t, char32_t);
- bool (*font_has_char)(const void *, godot_rid *, char32_t);
- godot_string (*font_get_supported_chars)(const void *, godot_rid *);
- void (*font_render_range)(void *, godot_rid *, const godot_vector2i *, char32_t, char32_t);
- void (*font_render_glyph)(void *, godot_rid *, const godot_vector2i *, int32_t);
- void (*font_draw_glyph)(const void *, godot_rid *, godot_rid *, godot_int, const godot_vector2 *, int32_t, const godot_color *);
- void (*font_draw_glyph_outline)(const void *, godot_rid *, godot_rid *, godot_int, godot_int, const godot_vector2 *, int32_t, const godot_color *);
- bool (*font_is_language_supported)(const void *, godot_rid *, const godot_string *);
- void (*font_set_language_support_override)(void *, godot_rid *, const godot_string *, bool);
- bool (*font_get_language_support_override)(const void *, godot_rid *, const godot_string *);
- void (*font_remove_language_support_override)(void *, godot_rid *, const godot_string *);
- godot_packed_string_array (*font_get_language_support_overrides)(const void *, godot_rid *);
- bool (*font_is_script_supported)(const void *, godot_rid *, const godot_string *);
- void (*font_set_script_support_override)(void *, godot_rid *, const godot_string *, bool);
- bool (*font_get_script_support_override)(const void *, godot_rid *, const godot_string *);
- void (*font_remove_script_support_override)(void *, godot_rid *, const godot_string *);
- godot_packed_string_array (*font_get_script_support_overrides)(const void *, godot_rid *);
- godot_dictionary (*font_supported_feature_list)(const void *, godot_rid *);
- godot_dictionary (*font_supported_variation_list)(const void *, godot_rid *);
- godot_real_t (*font_get_global_oversampling)(const void *);
- void (*font_set_global_oversampling)(void *, godot_real_t);
-
- godot_rid (*create_shaped_text)(void *, godot_int, godot_int);
- void (*shaped_text_clear)(void *, godot_rid *);
- void (*shaped_text_set_direction)(void *, godot_rid *, godot_int);
- godot_int (*shaped_text_get_direction)(void *, godot_rid *);
- void (*shaped_text_set_bidi_override)(void *, godot_rid *, const godot_packed_vector2i_array *);
- void (*shaped_text_set_orientation)(void *, godot_rid *, godot_int);
- godot_int (*shaped_text_get_orientation)(void *, godot_rid *);
- void (*shaped_text_set_preserve_invalid)(void *, godot_rid *, bool);
- bool (*shaped_text_get_preserve_invalid)(void *, godot_rid *);
- void (*shaped_text_set_preserve_control)(void *, godot_rid *, bool);
- bool (*shaped_text_get_preserve_control)(void *, godot_rid *);
- bool (*shaped_text_add_string)(void *, godot_rid *, const godot_string *, const godot_rid **, int, const godot_dictionary *, const godot_string *);
- bool (*shaped_text_add_object)(void *, godot_rid *, const godot_variant *, const godot_vector2 *, godot_int, godot_int);
- bool (*shaped_text_resize_object)(void *, godot_rid *, const godot_variant *, const godot_vector2 *, godot_int);
- godot_rid (*shaped_text_substr)(void *, godot_rid *, godot_int, godot_int);
- godot_rid (*shaped_text_get_parent)(void *, godot_rid *);
- godot_real_t (*shaped_text_fit_to_width)(void *, godot_rid *, godot_real_t, uint8_t);
- godot_real_t (*shaped_text_tab_align)(void *, godot_rid *, godot_packed_float32_array *);
- bool (*shaped_text_shape)(void *, godot_rid *);
- bool (*shaped_text_update_breaks)(void *, godot_rid *);
- bool (*shaped_text_update_justification_ops)(void *, godot_rid *);
- void (*shaped_text_overrun_trim_to_width)(void *, godot_rid *, godot_real_t, uint8_t);
- bool (*shaped_text_is_ready)(void *, godot_rid *);
- godot_packed_glyph_array (*shaped_text_get_glyphs)(void *, godot_rid *);
- godot_vector2i (*shaped_text_get_range)(void *, godot_rid *);
- godot_packed_glyph_array (*shaped_text_sort_logical)(void *, godot_rid *);
- godot_packed_vector2i_array (*shaped_text_get_line_breaks_adv)(void *, godot_rid *, godot_packed_float32_array *, int, bool, uint8_t);
- godot_packed_vector2i_array (*shaped_text_get_line_breaks)(void *, godot_rid *, godot_real_t, int, uint8_t);
- godot_packed_vector2i_array (*shaped_text_get_word_breaks)(void *, godot_rid *, int);
- godot_array (*shaped_text_get_objects)(void *, godot_rid *);
- godot_rect2 (*shaped_text_get_object_rect)(void *, godot_rid *, const godot_variant *);
- godot_vector2 (*shaped_text_get_size)(void *, godot_rid *);
- godot_real_t (*shaped_text_get_ascent)(void *, godot_rid *);
- godot_real_t (*shaped_text_get_descent)(void *, godot_rid *);
- godot_real_t (*shaped_text_get_width)(void *, godot_rid *);
- godot_real_t (*shaped_text_get_underline_position)(void *, godot_rid *);
- godot_real_t (*shaped_text_get_underline_thickness)(void *, godot_rid *);
-
- godot_string (*format_number)(void *, const godot_string *, const godot_string *);
- godot_string (*parse_number)(void *, const godot_string *, const godot_string *);
- godot_string (*percent_sign)(void *, const godot_string *);
-} godot_text_interface_gdnative;
-
-void GDAPI godot_text_register_interface(const godot_text_interface_gdnative *p_interface, const godot_string *p_name, uint32_t p_features);
-
-// Glyph
-
-void GDAPI godot_glyph_new(godot_glyph *r_dest);
-
-godot_vector2i GDAPI godot_glyph_get_range(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_range(godot_glyph *p_self, const godot_vector2i *p_range);
-
-godot_int GDAPI godot_glyph_get_count(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_count(godot_glyph *p_self, godot_int p_count);
-
-godot_int GDAPI godot_glyph_get_repeat(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_repeat(godot_glyph *p_self, godot_int p_repeat);
-
-godot_int GDAPI godot_glyph_get_flags(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_flags(godot_glyph *p_self, godot_int p_flags);
-
-godot_vector2 GDAPI godot_glyph_get_offset(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_offset(godot_glyph *p_self, const godot_vector2 *p_offset);
-
-godot_real_t GDAPI godot_glyph_get_advance(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_advance(godot_glyph *p_self, godot_real_t p_advance);
-
-godot_rid GDAPI godot_glyph_get_font(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_font(godot_glyph *p_self, godot_rid *p_font);
-
-godot_int GDAPI godot_glyph_get_font_size(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_font_size(godot_glyph *p_self, godot_int p_size);
-
-godot_int GDAPI godot_glyph_get_index(const godot_glyph *p_self);
-void GDAPI godot_glyph_set_index(godot_glyph *p_self, godot_int p_index);
-
-// GlyphArray
-
-void GDAPI godot_packed_glyph_array_new(godot_packed_glyph_array *r_dest);
-void GDAPI godot_packed_glyph_array_new_copy(godot_packed_glyph_array *r_dest, const godot_packed_glyph_array *p_src);
-
-const godot_glyph GDAPI *godot_packed_glyph_array_ptr(const godot_packed_glyph_array *p_self);
-godot_glyph GDAPI *godot_packed_glyph_array_ptrw(godot_packed_glyph_array *p_self);
-
-void GDAPI godot_packed_glyph_array_append(godot_packed_glyph_array *p_self, const godot_glyph *p_data);
-
-void GDAPI godot_packed_glyph_array_append_array(godot_packed_glyph_array *p_self, const godot_packed_glyph_array *p_array);
-
-godot_error GDAPI godot_packed_glyph_array_insert(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data);
-
-godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self, const godot_glyph *p_value);
-
-void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self);
-
-void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self);
-
-void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data);
-
-void GDAPI godot_packed_glyph_array_remove(godot_packed_glyph_array *p_self, godot_int p_idx);
-
-void GDAPI godot_packed_glyph_array_resize(godot_packed_glyph_array *p_self, godot_int p_size);
-
-void GDAPI godot_packed_glyph_array_set(godot_packed_glyph_array *p_self, godot_int p_idx, const godot_glyph *p_data);
-godot_glyph GDAPI godot_packed_glyph_array_get(const godot_packed_glyph_array *p_self, godot_int p_idx);
-
-godot_int GDAPI godot_packed_glyph_array_size(const godot_packed_glyph_array *p_self);
-
-godot_bool GDAPI godot_packed_glyph_array_is_empty(const godot_packed_glyph_array *p_self);
-
-void GDAPI godot_packed_glyph_array_destroy(godot_packed_glyph_array *p_self);
-
-// Grapheme
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !GODOT_NATIVETEXT_H */
diff --git a/modules/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 2d9b45cb07..598f7c7ad0 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -223,8 +223,8 @@ List<ClassAPI> generate_c_api_classes() {
enum_api_map[enum_name] = enum_api;
}
}
- for (const Map<StringName, EnumAPI>::Element *E = enum_api_map.front(); E; E = E->next()) {
- global_constants_api.enums.push_back(E->get());
+ for (const KeyValue<StringName, EnumAPI> &E : enum_api_map) {
+ global_constants_api.enums.push_back(E.value);
}
global_constants_api.constants.sort_custom<ConstantAPIComparator>();
api.push_back(global_constants_api);
diff --git a/modules/gdnative/nativescript/nativescript.cpp b/modules/gdnative/nativescript/nativescript.cpp
index 92ba9bd452..fb46bafb3c 100644
--- a/modules/gdnative/nativescript/nativescript.cpp
+++ b/modules/gdnative/nativescript/nativescript.cpp
@@ -360,8 +360,8 @@ void NativeScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
Set<MethodInfo> signals_;
while (script_data) {
- for (Map<StringName, NativeScriptDesc::Signal>::Element *S = script_data->signals_.front(); S; S = S->next()) {
- signals_.insert(S->get().signal);
+ for (const KeyValue<StringName, NativeScriptDesc::Signal> &S : script_data->signals_) {
+ signals_.insert(S.value.signal);
}
script_data = script_data->base_data;
@@ -401,8 +401,8 @@ void NativeScript::get_script_method_list(List<MethodInfo> *p_list) const {
Set<MethodInfo> methods;
while (script_data) {
- for (Map<StringName, NativeScriptDesc::Method>::Element *E = script_data->methods.front(); E; E = E->next()) {
- methods.insert(E->get().info);
+ for (const KeyValue<StringName, NativeScriptDesc::Method> &E : script_data->methods) {
+ methods.insert(E.value.info);
}
script_data = script_data->base_data;
@@ -857,9 +857,9 @@ NativeScriptLanguage *NativeScriptLanguage::singleton;
void NativeScriptLanguage::_unload_stuff(bool p_reload) {
Map<String, Ref<GDNative>> erase_and_unload;
- for (Map<String, Map<StringName, NativeScriptDesc>>::Element *L = library_classes.front(); L; L = L->next()) {
- String lib_path = L->key();
- Map<StringName, NativeScriptDesc> classes = L->get();
+ for (KeyValue<String, Map<StringName, NativeScriptDesc>> &L : library_classes) {
+ String lib_path = L.key;
+ Map<StringName, NativeScriptDesc> classes = L.value;
if (p_reload) {
Map<String, Ref<GDNative>>::Element *E = library_gdnatives.find(lib_path);
@@ -890,9 +890,9 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) {
gdn = E->get();
}
- for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) {
+ for (KeyValue<StringName, NativeScriptDesc> &C : classes) {
// free property stuff first
- for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C->get().properties.front(); P; P = P.next()) {
+ for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C.value.properties.front(); P; P = P.next()) {
if (P.get().getter.free_func) {
P.get().getter.free_func(P.get().getter.method_data);
}
@@ -903,28 +903,28 @@ void NativeScriptLanguage::_unload_stuff(bool p_reload) {
}
// free method stuff
- for (Map<StringName, NativeScriptDesc::Method>::Element *M = C->get().methods.front(); M; M = M->next()) {
- if (M->get().method.free_func) {
- M->get().method.free_func(M->get().method.method_data);
+ for (const KeyValue<StringName, NativeScriptDesc::Method> &M : C.value.methods) {
+ if (M.value.method.free_func) {
+ M.value.method.free_func(M.value.method.method_data);
}
}
// free constructor/destructor
- if (C->get().create_func.free_func) {
- C->get().create_func.free_func(C->get().create_func.method_data);
+ if (C.value.create_func.free_func) {
+ C.value.create_func.free_func(C.value.create_func.method_data);
}
- if (C->get().destroy_func.free_func) {
- C->get().destroy_func.free_func(C->get().destroy_func.method_data);
+ if (C.value.destroy_func.free_func) {
+ C.value.destroy_func.free_func(C.value.destroy_func.method_data);
}
}
erase_and_unload.insert(lib_path, gdn);
}
- for (Map<String, Ref<GDNative>>::Element *E = erase_and_unload.front(); E; E = E->next()) {
- String lib_path = E->key();
- Ref<GDNative> gdn = E->get();
+ for (KeyValue<String, Ref<GDNative>> &E : erase_and_unload) {
+ String lib_path = E.key;
+ Ref<GDNative> gdn = E.value;
library_classes.erase(lib_path);
@@ -957,8 +957,8 @@ NativeScriptLanguage::NativeScriptLanguage() {
}
NativeScriptLanguage::~NativeScriptLanguage() {
- for (Map<String, Ref<GDNative>>::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
- Ref<GDNative> lib = L->get();
+ for (KeyValue<String, Ref<GDNative>> &L : NSL->library_gdnatives) {
+ Ref<GDNative> lib = L.value;
// only shut down valid libs, duh!
if (lib.is_valid()) {
// If it's a singleton-library then the gdnative module
@@ -1157,15 +1157,15 @@ int NativeScriptLanguage::profiling_get_accumulated_data(ProfilingInfo *p_info_a
int current = 0;
- for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
+ for (const KeyValue<StringName, ProfileData> &d : profile_data) {
if (current >= p_info_max) {
break;
}
- p_info_arr[current].call_count = d->get().call_count;
- p_info_arr[current].self_time = d->get().self_time;
- p_info_arr[current].total_time = d->get().total_time;
- p_info_arr[current].signature = d->get().signature;
+ p_info_arr[current].call_count = d.value.call_count;
+ p_info_arr[current].self_time = d.value.self_time;
+ p_info_arr[current].total_time = d.value.total_time;
+ p_info_arr[current].signature = d.value.signature;
current++;
}
@@ -1181,16 +1181,16 @@ int NativeScriptLanguage::profiling_get_frame_data(ProfilingInfo *p_info_arr, in
int current = 0;
- for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
+ for (const KeyValue<StringName, ProfileData> &d : profile_data) {
if (current >= p_info_max) {
break;
}
- if (d->get().last_frame_call_count) {
- p_info_arr[current].call_count = d->get().last_frame_call_count;
- p_info_arr[current].self_time = d->get().last_frame_self_time;
- p_info_arr[current].total_time = d->get().last_frame_total_time;
- p_info_arr[current].signature = d->get().signature;
+ if (d.value.last_frame_call_count) {
+ p_info_arr[current].call_count = d.value.last_frame_call_count;
+ p_info_arr[current].self_time = d.value.last_frame_self_time;
+ p_info_arr[current].total_time = d.value.last_frame_total_time;
+ p_info_arr[current].signature = d.value.signature;
current++;
}
}
@@ -1503,9 +1503,9 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
if (L) {
Map<StringName, NativeScriptDesc> classes = L->get();
- for (Map<StringName, NativeScriptDesc>::Element *C = classes.front(); C; C = C->next()) {
+ for (KeyValue<StringName, NativeScriptDesc> &C : classes) {
// free property stuff first
- for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C->get().properties.front(); P; P = P.next()) {
+ for (OrderedHashMap<StringName, NativeScriptDesc::Property>::Element P = C.value.properties.front(); P; P = P.next()) {
if (P.get().getter.free_func) {
P.get().getter.free_func(P.get().getter.method_data);
}
@@ -1516,19 +1516,19 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
}
// free method stuff
- for (Map<StringName, NativeScriptDesc::Method>::Element *M = C->get().methods.front(); M; M = M->next()) {
- if (M->get().method.free_func) {
- M->get().method.free_func(M->get().method.method_data);
+ for (const KeyValue<StringName, NativeScriptDesc::Method> &M : C.value.methods) {
+ if (M.value.method.free_func) {
+ M.value.method.free_func(M.value.method.method_data);
}
}
// free constructor/destructor
- if (C->get().create_func.free_func) {
- C->get().create_func.free_func(C->get().create_func.method_data);
+ if (C.value.create_func.free_func) {
+ C.value.create_func.free_func(C.value.create_func.method_data);
}
- if (C->get().destroy_func.free_func) {
- C->get().destroy_func.free_func(C->get().destroy_func.method_data);
+ if (C.value.destroy_func.free_func) {
+ C.value.destroy_func.free_func(C.value.destroy_func.method_data);
}
}
@@ -1548,14 +1548,14 @@ void NativeScriptLanguage::unregister_script(NativeScript *script) {
void NativeScriptLanguage::call_libraries_cb(const StringName &name) {
// library_gdnatives is modified only from the main thread, so it's safe not to use mutex here
- for (Map<String, Ref<GDNative>>::Element *L = library_gdnatives.front(); L; L = L->next()) {
- if (L->get().is_null()) {
+ for (KeyValue<String, Ref<GDNative>> &L : library_gdnatives) {
+ if (L.value.is_null()) {
continue;
}
- if (L->get()->is_initialized()) {
+ if (L.value->is_initialized()) {
void *proc_ptr;
- Error err = L->get()->get_symbol(L->get()->get_library()->get_symbol_prefix() + name, proc_ptr);
+ Error err = L.value->get_symbol(L.value->get_library()->get_symbol_prefix() + name, proc_ptr);
if (!err) {
((void (*)())proc_ptr)();
@@ -1584,13 +1584,13 @@ void NativeScriptLanguage::frame() {
{
MutexLock lock(mutex);
- for (Map<StringName, ProfileData>::Element *d = profile_data.front(); d; d = d->next()) {
- d->get().last_frame_call_count = d->get().frame_call_count;
- d->get().last_frame_self_time = d->get().frame_self_time;
- d->get().last_frame_total_time = d->get().frame_total_time;
- d->get().frame_call_count = 0;
- d->get().frame_self_time = 0;
- d->get().frame_total_time = 0;
+ for (KeyValue<StringName, ProfileData> &d : profile_data) {
+ d.value.last_frame_call_count = d.value.frame_call_count;
+ d.value.last_frame_self_time = d.value.frame_self_time;
+ d.value.last_frame_total_time = d.value.frame_total_time;
+ d.value.frame_call_count = 0;
+ d.value.frame_self_time = 0;
+ d.value.frame_total_time = 0;
}
}
#endif
@@ -1651,8 +1651,8 @@ void NativeReloadNode::_notification(int p_what) {
MutexLock lock(NSL->mutex);
NSL->_unload_stuff(true);
- for (Map<String, Ref<GDNative>>::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
- Ref<GDNative> gdn = L->get();
+ for (KeyValue<String, Ref<GDNative>> &L : NSL->library_gdnatives) {
+ Ref<GDNative> gdn = L.value;
if (gdn.is_null()) {
continue;
@@ -1685,8 +1685,8 @@ void NativeReloadNode::_notification(int p_what) {
MutexLock lock(NSL->mutex);
Set<StringName> libs_to_remove;
- for (Map<String, Ref<GDNative>>::Element *L = NSL->library_gdnatives.front(); L; L = L->next()) {
- Ref<GDNative> gdn = L->get();
+ for (KeyValue<String, Ref<GDNative>> &L : NSL->library_gdnatives) {
+ Ref<GDNative> gdn = L.value;
if (gdn.is_null()) {
continue;
@@ -1703,24 +1703,24 @@ void NativeReloadNode::_notification(int p_what) {
}
if (!gdn->initialize()) {
- libs_to_remove.insert(L->key());
+ libs_to_remove.insert(L.key);
continue;
}
- NSL->library_classes.insert(L->key(), Map<StringName, NativeScriptDesc>());
+ NSL->library_classes.insert(L.key, Map<StringName, NativeScriptDesc>());
// here the library registers all the classes and stuff.
void *proc_ptr;
Error err = gdn->get_symbol(gdn->get_library()->get_symbol_prefix() + "nativescript_init", proc_ptr);
if (err != OK) {
- ERR_PRINT(String("No godot_nativescript_init in \"" + L->key() + "\" found").utf8().get_data());
+ ERR_PRINT(String("No godot_nativescript_init in \"" + L.key + "\" found").utf8().get_data());
} else {
- ((void (*)(void *))proc_ptr)((void *)&L->key());
+ ((void (*)(void *))proc_ptr)((void *)&L.key);
}
- for (Map<String, Set<NativeScript *>>::Element *U = NSL->library_script_users.front(); U; U = U->next()) {
- for (Set<NativeScript *>::Element *S = U->get().front(); S; S = S->next()) {
+ for (KeyValue<String, Set<NativeScript *>> &U : NSL->library_script_users) {
+ for (Set<NativeScript *>::Element *S = U.value.front(); S; S = S->next()) {
NativeScript *script = S->get();
if (script->placeholders.size() == 0) {
diff --git a/modules/gdnative/net/SCsub b/modules/gdnative/net/SCsub
deleted file mode 100644
index b76500c003..0000000000
--- a/modules/gdnative/net/SCsub
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_gdnative")
-
-env_net = env_gdnative.Clone()
-
-has_webrtc = env_net["module_webrtc_enabled"]
-if has_webrtc:
- env_net.Append(CPPDEFINES=["WEBRTC_GDNATIVE_ENABLED"])
-
-env_net.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.cpp b/modules/gdnative/net/multiplayer_peer_gdnative.cpp
deleted file mode 100644
index 575d5f5060..0000000000
--- a/modules/gdnative/net/multiplayer_peer_gdnative.cpp
+++ /dev/null
@@ -1,136 +0,0 @@
-/*************************************************************************/
-/* multiplayer_peer_gdnative.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 "multiplayer_peer_gdnative.h"
-
-MultiplayerPeerGDNative::MultiplayerPeerGDNative() {
- interface = nullptr;
-}
-
-MultiplayerPeerGDNative::~MultiplayerPeerGDNative() {
-}
-
-void MultiplayerPeerGDNative::set_native_multiplayer_peer(const godot_net_multiplayer_peer *p_interface) {
- interface = p_interface;
-}
-
-Error MultiplayerPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size);
-}
-
-Error MultiplayerPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size);
-}
-
-int MultiplayerPeerGDNative::get_max_packet_size() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_max_packet_size(interface->data);
-}
-
-int MultiplayerPeerGDNative::get_available_packet_count() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_available_packet_count(interface->data);
-}
-
-/* MultiplayerPeer */
-void MultiplayerPeerGDNative::set_transfer_channel(int p_channel) {
- ERR_FAIL_COND(interface == nullptr);
- return interface->set_transfer_channel(interface->data, p_channel);
-}
-
-int MultiplayerPeerGDNative::get_transfer_channel() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_transfer_channel(interface->data);
-}
-
-void MultiplayerPeerGDNative::set_transfer_mode(Multiplayer::TransferMode p_mode) {
- ERR_FAIL_COND(interface == nullptr);
- interface->set_transfer_mode(interface->data, (godot_int)p_mode);
-}
-
-Multiplayer::TransferMode MultiplayerPeerGDNative::get_transfer_mode() const {
- ERR_FAIL_COND_V(interface == nullptr, Multiplayer::TRANSFER_MODE_UNRELIABLE);
- return (Multiplayer::TransferMode)interface->get_transfer_mode(interface->data);
-}
-
-void MultiplayerPeerGDNative::set_target_peer(int p_peer_id) {
- ERR_FAIL_COND(interface == nullptr);
- interface->set_target_peer(interface->data, p_peer_id);
-}
-
-int MultiplayerPeerGDNative::get_packet_peer() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_packet_peer(interface->data);
-}
-
-bool MultiplayerPeerGDNative::is_server() const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->is_server(interface->data);
-}
-
-void MultiplayerPeerGDNative::poll() {
- ERR_FAIL_COND(interface == nullptr);
- interface->poll(interface->data);
-}
-
-int MultiplayerPeerGDNative::get_unique_id() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_unique_id(interface->data);
-}
-
-void MultiplayerPeerGDNative::set_refuse_new_connections(bool p_enable) {
- ERR_FAIL_COND(interface == nullptr);
- interface->set_refuse_new_connections(interface->data, p_enable);
-}
-
-bool MultiplayerPeerGDNative::is_refusing_new_connections() const {
- ERR_FAIL_COND_V(interface == nullptr, true);
- return interface->is_refusing_new_connections(interface->data);
-}
-
-MultiplayerPeer::ConnectionStatus MultiplayerPeerGDNative::get_connection_status() const {
- ERR_FAIL_COND_V(interface == nullptr, CONNECTION_DISCONNECTED);
- return (ConnectionStatus)interface->get_connection_status(interface->data);
-}
-
-void MultiplayerPeerGDNative::_bind_methods() {
- ADD_PROPERTY_DEFAULT("transfer_channel", 0);
- ADD_PROPERTY_DEFAULT("transfer_mode", Multiplayer::TRANSFER_MODE_UNRELIABLE);
- ADD_PROPERTY_DEFAULT("refuse_new_connections", true);
-}
-
-extern "C" {
-
-void GDAPI godot_net_bind_multiplayer_peer(godot_object *p_obj, const godot_net_multiplayer_peer *p_impl) {
- ((MultiplayerPeerGDNative *)p_obj)->set_native_multiplayer_peer(p_impl);
-}
-}
diff --git a/modules/gdnative/net/multiplayer_peer_gdnative.h b/modules/gdnative/net/multiplayer_peer_gdnative.h
deleted file mode 100644
index 33e424d284..0000000000
--- a/modules/gdnative/net/multiplayer_peer_gdnative.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/*************************************************************************/
-/* multiplayer_peer_gdnative.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 MULTIPLAYER_PEER_GDNATIVE_H
-#define MULTIPLAYER_PEER_GDNATIVE_H
-
-#include "core/multiplayer/multiplayer_peer.h"
-#include "modules/gdnative/gdnative.h"
-#include "modules/gdnative/include/net/godot_net.h"
-
-class MultiplayerPeerGDNative : public MultiplayerPeer {
- GDCLASS(MultiplayerPeerGDNative, MultiplayerPeer);
-
-protected:
- static void _bind_methods();
- const godot_net_multiplayer_peer *interface;
-
-public:
- MultiplayerPeerGDNative();
- ~MultiplayerPeerGDNative();
-
- /* Sets the interface implementation from GDNative */
- void set_native_multiplayer_peer(const godot_net_multiplayer_peer *p_impl);
-
- /* Specific to PacketPeer */
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const override;
- virtual int get_available_packet_count() const override;
-
- /* Specific to MultiplayerPeer */
- virtual void set_transfer_channel(int p_channel) override;
- virtual int get_transfer_channel() const override;
- virtual void set_transfer_mode(Multiplayer::TransferMode p_mode) override;
- virtual Multiplayer::TransferMode get_transfer_mode() const override;
- virtual void set_target_peer(int p_peer_id) override;
-
- virtual int get_packet_peer() const override;
-
- virtual bool is_server() const override;
-
- virtual void poll() override;
-
- virtual int get_unique_id() const override;
-
- virtual void set_refuse_new_connections(bool p_enable) override;
- virtual bool is_refusing_new_connections() const override;
-
- virtual ConnectionStatus get_connection_status() const override;
-};
-
-#endif // MULTIPLAYER_PEER_GDNATIVE_H
diff --git a/modules/gdnative/net/packet_peer_gdnative.cpp b/modules/gdnative/net/packet_peer_gdnative.cpp
deleted file mode 100644
index 3bcdfed8ff..0000000000
--- a/modules/gdnative/net/packet_peer_gdnative.cpp
+++ /dev/null
@@ -1,72 +0,0 @@
-/*************************************************************************/
-/* packet_peer_gdnative.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 "packet_peer_gdnative.h"
-
-PacketPeerGDNative::PacketPeerGDNative() {
- interface = nullptr;
-}
-
-PacketPeerGDNative::~PacketPeerGDNative() {
-}
-
-void PacketPeerGDNative::set_native_packet_peer(const godot_net_packet_peer *p_impl) {
- interface = p_impl;
-}
-
-void PacketPeerGDNative::_bind_methods() {
-}
-
-Error PacketPeerGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size);
-}
-
-Error PacketPeerGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size);
-}
-
-int PacketPeerGDNative::get_max_packet_size() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_max_packet_size(interface->data);
-}
-
-int PacketPeerGDNative::get_available_packet_count() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_available_packet_count(interface->data);
-}
-
-extern "C" {
-
-void GDAPI godot_net_bind_packet_peer(godot_object *p_obj, const godot_net_packet_peer *p_impl) {
- ((PacketPeerGDNative *)p_obj)->set_native_packet_peer(p_impl);
-}
-}
diff --git a/modules/gdnative/net/register_types.cpp b/modules/gdnative/net/register_types.cpp
deleted file mode 100644
index 46c383e5ae..0000000000
--- a/modules/gdnative/net/register_types.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 "register_types.h"
-#include "multiplayer_peer_gdnative.h"
-#include "packet_peer_gdnative.h"
-#include "stream_peer_gdnative.h"
-
-void register_net_types() {
- GDREGISTER_CLASS(MultiplayerPeerGDNative);
- GDREGISTER_CLASS(PacketPeerGDNative);
- GDREGISTER_CLASS(StreamPeerGDNative);
-}
-
-void unregister_net_types() {
-}
diff --git a/modules/gdnative/net/register_types.h b/modules/gdnative/net/register_types.h
deleted file mode 100644
index c99c6f6fbf..0000000000
--- a/modules/gdnative/net/register_types.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*************************************************************************/
-/* register_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 NET_REGISTER_TYPES_H
-#define NET_REGISTER_TYPES_H
-
-void register_net_types();
-void unregister_net_types();
-
-#endif // NET_REGISTER_TYPES_H
diff --git a/modules/gdnative/net/stream_peer_gdnative.h b/modules/gdnative/net/stream_peer_gdnative.h
deleted file mode 100644
index dd5abceb83..0000000000
--- a/modules/gdnative/net/stream_peer_gdnative.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*************************************************************************/
-/* stream_peer_gdnative.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 STREAM_PEER_GDNATIVE_H
-#define STREAM_PEER_GDNATIVE_H
-
-#include "core/io/stream_peer.h"
-#include "modules/gdnative/gdnative.h"
-#include "modules/gdnative/include/net/godot_net.h"
-
-class StreamPeerGDNative : public StreamPeer {
- GDCLASS(StreamPeerGDNative, StreamPeer);
-
-protected:
- static void _bind_methods();
- const godot_net_stream_peer *interface;
-
-public:
- StreamPeerGDNative();
- ~StreamPeerGDNative();
-
- /* Sets the interface implementation from GDNative */
- void set_native_stream_peer(const godot_net_stream_peer *p_interface);
-
- /* Specific to StreamPeer */
- Error put_data(const uint8_t *p_data, int p_bytes) override;
- Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) override;
- Error get_data(uint8_t *p_buffer, int p_bytes) override;
- Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) override;
- int get_available_bytes() const override;
-};
-
-#endif // STREAM_PEER_GDNATIVE_H
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index e4c2b20224..a4ab5663ef 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -35,7 +35,6 @@
#include "gdnative.h"
#include "nativescript/register_types.h"
-#include "net/register_types.h"
#include "pluginscript/register_types.h"
#include "videodecoder/register_types.h"
@@ -265,7 +264,6 @@ void register_gdnative_types() {
GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall);
- register_net_types();
register_nativescript_types();
register_pluginscript_types();
register_videodecoder_types();
@@ -329,7 +327,6 @@ void unregister_gdnative_types() {
unregister_videodecoder_types();
unregister_pluginscript_types();
unregister_nativescript_types();
- unregister_net_types();
memdelete(GDNativeCallRegistry::singleton);
diff --git a/modules/gdnative/text/SCsub b/modules/gdnative/text/SCsub
deleted file mode 100644
index 0b2db3b504..0000000000
--- a/modules/gdnative/text/SCsub
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_gdnative")
-
-env_gdnative.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/gdnative/text/config.py b/modules/gdnative/text/config.py
deleted file mode 100644
index d22f9454ed..0000000000
--- a/modules/gdnative/text/config.py
+++ /dev/null
@@ -1,6 +0,0 @@
-def can_build(env, platform):
- return True
-
-
-def configure(env):
- pass
diff --git a/modules/gdnative/text/register_types.cpp b/modules/gdnative/text/register_types.cpp
deleted file mode 100644
index 67385d2fbf..0000000000
--- a/modules/gdnative/text/register_types.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-/*************************************************************************/
-/* register_types.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 "register_types.h"
-#include "text_server_gdnative.h"
-
-void register_text_server_gdn_types() {}
-
-void unregister_text_server_gdn_types() {}
diff --git a/modules/gdnative/text/text_server_gdnative.cpp b/modules/gdnative/text/text_server_gdnative.cpp
deleted file mode 100644
index 39db8ae636..0000000000
--- a/modules/gdnative/text/text_server_gdnative.cpp
+++ /dev/null
@@ -1,1086 +0,0 @@
-/*************************************************************************/
-/* text_server_gdnative.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 "text_server_gdnative.h"
-
-bool TextServerGDNative::has_feature(Feature p_feature) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->has_feature(data, (godot_int)p_feature);
-}
-
-String TextServerGDNative::get_name() const {
- ERR_FAIL_COND_V(interface == nullptr, String());
- godot_string result = interface->get_name(data);
- String name = *(String *)&result;
- godot_string_destroy(&result);
- return name;
-}
-
-void TextServerGDNative::free(RID p_rid) {
- ERR_FAIL_COND(interface == nullptr);
- interface->free(data, (godot_rid *)&p_rid);
-}
-
-bool TextServerGDNative::has(RID p_rid) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->has(data, (godot_rid *)&p_rid);
-}
-
-bool TextServerGDNative::load_support_data(const String &p_filename) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->load_support_data(data, (godot_string *)&p_filename);
-}
-
-#ifdef TOOLS_ENABLED
-
-String TextServerGDNative::get_support_data_filename() {
- ERR_FAIL_COND_V(interface == nullptr, String());
- godot_string result = interface->get_support_data_filename(data);
- String name = *(String *)&result;
- godot_string_destroy(&result);
- return name;
-}
-
-String TextServerGDNative::get_support_data_info() {
- ERR_FAIL_COND_V(interface == nullptr, String());
- godot_string result = interface->get_support_data_info(data);
- String info = *(String *)&result;
- godot_string_destroy(&result);
- return info;
-}
-
-bool TextServerGDNative::save_support_data(const String &p_filename) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->save_support_data(data, (godot_string *)&p_filename);
-}
-
-#endif
-
-bool TextServerGDNative::is_locale_right_to_left(const String &p_locale) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->is_locale_right_to_left(data, (godot_string *)&p_locale);
-}
-
-int32_t TextServerGDNative::name_to_tag(const String &p_name) const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->name_to_tag(data, (godot_string *)&p_name);
-}
-
-String TextServerGDNative::tag_to_name(int32_t p_tag) const {
- ERR_FAIL_COND_V(interface == nullptr, String());
- godot_string result = interface->tag_to_name(data, p_tag);
- String name = *(String *)&result;
- godot_string_destroy(&result);
- return name;
-}
-
-/*************************************************************************/
-/* Font */
-/*************************************************************************/
-
-RID TextServerGDNative::create_font() {
- ERR_FAIL_COND_V(interface == nullptr, RID());
- godot_rid result = interface->create_font(data);
- RID rid = *(RID *)&result;
- return rid;
-}
-
-void TextServerGDNative::font_set_data(RID p_font_rid, const PackedByteArray &p_data) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_data(data, (godot_rid *)&p_font_rid, (const godot_packed_byte_array *)&p_data);
-}
-
-void TextServerGDNative::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_data_ptr(data, (godot_rid *)&p_font_rid, p_data_ptr, p_data_size);
-}
-
-void TextServerGDNative::font_set_antialiased(RID p_font_rid, bool p_antialiased) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_antialiased(data, (godot_rid *)&p_font_rid, p_antialiased);
-}
-
-bool TextServerGDNative::font_is_antialiased(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_is_antialiased(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_multichannel_signed_distance_field(data, (godot_rid *)&p_font_rid, p_msdf);
-}
-
-bool TextServerGDNative::font_is_multichannel_signed_distance_field(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_is_multichannel_signed_distance_field(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_msdf_pixel_range(data, (godot_rid *)&p_font_rid, p_msdf_pixel_range);
-}
-
-int TextServerGDNative::font_get_msdf_pixel_range(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->font_get_msdf_pixel_range(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_msdf_size(data, (godot_rid *)&p_font_rid, p_msdf_size);
-}
-
-int TextServerGDNative::font_get_msdf_size(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->font_get_msdf_size(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_fixed_size(data, (godot_rid *)&p_font_rid, p_fixed_size);
-}
-
-int TextServerGDNative::font_get_fixed_size(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->font_get_fixed_size(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_force_autohinter(data, (godot_rid *)&p_font_rid, p_force_autohinter);
-}
-
-bool TextServerGDNative::font_is_force_autohinter(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_is_force_autohinter(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_hinting(data, (godot_rid *)&p_font_rid, (godot_int)p_hinting);
-}
-
-TextServer::Hinting TextServerGDNative::font_get_hinting(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, TextServer::HINTING_NONE);
- return (TextServer::Hinting)interface->font_get_hinting(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_variation_coordinates(data, (godot_rid *)&p_font_rid, (const godot_dictionary *)&p_variation_coordinates);
-}
-
-Dictionary TextServerGDNative::font_get_variation_coordinates(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, Dictionary());
- godot_dictionary result = interface->font_get_variation_coordinates(data, (godot_rid *)&p_font_rid);
- Dictionary dict = *(Dictionary *)&result;
- godot_dictionary_destroy(&result);
- return dict;
-}
-
-void TextServerGDNative::font_set_oversampling(RID p_font_rid, real_t p_oversampling) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_oversampling(data, (godot_rid *)&p_font_rid, p_oversampling);
-}
-
-real_t TextServerGDNative::font_get_oversampling(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.0f);
- return interface->font_get_oversampling(data, (godot_rid *)&p_font_rid);
-}
-
-Array TextServerGDNative::font_get_size_cache_list(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, Array());
- godot_array result = interface->font_get_size_cache_list(data, (godot_rid *)&p_font_rid);
- Array list = *(Array *)&result;
- godot_array_destroy(&result);
- return list;
-}
-
-void TextServerGDNative::font_clear_size_cache(RID p_font_rid) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_clear_size_cache(data, (godot_rid *)&p_font_rid);
-}
-
-void TextServerGDNative::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_remove_size_cache(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-}
-
-void TextServerGDNative::font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_ascent(data, (godot_rid *)&p_font_rid, p_size, p_ascent);
-}
-
-real_t TextServerGDNative::font_get_ascent(RID p_font_rid, int p_size) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.0f);
- return interface->font_get_ascent(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_descent(RID p_font_rid, int p_size, real_t p_descent) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_descent(data, (godot_rid *)&p_font_rid, p_size, p_descent);
-}
-
-real_t TextServerGDNative::font_get_descent(RID p_font_rid, int p_size) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.0f);
- return interface->font_get_descent(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_underline_position(data, (godot_rid *)&p_font_rid, p_size, p_underline_position);
-}
-
-real_t TextServerGDNative::font_get_underline_position(RID p_font_rid, int p_size) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.0f);
- return interface->font_get_underline_position(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_underline_thickness(data, (godot_rid *)&p_font_rid, p_size, p_underline_thickness);
-}
-
-real_t TextServerGDNative::font_get_underline_thickness(RID p_font_rid, int p_size) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.0f);
- return interface->font_get_underline_thickness(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_scale(RID p_font_rid, int p_size, real_t p_scale) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_scale(data, (godot_rid *)&p_font_rid, p_size, p_scale);
-}
-
-real_t TextServerGDNative::font_get_scale(RID p_font_rid, int p_size) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.0f);
- return interface->font_get_scale(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_spacing(data, (godot_rid *)&p_font_rid, p_size, (godot_int)p_spacing, p_value);
-}
-
-int TextServerGDNative::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->font_get_spacing(data, (godot_rid *)&p_font_rid, p_size, (godot_int)p_spacing);
-}
-
-int TextServerGDNative::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const {
- ERR_FAIL_COND_V(interface == nullptr, -1);
- return interface->font_get_texture_count(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-}
-
-void TextServerGDNative::font_clear_textures(RID p_font_rid, const Vector2i &p_size) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_clear_textures(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-}
-
-void TextServerGDNative::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_remove_texture(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index);
-}
-
-void TextServerGDNative::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_texture_image(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index, (const godot_object *)p_image.ptr());
-}
-
-Ref<Image> TextServerGDNative::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
- ERR_FAIL_COND_V(interface == nullptr, Ref<Image>());
- godot_object *result = interface->font_get_texture_image(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index);
- return Ref<Image>((Image *)result);
-}
-
-void TextServerGDNative::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_texture_offsets(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index, (const godot_packed_int32_array *)&p_offset);
-}
-
-PackedInt32Array TextServerGDNative::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
- ERR_FAIL_COND_V(interface == nullptr, PackedInt32Array());
- godot_packed_int32_array result = interface->font_get_texture_offsets(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_texture_index);
- PackedInt32Array offset = *(PackedInt32Array *)&result;
- godot_packed_int32_array_destroy(&result);
- return offset;
-}
-
-Array TextServerGDNative::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const {
- ERR_FAIL_COND_V(interface == nullptr, Array());
- godot_array result = interface->font_get_glyph_list(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
- Array list = *(Array *)&result;
- godot_array_destroy(&result);
- return list;
-}
-
-void TextServerGDNative::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_clear_glyphs(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size);
-}
-
-void TextServerGDNative::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_remove_glyph(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
-}
-
-Vector2 TextServerGDNative::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector2());
- godot_vector2 result = interface->font_get_glyph_advance(data, (godot_rid *)&p_font_rid, p_size, p_glyph);
- Vector2 adv = *(Vector2 *)&result;
- return adv;
-}
-
-void TextServerGDNative::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_glyph_advance(data, (godot_rid *)&p_font_rid, p_size, p_glyph, (const godot_vector2 *)&p_advance);
-}
-
-Vector2 TextServerGDNative::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector2());
- godot_vector2 result = interface->font_get_glyph_offset(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
- Vector2 off = *(Vector2 *)&result;
- return off;
-}
-
-void TextServerGDNative::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_glyph_offset(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph, (const godot_vector2 *)&p_offset);
-}
-
-Vector2 TextServerGDNative::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector2());
- godot_vector2 result = interface->font_get_glyph_size(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
- Vector2 sz = *(Vector2 *)&result;
- return sz;
-}
-
-void TextServerGDNative::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_glyph_size(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph, (const godot_vector2 *)&p_gl_size);
-}
-
-Rect2 TextServerGDNative::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- ERR_FAIL_COND_V(interface == nullptr, Rect2());
- godot_rect2 result = interface->font_get_glyph_uv_rect(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
- Rect2 uv = *(Rect2 *)&result;
- return uv;
-}
-
-void TextServerGDNative::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_glyph_uv_rect(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph, (const godot_rect2 *)&p_uv_rect);
-}
-
-int TextServerGDNative::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- ERR_FAIL_COND_V(interface == nullptr, -1);
- return interface->font_get_glyph_texture_idx(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph);
-}
-
-void TextServerGDNative::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_glyph_texture_idx(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_glyph, p_texture_idx);
-}
-
-bool TextServerGDNative::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_get_glyph_contours(data, (godot_rid *)&p_font_rid, p_size, p_index, (godot_packed_vector3_array *)&r_points, (godot_packed_int32_array *)&r_contours, &r_orientation);
-}
-
-Array TextServerGDNative::font_get_kerning_list(RID p_font_rid, int p_size) const {
- ERR_FAIL_COND_V(interface == nullptr, Array());
- godot_array result = interface->font_get_kerning_list(data, (godot_rid *)&p_font_rid, p_size);
- Array list = *(Array *)&result;
- godot_array_destroy(&result);
- return list;
-}
-
-void TextServerGDNative::font_clear_kerning_map(RID p_font_rid, int p_size) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_clear_kerning_map(data, (godot_rid *)&p_font_rid, p_size);
-}
-
-void TextServerGDNative::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_remove_kerning(data, (godot_rid *)&p_font_rid, p_size, (const godot_vector2i *)&p_glyph_pair);
-}
-
-void TextServerGDNative::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_kerning(data, (godot_rid *)&p_font_rid, p_size, (const godot_vector2i *)&p_glyph_pair, (const godot_vector2 *)&p_kerning);
-}
-
-Vector2 TextServerGDNative::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector2());
- godot_vector2 result = interface->font_get_kerning(data, (godot_rid *)&p_font_rid, p_size, (const godot_vector2i *)&p_glyph_pair);
- Vector2 kern = *(Vector2 *)&result;
- return kern;
-}
-
-int32_t TextServerGDNative::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->font_get_glyph_index(data, (godot_rid *)&p_font_rid, p_size, p_char, p_variation_selector);
-}
-
-bool TextServerGDNative::font_has_char(RID p_font_rid, char32_t p_char) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_has_char(data, (godot_rid *)&p_font_rid, p_char);
-}
-
-String TextServerGDNative::font_get_supported_chars(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, String());
- godot_string result = interface->font_get_supported_chars(data, (godot_rid *)&p_font_rid);
- String chars = *(String *)&result;
- godot_string_destroy(&result);
- return chars;
-}
-
-void TextServerGDNative::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_render_range(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_start, p_end);
-}
-
-void TextServerGDNative::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_render_glyph(data, (godot_rid *)&p_font_rid, (const godot_vector2i *)&p_size, p_index);
-}
-
-void TextServerGDNative::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_draw_glyph(data, (godot_rid *)&p_font_rid, (godot_rid *)&p_canvas, p_size, (const godot_vector2 *)&p_pos, p_index, (const godot_color *)&p_color);
-}
-
-void TextServerGDNative::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_draw_glyph_outline(data, (godot_rid *)&p_font_rid, (godot_rid *)&p_canvas, p_size, p_outline_size, (const godot_vector2 *)&p_pos, p_index, (const godot_color *)&p_color);
-}
-
-bool TextServerGDNative::font_is_language_supported(RID p_font_rid, const String &p_language) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_is_language_supported(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_language);
-}
-
-void TextServerGDNative::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_language_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_language, p_supported);
-}
-
-bool TextServerGDNative::font_get_language_support_override(RID p_font_rid, const String &p_language) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_get_language_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_language);
-}
-
-void TextServerGDNative::font_remove_language_support_override(RID p_font_rid, const String &p_language) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_remove_language_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_language);
-}
-
-Vector<String> TextServerGDNative::font_get_language_support_overrides(RID p_font_rid) {
- ERR_FAIL_COND_V(interface == nullptr, PackedStringArray());
- godot_packed_string_array result = interface->font_get_language_support_overrides(data, (godot_rid *)&p_font_rid);
- PackedStringArray list = *(PackedStringArray *)&result;
- godot_packed_string_array_destroy(&result);
- return list;
-}
-
-bool TextServerGDNative::font_is_script_supported(RID p_font_rid, const String &p_script) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_is_script_supported(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_script);
-}
-
-void TextServerGDNative::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_script_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_script, p_supported);
-}
-
-bool TextServerGDNative::font_get_script_support_override(RID p_font_rid, const String &p_script) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->font_get_script_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_script);
-}
-
-void TextServerGDNative::font_remove_script_support_override(RID p_font_rid, const String &p_script) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_remove_script_support_override(data, (godot_rid *)&p_font_rid, (const godot_string *)&p_script);
-}
-
-Vector<String> TextServerGDNative::font_get_script_support_overrides(RID p_font_rid) {
- ERR_FAIL_COND_V(interface == nullptr, PackedStringArray());
- godot_packed_string_array result = interface->font_get_script_support_overrides(data, (godot_rid *)&p_font_rid);
- PackedStringArray list = *(PackedStringArray *)&result;
- godot_packed_string_array_destroy(&result);
- return list;
-}
-
-Dictionary TextServerGDNative::font_supported_feature_list(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, Dictionary());
- godot_dictionary result = interface->font_supported_feature_list(data, (godot_rid *)&p_font_rid);
- Dictionary dict = *(Dictionary *)&result;
- godot_dictionary_destroy(&result);
- return dict;
-}
-
-Dictionary TextServerGDNative::font_supported_variation_list(RID p_font_rid) const {
- ERR_FAIL_COND_V(interface == nullptr, Dictionary());
- godot_dictionary result = interface->font_supported_variation_list(data, (godot_rid *)&p_font_rid);
- Dictionary dict = *(Dictionary *)&result;
- godot_dictionary_destroy(&result);
- return dict;
-}
-
-real_t TextServerGDNative::font_get_global_oversampling() const {
- ERR_FAIL_COND_V(interface == nullptr, 0.0f);
- return interface->font_get_global_oversampling(data);
-}
-
-void TextServerGDNative::font_set_global_oversampling(real_t p_oversampling) {
- ERR_FAIL_COND(interface == nullptr);
- interface->font_set_global_oversampling(data, p_oversampling);
-}
-
-/*************************************************************************/
-/* Shaped text buffer interface */
-/*************************************************************************/
-
-RID TextServerGDNative::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
- ERR_FAIL_COND_V(interface == nullptr, RID());
- godot_rid result = interface->create_shaped_text(data, (godot_int)p_direction, (godot_int)p_orientation);
- RID rid = *(RID *)&result;
- return rid;
-}
-
-void TextServerGDNative::shaped_text_clear(RID p_shaped) {
- ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_clear(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
- ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_set_direction(data, (godot_rid *)&p_shaped, (godot_int)p_direction);
-}
-
-TextServer::Direction TextServerGDNative::shaped_text_get_direction(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, TextServer::DIRECTION_LTR);
- return (TextServer::Direction)interface->shaped_text_get_direction(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
- ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_set_orientation(data, (godot_rid *)&p_shaped, (godot_int)p_orientation);
-}
-
-TextServer::Orientation TextServerGDNative::shaped_text_get_orientation(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, TextServer::ORIENTATION_HORIZONTAL);
- return (TextServer::Orientation)interface->shaped_text_get_orientation(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
- ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_set_bidi_override(data, (godot_rid *)&p_shaped, (const godot_packed_vector2i_array *)&p_override);
-}
-
-void TextServerGDNative::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
- ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_set_preserve_invalid(data, (godot_rid *)&p_shaped, p_enabled);
-}
-
-bool TextServerGDNative::shaped_text_get_preserve_invalid(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return (TextServer::Orientation)interface->shaped_text_get_preserve_invalid(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
- ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_set_preserve_control(data, (godot_rid *)&p_shaped, p_enabled);
-}
-
-bool TextServerGDNative::shaped_text_get_preserve_control(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return (TextServer::Orientation)interface->shaped_text_get_preserve_control(data, (godot_rid *)&p_shaped);
-}
-
-bool TextServerGDNative::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->shaped_text_add_string(data, (godot_rid *)&p_shaped, (const godot_string *)&p_text, (const godot_rid **)p_fonts.ptr(), p_size, (const godot_dictionary *)&p_opentype_features, (const godot_string *)&p_language);
-}
-
-bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->shaped_text_add_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align, p_length);
-}
-
-bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->shaped_text_resize_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align);
-}
-
-RID TextServerGDNative::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
- ERR_FAIL_COND_V(interface == nullptr, RID());
- godot_rid result = interface->shaped_text_substr(data, (godot_rid *)&p_shaped, (godot_int)p_start, (godot_int)p_length);
- RID rid = *(RID *)&result;
- return rid;
-}
-
-RID TextServerGDNative::shaped_text_get_parent(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, RID());
- godot_rid result = interface->shaped_text_get_parent(data, (godot_rid *)&p_shaped);
- RID rid = *(RID *)&result;
- return rid;
-}
-
-real_t TextServerGDNative::shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t p_jst_flags) {
- ERR_FAIL_COND_V(interface == nullptr, 0.f);
- return interface->shaped_text_fit_to_width(data, (godot_rid *)&p_shaped, p_width, p_jst_flags);
-}
-
-real_t TextServerGDNative::shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) {
- ERR_FAIL_COND_V(interface == nullptr, 0.f);
- return interface->shaped_text_tab_align(data, (godot_rid *)&p_shaped, (godot_packed_float32_array *)&p_tab_stops);
-}
-
-bool TextServerGDNative::shaped_text_shape(RID p_shaped) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->shaped_text_shape(data, (godot_rid *)&p_shaped);
-}
-
-bool TextServerGDNative::shaped_text_update_breaks(RID p_shaped) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->shaped_text_update_breaks(data, (godot_rid *)&p_shaped);
-}
-
-bool TextServerGDNative::shaped_text_update_justification_ops(RID p_shaped) {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->shaped_text_update_justification_ops(data, (godot_rid *)&p_shaped);
-}
-
-void TextServerGDNative::shaped_text_overrun_trim_to_width(RID p_shaped_line, real_t p_width, uint8_t p_trim_flags) {
- ERR_FAIL_COND(interface == nullptr);
- interface->shaped_text_overrun_trim_to_width(data, (godot_rid *)&p_shaped_line, p_width, p_trim_flags);
-};
-
-bool TextServerGDNative::shaped_text_is_ready(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->shaped_text_is_ready(data, (godot_rid *)&p_shaped);
-}
-
-Vector<TextServer::Glyph> TextServerGDNative::shaped_text_get_glyphs(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector<TextServer::Glyph>());
- godot_packed_glyph_array result = interface->shaped_text_get_glyphs(data, (godot_rid *)&p_shaped);
- Vector<TextServer::Glyph> glyphs = *(Vector<TextServer::Glyph> *)&result;
- godot_packed_glyph_array_destroy(&result);
- return glyphs;
-}
-
-Vector2i TextServerGDNative::shaped_text_get_range(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector2i());
- godot_vector2i result = interface->shaped_text_get_range(data, (godot_rid *)&p_shaped);
- Vector2i range = *(Vector2i *)&result;
- return range;
-}
-
-Vector<TextServer::Glyph> TextServerGDNative::shaped_text_sort_logical(RID p_shaped) {
- ERR_FAIL_COND_V(interface == nullptr, Vector<TextServer::Glyph>());
- godot_packed_glyph_array result = interface->shaped_text_sort_logical(data, (godot_rid *)&p_shaped);
- Vector<TextServer::Glyph> glyphs = *(Vector<TextServer::Glyph> *)&result;
- godot_packed_glyph_array_destroy(&result);
- return glyphs;
-}
-
-Vector<Vector2i> TextServerGDNative::shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<real_t> &p_width, int p_start, bool p_once, uint8_t p_break_flags) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
- if (interface->shaped_text_get_line_breaks_adv != nullptr) {
- godot_packed_vector2i_array result = interface->shaped_text_get_line_breaks_adv(data, (godot_rid *)&p_shaped, (godot_packed_float32_array *)&p_width, p_start, p_once, p_break_flags);
- Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
- godot_packed_vector2i_array_destroy(&result);
- return breaks;
- } else {
- return TextServer::shaped_text_get_line_breaks_adv(p_shaped, p_width, p_break_flags);
- }
-}
-
-Vector<Vector2i> TextServerGDNative::shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint8_t p_break_flags) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
- if (interface->shaped_text_get_line_breaks != nullptr) {
- godot_packed_vector2i_array result = interface->shaped_text_get_line_breaks(data, (godot_rid *)&p_shaped, p_width, p_start, p_break_flags);
- Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
- godot_packed_vector2i_array_destroy(&result);
- return breaks;
- } else {
- return TextServer::shaped_text_get_line_breaks(p_shaped, p_width, p_break_flags);
- }
-}
-
-Vector<Vector2i> TextServerGDNative::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const {
- ERR_FAIL_COND_V(interface == nullptr, Vector<Vector2i>());
- if (interface->shaped_text_get_word_breaks != nullptr) {
- godot_packed_vector2i_array result = interface->shaped_text_get_word_breaks(data, (godot_rid *)&p_shaped, p_grapheme_flags);
- Vector<Vector2i> breaks = *(Vector<Vector2i> *)&result;
- godot_packed_vector2i_array_destroy(&result);
- return breaks;
- } else {
- return TextServer::shaped_text_get_word_breaks(p_shaped, p_grapheme_flags);
- }
-}
-
-Array TextServerGDNative::shaped_text_get_objects(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, Array());
- godot_array result = interface->shaped_text_get_objects(data, (godot_rid *)&p_shaped);
- Array rect = *(Array *)&result;
- return rect;
-}
-
-Rect2 TextServerGDNative::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
- ERR_FAIL_COND_V(interface == nullptr, Rect2());
- godot_rect2 result = interface->shaped_text_get_object_rect(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key);
- Rect2 rect = *(Rect2 *)&result;
- return rect;
-}
-
-Size2 TextServerGDNative::shaped_text_get_size(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, Size2());
- godot_vector2 result = interface->shaped_text_get_size(data, (godot_rid *)&p_shaped);
- Size2 size = *(Size2 *)&result;
- return size;
-}
-
-real_t TextServerGDNative::shaped_text_get_ascent(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.f);
- return interface->shaped_text_get_ascent(data, (godot_rid *)&p_shaped);
-}
-
-real_t TextServerGDNative::shaped_text_get_descent(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.f);
- return interface->shaped_text_get_descent(data, (godot_rid *)&p_shaped);
-}
-
-real_t TextServerGDNative::shaped_text_get_width(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.f);
- return interface->shaped_text_get_width(data, (godot_rid *)&p_shaped);
-}
-
-real_t TextServerGDNative::shaped_text_get_underline_position(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.f);
- return interface->shaped_text_get_underline_position(data, (godot_rid *)&p_shaped);
-}
-
-real_t TextServerGDNative::shaped_text_get_underline_thickness(RID p_shaped) const {
- ERR_FAIL_COND_V(interface == nullptr, 0.f);
- return interface->shaped_text_get_underline_thickness(data, (godot_rid *)&p_shaped);
-}
-
-String TextServerGDNative::format_number(const String &p_string, const String &p_language) const {
- ERR_FAIL_COND_V(interface == nullptr, String());
- godot_string result = interface->format_number(data, (const godot_string *)&p_string, (const godot_string *)&p_language);
- if (interface->format_number == nullptr) {
- return p_string;
- }
- String ret = *(String *)&result;
- godot_string_destroy(&result);
- return ret;
-}
-
-String TextServerGDNative::parse_number(const String &p_string, const String &p_language) const {
- ERR_FAIL_COND_V(interface == nullptr, String());
- if (interface->parse_number == nullptr) {
- return p_string;
- }
- godot_string result = interface->parse_number(data, (const godot_string *)&p_string, (const godot_string *)&p_language);
- String ret = *(String *)&result;
- godot_string_destroy(&result);
- return ret;
-}
-
-String TextServerGDNative::percent_sign(const String &p_language) const {
- ERR_FAIL_COND_V(interface == nullptr, String());
- if (interface->percent_sign == nullptr) {
- return "%";
- }
- godot_string result = interface->percent_sign(data, (const godot_string *)&p_language);
- String ret = *(String *)&result;
- godot_string_destroy(&result);
- return ret;
-}
-
-TextServer *TextServerGDNative::create_func(Error &r_error, void *p_user_data) {
- const godot_text_interface_gdnative *interface = (const godot_text_interface_gdnative *)p_user_data;
- r_error = OK;
-
- TextServerGDNative *server = memnew(TextServerGDNative());
- server->interface = interface;
- server->data = interface->constructor((godot_object *)server);
-
- return server;
-}
-
-TextServerGDNative::TextServerGDNative() {
- data = nullptr;
- interface = nullptr;
-}
-
-TextServerGDNative::~TextServerGDNative() {
- if (interface != nullptr) {
- interface->destructor(data);
- data = nullptr;
- interface = nullptr;
- }
-}
-
-/*************************************************************************/
-/* GDNative functions */
-/*************************************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-static_assert(sizeof(godot_glyph) == sizeof(TextServer::Glyph), "Glyph size mismatch");
-static_assert(sizeof(godot_packed_glyph_array) == sizeof(Vector<TextServer::Glyph>), "Vector<Glyph> size mismatch");
-
-void GDAPI godot_text_register_interface(const godot_text_interface_gdnative *p_interface, const godot_string *p_name, uint32_t p_features) {
- ERR_FAIL_COND(p_interface->version.major != 1);
- String name = *(String *)p_name;
- TextServerManager::register_create_function(name + "(GDNative)", p_features, TextServerGDNative::create_func, (void *)p_interface);
-}
-
-// Glyph
-
-void GDAPI godot_glyph_new(godot_glyph *r_dest) {
- TextServer::Glyph *dest = (TextServer::Glyph *)r_dest;
- *dest = TextServer::Glyph();
-}
-
-godot_vector2i GDAPI godot_glyph_get_range(const godot_glyph *p_self) {
- godot_vector2i dest;
- Vector2i *d = (Vector2i *)&dest;
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- d->x = self->start;
- d->y = self->end;
- return dest;
-}
-
-void GDAPI godot_glyph_set_range(godot_glyph *p_self, const godot_vector2i *p_range) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- const Vector2i *range = (const Vector2i *)p_range;
- self->start = range->x;
- self->end = range->y;
-}
-
-godot_int GDAPI godot_glyph_get_count(const godot_glyph *p_self) {
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- return self->count;
-}
-
-void GDAPI godot_glyph_set_count(godot_glyph *p_self, godot_int p_count) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- self->count = p_count;
-}
-
-godot_int GDAPI godot_glyph_get_repeat(const godot_glyph *p_self) {
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- return self->repeat;
-}
-
-void GDAPI godot_glyph_set_repeat(godot_glyph *p_self, godot_int p_repeat) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- self->repeat = p_repeat;
-}
-
-godot_int GDAPI godot_glyph_get_flags(const godot_glyph *p_self) {
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- return self->flags;
-}
-
-void GDAPI godot_glyph_set_flags(godot_glyph *p_self, godot_int p_flags) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- self->flags = p_flags;
-}
-
-godot_vector2 GDAPI godot_glyph_get_offset(const godot_glyph *p_self) {
- godot_vector2 dest;
- Vector2 *d = (Vector2 *)&dest;
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- d->x = self->x_off;
- d->y = self->y_off;
- return dest;
-}
-
-void GDAPI godot_glyph_set_offset(godot_glyph *p_self, const godot_vector2 *p_offset) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- const Vector2 *offset = (const Vector2 *)p_offset;
- self->x_off = offset->x;
- self->y_off = offset->y;
-}
-
-godot_real_t GDAPI godot_glyph_get_advance(const godot_glyph *p_self) {
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- return self->advance;
-}
-
-void GDAPI godot_glyph_set_advance(godot_glyph *p_self, godot_real_t p_advance) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- self->advance = p_advance;
-}
-
-godot_rid GDAPI godot_glyph_get_font(const godot_glyph *p_self) {
- godot_rid dest;
- RID *d = (RID *)&dest;
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- *d = self->font_rid;
- return dest;
-}
-
-void GDAPI godot_glyph_set_font(godot_glyph *p_self, godot_rid *p_font) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- const RID *font = (const RID *)p_font;
- self->font_rid = *font;
-}
-
-godot_int GDAPI godot_glyph_get_font_size(const godot_glyph *p_self) {
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- return self->font_size;
-}
-
-void GDAPI godot_glyph_set_font_size(godot_glyph *p_self, godot_int p_size) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- self->font_size = p_size;
-}
-
-godot_int GDAPI godot_glyph_get_index(const godot_glyph *p_self) {
- const TextServer::Glyph *self = (const TextServer::Glyph *)p_self;
- return self->index;
-}
-
-void GDAPI godot_glyph_set_index(godot_glyph *p_self, godot_int p_index) {
- TextServer::Glyph *self = (TextServer::Glyph *)p_self;
- self->index = p_index;
-}
-
-// GlyphArray
-
-void GDAPI godot_packed_glyph_array_new(godot_packed_glyph_array *r_dest) {
- Vector<TextServer::Glyph> *dest = (Vector<TextServer::Glyph> *)r_dest;
- memnew_placement(dest, Vector<TextServer::Glyph>);
-}
-
-void GDAPI godot_packed_glyph_array_new_copy(godot_packed_glyph_array *r_dest, const godot_packed_glyph_array *p_src) {
- Vector<TextServer::Glyph> *dest = (Vector<TextServer::Glyph> *)r_dest;
- const Vector<TextServer::Glyph> *src = (const Vector<TextServer::Glyph> *)p_src;
- memnew_placement(dest, Vector<TextServer::Glyph>(*src));
-}
-
-const godot_glyph GDAPI *godot_packed_glyph_array_ptr(const godot_packed_glyph_array *p_self) {
- const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
- return (const godot_glyph *)self->ptr();
-}
-
-godot_glyph GDAPI *godot_packed_glyph_array_ptrw(godot_packed_glyph_array *p_self) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- return (godot_glyph *)self->ptrw();
-}
-
-void GDAPI godot_packed_glyph_array_append(godot_packed_glyph_array *p_self, const godot_glyph *p_data) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_glyph_array_append_array(godot_packed_glyph_array *p_self, const godot_packed_glyph_array *p_array) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- Vector<TextServer::Glyph> *array = (Vector<TextServer::Glyph> *)p_array;
- self->append_array(*array);
-}
-
-godot_error GDAPI godot_packed_glyph_array_insert(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
- return (godot_error)self->insert(p_idx, s);
-}
-
-godot_bool GDAPI godot_packed_glyph_array_has(godot_packed_glyph_array *p_self, const godot_glyph *p_value) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- TextServer::Glyph &v = *(TextServer::Glyph *)p_value;
- return (godot_bool)self->has(v);
-}
-
-void GDAPI godot_packed_glyph_array_sort(godot_packed_glyph_array *p_self) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- self->sort();
-}
-
-void GDAPI godot_packed_glyph_array_reverse(godot_packed_glyph_array *p_self) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- self->reverse();
-}
-
-void GDAPI godot_packed_glyph_array_push_back(godot_packed_glyph_array *p_self, const godot_glyph *p_data) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
- self->push_back(s);
-}
-
-void GDAPI godot_packed_glyph_array_remove(godot_packed_glyph_array *p_self, const godot_int p_idx) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- self->remove(p_idx);
-}
-
-void GDAPI godot_packed_glyph_array_resize(godot_packed_glyph_array *p_self, const godot_int p_size) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- self->resize(p_size);
-}
-
-void GDAPI godot_packed_glyph_array_set(godot_packed_glyph_array *p_self, const godot_int p_idx, const godot_glyph *p_data) {
- Vector<TextServer::Glyph> *self = (Vector<TextServer::Glyph> *)p_self;
- TextServer::Glyph &s = *(TextServer::Glyph *)p_data;
- self->set(p_idx, s);
-}
-
-godot_glyph GDAPI godot_packed_glyph_array_get(const godot_packed_glyph_array *p_self, const godot_int p_idx) {
- const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
- godot_glyph v;
- TextServer::Glyph *s = (TextServer::Glyph *)&v;
- *s = self->get(p_idx);
- return v;
-}
-
-godot_int GDAPI godot_packed_glyph_array_size(const godot_packed_glyph_array *p_self) {
- const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
- return self->size();
-}
-
-godot_bool GDAPI godot_packed_glyph_array_is_empty(const godot_packed_glyph_array *p_self) {
- const Vector<TextServer::Glyph> *self = (const Vector<TextServer::Glyph> *)p_self;
- return self->is_empty();
-}
-
-void GDAPI godot_packed_glyph_array_destroy(godot_packed_glyph_array *p_self) {
- ((Vector<TextServer::Glyph> *)p_self)->~Vector();
-}
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/modules/gdnative/text/text_server_gdnative.h b/modules/gdnative/text/text_server_gdnative.h
deleted file mode 100644
index f081637e23..0000000000
--- a/modules/gdnative/text/text_server_gdnative.h
+++ /dev/null
@@ -1,254 +0,0 @@
-/*************************************************************************/
-/* text_server_gdnative.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 TEXT_SERVER_GDNATIVE_H
-#define TEXT_SERVER_GDNATIVE_H
-
-#include "modules/gdnative/gdnative.h"
-
-#include "servers/text_server.h"
-
-class TextServerGDNative : public TextServer {
- GDCLASS(TextServerGDNative, TextServer);
-
- const godot_text_interface_gdnative *interface = nullptr;
- void *data = nullptr;
-
-protected:
- static void _bind_methods(){};
-
-public:
- virtual bool has_feature(Feature p_feature) override;
- virtual String get_name() const override;
-
- virtual void free(RID p_rid) override;
- virtual bool has(RID p_rid) override;
- virtual bool load_support_data(const String &p_filename) override;
-
-#ifdef TOOLS_ENABLED
- virtual String get_support_data_filename() override;
- virtual String get_support_data_info() override;
- virtual bool save_support_data(const String &p_filename) override;
-#endif
-
- virtual bool is_locale_right_to_left(const String &p_locale) override;
-
- virtual int32_t name_to_tag(const String &p_name) const override;
- virtual String tag_to_name(int32_t p_tag) const override;
-
- /* Font interface */
- virtual RID create_font() override;
-
- virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override;
- virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override;
-
- virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override;
- virtual bool font_is_antialiased(RID p_font_rid) const override;
-
- virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override;
- virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override;
-
- virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override;
- virtual int font_get_msdf_pixel_range(RID p_font_rid) const override;
-
- virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override;
- virtual int font_get_msdf_size(RID p_font_rid) const override;
-
- virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override;
- virtual int font_get_fixed_size(RID p_font_rid) const override;
-
- virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override;
- virtual bool font_is_force_autohinter(RID p_font_rid) const override;
-
- virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) override;
- virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const override;
-
- virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
- virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
-
- virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) override;
- virtual real_t font_get_oversampling(RID p_font_rid) const override;
-
- virtual Array font_get_size_cache_list(RID p_font_rid) const override;
- virtual void font_clear_size_cache(RID p_font_rid) override;
- virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override;
-
- virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) override;
- virtual real_t font_get_ascent(RID p_font_rid, int p_size) const override;
-
- virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) override;
- virtual real_t font_get_descent(RID p_font_rid, int p_size) const override;
-
- virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) override;
- virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const override;
-
- virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) override;
- virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const override;
-
- virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) override;
- virtual real_t font_get_scale(RID p_font_rid, int p_size) const override;
-
- virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
- virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
-
- virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override;
- virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override;
- virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override;
-
- virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override;
- virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
-
- virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override;
- virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override;
-
- virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override;
- virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override;
- virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override;
-
- virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override;
-
- virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override;
-
- virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override;
-
- virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override;
-
- virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
- virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
-
- virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
-
- virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
- virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
- virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override;
-
- virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override;
- virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override;
-
- virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override;
-
- virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override;
- virtual String font_get_supported_chars(RID p_font_rid) const override;
-
- virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override;
- virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override;
-
- virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
- virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override;
-
- virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override;
- virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override;
- virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override;
- virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override;
- virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override;
-
- virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override;
- virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override;
- virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override;
- virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override;
- virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override;
-
- virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
- virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
-
- virtual real_t font_get_global_oversampling() const override;
- virtual void font_set_global_oversampling(real_t p_oversampling) override;
-
- /* Shaped text buffer interface */
-
- virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
-
- virtual void shaped_text_clear(RID p_shaped) override;
-
- virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
- virtual Direction shaped_text_get_direction(RID p_shaped) const override;
-
- virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) override;
-
- virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
- virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
-
- virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override;
- virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override;
-
- virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) override;
- virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
-
- virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
- virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
- virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
-
- virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
- virtual RID shaped_text_get_parent(RID p_shaped) const override;
-
- virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
- virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) override;
-
- virtual bool shaped_text_shape(RID p_shaped) override;
- virtual bool shaped_text_update_breaks(RID p_shaped) override;
- virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
-
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) override;
-
- virtual bool shaped_text_is_ready(RID p_shaped) const override;
-
- virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
-
- virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
-
- virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override;
- virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<real_t> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override;
- virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start = 0, uint8_t p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override;
- virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const override;
- virtual Array shaped_text_get_objects(RID p_shaped) const override;
- virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
-
- virtual Size2 shaped_text_get_size(RID p_shaped) const override;
- virtual real_t shaped_text_get_ascent(RID p_shaped) const override;
- virtual real_t shaped_text_get_descent(RID p_shaped) const override;
- virtual real_t shaped_text_get_width(RID p_shaped) const override;
- virtual real_t shaped_text_get_underline_position(RID p_shaped) const override;
- virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const override;
-
- virtual String format_number(const String &p_string, const String &p_language = "") const override;
- virtual String parse_number(const String &p_string, const String &p_language = "") const override;
- virtual String percent_sign(const String &p_language = "") const override;
-
- static TextServer *create_func(Error &r_error, void *p_user_data);
-
- TextServerGDNative();
- ~TextServerGDNative();
-};
-
-#endif // TEXT_SERVER_GDNATIVE_H
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 51b3452a3a..631ee4d895 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -176,7 +176,8 @@
<method name="range" qualifiers="vararg">
<return type="Array" />
<description>
- Returns an array with the given range. Range can be 1 argument N (0 to N-1), two arguments (initial, final-1) or three arguments (initial, final-1, increment).
+ Returns an array with the given range. Range can be 1 argument [code]N[/code] (0 to [code]N[/code] - 1), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). Returns an empty array if the range isn't valid (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]).
+ Returns an array with the given range. [code]range()[/code] can have 1 argument N ([code]0[/code] to [code]N - 1[/code]), two arguments ([code]initial[/code], [code]final - 1[/code]) or three arguments ([code]initial[/code], [code]final - 1[/code], [code]increment[/code]). [code]increment[/code] can be negative. If [code]increment[/code] is negative, [code]final - 1[/code] will become [code]final + 1[/code]. Also, the initial value must be greater than the final value for the loop to run.
[codeblock]
print(range(4))
print(range(2, 5))
@@ -188,6 +189,20 @@
[2, 3, 4]
[0, 2, 4]
[/codeblock]
+ To iterate over an [Array] backwards, use:
+ [codeblock]
+ var array = [3, 6, 9]
+ var i := array.size() - 1
+ while i &gt;= 0:
+ print(array[i])
+ i -= 1
+ [/codeblock]
+ Output:
+ [codeblock]
+ 9
+ 6
+ 3
+ [/codeblock]
</description>
</method>
<method name="str" qualifiers="vararg">
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 72738f027a..0a448ed88c 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -8,7 +8,7 @@
[method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
- <link title="GDScript tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/index.html</link>
+ <link title="GDScript documentation index">https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/index.html</link>
</tutorials>
<methods>
<method name="get_as_byte_code" qualifiers="const">
@@ -30,6 +30,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index ab441d194a..6529154e5c 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -467,7 +467,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
List<StringName> global_classes;
ScriptServer::get_global_class_list(&global_classes);
for (const StringName &E : global_classes) {
- keywords[String(E)] = usertype_color;
+ keywords[E] = usertype_color;
}
/* Autoloads. */
@@ -486,7 +486,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
List<String> core_types;
gdscript->get_core_type_words(&core_types);
for (const String &E : core_types) {
- keywords[E] = basetype_color;
+ keywords[StringName(E)] = basetype_color;
}
/* Reserved words. */
@@ -496,9 +496,9 @@ void GDScriptSyntaxHighlighter::_update_cache() {
gdscript->get_reserved_words(&keyword_list);
for (const String &E : keyword_list) {
if (gdscript->is_control_flow_keyword(E)) {
- keywords[E] = control_flow_keyword_color;
+ keywords[StringName(E)] = control_flow_keyword_color;
} else {
- keywords[E] = keyword_color;
+ keywords[StringName(E)] = keyword_color;
}
}
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index fabd64dab8..07f21b34ae 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -47,8 +47,8 @@ private:
Vector<ColorRegion> color_regions;
Map<int, int> color_region_cache;
- Dictionary keywords;
- Dictionary member_keywords;
+ HashMap<StringName, Color> keywords;
+ HashMap<StringName, Color> member_keywords;
enum Type {
NONE,
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 5409b3ff79..2bae838543 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -87,6 +87,19 @@ Object *GDScriptNativeClass::instantiate() {
return ClassDB::instantiate(name);
}
+GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
+ if (p_script->initializer) {
+ return p_script->initializer;
+ } else {
+ GDScript *base = p_script->_base;
+ if (base != nullptr) {
+ return _super_constructor(base);
+ } else {
+ return nullptr;
+ }
+ }
+}
+
void GDScript::_super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error) {
GDScript *base = p_script->_base;
if (base != nullptr) {
@@ -109,8 +122,8 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
instance->owner_id = p_owner->get_instance_id();
#ifdef DEBUG_ENABLED
//needed for hot reloading
- for (Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) {
- instance->member_indices_cache[E->key()] = E->get().index;
+ for (const KeyValue<StringName, MemberInfo> &E : member_indices) {
+ instance->member_indices_cache[E.key] = E.value.index;
}
#endif
instance->owner->set_script_instance(instance);
@@ -135,6 +148,8 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco
if (p_argcount < 0) {
return instance;
}
+
+ initializer = _super_constructor(this);
if (initializer != nullptr) {
initializer->call(instance, p_args, p_argcount, r_error);
if (r_error.error != Callable::CallError::CALL_OK) {
@@ -238,10 +253,10 @@ void GDScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder) {
void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const {
const GDScript *current = this;
while (current) {
- for (const Map<StringName, GDScriptFunction *>::Element *E = current->member_functions.front(); E; E = E->next()) {
- GDScriptFunction *func = E->get();
+ for (const KeyValue<StringName, GDScriptFunction *> &E : current->member_functions) {
+ GDScriptFunction *func = E.value;
MethodInfo mi;
- mi.name = E->key();
+ mi.name = E.key;
for (int i = 0; i < func->get_argument_count(); i++) {
PropertyInfo arginfo = func->get_argument_type(i);
#ifdef TOOLS_ENABLED
@@ -271,11 +286,11 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl
while (sptr) {
Vector<_GDScriptMemberSort> msort;
- for (Map<StringName, PropertyInfo>::Element *E = sptr->member_info.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, PropertyInfo> &E : sptr->member_info) {
_GDScriptMemberSort ms;
- ERR_CONTINUE(!sptr->member_indices.has(E->key()));
- ms.index = sptr->member_indices[E->key()].index;
- ms.name = E->key();
+ ERR_CONTINUE(!sptr->member_indices.has(E.key));
+ ms.index = sptr->member_indices[E.key].index;
+ ms.name = E.key;
msort.push_back(ms);
}
@@ -397,8 +412,8 @@ void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<Pro
base_cache->_update_exports_values(values, propnames);
}
- for (Map<StringName, Variant>::Element *E = member_default_values_cache.front(); E; E = E->next()) {
- values[E->key()] = E->get();
+ for (const KeyValue<StringName, Variant> &E : member_default_values_cache) {
+ values[E.key] = E.value;
}
for (const PropertyInfo &E : members_cache) {
@@ -456,9 +471,9 @@ void GDScript::_update_doc() {
doc.description = doc_description;
doc.tutorials = doc_tutorials;
- for (Map<String, DocData::EnumDoc>::Element *E = doc_enums.front(); E; E = E->next()) {
- if (E->value().description != "") {
- doc.enums[E->key()] = E->value().description;
+ for (const KeyValue<String, DocData::EnumDoc> &E : doc_enums) {
+ if (E.value.description != "") {
+ doc.enums[E.key] = E.value.description;
}
}
@@ -537,29 +552,29 @@ void GDScript::_update_doc() {
doc.signals.push_back(signal_doc);
}
- for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
- if (subclasses.has(E->key())) {
+ for (const KeyValue<StringName, Variant> &E : constants) {
+ if (subclasses.has(E.key)) {
continue;
}
// Enums.
bool is_enum = false;
- if (E->value().get_type() == Variant::DICTIONARY) {
- if (doc_enums.has(E->key())) {
+ if (E.value.get_type() == Variant::DICTIONARY) {
+ if (doc_enums.has(E.key)) {
is_enum = true;
- for (int i = 0; i < doc_enums[E->key()].values.size(); i++) {
- doc_enums[E->key()].values.write[i].enumeration = E->key();
- doc.constants.push_back(doc_enums[E->key()].values[i]);
+ for (int i = 0; i < doc_enums[E.key].values.size(); i++) {
+ doc_enums[E.key].values.write[i].enumeration = E.key;
+ doc.constants.push_back(doc_enums[E.key].values[i]);
}
}
}
if (!is_enum && doc_enums.has("@unnamed_enums")) {
for (int i = 0; i < doc_enums["@unnamed_enums"].values.size(); i++) {
- if (E->key() == doc_enums["@unnamed_enums"].values[i].name) {
+ if (E.key == doc_enums["@unnamed_enums"].values[i].name) {
is_enum = true;
DocData::ConstantDoc constant_doc;
constant_doc.enumeration = "@unnamed_enums";
- DocData::constant_doc_from_variant(constant_doc, E->key(), E->value(), doc_enums["@unnamed_enums"].values[i].description);
+ DocData::constant_doc_from_variant(constant_doc, E.key, E.value, doc_enums["@unnamed_enums"].values[i].description);
doc.constants.push_back(constant_doc);
break;
}
@@ -568,16 +583,16 @@ void GDScript::_update_doc() {
if (!is_enum) {
DocData::ConstantDoc constant_doc;
String doc_description;
- if (doc_constants.has(E->key())) {
- doc_description = doc_constants[E->key()];
+ if (doc_constants.has(E.key)) {
+ doc_description = doc_constants[E.key];
}
- DocData::constant_doc_from_variant(constant_doc, E->key(), E->value(), doc_description);
+ DocData::constant_doc_from_variant(constant_doc, E.key, E.value, doc_description);
doc.constants.push_back(constant_doc);
}
}
- for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
- E->get()->_update_doc();
+ for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
+ E.value->_update_doc();
}
_add_doc(doc);
@@ -769,8 +784,8 @@ void GDScript::update_exports() {
void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
p_sc->path = p_path;
- for (Map<StringName, Ref<GDScript>>::Element *E = p_sc->subclasses.front(); E; E = E->next()) {
- _set_subclass_path(E->get(), p_path);
+ for (KeyValue<StringName, Ref<GDScript>> &E : p_sc->subclasses) {
+ _set_subclass_path(E.value, p_path);
}
}
@@ -871,8 +886,8 @@ Error GDScript::reload(bool p_keep_state) {
valid = true;
- for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
- _set_subclass_path(E->get(), path);
+ for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
+ _set_subclass_path(E.value, path);
}
_init_rpc_methods_properties();
@@ -886,8 +901,8 @@ ScriptLanguage *GDScript::get_language() const {
void GDScript::get_constants(Map<StringName, Variant> *p_constants) {
if (p_constants) {
- for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
- (*p_constants)[E->key()] = E->value();
+ for (const KeyValue<StringName, Variant> &E : constants) {
+ (*p_constants)[E.key] = E.value;
}
}
}
@@ -1017,9 +1032,9 @@ const Map<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions(
}
StringName GDScript::debug_get_member_by_index(int p_idx) const {
- for (const Map<StringName, MemberInfo>::Element *E = member_indices.front(); E; E = E->next()) {
- if (E->get().index == p_idx) {
- return E->key();
+ for (const KeyValue<StringName, MemberInfo> &E : member_indices) {
+ if (E.value.index == p_idx) {
+ return E.key;
}
}
@@ -1064,12 +1079,12 @@ bool GDScript::has_script_signal(const StringName &p_signal) const {
}
void GDScript::_get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const {
- for (const Map<StringName, Vector<StringName>>::Element *E = _signals.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, Vector<StringName>> &E : _signals) {
MethodInfo mi;
- mi.name = E->key();
- for (int i = 0; i < E->get().size(); i++) {
+ mi.name = E.key;
+ for (int i = 0; i < E.value.size(); i++) {
PropertyInfo arg;
- arg.name = E->get()[i];
+ arg.name = E.value[i];
mi.arguments.push_back(arg);
}
r_list->push_back(mi);
@@ -1127,11 +1142,11 @@ void GDScript::_save_orphaned_subclasses() {
};
Vector<ClassRefWithName> weak_subclasses;
// collect subclasses ObjectID and name
- for (Map<StringName, Ref<GDScript>>::Element *E = subclasses.front(); E; E = E->next()) {
- E->get()->_owner = nullptr; //bye, you are no longer owned cause I died
+ for (KeyValue<StringName, Ref<GDScript>> &E : subclasses) {
+ E.value->_owner = nullptr; //bye, you are no longer owned cause I died
ClassRefWithName subclass;
- subclass.id = E->get()->get_instance_id();
- subclass.fully_qualified_name = E->get()->fully_qualified_name;
+ subclass.id = E.value->get_instance_id();
+ subclass.fully_qualified_name = E.value->fully_qualified_name;
weak_subclasses.push_back(subclass);
}
@@ -1163,10 +1178,10 @@ void GDScript::_init_rpc_methods_properties() {
Map<StringName, Ref<GDScript>>::Element *sub_E = subclasses.front();
while (cscript) {
// RPC Methods
- for (Map<StringName, GDScriptFunction *>::Element *E = cscript->member_functions.front(); E; E = E->next()) {
- Multiplayer::RPCConfig config = E->get()->get_rpc_config();
+ for (KeyValue<StringName, GDScriptFunction *> &E : cscript->member_functions) {
+ Multiplayer::RPCConfig config = E.value->get_rpc_config();
if (config.rpc_mode != Multiplayer::RPC_MODE_DISABLED) {
- config.name = E->get()->get_name();
+ config.name = E.value->get_name();
if (rpc_functions.find(config) == -1) {
rpc_functions.push_back(config);
}
@@ -1200,8 +1215,8 @@ GDScript::~GDScript() {
}
}
- for (Map<StringName, GDScriptFunction *>::Element *E = member_functions.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<StringName, GDScriptFunction *> &E : member_functions) {
+ memdelete(E.value);
}
if (GDScriptCache::singleton) { // Cache may have been already destroyed at engine shutdown.
@@ -1427,11 +1442,11 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
//instance a fake script for editing the values
Vector<_GDScriptMemberSort> msort;
- for (Map<StringName, PropertyInfo>::Element *F = sptr->member_info.front(); F; F = F->next()) {
+ for (const KeyValue<StringName, PropertyInfo> &F : sptr->member_info) {
_GDScriptMemberSort ms;
- ERR_CONTINUE(!sptr->member_indices.has(F->key()));
- ms.index = sptr->member_indices[F->key()].index;
- ms.name = F->key();
+ ERR_CONTINUE(!sptr->member_indices.has(F.key));
+ ms.index = sptr->member_indices[F.key].index;
+ ms.name = F.key;
msort.push_back(ms);
}
@@ -1452,11 +1467,11 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
const GDScript *sptr = script.ptr();
while (sptr) {
- for (Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, GDScriptFunction *> &E : sptr->member_functions) {
MethodInfo mi;
- mi.name = E->key();
+ mi.name = E.key;
mi.flags |= METHOD_FLAG_FROM_SCRIPT;
- for (int i = 0; i < E->get()->get_argument_count(); i++) {
+ for (int i = 0; i < E.value->get_argument_count(); i++) {
mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
}
p_list->push_back(mi);
@@ -1554,10 +1569,10 @@ void GDScriptInstance::reload_members() {
new_members.resize(script->member_indices.size());
//pass the values to the new indices
- for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
- if (member_indices_cache.has(E->key())) {
- Variant value = members[member_indices_cache[E->key()]];
- new_members.write[E->get().index] = value;
+ for (KeyValue<StringName, GDScript::MemberInfo> &E : script->member_indices) {
+ if (member_indices_cache.has(E.key)) {
+ Variant value = members[member_indices_cache[E.key]];
+ new_members.write[E.value.index] = value;
}
}
@@ -1566,8 +1581,8 @@ void GDScriptInstance::reload_members() {
//pass the values to the new indices
member_indices_cache.clear();
- for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
- member_indices_cache[E->key()] = E->get().index;
+ for (const KeyValue<StringName, GDScript::MemberInfo> &E : script->member_indices) {
+ member_indices_cache[E.key] = E.value.index;
}
#endif
@@ -1875,21 +1890,21 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
#endif
- for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = script->pending_reload_state.front(); F; F = F->next()) {
- map[F->key()] = F->get(); //pending to reload, use this one instead
+ for (const KeyValue<ObjectID, List<Pair<StringName, Variant>>> &F : script->pending_reload_state) {
+ map[F.key] = F.value; //pending to reload, use this one instead
}
}
}
- for (Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>>::Element *E = to_reload.front(); E; E = E->next()) {
- Ref<GDScript> scr = E->key();
+ for (KeyValue<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> &E : to_reload) {
+ Ref<GDScript> scr = E.key;
scr->reload(p_soft_reload);
//restore state if saved
- for (Map<ObjectID, List<Pair<StringName, Variant>>>::Element *F = E->get().front(); F; F = F->next()) {
- List<Pair<StringName, Variant>> &saved_state = F->get();
+ for (KeyValue<ObjectID, List<Pair<StringName, Variant>>> &F : E.value) {
+ List<Pair<StringName, Variant>> &saved_state = F.value;
- Object *obj = ObjectDB::get_instance(F->key());
+ Object *obj = ObjectDB::get_instance(F.key);
if (!obj) {
continue;
}
@@ -2195,15 +2210,15 @@ GDScriptLanguage::~GDScriptLanguage() {
// is not the same as before).
script->reference();
- for (Map<StringName, GDScriptFunction *>::Element *E = script->member_functions.front(); E; E = E->next()) {
- GDScriptFunction *func = E->get();
+ for (KeyValue<StringName, GDScriptFunction *> &E : script->member_functions) {
+ GDScriptFunction *func = E.value;
for (int i = 0; i < func->argument_types.size(); i++) {
func->argument_types.write[i].script_type_ref = Ref<Script>();
}
func->return_type.script_type_ref = Ref<Script>();
}
- for (Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.front(); E; E = E->next()) {
- E->get().data_type.script_type_ref = Ref<Script>();
+ for (KeyValue<StringName, GDScript::MemberInfo> &E : script->member_indices) {
+ E.value.data_type.script_type_ref = Ref<Script>();
}
s = s->next();
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index a6fd7b3b5d..791f8a1431 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -130,6 +130,7 @@ class GDScript : public Script {
SelfList<GDScriptFunctionState>::List pending_func_states;
+ GDScriptFunction *_super_constructor(GDScript *p_script);
void _super_implicit_constructor(GDScript *p_script, GDScriptInstance *p_instance, Callable::CallError &r_error);
GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error);
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index f2b601dc2c..8bd288cf0f 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -171,7 +171,12 @@ Error GDScriptAnalyzer::check_native_member_name_conflict(const StringName &p_me
}
if (class_exists(p_member_name)) {
- push_error(vformat(R"(The class "%s" shadows a native class.)", p_member_name), p_member_node);
+ push_error(vformat(R"(The member "%s" shadows a native class.)", p_member_name), p_member_node);
+ return ERR_PARSE_ERROR;
+ }
+
+ if (GDScriptParser::get_builtin_type(p_member_name) != Variant::VARIANT_MAX) {
+ push_error(vformat(R"(The member "%s" cannot have the same name as a builtin type.)", p_member_name), p_member_node);
return ERR_PARSE_ERROR;
}
@@ -218,6 +223,17 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
p_class->fqcn = p_class->outer->fqcn + "::" + String(p_class->identifier->name);
}
+ if (p_class->identifier) {
+ StringName class_name = p_class->identifier->name;
+ if (class_exists(class_name)) {
+ push_error(vformat(R"(Class "%s" hides a native class.)", class_name), p_class->identifier);
+ } else if (ScriptServer::is_global_class(class_name) && (ScriptServer::get_global_class_path(class_name) != parser->script_path || p_class != parser->head)) {
+ push_error(vformat(R"(Class "%s" hides a global script class.)", class_name), p_class->identifier);
+ } else if (ProjectSettings::get_singleton()->has_autoload(class_name) && ProjectSettings::get_singleton()->get_autoload(class_name).is_singleton) {
+ push_error(vformat(R"(Class "%s" hides an autoload singleton.)", class_name), p_class->identifier);
+ }
+ }
+
GDScriptParser::DataType result;
// Set datatype for class.
@@ -228,6 +244,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
class_type.kind = GDScriptParser::DataType::CLASS;
class_type.class_type = p_class;
class_type.script_path = parser->script_path;
+ class_type.builtin_type = Variant::OBJECT;
p_class->set_datatype(class_type);
if (!p_class->extends_used) {
@@ -242,6 +259,9 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class,
int extends_index = 0;
if (!p_class->extends_path.is_empty()) {
+ if (p_class->extends_path.is_relative_path()) {
+ p_class->extends_path = class_type.script_path.get_base_dir().plus_file(p_class->extends_path).simplify_path();
+ }
Ref<GDScriptParserRef> parser = get_parser_for(p_class->extends_path);
if (parser.is_null()) {
push_error(vformat(R"(Could not resolve super class path "%s".)", p_class->extends_path), p_class);
@@ -450,6 +470,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
GDScriptParser::DataType container_type = resolve_datatype(p_type->container_type);
if (container_type.kind != GDScriptParser::DataType::VARIANT) {
+ container_type.is_meta_type = false;
result.set_container_element_type(container_type);
}
}
@@ -681,8 +702,9 @@ void GDScriptAnalyzer::resolve_class_interface(GDScriptParser::ClassNode *p_clas
specified_type.is_meta_type = false;
}
- GDScriptParser::DataType datatype = member.constant->get_datatype();
+ GDScriptParser::DataType datatype;
if (member.constant->initializer) {
+ datatype = member.constant->initializer->get_datatype();
if (member.constant->initializer->type == GDScriptParser::Node::ARRAY) {
GDScriptParser::ArrayNode *array = static_cast<GDScriptParser::ArrayNode *>(member.constant->initializer);
const_fold_array(array);
@@ -854,18 +876,34 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
GDScriptParser::ClassNode *previous_class = parser->current_class;
parser->current_class = p_class;
- // Do functions now.
+ // Do functions and properties now.
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
- if (member.type != GDScriptParser::ClassNode::Member::FUNCTION) {
- continue;
- }
+ if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) {
+ resolve_function_body(member.function);
- resolve_function_body(member.function);
+ // Apply annotations.
+ for (GDScriptParser::AnnotationNode *&E : member.function->annotations) {
+ E->apply(parser, member.function);
+ }
+ } else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) {
+ if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) {
+ if (member.variable->getter != nullptr) {
+ member.variable->getter->set_datatype(member.variable->datatype);
- // Apply annotations.
- for (GDScriptParser::AnnotationNode *&E : member.function->annotations) {
- E->apply(parser, member.function);
+ resolve_function_body(member.variable->getter);
+ }
+ if (member.variable->setter != nullptr) {
+ resolve_function_signature(member.variable->setter);
+
+ if (member.variable->setter->parameters.size() > 0) {
+ member.variable->setter->parameters[0]->datatype_specifier = member.variable->datatype_specifier;
+ member.variable->setter->parameters[0]->set_datatype(member.get_datatype());
+ }
+
+ resolve_function_body(member.variable->setter);
+ }
+ }
}
}
@@ -881,17 +919,80 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
resolve_class_body(member.m_class);
}
- // Check unused variables.
+ // Check unused variables and datatypes of property getters and setters.
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
- if (member.type != GDScriptParser::ClassNode::Member::VARIABLE) {
- continue;
- }
+ if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
#ifdef DEBUG_ENABLED
- if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) {
- parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name);
- }
+ if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) {
+ parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name);
+ }
+#endif
+
+ if (member.variable->property == GDScriptParser::VariableNode::PROP_SETGET) {
+ GDScriptParser::FunctionNode *getter_function = nullptr;
+ GDScriptParser::FunctionNode *setter_function = nullptr;
+
+ bool has_valid_getter = false;
+ bool has_valid_setter = false;
+
+ if (member.variable->getter_pointer != nullptr) {
+ if (p_class->has_function(member.variable->getter_pointer->name)) {
+ getter_function = p_class->get_member(member.variable->getter_pointer->name).function;
+ }
+
+ if (getter_function == nullptr) {
+ push_error(vformat(R"(Getter "%s" not found.)", member.variable->getter_pointer->name), member.variable);
+
+ } else if (getter_function->parameters.size() != 0 || getter_function->datatype.has_no_type()) {
+ push_error(vformat(R"(Function "%s" cannot be used as getter because of its signature.)", getter_function->identifier->name), member.variable);
+
+ } else if (!is_type_compatible(member.variable->datatype, getter_function->datatype, true)) {
+ push_error(vformat(R"(Function with return type "%s" cannot be used as getter for a property of type "%s".)", getter_function->datatype.to_string(), member.variable->datatype.to_string()), member.variable);
+
+ } else {
+ has_valid_getter = true;
+
+#ifdef DEBUG_ENABLED
+ if (member.variable->datatype.builtin_type == Variant::INT && getter_function->datatype.builtin_type == Variant::FLOAT) {
+ parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION);
+ }
#endif
+ }
+ }
+
+ if (member.variable->setter_pointer != nullptr) {
+ if (p_class->has_function(member.variable->setter_pointer->name)) {
+ setter_function = p_class->get_member(member.variable->setter_pointer->name).function;
+ }
+
+ if (setter_function == nullptr) {
+ push_error(vformat(R"(Setter "%s" not found.)", member.variable->setter_pointer->name), member.variable);
+
+ } else if (setter_function->parameters.size() != 1) {
+ push_error(vformat(R"(Function "%s" cannot be used as setter because of its signature.)", setter_function->identifier->name), member.variable);
+
+ } else if (!is_type_compatible(member.variable->datatype, setter_function->parameters[0]->datatype, true)) {
+ push_error(vformat(R"(Function with argument type "%s" cannot be used as setter for a property of type "%s".)", setter_function->parameters[0]->datatype.to_string(), member.variable->datatype.to_string()), member.variable);
+
+ } else {
+ has_valid_setter = true;
+
+#ifdef DEBUG_ENABLED
+ if (member.variable->datatype.builtin_type == Variant::INT && setter_function->return_type->datatype.builtin_type == Variant::FLOAT) {
+ parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION);
+ }
+#endif
+ }
+ }
+
+ if (member.variable->datatype.is_variant() && has_valid_getter && has_valid_setter) {
+ if (!is_type_compatible(getter_function->datatype, setter_function->parameters[0]->datatype, true)) {
+ push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable);
+ }
+ }
+ }
+ }
}
}
@@ -1015,7 +1116,10 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
return_type.is_meta_type = false;
p_function->set_datatype(return_type);
if (p_function->return_type) {
- push_error("Constructor cannot have an explicit return type.", p_function->return_type);
+ GDScriptParser::DataType declared_return = resolve_datatype(p_function->return_type);
+ if (declared_return.kind != GDScriptParser::DataType::BUILTIN || declared_return.builtin_type != Variant::NIL) {
+ push_error("Constructor cannot have an explicit return type.", p_function->return_type);
+ }
}
} else {
GDScriptParser::DataType return_type = resolve_datatype(p_function->return_type);
@@ -1172,12 +1276,30 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
}
}
- if (!list_resolved) {
+ GDScriptParser::DataType variable_type;
+ if (list_resolved) {
+ variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ variable_type.kind = GDScriptParser::DataType::BUILTIN;
+ variable_type.builtin_type = Variant::INT; // Can this ever be a float or something else?
+ p_for->variable->set_datatype(variable_type);
+ } else if (p_for->list) {
resolve_node(p_for->list);
+ if (p_for->list->datatype.has_container_element_type()) {
+ variable_type = p_for->list->datatype.get_container_element_type();
+ variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ } else if (p_for->list->datatype.is_typed_container_type()) {
+ variable_type = p_for->list->datatype.get_typed_container_type();
+ variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ } else {
+ // Last resort
+ // TODO: Must other cases be handled? Must we mark as unsafe?
+ variable_type.type_source = GDScriptParser::DataType::UNDETECTED;
+ variable_type.kind = GDScriptParser::DataType::VARIANT;
+ }
+ }
+ if (p_for->variable) {
+ p_for->variable->set_datatype(variable_type);
}
-
- // TODO: If list is a typed array, the variable should be an element.
- // Also applicable for constant range() (so variable is int or float).
resolve_suite(p_for->loop);
p_for->set_datatype(p_for->loop->get_datatype());
@@ -1465,8 +1587,7 @@ void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parame
}
if (p_parameter->datatype_specifier != nullptr) {
- resolve_datatype(p_parameter->datatype_specifier);
- result = p_parameter->datatype_specifier->get_datatype();
+ result = resolve_datatype(p_parameter->datatype_specifier);
result.is_meta_type = false;
if (p_parameter->default_value != nullptr) {
@@ -1478,18 +1599,30 @@ void GDScriptAnalyzer::resolve_parameter(GDScriptParser::ParameterNode *p_parame
}
}
+ if (result.builtin_type == Variant::Type::NIL && result.type_source == GDScriptParser::DataType::ANNOTATED_INFERRED && p_parameter->datatype_specifier == nullptr) {
+ push_error(vformat(R"(Could not infer the type of the variable "%s" because the initial value is "null".)", p_parameter->identifier->name), p_parameter->default_value);
+ }
+
p_parameter->set_datatype(result);
}
void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
GDScriptParser::DataType result;
+ GDScriptParser::DataType expected_type;
+ bool has_expected_type = false;
+
+ if (parser->current_function != nullptr) {
+ expected_type = parser->current_function->get_datatype();
+ has_expected_type = true;
+ }
+
if (p_return->return_value != nullptr) {
reduce_expression(p_return->return_value);
if (p_return->return_value->type == GDScriptParser::Node::ARRAY) {
// Check if assigned value is an array literal, so we can make it a typed array too if appropriate.
- if (parser->current_function->get_datatype().has_container_element_type() && p_return->return_value->type == GDScriptParser::Node::ARRAY) {
- update_array_literal_element_type(parser->current_function->get_datatype(), static_cast<GDScriptParser::ArrayNode *>(p_return->return_value));
+ if (has_expected_type && expected_type.has_container_element_type() && p_return->return_value->type == GDScriptParser::Node::ARRAY) {
+ update_array_literal_element_type(expected_type, static_cast<GDScriptParser::ArrayNode *>(p_return->return_value));
}
}
result = p_return->return_value->get_datatype();
@@ -1501,23 +1634,24 @@ void GDScriptAnalyzer::resolve_return(GDScriptParser::ReturnNode *p_return) {
result.is_constant = true;
}
- GDScriptParser::DataType function_type = parser->current_function->get_datatype();
- function_type.is_meta_type = false;
- if (function_type.is_hard_type()) {
- if (!is_type_compatible(function_type, result)) {
- // Try other way. Okay but not safe.
- if (!is_type_compatible(result, function_type)) {
- push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), function_type.to_string()), p_return);
- } else {
- // TODO: Add warning.
- mark_node_unsafe(p_return);
- }
+ if (has_expected_type) {
+ expected_type.is_meta_type = false;
+ if (expected_type.is_hard_type()) {
+ if (!is_type_compatible(expected_type, result)) {
+ // Try other way. Okay but not safe.
+ if (!is_type_compatible(result, expected_type)) {
+ push_error(vformat(R"(Cannot return value of type "%s" because the function return type is "%s".)", result.to_string(), expected_type.to_string()), p_return);
+ } else {
+ // TODO: Add warning.
+ mark_node_unsafe(p_return);
+ }
#ifdef DEBUG_ENABLED
- } else if (function_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
- parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
- } else if (result.is_variant()) {
- mark_node_unsafe(p_return);
+ } else if (expected_type.builtin_type == Variant::INT && result.builtin_type == Variant::FLOAT) {
+ parser->push_warning(p_return, GDScriptWarning::NARROWING_CONVERSION);
+ } else if (result.is_variant()) {
+ mark_node_unsafe(p_return);
#endif
+ }
}
}
@@ -1698,7 +1832,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
}
- if (!assignee_type.is_variant() && !assigned_value_type.is_variant()) {
+ if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) {
bool compatible = true;
GDScriptParser::DataType op_type = assigned_value_type;
if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
@@ -1720,7 +1854,6 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
} else {
// TODO: Warning in this case.
mark_node_unsafe(p_assignment);
- p_assignment->use_conversion_assign = true;
}
}
} else {
@@ -1748,21 +1881,27 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
identifier->variable_source->set_datatype(id_type);
}
} break;
+ case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER: {
+ GDScriptParser::DataType id_type = identifier->parameter_source->get_datatype();
+ if (!id_type.is_hard_type()) {
+ id_type.kind = GDScriptParser::DataType::VARIANT;
+ id_type.type_source = GDScriptParser::DataType::UNDETECTED;
+ identifier->parameter_source->set_datatype(id_type);
+ }
+ } break;
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: {
GDScriptParser::DataType id_type = identifier->variable_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = assigned_value_type;
- id_type.type_source = GDScriptParser::DataType::INFERRED;
- id_type.is_constant = false;
+ id_type.kind = GDScriptParser::DataType::VARIANT;
+ id_type.type_source = GDScriptParser::DataType::UNDETECTED;
identifier->variable_source->set_datatype(id_type);
}
} break;
case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: {
GDScriptParser::DataType id_type = identifier->bind_source->get_datatype();
if (!id_type.is_hard_type()) {
- id_type = assigned_value_type;
- id_type.type_source = GDScriptParser::DataType::INFERRED;
- id_type.is_constant = false;
+ id_type.kind = GDScriptParser::DataType::VARIANT;
+ id_type.type_source = GDScriptParser::DataType::UNDETECTED;
identifier->variable_source->set_datatype(id_type);
}
} break;
@@ -2223,10 +2362,10 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool is_awa
if (get_function_signature(p_call, base_type, p_call->function_name, return_type, par_types, default_arg_count, is_static, is_vararg)) {
// If the function require typed arrays we must make literals be typed.
- for (Map<int, GDScriptParser::ArrayNode *>::Element *E = arrays.front(); E; E = E->next()) {
- int index = E->key();
+ for (const KeyValue<int, GDScriptParser::ArrayNode *> &E : arrays) {
+ int index = E.key;
if (index < par_types.size() && par_types[index].has_container_element_type()) {
- update_array_literal_element_type(par_types[index], E->get());
+ update_array_literal_element_type(par_types[index], E.value);
}
}
validate_call_arg(par_types, default_arg_count, is_vararg, p_call);
@@ -2409,13 +2548,15 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->is_constant = true;
p_identifier->reduced_value = result;
p_identifier->set_datatype(type_from_variant(result, p_identifier));
- } else {
+ } else if (base.is_hard_type()) {
push_error(vformat(R"(Cannot find constant "%s" on type "%s".)", name, base.to_string()), p_identifier);
}
} else {
switch (base.builtin_type) {
case Variant::NIL: {
- push_error(vformat(R"(Invalid get index "%s" on base Nil)", name), p_identifier);
+ if (base.is_hard_type()) {
+ push_error(vformat(R"(Invalid get index "%s" on base Nil)", name), p_identifier);
+ }
return;
}
case Variant::DICTIONARY: {
@@ -2436,7 +2577,9 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
return;
}
}
- push_error(vformat(R"(Cannot find property "%s" on base "%s".)", name, base.to_string()), p_identifier);
+ if (base.is_hard_type()) {
+ push_error(vformat(R"(Cannot find property "%s" on base "%s".)", name, base.to_string()), p_identifier);
+ }
}
}
}
@@ -2457,7 +2600,10 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
result.enum_type = name;
p_identifier->set_datatype(result);
} else {
- push_error(vformat(R"(Cannot find value "%s" in "%s".)", name, base.to_string()), p_identifier);
+ // Consider as a Dictionary
+ GDScriptParser::DataType dummy;
+ dummy.kind = GDScriptParser::DataType::VARIANT;
+ p_identifier->set_datatype(dummy);
}
} else {
push_error(R"(Cannot get property from enum value.)", p_identifier);
@@ -2516,14 +2662,29 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
while (outer != nullptr) {
if (outer->has_member(name)) {
const GDScriptParser::ClassNode::Member &member = outer->get_member(name);
- if (member.type == GDScriptParser::ClassNode::Member::CONSTANT) {
- // TODO: Make sure loops won't cause problem. And make special error message for those.
- // For out-of-order resolution:
- reduce_expression(member.constant->initializer);
- p_identifier->set_datatype(member.get_datatype());
- p_identifier->is_constant = true;
- p_identifier->reduced_value = member.constant->initializer->reduced_value;
- return;
+ switch (member.type) {
+ case GDScriptParser::ClassNode::Member::CONSTANT: {
+ // TODO: Make sure loops won't cause problem. And make special error message for those.
+ // For out-of-order resolution:
+ reduce_expression(member.constant->initializer);
+ p_identifier->set_datatype(member.get_datatype());
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = member.constant->initializer->reduced_value;
+ return;
+ } break;
+ case GDScriptParser::ClassNode::Member::ENUM_VALUE: {
+ p_identifier->set_datatype(member.get_datatype());
+ p_identifier->is_constant = true;
+ p_identifier->reduced_value = member.enum_value.value;
+ return;
+ } break;
+ case GDScriptParser::ClassNode::Member::ENUM: {
+ p_identifier->set_datatype(member.get_datatype());
+ p_identifier->is_constant = false;
+ return;
+ } break;
+ default:
+ break;
}
}
outer = outer->outer;
@@ -2536,10 +2697,13 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
const StringName &native = base.native_type;
if (class_exists(native)) {
- PropertyInfo prop_info;
MethodInfo method_info;
- if (ClassDB::get_property_info(native, name, &prop_info)) {
- p_identifier->set_datatype(type_from_property(prop_info));
+ if (ClassDB::has_property(native, name)) {
+ StringName getter_name = ClassDB::get_property_getter(native, name);
+ MethodBind *getter = ClassDB::get_method(native, getter_name);
+ if (getter != nullptr) {
+ p_identifier->set_datatype(type_from_property(getter->get_return_info()));
+ }
return;
}
if (ClassDB::get_method_info(native, name, &method_info)) {
@@ -2837,6 +3001,9 @@ void GDScriptAnalyzer::reduce_self(GDScriptParser::SelfNode *p_self) {
}
void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscript) {
+ if (p_subscript->base == nullptr) {
+ return;
+ }
if (p_subscript->base->type == GDScriptParser::Node::IDENTIFIER) {
reduce_identifier(static_cast<GDScriptParser::IdentifierNode *>(p_subscript->base), true);
} else {
@@ -2864,7 +3031,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
} else {
GDScriptParser::DataType base_type = p_subscript->base->get_datatype();
- if (base_type.is_variant()) {
+ if (base_type.is_variant() || !base_type.is_hard_type()) {
result_type.kind = GDScriptParser::DataType::VARIANT;
mark_node_unsafe(p_subscript);
} else {
@@ -2987,6 +3154,9 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
result_type.kind = GDScriptParser::DataType::BUILTIN;
result_type.type_source = base_type.is_hard_type() ? GDScriptParser::DataType::ANNOTATED_INFERRED : GDScriptParser::DataType::INFERRED;
+ if (base_type.kind != GDScriptParser::DataType::BUILTIN) {
+ base_type.builtin_type = Variant::OBJECT;
+ }
switch (base_type.builtin_type) {
// Can't index at all.
case Variant::RID:
@@ -3047,6 +3217,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
case Variant::PLANE:
case Variant::COLOR:
case Variant::DICTIONARY:
+ case Variant::OBJECT:
result_type.kind = GDScriptParser::DataType::VARIANT;
result_type.type_source = GDScriptParser::DataType::UNDETECTED;
break;
@@ -3061,7 +3232,6 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
}
break;
// Here for completeness.
- case Variant::OBJECT:
case Variant::VARIANT_MAX:
break;
}
@@ -3228,7 +3398,13 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
current = current->_owner;
}
- Ref<GDScriptParserRef> ref = get_parser_for(current->path);
+ Ref<GDScriptParserRef> ref = get_parser_for(current->get_path());
+ if (ref.is_null()) {
+ push_error("Could not find script in path.", p_source);
+ GDScriptParser::DataType error_type;
+ error_type.kind = GDScriptParser::DataType::VARIANT;
+ return error_type;
+ }
ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED);
GDScriptParser::ClassNode *found = ref->get_parser()->head;
@@ -3612,6 +3788,11 @@ bool GDScriptAnalyzer::is_type_compatible(const GDScriptParser::DataType &p_targ
if (p_source.kind == GDScriptParser::DataType::BUILTIN && p_source.builtin_type == Variant::INT) {
return true;
}
+ if (p_source.kind == GDScriptParser::DataType::ENUM) {
+ if (p_source.native_type == p_target.native_type) {
+ return true;
+ }
+ }
if (p_source.kind == GDScriptParser::DataType::ENUM_VALUE) {
if (p_source.native_type == p_target.native_type && p_target.enum_values.has(p_source.enum_type)) {
return true;
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index bed67b55f0..6a7e4278d2 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -209,8 +209,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
if (name_map.size()) {
function->global_names.resize(name_map.size());
function->_global_names_ptr = &function->global_names[0];
- for (Map<StringName, int>::Element *E = name_map.front(); E; E = E->next()) {
- function->global_names.write[E->get()] = E->key();
+ for (const KeyValue<StringName, int> &E : name_map) {
+ function->global_names.write[E.value] = E.key;
}
function->_global_names_count = function->global_names.size();
@@ -241,8 +241,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->operator_funcs.resize(operator_func_map.size());
function->_operator_funcs_count = function->operator_funcs.size();
function->_operator_funcs_ptr = function->operator_funcs.ptr();
- for (const Map<Variant::ValidatedOperatorEvaluator, int>::Element *E = operator_func_map.front(); E; E = E->next()) {
- function->operator_funcs.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedOperatorEvaluator, int> &E : operator_func_map) {
+ function->operator_funcs.write[E.value] = E.key;
}
} else {
function->_operator_funcs_count = 0;
@@ -253,8 +253,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->setters.resize(setters_map.size());
function->_setters_count = function->setters.size();
function->_setters_ptr = function->setters.ptr();
- for (const Map<Variant::ValidatedSetter, int>::Element *E = setters_map.front(); E; E = E->next()) {
- function->setters.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedSetter, int> &E : setters_map) {
+ function->setters.write[E.value] = E.key;
}
} else {
function->_setters_count = 0;
@@ -265,8 +265,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->getters.resize(getters_map.size());
function->_getters_count = function->getters.size();
function->_getters_ptr = function->getters.ptr();
- for (const Map<Variant::ValidatedGetter, int>::Element *E = getters_map.front(); E; E = E->next()) {
- function->getters.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedGetter, int> &E : getters_map) {
+ function->getters.write[E.value] = E.key;
}
} else {
function->_getters_count = 0;
@@ -277,8 +277,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->keyed_setters.resize(keyed_setters_map.size());
function->_keyed_setters_count = function->keyed_setters.size();
function->_keyed_setters_ptr = function->keyed_setters.ptr();
- for (const Map<Variant::ValidatedKeyedSetter, int>::Element *E = keyed_setters_map.front(); E; E = E->next()) {
- function->keyed_setters.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedKeyedSetter, int> &E : keyed_setters_map) {
+ function->keyed_setters.write[E.value] = E.key;
}
} else {
function->_keyed_setters_count = 0;
@@ -289,8 +289,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->keyed_getters.resize(keyed_getters_map.size());
function->_keyed_getters_count = function->keyed_getters.size();
function->_keyed_getters_ptr = function->keyed_getters.ptr();
- for (const Map<Variant::ValidatedKeyedGetter, int>::Element *E = keyed_getters_map.front(); E; E = E->next()) {
- function->keyed_getters.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedKeyedGetter, int> &E : keyed_getters_map) {
+ function->keyed_getters.write[E.value] = E.key;
}
} else {
function->_keyed_getters_count = 0;
@@ -301,8 +301,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->indexed_setters.resize(indexed_setters_map.size());
function->_indexed_setters_count = function->indexed_setters.size();
function->_indexed_setters_ptr = function->indexed_setters.ptr();
- for (const Map<Variant::ValidatedIndexedSetter, int>::Element *E = indexed_setters_map.front(); E; E = E->next()) {
- function->indexed_setters.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedIndexedSetter, int> &E : indexed_setters_map) {
+ function->indexed_setters.write[E.value] = E.key;
}
} else {
function->_indexed_setters_count = 0;
@@ -313,8 +313,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->indexed_getters.resize(indexed_getters_map.size());
function->_indexed_getters_count = function->indexed_getters.size();
function->_indexed_getters_ptr = function->indexed_getters.ptr();
- for (const Map<Variant::ValidatedIndexedGetter, int>::Element *E = indexed_getters_map.front(); E; E = E->next()) {
- function->indexed_getters.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedIndexedGetter, int> &E : indexed_getters_map) {
+ function->indexed_getters.write[E.value] = E.key;
}
} else {
function->_indexed_getters_count = 0;
@@ -325,8 +325,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->builtin_methods.resize(builtin_method_map.size());
function->_builtin_methods_ptr = function->builtin_methods.ptr();
function->_builtin_methods_count = builtin_method_map.size();
- for (const Map<Variant::ValidatedBuiltInMethod, int>::Element *E = builtin_method_map.front(); E; E = E->next()) {
- function->builtin_methods.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedBuiltInMethod, int> &E : builtin_method_map) {
+ function->builtin_methods.write[E.value] = E.key;
}
} else {
function->_builtin_methods_ptr = nullptr;
@@ -337,8 +337,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->constructors.resize(constructors_map.size());
function->_constructors_ptr = function->constructors.ptr();
function->_constructors_count = constructors_map.size();
- for (const Map<Variant::ValidatedConstructor, int>::Element *E = constructors_map.front(); E; E = E->next()) {
- function->constructors.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedConstructor, int> &E : constructors_map) {
+ function->constructors.write[E.value] = E.key;
}
} else {
function->_constructors_ptr = nullptr;
@@ -349,8 +349,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->utilities.resize(utilities_map.size());
function->_utilities_ptr = function->utilities.ptr();
function->_utilities_count = utilities_map.size();
- for (const Map<Variant::ValidatedUtilityFunction, int>::Element *E = utilities_map.front(); E; E = E->next()) {
- function->utilities.write[E->get()] = E->key();
+ for (const KeyValue<Variant::ValidatedUtilityFunction, int> &E : utilities_map) {
+ function->utilities.write[E.value] = E.key;
}
} else {
function->_utilities_ptr = nullptr;
@@ -361,8 +361,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->gds_utilities.resize(gds_utilities_map.size());
function->_gds_utilities_ptr = function->gds_utilities.ptr();
function->_gds_utilities_count = gds_utilities_map.size();
- for (const Map<GDScriptUtilityFunctions::FunctionPtr, int>::Element *E = gds_utilities_map.front(); E; E = E->next()) {
- function->gds_utilities.write[E->get()] = E->key();
+ for (const KeyValue<GDScriptUtilityFunctions::FunctionPtr, int> &E : gds_utilities_map) {
+ function->gds_utilities.write[E.value] = E.key;
}
} else {
function->_gds_utilities_ptr = nullptr;
@@ -373,8 +373,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->methods.resize(method_bind_map.size());
function->_methods_ptr = function->methods.ptrw();
function->_methods_count = method_bind_map.size();
- for (const Map<MethodBind *, int>::Element *E = method_bind_map.front(); E; E = E->next()) {
- function->methods.write[E->get()] = E->key();
+ for (const KeyValue<MethodBind *, int> &E : method_bind_map) {
+ function->methods.write[E.value] = E.key;
}
} else {
function->_methods_ptr = nullptr;
@@ -385,8 +385,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->lambdas.resize(lambdas_map.size());
function->_lambdas_ptr = function->lambdas.ptrw();
function->_lambdas_count = lambdas_map.size();
- for (const Map<GDScriptFunction *, int>::Element *E = lambdas_map.front(); E; E = E->next()) {
- function->lambdas.write[E->get()] = E->key();
+ for (const KeyValue<GDScriptFunction *, int> &E : lambdas_map) {
+ function->lambdas.write[E.value] = E.key;
}
} else {
function->_lambdas_ptr = nullptr;
@@ -692,7 +692,8 @@ void GDScriptByteCodeGenerator::write_end_ternary() {
void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) {
if (HAS_BUILTIN_TYPE(p_target)) {
- if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type)) {
+ if (IS_BUILTIN_TYPE(p_index, Variant::INT) && Variant::get_member_validated_indexed_setter(p_target.type.builtin_type) &&
+ IS_BUILTIN_TYPE(p_source, Variant::get_indexed_element_type(p_target.type.builtin_type))) {
// Use indexed setter instead.
Variant::ValidatedIndexedSetter setter = Variant::get_member_validated_indexed_setter(p_target.type.builtin_type);
append(GDScriptFunction::OPCODE_SET_INDEXED_VALIDATED, 3);
@@ -746,7 +747,8 @@ void GDScriptByteCodeGenerator::write_get(const Address &p_target, const Address
}
void GDScriptByteCodeGenerator::write_set_named(const Address &p_target, const StringName &p_name, const Address &p_source) {
- if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name)) {
+ if (HAS_BUILTIN_TYPE(p_target) && Variant::get_member_validated_setter(p_target.type.builtin_type, p_name) &&
+ IS_BUILTIN_TYPE(p_source, Variant::get_member_type(p_target.type.builtin_type, p_name))) {
Variant::ValidatedSetter setter = Variant::get_member_validated_setter(p_target.type.builtin_type, p_name);
append(GDScriptFunction::OPCODE_SET_NAMED_VALIDATED, 2);
append(p_target);
@@ -864,6 +866,12 @@ void GDScriptByteCodeGenerator::write_assign_default_parameter(const Address &p_
function->default_arguments.push_back(opcodes.size());
}
+void GDScriptByteCodeGenerator::write_store_global(const Address &p_dst, int p_global_index) {
+ append(GDScriptFunction::OPCODE_STORE_GLOBAL, 1);
+ append(p_dst);
+ append(p_global_index);
+}
+
void GDScriptByteCodeGenerator::write_store_named_global(const Address &p_dst, const StringName &p_global) {
append(GDScriptFunction::OPCODE_STORE_NAMED_GLOBAL, 1);
append(p_dst);
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index ce1a043b28..fbbf5802fd 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -153,12 +153,12 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
#endif
locals.resize(current_locals);
if (debug_stack) {
- for (Map<StringName, int>::Element *E = block_identifiers.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, int> &E : block_identifiers) {
GDScriptFunction::StackDebug sd;
sd.added = false;
- sd.identifier = E->key();
+ sd.identifier = E.key;
sd.line = current_line;
- sd.pos = E->get();
+ sd.pos = E.value;
stack_debug.push_back(sd);
}
block_identifiers = block_identifier_stack.back()->get();
@@ -454,6 +454,7 @@ public:
virtual void write_assign_true(const Address &p_target) override;
virtual void write_assign_false(const Address &p_target) override;
virtual void write_assign_default_parameter(const Address &p_dst, const Address &p_src) override;
+ virtual void write_store_global(const Address &p_dst, int p_global_index) override;
virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) override;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) override;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 07f50d14dc..bb0d9e9e9b 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -51,32 +51,34 @@ GDScriptParser *GDScriptParserRef::get_parser() const {
Error GDScriptParserRef::raise_status(Status p_new_status) {
ERR_FAIL_COND_V(parser == nullptr, ERR_INVALID_DATA);
- Error result = OK;
+ if (result != OK) {
+ return result;
+ }
while (p_new_status > status) {
switch (status) {
case EMPTY:
- result = parser->parse(GDScriptCache::get_source_code(path), path, false);
status = PARSED;
+ result = parser->parse(GDScriptCache::get_source_code(path), path, false);
break;
case PARSED: {
analyzer = memnew(GDScriptAnalyzer(parser));
- Error inheritance_result = analyzer->resolve_inheritance();
status = INHERITANCE_SOLVED;
+ Error inheritance_result = analyzer->resolve_inheritance();
if (result == OK) {
result = inheritance_result;
}
} break;
case INHERITANCE_SOLVED: {
- Error interface_result = analyzer->resolve_interface();
status = INTERFACE_SOLVED;
+ Error interface_result = analyzer->resolve_interface();
if (result == OK) {
result = interface_result;
}
} break;
case INTERFACE_SOLVED: {
- Error body_result = analyzer->resolve_body();
status = FULLY_SOLVED;
+ Error body_result = analyzer->resolve_body();
if (result == OK) {
result = body_result;
}
@@ -86,14 +88,6 @@ Error GDScriptParserRef::raise_status(Status p_new_status) {
}
}
if (result != OK) {
- if (parser != nullptr) {
- memdelete(parser);
- parser = nullptr;
- }
- if (analyzer != nullptr) {
- memdelete(analyzer);
- analyzer = nullptr;
- }
return result;
}
}
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 943638d29f..9fb661d031 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -54,6 +54,7 @@ private:
GDScriptParser *parser = nullptr;
GDScriptAnalyzer *analyzer = nullptr;
Status status = EMPTY;
+ Error result = OK;
String path;
friend class GDScriptCache;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index 7713d13bc8..e6ecc92d55 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -115,6 +115,7 @@ public:
virtual void write_assign_true(const Address &p_target) = 0;
virtual void write_assign_false(const Address &p_target) = 0;
virtual void write_assign_default_parameter(const Address &dst, const Address &src) = 0;
+ virtual void write_store_global(const Address &p_dst, int p_global_index) = 0;
virtual void write_store_named_global(const Address &p_dst, const StringName &p_global) = 0;
virtual void write_cast(const Address &p_target, const Address &p_source, const GDScriptDataType &p_type) = 0;
virtual void write_call(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 736f6eae79..1f9aad40af 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -35,6 +35,8 @@
#include "gdscript_cache.h"
#include "gdscript_utility_functions.h"
+#include "core/config/project_settings.h"
+
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
if (codegen.function_node && codegen.function_node->is_static) {
return false;
@@ -107,7 +109,9 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
// Locate class by constructing the path to it and following that path
GDScriptParser::ClassNode *class_type = p_datatype.class_type;
if (class_type) {
- if ((!main_script->path.is_empty() && class_type->fqcn.begins_with(main_script->path)) || (!main_script->name.is_empty() && class_type->fqcn.begins_with(main_script->name))) {
+ const bool is_inner_by_path = (!main_script->path.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->path);
+ const bool is_inner_by_name = (!main_script->name.is_empty()) && (class_type->fqcn.split("::")[0] == main_script->name);
+ if (is_inner_by_path || is_inner_by_name) {
// Local class.
List<StringName> names;
while (class_type->outer) {
@@ -316,10 +320,21 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
}
+ // Try globals.
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
- int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
- Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
- return codegen.add_constant(global); // TODO: Get type.
+ // If it's an autoload singleton, we postpone to load it at runtime.
+ // This is so one autoload doesn't try to load another before it's compiled.
+ OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+ if (autoloads.has(identifier) && autoloads[identifier].is_singleton) {
+ GDScriptCodeGenerator::Address global = codegen.add_temporary(_gdtype_from_datatype(in->get_datatype()));
+ int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
+ gen->write_store_global(global, idx);
+ return global;
+ } else {
+ int idx = GDScriptLanguage::get_singleton()->get_global_map()[identifier];
+ Variant global = GDScriptLanguage::get_singleton()->get_global_array()[idx];
+ return codegen.add_constant(global);
+ }
}
// Try global classes.
@@ -427,7 +442,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
break;
case GDScriptParser::DictionaryNode::LUA_TABLE:
// Lua-style: key is an identifier interpreted as StringName.
- StringName key = static_cast<const GDScriptParser::IdentifierNode *>(dn->elements[i].key)->name;
+ StringName key = dn->elements[i].key->reduced_value.operator StringName();
element = codegen.add_constant(key);
break;
}
@@ -951,7 +966,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Perform operator if any.
if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
- GDScriptCodeGenerator::Address value = codegen.add_temporary();
+ GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype()));
if (subscript->is_attribute) {
gen->write_get_named(value, name, prev_base);
} else {
@@ -1006,25 +1021,32 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
} else if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER && _is_class_member_property(codegen, static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name)) {
// Assignment to member property.
- GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
+ GDScriptCodeGenerator::Address assigned_value = _parse_expression(codegen, r_error, assignment->assigned_value);
if (r_error) {
return GDScriptCodeGenerator::Address();
}
- GDScriptCodeGenerator::Address assign_temp = assigned;
+
+ GDScriptCodeGenerator::Address to_assign = assigned_value;
+ bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
- if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ if (has_operation) {
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary();
GDScriptCodeGenerator::Address member = codegen.add_temporary();
gen->write_get_member(member, name);
- gen->write_binary_operator(assigned, assignment->variant_op, member, assigned);
- gen->pop_temporary();
+ gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value);
+ gen->pop_temporary(); // Pop member temp.
+ to_assign = op_result;
}
- gen->write_set_member(assigned, name);
+ gen->write_set_member(to_assign, name);
- if (assign_temp.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (to_assign.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop the assigned expression or the temp result if it has operation.
+ }
+ if (has_operation && assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop the assigned expression if not done before.
}
} else {
// Regular assignment.
@@ -1058,19 +1080,25 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
}
- GDScriptCodeGenerator::Address assigned = _parse_expression(codegen, r_error, assignment->assigned_value);
- GDScriptCodeGenerator::Address op_result;
+ GDScriptCodeGenerator::Address assigned_value = _parse_expression(codegen, r_error, assignment->assigned_value);
if (r_error) {
return GDScriptCodeGenerator::Address();
}
- if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ GDScriptCodeGenerator::Address to_assign;
+ bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
+ if (has_operation) {
// Perform operation.
- op_result = codegen.add_temporary();
- gen->write_binary_operator(op_result, assignment->variant_op, target, assigned);
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address og_value = _parse_expression(codegen, r_error, assignment->assignee);
+ gen->write_binary_operator(op_result, assignment->variant_op, og_value, assigned_value);
+ to_assign = op_result;
+
+ if (og_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary();
+ }
} else {
- op_result = assigned;
- assigned = GDScriptCodeGenerator::Address();
+ to_assign = assigned_value;
}
GDScriptDataType assign_type = _gdtype_from_datatype(assignment->assignee->get_datatype());
@@ -1078,25 +1106,25 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (has_setter && !is_in_setter) {
// Call setter.
Vector<GDScriptCodeGenerator::Address> args;
- args.push_back(op_result);
+ args.push_back(to_assign);
gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), setter_function, args);
} else {
// Just assign.
if (assignment->use_conversion_assign) {
- gen->write_assign_with_conversion(target, op_result);
+ gen->write_assign_with_conversion(target, to_assign);
} else {
- gen->write_assign(target, op_result);
+ gen->write_assign(target, to_assign);
}
}
- if (op_result.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (to_assign.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop assigned value or temp operation result.
}
- if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ if (has_operation && assigned_value.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
+ gen->pop_temporary(); // Pop assigned value if not done before.
}
if (target.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
- gen->pop_temporary();
+ gen->pop_temporary(); // Pop the target to assignment.
}
}
return GDScriptCodeGenerator::Address(); // Assignment does not return a value.
@@ -2061,77 +2089,18 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter) {
Error error = OK;
- CodeGen codegen;
- codegen.generator = memnew(GDScriptByteCodeGenerator);
-
- codegen.class_node = p_class;
- codegen.script = p_script;
-
- StringName func_name;
-
- if (p_is_setter) {
- func_name = "@" + p_variable->identifier->name + "_setter";
- } else {
- func_name = "@" + p_variable->identifier->name + "_getter";
- }
- codegen.function_name = func_name;
+ GDScriptParser::FunctionNode *function;
- GDScriptDataType return_type;
if (p_is_setter) {
- return_type.has_type = true;
- return_type.kind = GDScriptDataType::BUILTIN;
- return_type.builtin_type = Variant::NIL;
+ function = p_variable->setter;
} else {
- return_type = _gdtype_from_datatype(p_variable->get_datatype(), p_script);
+ function = p_variable->getter;
}
- codegen.generator->write_start(p_script, func_name, false, Multiplayer::RPCConfig(), return_type);
+ _parse_function(error, p_script, p_class, function);
- if (p_is_setter) {
- uint32_t par_addr = codegen.generator->add_parameter(p_variable->setter_parameter->name, false, _gdtype_from_datatype(p_variable->get_datatype()));
- codegen.parameters[p_variable->setter_parameter->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, _gdtype_from_datatype(p_variable->get_datatype()));
- }
-
- error = _parse_block(codegen, p_is_setter ? p_variable->setter : p_variable->getter);
- if (error) {
- memdelete(codegen.generator);
- return error;
- }
-
- GDScriptFunction *gd_function = codegen.generator->write_end();
-
- p_script->member_functions[func_name] = gd_function;
-
-#ifdef DEBUG_ENABLED
- if (EngineDebugger::is_active()) {
- String signature;
- //path
- if (p_script->get_path() != String()) {
- signature += p_script->get_path();
- }
- //loc
- signature += "::" + itos(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line);
-
- //function and class
-
- if (p_class->identifier) {
- signature += "::" + String(p_class->identifier->name) + "." + String(func_name);
- } else {
- signature += "::" + String(func_name);
- }
-
- codegen.generator->set_signature(signature);
- }
-#endif
- codegen.generator->set_initial_line(p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line);
-
-#ifdef TOOLS_ENABLED
- p_script->member_lines[func_name] = p_is_setter ? p_variable->setter->start_line : p_variable->getter->start_line;
-#endif
- memdelete(codegen.generator);
-
- return OK;
+ return error;
}
Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
@@ -2174,8 +2143,8 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->_base = nullptr;
p_script->members.clear();
p_script->constants.clear();
- for (Map<StringName, GDScriptFunction *>::Element *E = p_script->member_functions.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<StringName, GDScriptFunction *> &E : p_script->member_functions) {
+ memdelete(E.value);
}
p_script->member_functions.clear();
p_script->member_indices.clear();
@@ -2500,8 +2469,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
instance->owner = E->get();
//needed for hot reloading
- for (Map<StringName, GDScript::MemberInfo>::Element *F = p_script->member_indices.front(); F; F = F->next()) {
- instance->member_indices_cache[F->key()] = F->get().index;
+ for (const KeyValue<StringName, GDScript::MemberInfo> &F : p_script->member_indices) {
+ instance->member_indices_cache[F.key] = F.value.index;
}
instance->owner->set_script_instance(instance);
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 1acb9ceddc..9287df2ea0 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -914,6 +914,14 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5;
} break;
DISASSEMBLE_ITERATE_TYPES(DISASSEMBLE_ITERATE);
+ case OPCODE_STORE_GLOBAL: {
+ text += "store global ";
+ text += DADDR(1);
+ text += " = ";
+ text += String::num_int64(_code_ptr[ip + 2]);
+
+ incr += 3;
+ } break;
case OPCODE_STORE_NAMED_GLOBAL: {
text += "store named global ";
text += DADDR(1);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index f809a4dab8..71d2699c2e 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -173,8 +173,8 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li
get_function_names_recursively(cl, "", funcs);
- for (Map<int, String>::Element *E = funcs.front(); E; E = E->next()) {
- r_functions->push_back(E->get() + ":" + itos(E->key()));
+ for (const KeyValue<int, String> &E : funcs) {
+ r_functions->push_back(E.value + ":" + itos(E.key));
}
}
@@ -344,9 +344,9 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *
const Map<StringName, GDScript::MemberInfo> &mi = script->debug_get_member_indices();
- for (const Map<StringName, GDScript::MemberInfo>::Element *E = mi.front(); E; E = E->next()) {
- p_members->push_back(E->key());
- p_values->push_back(instance->debug_get_member_by_index(E->get().index));
+ for (const KeyValue<StringName, GDScript::MemberInfo> &E : mi) {
+ p_members->push_back(E.key);
+ p_values->push_back(instance->debug_get_member_by_index(E.value.index));
}
}
@@ -370,14 +370,14 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
List<Pair<String, Variant>> cinfo;
get_public_constants(&cinfo);
- for (const Map<StringName, int>::Element *E = name_idx.front(); E; E = E->next()) {
- if (ClassDB::class_exists(E->key()) || Engine::get_singleton()->has_singleton(E->key())) {
+ for (const KeyValue<StringName, int> &E : name_idx) {
+ if (ClassDB::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) {
continue;
}
bool is_script_constant = false;
for (List<Pair<String, Variant>>::Element *CE = cinfo.front(); CE; CE = CE->next()) {
- if (CE->get().first == E->key()) {
+ if (CE->get().first == E.key) {
is_script_constant = true;
break;
}
@@ -386,7 +386,7 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
continue;
}
- const Variant &var = globals[E->value()];
+ const Variant &var = globals[E.value];
if (Object *obj = var) {
if (Object::cast_to<GDScriptNativeClass>(obj)) {
continue;
@@ -395,7 +395,7 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
bool skip = false;
for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
- if (E->key() == CoreConstants::get_global_constant_name(i)) {
+ if (E.key == CoreConstants::get_global_constant_name(i)) {
skip = true;
break;
}
@@ -404,7 +404,7 @@ void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant>
continue;
}
- p_globals->push_back(E->key());
+ p_globals->push_back(E.key);
p_values->push_back(var);
}
}
@@ -637,7 +637,7 @@ static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String
}
static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, Map<String, ScriptCodeCompletionOption> &r_result) {
- if (p_annotation->name == "@export_range" || p_annotation->name == "@export_exp_range") {
+ if (p_annotation->name == "@export_range") {
if (p_argument == 3 || p_argument == 4) {
// Slider hint.
ScriptCodeCompletionOption slider1("or_greater", ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
@@ -781,6 +781,9 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions) {
continue;
}
+ if (r_result.has(member.constant->identifier->name)) {
+ continue;
+ }
option = ScriptCodeCompletionOption(member.constant->identifier->name, ScriptCodeCompletionOption::KIND_CONSTANT);
if (member.constant->initializer) {
option.default_value = member.constant->initializer->reduced_value;
@@ -872,8 +875,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
Map<StringName, Variant> constants;
scr->get_constants(&constants);
- for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) {
- ScriptCodeCompletionOption option(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ for (const KeyValue<StringName, Variant> &E : constants) {
+ ScriptCodeCompletionOption option(E.key.operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
r_result.insert(option.display, option);
}
@@ -1086,6 +1089,15 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
kwa++;
}
+ List<StringName> utility_func_names;
+ Variant::get_utility_function_list(&utility_func_names);
+
+ for (List<StringName>::Element *E = utility_func_names.front(); E; E = E->next()) {
+ ScriptCodeCompletionOption option(E->get(), ScriptCodeCompletionOption::KIND_FUNCTION);
+ option.insert_text += "(";
+ r_result.insert(option.display, option);
+ }
+
OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
if (!E.value().is_singleton) {
@@ -1096,12 +1108,12 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
}
// Native classes and global constants.
- for (const Map<StringName, int>::Element *E = GDScriptLanguage::get_singleton()->get_global_map().front(); E; E = E->next()) {
+ for (const KeyValue<StringName, int> &E : GDScriptLanguage::get_singleton()->get_global_map()) {
ScriptCodeCompletionOption option;
- if (ClassDB::class_exists(E->key()) || Engine::get_singleton()->has_singleton(E->key())) {
- option = ScriptCodeCompletionOption(E->key().operator String(), ScriptCodeCompletionOption::KIND_CLASS);
+ if (ClassDB::class_exists(E.key) || Engine::get_singleton()->has_singleton(E.key)) {
+ option = ScriptCodeCompletionOption(E.key.operator String(), ScriptCodeCompletionOption::KIND_CLASS);
} else {
- option = ScriptCodeCompletionOption(E->key().operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
+ option = ScriptCodeCompletionOption(E.key.operator String(), ScriptCodeCompletionOption::KIND_CONSTANT);
}
r_result.insert(option.display, option);
}
@@ -1733,7 +1745,7 @@ static bool _guess_identifier_type(GDScriptParser::CompletionContext &p_context,
}
}
- if (is_function_parameter && p_context.current_function && p_context.current_class) {
+ if (is_function_parameter && p_context.current_function && p_context.current_function->source_lambda == nullptr && p_context.current_class) {
// Check if it's override of native function, then we can assume the type from the signature.
GDScriptParser::DataType base_type = p_context.current_class->base_type;
while (base_type.is_set()) {
@@ -2219,8 +2231,11 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
if (obj) {
List<String> options;
obj->get_argument_options(p_method, p_argidx, &options);
- for (const String &F : options) {
- ScriptCodeCompletionOption option(F, ScriptCodeCompletionOption::KIND_FUNCTION);
+ for (String &opt : options) {
+ if (opt.is_quoted()) {
+ opt = opt.unquote().quote(quote_style); // Handle user preference.
+ }
+ ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_FUNCTION);
r_result.insert(option.display, option);
}
}
@@ -2319,7 +2334,11 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
GDScriptCompletionIdentifier connect_base;
- if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
+ if (Variant::has_utility_function(call->function_name)) {
+ MethodInfo info = Variant::get_utility_function_info(call->function_name);
+ r_arghint = _make_arguments_hint(info, p_argidx);
+ return;
+ } else if (GDScriptUtilityFunctions::function_exists(call->function_name)) {
MethodInfo info = GDScriptUtilityFunctions::get_function_info(call->function_name);
r_arghint = _make_arguments_hint(info, p_argidx);
return;
@@ -2640,23 +2659,26 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
} break;
case GDScriptParser::COMPLETION_GET_NODE: {
+ // Handles the `$Node/Path` or `$"Some NodePath"` syntax specifically.
if (p_owner) {
List<String> opts;
p_owner->get_argument_options("get_node", 0, &opts);
for (const String &E : opts) {
+ r_forced = true;
String opt = E.strip_edges();
if (opt.is_quoted()) {
- r_forced = true;
- String idopt = opt.unquote();
- if (idopt.replace("/", "_").is_valid_identifier()) {
- ScriptCodeCompletionOption option(idopt, ScriptCodeCompletionOption::KIND_NODE_PATH);
- options.insert(option.display, option);
- } else {
- ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH);
- options.insert(option.display, option);
- }
+ // Remove quotes so that we can handle user preferred quote style,
+ // or handle NodePaths which are valid identifiers and don't need quotes.
+ opt = opt.unquote();
+ }
+ // The path needs quotes if it's not a valid identifier (with an exception
+ // for "/" as path separator, which also doesn't require quotes).
+ if (!opt.replace("/", "_").is_valid_identifier()) {
+ opt = opt.quote(quote_style); // Handle user preference.
}
+ ScriptCodeCompletionOption option(opt, ScriptCodeCompletionOption::KIND_NODE_PATH);
+ options.insert(option.display, option);
}
// Get autoloads.
@@ -2677,8 +2699,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
} break;
}
- for (Map<String, ScriptCodeCompletionOption>::Element *E = options.front(); E; E = E->next()) {
- r_options->push_back(E->get());
+ for (const KeyValue<String, ScriptCodeCompletionOption> &E : options) {
+ r_options->push_back(E.value);
}
return OK;
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index 876c508689..a3f0c7dfef 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -120,11 +120,11 @@ void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<String
}
List<_GDFKCS> stackpositions;
- for (Map<StringName, _GDFKC>::Element *E = sdmap.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, _GDFKC> &E : sdmap) {
_GDFKCS spp;
- spp.id = E->key();
- spp.order = E->get().order;
- spp.pos = E->get().pos.back()->get();
+ spp.id = E.key;
+ spp.order = E.value.order;
+ spp.pos = E.value.pos.back()->get();
stackpositions.push_back(spp);
}
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index b21cb47910..9d076a8e4c 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -348,6 +348,7 @@ public:
OPCODE_ITERATE_PACKED_VECTOR3_ARRAY,
OPCODE_ITERATE_PACKED_COLOR_ARRAY,
OPCODE_ITERATE_OBJECT,
+ OPCODE_STORE_GLOBAL,
OPCODE_STORE_NAMED_GLOBAL,
OPCODE_TYPE_ADJUST_BOOL,
OPCODE_TYPE_ADJUST_INT,
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 64a393f90c..40be5cb324 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -337,12 +337,29 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
tokenizer.set_cursor_position(cursor_line, cursor_column);
script_path = p_script_path;
current = tokenizer.scan();
- // Avoid error as the first token.
- while (current.type == GDScriptTokenizer::Token::ERROR) {
- push_error(current.literal);
+ // Avoid error or newline as the first token.
+ // The latter can mess with the parser when opening files filled exclusively with comments and newlines.
+ while (current.type == GDScriptTokenizer::Token::ERROR || current.type == GDScriptTokenizer::Token::NEWLINE) {
+ if (current.type == GDScriptTokenizer::Token::ERROR) {
+ push_error(current.literal);
+ }
current = tokenizer.scan();
}
+#ifdef DEBUG_ENABLED
+ // Warn about parsing an empty script file:
+ if (current.type == GDScriptTokenizer::Token::TK_EOF) {
+ // Create a dummy Node for the warning, pointing to the very beginning of the file
+ Node *nd = alloc_node<PassNode>();
+ nd->start_line = 1;
+ nd->start_column = 0;
+ nd->end_line = 1;
+ nd->leftmost_column = 0;
+ nd->rightmost_column = 0;
+ push_warning(nd, GDScriptWarning::EMPTY_FILE);
+ }
+#endif
+
push_multiline(false); // Keep one for the whole parsing.
parse_program();
pop_multiline();
@@ -562,12 +579,12 @@ void GDScriptParser::parse_program() {
}
}
- parse_class_body();
+ parse_class_body(true);
#ifdef TOOLS_ENABLED
- for (Map<int, GDScriptTokenizer::CommentData>::Element *E = tokenizer.get_comments().front(); E; E = E->next()) {
- if (E->get().new_line && E->get().comment.begins_with("##")) {
- class_doc_line = MIN(class_doc_line, E->key());
+ for (const KeyValue<int, GDScriptTokenizer::CommentData> &E : tokenizer.get_comments()) {
+ if (E.value.new_line && E.value.comment.begins_with("##")) {
+ class_doc_line = MIN(class_doc_line, E.key);
}
}
if (has_comment(class_doc_line)) {
@@ -598,9 +615,10 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class() {
}
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after class declaration.)");
- consume(GDScriptTokenizer::Token::NEWLINE, R"(Expected newline after class declaration.)");
- if (!consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block after class declaration.)")) {
+ bool multiline = match(GDScriptTokenizer::Token::NEWLINE);
+
+ if (multiline && !consume(GDScriptTokenizer::Token::INDENT, R"(Expected indented block after class declaration.)")) {
current_class = previous_class;
return n_class;
}
@@ -613,9 +631,11 @@ GDScriptParser::ClassNode *GDScriptParser::parse_class() {
end_statement("superclass");
}
- parse_class_body();
+ parse_class_body(multiline);
- consume(GDScriptTokenizer::Token::DEDENT, R"(Missing unindent at the end of the class body.)");
+ if (multiline) {
+ consume(GDScriptTokenizer::Token::DEDENT, R"(Missing unindent at the end of the class body.)");
+ }
current_class = previous_class;
return n_class;
@@ -730,7 +750,7 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
}
}
-void GDScriptParser::parse_class_body() {
+void GDScriptParser::parse_class_body(bool p_is_multiline) {
bool class_end = false;
while (!class_end && !is_at_end()) {
switch (current.type) {
@@ -776,6 +796,9 @@ void GDScriptParser::parse_class_body() {
if (panic_mode) {
synchronize();
}
+ if (!p_is_multiline) {
+ class_end = true;
+ }
}
}
@@ -924,7 +947,7 @@ GDScriptParser::VariableNode *GDScriptParser::parse_property(VariableNode *p_var
void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
switch (p_variable->property) {
- case VariableNode::PROP_INLINE:
+ case VariableNode::PROP_INLINE: {
consume(GDScriptTokenizer::Token::PARENTHESIS_OPEN, R"(Expected "(" after "set".)");
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected parameter name after "(".)")) {
p_variable->setter_parameter = parse_identifier();
@@ -932,9 +955,30 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected ")" after parameter name.)*");
consume(GDScriptTokenizer::Token::COLON, R"*(Expected ":" after ")".)*");
- p_variable->setter = parse_suite("setter definition");
- break;
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = "@" + p_variable->identifier->name + "_setter";
+
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->identifier = identifier;
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ ParameterNode *parameter = alloc_node<ParameterNode>();
+ parameter->identifier = p_variable->setter_parameter;
+
+ function->parameters_indices[parameter->identifier->name] = 0;
+ function->parameters.push_back(parameter);
+ SuiteNode *body = alloc_node<SuiteNode>();
+ body->add_local(parameter, function);
+
+ function->body = parse_suite("setter declaration", body);
+
+ p_variable->setter = function;
+ current_function = previous_function;
+ break;
+ }
case VariableNode::PROP_SETGET:
consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "set")");
make_completion_context(COMPLETION_PROPERTY_METHOD, p_variable);
@@ -949,11 +993,25 @@ void GDScriptParser::parse_property_setter(VariableNode *p_variable) {
void GDScriptParser::parse_property_getter(VariableNode *p_variable) {
switch (p_variable->property) {
- case VariableNode::PROP_INLINE:
+ case VariableNode::PROP_INLINE: {
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "get".)");
- p_variable->getter = parse_suite("getter definition");
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = "@" + p_variable->identifier->name + "_getter";
+
+ FunctionNode *function = alloc_node<FunctionNode>();
+ function->identifier = identifier;
+
+ FunctionNode *previous_function = current_function;
+ current_function = function;
+
+ SuiteNode *body = alloc_node<SuiteNode>();
+ function->body = parse_suite("getter declaration", body);
+
+ p_variable->getter = function;
+ current_function = previous_function;
break;
+ }
case VariableNode::PROP_SETGET:
consume(GDScriptTokenizer::Token::EQUAL, R"(Expected "=" after "get")");
make_completion_context(COMPLETION_PROPERTY_METHOD, p_variable);
@@ -1036,7 +1094,9 @@ GDScriptParser::SignalNode *GDScriptParser::parse_signal() {
SignalNode *signal = alloc_node<SignalNode>();
signal->identifier = parse_identifier();
- if (match(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {
+ if (check(GDScriptTokenizer::Token::PARENTHESIS_OPEN)) {
+ push_multiline(true);
+ advance();
do {
if (check(GDScriptTokenizer::Token::PARENTHESIS_CLOSE)) {
// Allow for trailing comma.
@@ -1059,6 +1119,7 @@ GDScriptParser::SignalNode *GDScriptParser::parse_signal() {
}
} while (match(GDScriptTokenizer::Token::COMMA) && !is_at_end());
+ pop_multiline();
consume(GDScriptTokenizer::Token::PARENTHESIS_CLOSE, R"*(Expected closing ")" after signal parameters.)*");
}
@@ -1341,6 +1402,9 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context,
int error_count = 0;
do {
+ if (!multiline && previous.type == GDScriptTokenizer::Token::SEMICOLON && check(GDScriptTokenizer::Token::NEWLINE)) {
+ break;
+ }
Node *statement = parse_statement();
if (statement == nullptr) {
if (error_count++ > 100) {
@@ -1381,7 +1445,7 @@ GDScriptParser::SuiteNode *GDScriptParser::parse_suite(const String &p_context,
break;
}
- } while (multiline && !check(GDScriptTokenizer::Token::DEDENT) && !lambda_ended && !is_at_end());
+ } while ((multiline || previous.type == GDScriptTokenizer::Token::SEMICOLON) && !check(GDScriptTokenizer::Token::DEDENT) && !lambda_ended && !is_at_end());
if (multiline) {
if (!lambda_ended) {
@@ -1591,6 +1655,10 @@ GDScriptParser::ForNode *GDScriptParser::parse_for() {
n_for->list = parse_expression(false);
+ if (!n_for->list) {
+ push_error(R"(Expected a list or range after "in".)");
+ }
+
consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "for" condition.)");
// Save break/continue state.
@@ -1682,6 +1750,7 @@ GDScriptParser::MatchNode *GDScriptParser::parse_match() {
while (!check(GDScriptTokenizer::Token::DEDENT) && !is_at_end()) {
MatchBranchNode *branch = parse_match_branch();
if (branch == nullptr) {
+ advance();
continue;
}
@@ -1745,7 +1814,9 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
push_error(R"(No pattern found for "match" branch.)");
}
- consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "match" patterns.)");
+ if (!consume(GDScriptTokenizer::Token::COLON, R"(Expected ":" after "match" patterns.)")) {
+ return nullptr;
+ }
// Save continue state.
bool could_continue = can_continue;
@@ -1778,15 +1849,6 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_
PatternNode *pattern = alloc_node<PatternNode>();
switch (current.type) {
- case GDScriptTokenizer::Token::LITERAL:
- advance();
- pattern->pattern_type = PatternNode::PT_LITERAL;
- pattern->literal = parse_literal();
- if (pattern->literal == nullptr) {
- // Error happened.
- return nullptr;
- }
- break;
case GDScriptTokenizer::Token::VAR: {
// Bind.
advance();
@@ -1849,44 +1911,44 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_
// Dictionary.
advance();
pattern->pattern_type = PatternNode::PT_DICTIONARY;
-
- if (!check(GDScriptTokenizer::Token::BRACE_CLOSE) && !is_at_end()) {
- do {
- if (match(GDScriptTokenizer::Token::PERIOD_PERIOD)) {
- // Rest.
+ do {
+ if (check(GDScriptTokenizer::Token::BRACE_CLOSE) || is_at_end()) {
+ break;
+ }
+ if (match(GDScriptTokenizer::Token::PERIOD_PERIOD)) {
+ // Rest.
+ if (pattern->rest_used) {
+ push_error(R"(The ".." pattern must be the last element in the pattern dictionary.)");
+ } else {
+ PatternNode *sub_pattern = alloc_node<PatternNode>();
+ sub_pattern->pattern_type = PatternNode::PT_REST;
+ pattern->dictionary.push_back({ nullptr, sub_pattern });
+ pattern->rest_used = true;
+ }
+ } else {
+ ExpressionNode *key = parse_expression(false);
+ if (key == nullptr) {
+ push_error(R"(Expected expression as key for dictionary pattern.)");
+ }
+ if (match(GDScriptTokenizer::Token::COLON)) {
+ // Value pattern.
+ PatternNode *sub_pattern = parse_match_pattern(p_root_pattern != nullptr ? p_root_pattern : pattern);
+ if (sub_pattern == nullptr) {
+ continue;
+ }
if (pattern->rest_used) {
push_error(R"(The ".." pattern must be the last element in the pattern dictionary.)");
+ } else if (sub_pattern->pattern_type == PatternNode::PT_REST) {
+ push_error(R"(The ".." pattern cannot be used as a value.)");
} else {
- PatternNode *sub_pattern = alloc_node<PatternNode>();
- sub_pattern->pattern_type = PatternNode::PT_REST;
- pattern->dictionary.push_back({ nullptr, sub_pattern });
- pattern->rest_used = true;
+ pattern->dictionary.push_back({ key, sub_pattern });
}
} else {
- ExpressionNode *key = parse_expression(false);
- if (key == nullptr) {
- push_error(R"(Expected expression as key for dictionary pattern.)");
- }
- if (match(GDScriptTokenizer::Token::COLON)) {
- // Value pattern.
- PatternNode *sub_pattern = parse_match_pattern(p_root_pattern != nullptr ? p_root_pattern : pattern);
- if (sub_pattern == nullptr) {
- continue;
- }
- if (pattern->rest_used) {
- push_error(R"(The ".." pattern must be the last element in the pattern dictionary.)");
- } else if (sub_pattern->pattern_type == PatternNode::PT_REST) {
- push_error(R"(The ".." pattern cannot be used as a value.)");
- } else {
- pattern->dictionary.push_back({ key, sub_pattern });
- }
- } else {
- // Key match only.
- pattern->dictionary.push_back({ key, nullptr });
- }
+ // Key match only.
+ pattern->dictionary.push_back({ key, nullptr });
}
- } while (match(GDScriptTokenizer::Token::COMMA));
- }
+ }
+ } while (match(GDScriptTokenizer::Token::COMMA));
consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected "}" to close the dictionary pattern.)");
break;
}
@@ -1895,8 +1957,13 @@ GDScriptParser::PatternNode *GDScriptParser::parse_match_pattern(PatternNode *p_
ExpressionNode *expression = parse_expression(false);
if (expression == nullptr) {
push_error(R"(Expected expression for match pattern.)");
+ return nullptr;
} else {
- pattern->pattern_type = PatternNode::PT_EXPRESSION;
+ if (expression->type == GDScriptParser::Node::LITERAL) {
+ pattern->pattern_type = PatternNode::PT_LITERAL;
+ } else {
+ pattern->pattern_type = PatternNode::PT_EXPRESSION;
+ }
pattern->expression = expression;
}
break;
@@ -2107,22 +2174,34 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_unary_operator(ExpressionN
operation->operation = UnaryOpNode::OP_NEGATIVE;
operation->variant_op = Variant::OP_NEGATE;
operation->operand = parse_precedence(PREC_SIGN, false);
+ if (operation->operand == nullptr) {
+ push_error(R"(Expected expression after "-" operator.)");
+ }
break;
case GDScriptTokenizer::Token::PLUS:
operation->operation = UnaryOpNode::OP_POSITIVE;
operation->variant_op = Variant::OP_POSITIVE;
operation->operand = parse_precedence(PREC_SIGN, false);
+ if (operation->operand == nullptr) {
+ push_error(R"(Expected expression after "+" operator.)");
+ }
break;
case GDScriptTokenizer::Token::TILDE:
operation->operation = UnaryOpNode::OP_COMPLEMENT;
operation->variant_op = Variant::OP_BIT_NEGATE;
operation->operand = parse_precedence(PREC_BIT_NOT, false);
+ if (operation->operand == nullptr) {
+ push_error(R"(Expected expression after "~" operator.)");
+ }
break;
case GDScriptTokenizer::Token::NOT:
case GDScriptTokenizer::Token::BANG:
operation->operation = UnaryOpNode::OP_LOGIC_NOT;
operation->variant_op = Variant::OP_NOT;
operation->operand = parse_precedence(PREC_LOGIC_NOT, false);
+ if (operation->operand == nullptr) {
+ push_error(vformat(R"(Expected expression after "%s" operator.)", op_type == GDScriptTokenizer::Token::NOT ? "not" : "!"));
+ }
break;
default:
return nullptr; // Unreachable.
@@ -2259,6 +2338,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_ternary_operator(Expressio
operation->false_expr = parse_precedence(PREC_TERNARY, false);
+ if (operation->false_expr == nullptr) {
+ push_error(R"(Expected expression after "else".)");
+ }
+
return operation;
}
@@ -2370,8 +2453,12 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode
}
#ifdef DEBUG_ENABLED
- if (has_operator && source_variable != nullptr && source_variable->assignments == 0) {
- push_warning(assignment, GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, source_variable->identifier->name);
+ if (source_variable != nullptr) {
+ if (has_operator && source_variable->assignments == 0) {
+ push_warning(assignment, GDScriptWarning::UNASSIGNED_VARIABLE_OP_ASSIGN, source_variable->identifier->name);
+ }
+
+ source_variable->assignments += 1;
}
#endif
@@ -2386,7 +2473,9 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_await(ExpressionNode *p_pr
}
await->to_await = element;
- current_function->is_coroutine = true;
+ if (current_function) { // Might be null in a getter or setter.
+ current_function->is_coroutine = true;
+ }
return await;
}
@@ -2450,8 +2539,13 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
switch (dictionary->style) {
case DictionaryNode::LUA_TABLE:
- if (key != nullptr && key->type != Node::IDENTIFIER) {
- push_error("Expected identifier as LUA-style dictionary key.");
+ if (key != nullptr && key->type != Node::IDENTIFIER && key->type != Node::LITERAL) {
+ push_error("Expected identifier or string as LUA-style dictionary key.");
+ advance();
+ break;
+ }
+ if (key != nullptr && key->type == Node::LITERAL && static_cast<LiteralNode *>(key)->value.get_type() != Variant::STRING) {
+ push_error("Expected identifier or string as LUA-style dictionary key.");
advance();
break;
}
@@ -2463,8 +2557,14 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_dictionary(ExpressionNode
push_error(R"(Expected "=" after dictionary key.)");
}
}
- key->is_constant = true;
- key->reduced_value = static_cast<IdentifierNode *>(key)->name;
+ if (key != nullptr) {
+ key->is_constant = true;
+ if (key->type == Node::IDENTIFIER) {
+ key->reduced_value = static_cast<IdentifierNode *>(key)->name;
+ } else if (key->type == Node::LITERAL) {
+ key->reduced_value = StringName(static_cast<LiteralNode *>(key)->value.operator String());
+ }
+ }
break;
case DictionaryNode::PYTHON_DICT:
if (!match(GDScriptTokenizer::Token::COLON)) {
@@ -2543,6 +2643,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_subscript(ExpressionNode *
subscript->base = p_previous_operand;
subscript->index = parse_expression(false);
+ if (subscript->index == nullptr) {
+ push_error(R"(Expected expression after "[".)");
+ }
+
pop_multiline();
consume(GDScriptTokenizer::Token::BRACKET_CLOSE, R"(Expected "]" after subscription index.)");
@@ -2757,6 +2861,11 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_lambda(ExpressionNode *p_p
return lambda;
}
+GDScriptParser::ExpressionNode *GDScriptParser::parse_yield(ExpressionNode *p_previous_operand, bool p_can_assign) {
+ push_error(R"("yield" was removed in Godot 4.0. Use "await" instead.)");
+ return nullptr;
+}
+
GDScriptParser::ExpressionNode *GDScriptParser::parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign) {
// Just for better error messages.
GDScriptTokenizer::Token::Type invalid = previous.type;
@@ -3113,7 +3222,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, nullptr, PREC_NONE }, // TRAIT,
{ nullptr, nullptr, PREC_NONE }, // VAR,
{ nullptr, nullptr, PREC_NONE }, // VOID,
- { nullptr, nullptr, PREC_NONE }, // YIELD,
+ { &GDScriptParser::parse_yield, nullptr, PREC_NONE }, // YIELD,
// Punctuation
{ &GDScriptParser::parse_array, &GDScriptParser::parse_subscript, PREC_SUBSCRIPT }, // BRACKET_OPEN,
{ nullptr, nullptr, PREC_NONE }, // BRACKET_CLOSE,
@@ -3349,7 +3458,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
String enum_hint_string;
for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) {
- enum_hint_string += E->key().operator String().camelcase_to_underscore(true).capitalize().xml_escape();
+ enum_hint_string += E->key().operator String().capitalize().xml_escape();
enum_hint_string += ":";
enum_hint_string += String::num_int64(E->get()).xml_escape();
@@ -3411,22 +3520,22 @@ bool GDScriptParser::network_annotations(const AnnotationNode *p_annotation, Nod
}
for (int i = last; i >= 0; i--) {
String mode = p_annotation->resolved_arguments[i].operator String();
- if (mode == "any") {
- rpc_config.rpc_mode = Multiplayer::RPC_MODE_ANY;
- } else if (mode == "auth") {
+ if (mode == "any_peer") {
+ rpc_config.rpc_mode = Multiplayer::RPC_MODE_ANY_PEER;
+ } else if (mode == "authority") {
rpc_config.rpc_mode = Multiplayer::RPC_MODE_AUTHORITY;
- } else if (mode == "sync") {
- rpc_config.sync = true;
- } else if (mode == "nosync") {
- rpc_config.sync = false;
+ } else if (mode == "call_local") {
+ rpc_config.call_local = true;
+ } else if (mode == "call_remote") {
+ rpc_config.call_local = false;
} else if (mode == "reliable") {
rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE;
} else if (mode == "unreliable") {
rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_UNRELIABLE;
- } else if (mode == "ordered") {
- rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_ORDERED;
+ } else if (mode == "unreliable_ordered") {
+ rpc_config.transfer_mode = Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED;
} else {
- push_error(R"(Invalid RPC argument. Must be one of: 'sync'/'nosync' (local calls), 'any'/'auth' (permission), 'reliable'/'unreliable'/'ordered' (transfer mode).)", p_annotation);
+ push_error(R"(Invalid RPC argument. Must be one of: 'call_local'/'call_remote' (local calls), 'any_peer'/'authority' (permission), 'reliable'/'unreliable'/'unreliable_ordered' (transfer mode).)", p_annotation);
}
}
}
@@ -3538,6 +3647,39 @@ String GDScriptParser::DataType::to_string() const {
ERR_FAIL_V_MSG("<unresolved type", "Kind set outside the enum range.");
}
+static Variant::Type _variant_type_to_typed_array_element_type(Variant::Type p_type) {
+ switch (p_type) {
+ case Variant::PACKED_BYTE_ARRAY:
+ case Variant::PACKED_INT32_ARRAY:
+ case Variant::PACKED_INT64_ARRAY:
+ return Variant::INT;
+ case Variant::PACKED_FLOAT32_ARRAY:
+ case Variant::PACKED_FLOAT64_ARRAY:
+ return Variant::FLOAT;
+ case Variant::PACKED_STRING_ARRAY:
+ return Variant::STRING;
+ case Variant::PACKED_VECTOR2_ARRAY:
+ return Variant::VECTOR2;
+ case Variant::PACKED_VECTOR3_ARRAY:
+ return Variant::VECTOR3;
+ case Variant::PACKED_COLOR_ARRAY:
+ return Variant::COLOR;
+ default:
+ return Variant::NIL;
+ }
+}
+
+bool GDScriptParser::DataType::is_typed_container_type() const {
+ return kind == GDScriptParser::DataType::BUILTIN && _variant_type_to_typed_array_element_type(builtin_type) != Variant::NIL;
+}
+
+GDScriptParser::DataType GDScriptParser::DataType::get_typed_container_type() const {
+ GDScriptParser::DataType type;
+ type.kind = GDScriptParser::DataType::BUILTIN;
+ type.builtin_type = _variant_type_to_typed_array_element_type(builtin_type);
+ return type;
+}
+
/*---------- PRETTY PRINT FOR DEBUG ----------*/
#ifdef DEBUG_ENABLED
@@ -4330,7 +4472,7 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) {
if (p_variable->property == VariableNode::PROP_INLINE) {
push_line(":");
increase_indent();
- print_suite(p_variable->getter);
+ print_suite(p_variable->getter->body);
decrease_indent();
} else {
push_line(" =");
@@ -4350,7 +4492,7 @@ void GDScriptParser::TreePrinter::print_variable(VariableNode *p_variable) {
}
push_line("):");
increase_indent();
- print_suite(p_variable->setter);
+ print_suite(p_variable->setter->body);
decrease_indent();
} else {
push_line(" =");
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 4902f0d4a6..af9b973ada 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -161,6 +161,10 @@ public:
container_element_type = nullptr;
}
+ bool is_typed_container_type() const;
+
+ GDScriptParser::DataType get_typed_container_type() const;
+
bool operator==(const DataType &p_other) const {
if (type_source == UNDETECTED || p_other.type_source == UNDETECTED) {
return true; // Can be consireded equal for parsing purposes.
@@ -1105,12 +1109,12 @@ public:
PropertyStyle property = PROP_NONE;
union {
- SuiteNode *setter = nullptr;
+ FunctionNode *setter = nullptr;
IdentifierNode *setter_pointer;
};
IdentifierNode *setter_parameter = nullptr;
union {
- SuiteNode *getter = nullptr;
+ FunctionNode *getter = nullptr;
IdentifierNode *getter_pointer;
};
@@ -1320,7 +1324,7 @@ private:
ClassNode *parse_class();
void parse_class_name();
void parse_extends();
- void parse_class_body();
+ void parse_class_body(bool p_is_multiline);
template <class T>
void parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind);
SignalNode *parse_signal();
@@ -1384,6 +1388,7 @@ private:
ExpressionNode *parse_attribute(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_subscript(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_lambda(ExpressionNode *p_previous_operand, bool p_can_assign);
+ ExpressionNode *parse_yield(ExpressionNode *p_previous_operand, bool p_can_assign);
ExpressionNode *parse_invalid_token(ExpressionNode *p_previous_operand, bool p_can_assign);
TypeNode *parse_type(bool p_allow_void = false);
#ifdef TOOLS_ENABLED
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 62531473c3..f1b0079536 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -317,9 +317,9 @@ struct GDScriptUtilityFunctionsDefinitions {
d["@subpath"] = cp;
d["@path"] = p->get_path();
- for (Map<StringName, GDScript::MemberInfo>::Element *E = base->member_indices.front(); E; E = E->next()) {
- if (!d.has(E->key())) {
- d[E->key()] = ins->members[E->get().index];
+ for (const KeyValue<StringName, GDScript::MemberInfo> &E : base->member_indices) {
+ if (!d.has(E.key)) {
+ d[E.key] = ins->members[E.value.index];
}
}
*r_ret = d;
@@ -396,9 +396,9 @@ struct GDScriptUtilityFunctionsDefinitions {
GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(*r_ret)->get_script_instance());
Ref<GDScript> gd_ref = ins->get_script();
- for (Map<StringName, GDScript::MemberInfo>::Element *E = gd_ref->member_indices.front(); E; E = E->next()) {
- if (d.has(E->key())) {
- ins->members.write[E->get().index] = d[E->key()];
+ for (KeyValue<StringName, GDScript::MemberInfo> &E : gd_ref->member_indices) {
+ if (d.has(E.key)) {
+ ins->members.write[E.value.index] = d[E.key];
}
}
}
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 882256b7e3..1bc7ae086f 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -88,9 +88,9 @@ static String _get_var_type(const Variant *p_var) {
Object *bobj = p_var->get_validated_object_with_check(was_freed);
if (!bobj) {
if (was_freed) {
- basestr = "null instance";
- } else {
basestr = "previously freed";
+ } else {
+ basestr = "null instance";
}
} else {
basestr = bobj->get_class();
@@ -322,6 +322,7 @@ void (*type_init_function_table[])(Variant *) = {
&&OPCODE_ITERATE_PACKED_VECTOR3_ARRAY, \
&&OPCODE_ITERATE_PACKED_COLOR_ARRAY, \
&&OPCODE_ITERATE_OBJECT, \
+ &&OPCODE_STORE_GLOBAL, \
&&OPCODE_STORE_NAMED_GLOBAL, \
&&OPCODE_TYPE_ADJUST_BOOL, \
&&OPCODE_TYPE_ADJUST_INT, \
@@ -530,8 +531,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
- for (const Map<int, Variant::Type>::Element *E = temporary_slots.front(); E; E = E->next()) {
- type_init_function_table[E->get()](&stack[E->key()]);
+ for (const KeyValue<int, Variant::Type> &E : temporary_slots) {
+ type_init_function_table[E.value](&stack[E.key]);
}
String err_text;
@@ -1231,6 +1232,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GD_ERR_BREAK(to_type < 0 || to_type >= Variant::VARIANT_MAX);
+#ifdef DEBUG_ENABLED
+ if (src->operator Object *() && !src->get_validated_object()) {
+ err_text = "Trying to cast a freed object.";
+ OPCODE_BREAK;
+ }
+#endif
+
Callable::CallError err;
Variant::construct(to_type, *dst, (const Variant **)&src, 1, err);
@@ -1255,6 +1263,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GD_ERR_BREAK(!nc);
#ifdef DEBUG_ENABLED
+ if (src->operator Object *() && !src->get_validated_object()) {
+ err_text = "Trying to cast a freed object.";
+ OPCODE_BREAK;
+ }
if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
err_text = "Invalid cast: can't convert a non-object value to an object type.";
OPCODE_BREAK;
@@ -1283,6 +1295,10 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GD_ERR_BREAK(!base_type);
#ifdef DEBUG_ENABLED
+ if (src->operator Object *() && !src->get_validated_object()) {
+ err_text = "Trying to cast a freed object.";
+ OPCODE_BREAK;
+ }
if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
err_text = "Trying to assign a non-object value to a variable of type '" + base_type->get_path().get_file() + "'.";
OPCODE_BREAK;
@@ -1703,6 +1719,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#define OPCODE_CALL_PTR(m_type) \
OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
CHECK_SPACE(3 + instr_arg_count); \
+ ip += instr_arg_count; \
int argc = _code_ptr[ip + 1]; \
GET_INSTRUCTION_ARG(base, argc); \
MethodBind *method = _methods_ptr[_code_ptr[ip + 2]]; \
@@ -2122,7 +2139,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
retvalue = gdfs;
- Error err = sig.connect(Callable(gdfs.ptr(), "_signal_callback"), varray(gdfs), Object::CONNECT_ONESHOT);
+ Error err = sig.connect(callable_bind(Callable(gdfs.ptr(), "_signal_callback"), retvalue), Object::CONNECT_ONESHOT);
if (err != OK) {
err_text = "Error connecting to signal: " + sig.get_name() + " during await.";
OPCODE_BREAK;
@@ -3116,6 +3133,18 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_STORE_GLOBAL) {
+ CHECK_SPACE(3);
+ int global_idx = _code_ptr[ip + 2];
+ GD_ERR_BREAK(global_idx < 0 || global_idx >= GDScriptLanguage::get_singleton()->get_global_array_size());
+
+ GET_INSTRUCTION_ARG(dst, 0);
+ *dst = GDScriptLanguage::get_singleton()->get_global_array()[global_idx];
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_STORE_NAMED_GLOBAL) {
CHECK_SPACE(3);
int globalname_idx = _code_ptr[ip + 2];
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index ad41b60a4e..7a483a16ba 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -145,6 +145,9 @@ String GDScriptWarning::get_message() const {
case REDUNDANT_AWAIT: {
return R"("await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.)";
}
+ case EMPTY_FILE: {
+ return "Empty script file.";
+ }
case WARNING_MAX:
break; // Can't happen, but silences warning
}
@@ -190,6 +193,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"ASSERT_ALWAYS_TRUE",
"ASSERT_ALWAYS_FALSE",
"REDUNDANT_AWAIT",
+ "EMPTY_FILE",
};
static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 4b295b5eb8..8de46b08c1 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -68,6 +68,7 @@ public:
ASSERT_ALWAYS_TRUE, // Expression for assert argument is always true.
ASSERT_ALWAYS_FALSE, // Expression for assert argument is always false.
REDUNDANT_AWAIT, // await is used but expression is synchronous (not a signal nor a coroutine).
+ EMPTY_FILE, // A script file is empty.
WARNING_MAX,
};
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index d106b3b541..f4c0c4d9bb 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -165,7 +165,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
case ClassNode::Member::VARIABLE: {
lsp::DocumentSymbol symbol;
symbol.name = m.variable->identifier->name;
- symbol.kind = m.variable->property == VariableNode::PropertyStyle::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property;
+ symbol.kind = m.variable->property == VariableNode::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property;
symbol.deprecated = false;
symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line);
symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column);
@@ -491,7 +491,7 @@ String ExtendGDScriptParser::get_text_for_completion(const lsp::Position &p_curs
return longthing;
}
-String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_cursor, const String &p_symbol, bool p_func_requred) const {
+String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_cursor, const String &p_symbol, bool p_func_required) const {
String longthing;
int len = lines.size();
for (int i = 0; i < len; i++) {
@@ -513,7 +513,7 @@ String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_c
longthing += first_part;
longthing += String::chr(0xFFFF); //not unicode, represents the cursor
- if (p_func_requred) {
+ if (p_func_required) {
longthing += "("; // tell the parser this is a function call
}
longthing += last_part;
@@ -532,6 +532,9 @@ String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_c
String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &p_position, Vector2i &p_offset) const {
ERR_FAIL_INDEX_V(p_position.line, lines.size(), "");
String line = lines[p_position.line];
+ if (line.is_empty()) {
+ return "";
+ }
ERR_FAIL_INDEX_V(p_position.character, line.size(), "");
int start_pos = p_position.character;
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h
index 28b9b3c82a..5d7b16765b 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.h
+++ b/modules/gdscript/language_server/gdscript_extend_parser.h
@@ -85,7 +85,7 @@ public:
Error get_left_function_call(const lsp::Position &p_position, lsp::Position &r_func_pos, int &r_arg_index) const;
String get_text_for_completion(const lsp::Position &p_cursor) const;
- String get_text_for_lookup_symbol(const lsp::Position &p_cursor, const String &p_symbol = "", bool p_func_requred = false) const;
+ String get_text_for_lookup_symbol(const lsp::Position &p_cursor, const String &p_symbol = "", bool p_func_required = false) const;
String get_identifier_under_position(const lsp::Position &p_position, Vector2i &p_offset) const;
String get_uri() const;
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index b6c48468f5..5cf1e0fc5f 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -212,11 +212,11 @@ void GDScriptLanguageProtocol::initialized(const Variant &p_params) {
lsp::GodotCapabilities capabilities;
DocTools *doc = EditorHelp::get_doc_data();
- for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
+ for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
lsp::GodotNativeClassInfo gdclass;
- gdclass.name = E->get().name;
- gdclass.class_doc = &(E->get());
- if (ClassDB::ClassInfo *ptr = ClassDB::classes.getptr(StringName(E->get().name))) {
+ gdclass.name = E.value.name;
+ gdclass.class_doc = &(E.value);
+ if (ClassDB::ClassInfo *ptr = ClassDB::classes.getptr(StringName(E.value.name))) {
gdclass.class_info = ptr;
}
capabilities.native_classes.push_back(gdclass);
@@ -284,6 +284,23 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia
peer->res_queue.push_back(msg.utf8());
}
+void GDScriptLanguageProtocol::request_client(const String &p_method, const Variant &p_params, int p_client_id) {
+ if (p_client_id == -1) {
+ ERR_FAIL_COND_MSG(latest_client_id == -1,
+ "GDScript LSP: Can't notify client as none was connected.");
+ p_client_id = latest_client_id;
+ }
+ ERR_FAIL_COND(!clients.has(p_client_id));
+ Ref<LSPeer> peer = clients.get(p_client_id);
+ ERR_FAIL_COND(peer == nullptr);
+
+ Dictionary message = make_request(p_method, p_params, next_server_id);
+ next_server_id++;
+ String msg = Variant(message).to_json_string();
+ msg = format_output(msg);
+ peer->res_queue.push_back(msg.utf8());
+}
+
bool GDScriptLanguageProtocol::is_smart_resolve_enabled() const {
return bool(_EDITOR_GET("network/language_server/enable_smart_resolve"));
}
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h
index 5a2dd55c46..899446fb42 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.h
+++ b/modules/gdscript/language_server/gdscript_language_protocol.h
@@ -79,6 +79,8 @@ private:
int latest_client_id = 0;
int next_client_id = 0;
+ int next_server_id = 0;
+
Ref<GDScriptTextDocument> text_document;
Ref<GDScriptWorkspace> workspace;
@@ -107,6 +109,7 @@ public:
void stop();
void notify_client(const String &p_method, const Variant &p_params = Variant(), int p_client_id = -1);
+ void request_client(const String &p_method, const Variant &p_params = Variant(), int p_client_id = -1);
bool is_smart_resolve_enabled() const;
bool is_goto_native_symbols_enabled() const;
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index c47164d95b..41a2f9e4ad 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -36,6 +36,7 @@
#include "editor/editor_node.h"
GDScriptLanguageServer::GDScriptLanguageServer() {
+ _EDITOR_DEF("network/language_server/remote_host", host);
_EDITOR_DEF("network/language_server/remote_port", port);
_EDITOR_DEF("network/language_server/enable_smart_resolve", true);
_EDITOR_DEF("network/language_server/show_native_symbols_in_editor", false);
@@ -56,9 +57,10 @@ void GDScriptLanguageServer::_notification(int p_what) {
}
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ String host = String(_EDITOR_GET("network/language_server/remote_host"));
int port = (int)_EDITOR_GET("network/language_server/remote_port");
bool use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
- if (port != this->port || use_thread != this->use_thread) {
+ if (host != this->host || port != this->port || use_thread != this->use_thread) {
this->stop();
this->start();
}
@@ -76,9 +78,10 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) {
}
void GDScriptLanguageServer::start() {
+ host = String(_EDITOR_GET("network/language_server/remote_host"));
port = (int)_EDITOR_GET("network/language_server/remote_port");
use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
- if (protocol.start(port, IPAddress("127.0.0.1")) == OK) {
+ if (protocol.start(port, IPAddress(host)) == OK) {
EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
if (use_thread) {
thread_running = true;
diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h
index 29c5ddd70e..85a44a8cc1 100644
--- a/modules/gdscript/language_server/gdscript_language_server.h
+++ b/modules/gdscript/language_server/gdscript_language_server.h
@@ -44,6 +44,7 @@ class GDScriptLanguageServer : public EditorPlugin {
bool thread_running = false;
bool started = false;
bool use_thread = false;
+ String host = "127.0.0.1";
int port = 6008;
static void thread_main(void *p_userdata);
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 03b1e3fa44..92ce71f395 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -217,8 +217,8 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
} else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
arr = native_member_completions.duplicate();
- for (Map<String, ExtendGDScriptParser *>::Element *E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.front(); E; E = E->next()) {
- ExtendGDScriptParser *script = E->get();
+ for (KeyValue<String, ExtendGDScriptParser *> &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts) {
+ ExtendGDScriptParser *script = E.value;
const Array &items = script->get_member_completions();
const int start_size = arr.size();
@@ -428,6 +428,9 @@ GDScriptTextDocument::~GDScriptTextDocument() {
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
+ if (!path.begins_with("res://")) {
+ return;
+ }
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
EditorFileSystem::get_singleton()->update_file(path);
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 1512b4bb89..371e3de419 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -42,6 +42,7 @@
#include "scene/resources/packed_scene.h"
void GDScriptWorkspace::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("apply_new_signal"), &GDScriptWorkspace::apply_new_signal);
ClassDB::bind_method(D_METHOD("didDeleteFiles"), &GDScriptWorkspace::did_delete_files);
ClassDB::bind_method(D_METHOD("symbol"), &GDScriptWorkspace::symbol);
ClassDB::bind_method(D_METHOD("parse_script", "path", "content"), &GDScriptWorkspace::parse_script);
@@ -52,6 +53,54 @@ void GDScriptWorkspace::_bind_methods() {
ClassDB::bind_method(D_METHOD("generate_script_api", "path"), &GDScriptWorkspace::generate_script_api);
}
+void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PackedStringArray args) {
+ String function_signature = "func " + function;
+ Ref<Script> script = obj->get_script();
+
+ String source = script->get_source_code();
+
+ if (source.find(function_signature) != -1) {
+ return;
+ }
+
+ int first_class = source.find("\nclass ");
+ int start_line = 0;
+ if (first_class != -1) {
+ start_line = source.substr(0, first_class).split("\n").size();
+ } else {
+ start_line = source.split("\n").size();
+ }
+
+ String function_body = "\n\n" + function_signature + "(";
+ for (int i = 0; i < args.size(); ++i) {
+ function_body += args[i];
+ if (i < args.size() - 1) {
+ function_body += ", ";
+ }
+ }
+ function_body += ")";
+ if (EditorSettings::get_singleton()->get_setting("text_editor/completion/add_type_hints")) {
+ function_body += " -> void";
+ }
+ function_body += ":\n\tpass # Replace with function body.\n";
+
+ lsp::TextEdit text_edit;
+
+ if (first_class != -1) {
+ function_body += "\n\n";
+ }
+ text_edit.range.end.line = text_edit.range.start.line = start_line;
+
+ text_edit.newText = function_body;
+
+ String uri = get_file_uri(script->get_path());
+
+ lsp::ApplyWorkspaceEditParams params;
+ params.edit.add_edit(uri, text_edit);
+
+ GDScriptLanguageProtocol::get_singleton()->request_client("workspace/applyEdit", params.to_json());
+}
+
void GDScriptWorkspace::did_delete_files(const Dictionary &p_params) {
Array files = p_params["files"];
for (int i = 0; i < files.size(); ++i) {
@@ -212,9 +261,9 @@ Array GDScriptWorkspace::symbol(const Dictionary &p_params) {
String query = p_params["query"];
Array arr;
if (!query.is_empty()) {
- for (Map<String, ExtendGDScriptParser *>::Element *E = scripts.front(); E; E = E->next()) {
+ for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) {
Vector<lsp::DocumentedSymbolInformation> script_symbols;
- E->get()->get_symbols().symbol_tree_as_list(E->key(), script_symbols);
+ E.value->get_symbols().symbol_tree_as_list(E.key, script_symbols);
for (int i = 0; i < script_symbols.size(); ++i) {
if (query.is_subsequence_ofi(script_symbols[i].name)) {
lsp::DocumentedSymbolInformation symbol = script_symbols[i];
@@ -233,10 +282,10 @@ Error GDScriptWorkspace::initialize() {
}
DocTools *doc = EditorHelp::get_doc_data();
- for (Map<String, DocData::ClassDoc>::Element *E = doc->class_list.front(); E; E = E->next()) {
- const DocData::ClassDoc &class_data = E->value();
+ for (const KeyValue<String, DocData::ClassDoc> &E : doc->class_list) {
+ const DocData::ClassDoc &class_data = E.value;
lsp::DocumentSymbol class_symbol;
- String class_name = E->key();
+ String class_name = E.key;
class_symbol.name = class_name;
class_symbol.native_class = class_name;
class_symbol.kind = lsp::SymbolKind::Class;
@@ -344,22 +393,25 @@ Error GDScriptWorkspace::initialize() {
reload_all_workspace_scripts();
if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
- for (Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, lsp::DocumentSymbol> &E : native_symbols) {
ClassMembers members;
- const lsp::DocumentSymbol &class_symbol = E->get();
+ const lsp::DocumentSymbol &class_symbol = E.value;
for (int i = 0; i < class_symbol.children.size(); i++) {
const lsp::DocumentSymbol &symbol = class_symbol.children[i];
members.set(symbol.name, &symbol);
}
- native_members.set(E->key(), members);
+ native_members.set(E.key, members);
}
// cache member completions
- for (Map<String, ExtendGDScriptParser *>::Element *S = scripts.front(); S; S = S->next()) {
- S->get()->get_member_completions();
+ for (const KeyValue<String, ExtendGDScriptParser *> &S : scripts) {
+ S.value->get_member_completions();
}
}
+ EditorNode *editor_node = EditorNode::get_singleton();
+ editor_node->connect("script_add_function_request", callable_mp(this, &GDScriptWorkspace::apply_new_signal));
+
return OK;
}
@@ -551,7 +603,7 @@ void GDScriptWorkspace::completion(const lsp::CompletionParams &p_params, List<S
}
}
-const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name, bool p_func_requred) {
+const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name, bool p_func_required) {
const lsp::DocumentSymbol *symbol = nullptr;
String path = get_file_path(p_doc_pos.textDocument.uri);
@@ -576,7 +628,10 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
} else {
ScriptLanguage::LookupResult ret;
- if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_requred), symbol_identifier, path, nullptr, ret)) {
+ if (symbol_identifier == "new" && parser->get_lines()[p_doc_pos.position.line].replace(" ", "").replace("\t", "").find("new(") > -1) {
+ symbol_identifier = "_init";
+ }
+ if (OK == GDScriptLanguage::get_singleton()->lookup_code(parser->get_text_for_lookup_symbol(pos, symbol_identifier, p_func_required), symbol_identifier, path, nullptr, ret)) {
if (ret.type == ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION) {
String target_script_path = path;
if (!ret.script.is_null()) {
@@ -630,8 +685,8 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
class_ptr = native_members.next(class_ptr);
}
- for (Map<String, ExtendGDScriptParser *>::Element *E = scripts.front(); E; E = E->next()) {
- const ExtendGDScriptParser *script = E->get();
+ for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) {
+ const ExtendGDScriptParser *script = E.value;
const ClassMembers &members = script->get_members();
if (const lsp::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) {
r_list.push_back(*symbol);
@@ -731,12 +786,12 @@ GDScriptWorkspace::GDScriptWorkspace() {
GDScriptWorkspace::~GDScriptWorkspace() {
Set<String> cached_parsers;
- for (Map<String, ExtendGDScriptParser *>::Element *E = parse_results.front(); E; E = E->next()) {
- cached_parsers.insert(E->key());
+ for (const KeyValue<String, ExtendGDScriptParser *> &E : parse_results) {
+ cached_parsers.insert(E.key);
}
- for (Map<String, ExtendGDScriptParser *>::Element *E = scripts.front(); E; E = E->next()) {
- cached_parsers.insert(E->key());
+ for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) {
+ cached_parsers.insert(E.key);
}
for (Set<String>::Element *E = cached_parsers.front(); E; E = E->next()) {
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index 9496677449..6f5600b5cf 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -62,6 +62,8 @@ protected:
void list_script_files(const String &p_root_dir, List<String> &r_files);
+ void apply_new_signal(Object *obj, String function, PackedStringArray args);
+
public:
String root;
String root_uri;
@@ -85,7 +87,7 @@ public:
void publish_diagnostics(const String &p_path);
void completion(const lsp::CompletionParams &p_params, List<ScriptCodeCompletionOption> *r_options);
- const lsp::DocumentSymbol *resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name = "", bool p_func_requred = false);
+ const lsp::DocumentSymbol *resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name = "", bool p_func_required = false);
void resolve_related_symbols(const lsp::TextDocumentPositionParams &p_doc_pos, List<const lsp::DocumentSymbol *> &r_list);
const lsp::DocumentSymbol *resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params);
void resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list);
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index 9ac6c6bd4e..3710a84a28 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -263,19 +263,29 @@ struct WorkspaceEdit {
*/
Map<String, Vector<TextEdit>> changes;
+ _FORCE_INLINE_ void add_edit(const String &uri, const TextEdit &edit) {
+ if (changes.has(uri)) {
+ changes[uri].push_back(edit);
+ } else {
+ Vector<TextEdit> edits;
+ edits.push_back(edit);
+ changes[uri] = edits;
+ }
+ }
+
_FORCE_INLINE_ Dictionary to_json() const {
Dictionary dict;
Dictionary out_changes;
- for (Map<String, Vector<TextEdit>>::Element *E = changes.front(); E; E = E->next()) {
+ for (const KeyValue<String, Vector<TextEdit>> &E : changes) {
Array edits;
- for (int i = 0; i < E->get().size(); ++i) {
+ for (int i = 0; i < E.value.size(); ++i) {
Dictionary text_edit;
- text_edit["range"] = E->get()[i].range.to_json();
- text_edit["newText"] = E->get()[i].newText;
+ text_edit["range"] = E.value[i].range.to_json();
+ text_edit["newText"] = E.value[i].newText;
edits.push_back(text_edit);
}
- out_changes[E->key()] = edits;
+ out_changes[E.key] = edits;
}
dict["changes"] = out_changes;
@@ -1322,6 +1332,18 @@ struct DocumentSymbol {
}
};
+struct ApplyWorkspaceEditParams {
+ WorkspaceEdit edit;
+
+ Dictionary to_json() {
+ Dictionary dict;
+
+ dict["edit"] = edit.to_json();
+
+ return dict;
+ }
+};
+
struct NativeSymbolInspectParams {
String native_class;
String symbol_name;
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index 6225e5d1eb..50c1f68440 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -133,13 +133,12 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l
if (do_init_languages) {
init_language(p_source_dir);
-
- // Enable all warnings for GDScript, so we can test them.
- ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true);
- for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
- String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
- ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/" + warning, true);
- }
+ }
+ // Enable all warnings for GDScript, so we can test them.
+ ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true);
+ for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
+ String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
+ ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/" + warning, true);
}
// Enable printing to show results
@@ -415,6 +414,7 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
TestResult result;
result.status = GDTEST_OK;
result.output = String();
+ result.passed = false;
Error err = OK;
@@ -496,7 +496,12 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
}
return result;
}
-
+ // Script files matching this pattern are allowed to not contain a test() function.
+ if (source_file.match("*.notest.gd")) {
+ enable_stdout();
+ result.passed = check_output(result.output);
+ return result;
+ }
// Test running.
const Map<StringName, GDScriptFunction *>::Element *test_function_element = script->get_member_functions().find(GDScriptTestRunner::test_function_name);
if (test_function_element == nullptr) {
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.gd b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.gd
new file mode 100644
index 0000000000..9b722ea50a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.gd
@@ -0,0 +1,3 @@
+func test():
+ # Error here.
+ print(2.2 << 4)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.out b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.out
new file mode 100644
index 0000000000..7dee854d1a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_left_operand.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Invalid operands to operator <<, float and int.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.gd b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.gd
new file mode 100644
index 0000000000..0a4f647f57
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.gd
@@ -0,0 +1,3 @@
+func test():
+ # Error here.
+ print(2 >> 4.4)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.out b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.out
new file mode 100644
index 0000000000..1edbf47ec0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/bitwise_float_right_operand.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Invalid operands to operator >>, int and float.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.gd
new file mode 100644
index 0000000000..b84ccdce81
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.gd
@@ -0,0 +1,5 @@
+class Vector2:
+ pass
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out b/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out
new file mode 100644
index 0000000000..87863baf75
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/class_name_shadows_builtin_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The member "Vector2" cannot have the same name as a builtin type.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constant_name_shadows_builtin_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/constant_name_shadows_builtin_type.gd
new file mode 100644
index 0000000000..a7c0a29a69
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/constant_name_shadows_builtin_type.gd
@@ -0,0 +1,4 @@
+const Vector2 = 0
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constant_name_shadows_builtin_type.out b/modules/gdscript/tests/scripts/analyzer/errors/constant_name_shadows_builtin_type.out
new file mode 100644
index 0000000000..87863baf75
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/constant_name_shadows_builtin_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The member "Vector2" cannot have the same name as a builtin type.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.gd b/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.gd
new file mode 100644
index 0000000000..0ad2337c15
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.gd
@@ -0,0 +1,5 @@
+const CONSTANT = 25
+
+
+func test():
+ CONSTANT(123)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.out b/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.out
new file mode 100644
index 0000000000..f4051cd02c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/constant_used_as_function.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Member "CONSTANT" is not a function.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.gd b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.gd
new file mode 100644
index 0000000000..7a922cd73e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.gd
@@ -0,0 +1,6 @@
+func test():
+ var lua_dict = {
+ a = 1,
+ b = 2,
+ a = 3, # Duplicate isn't allowed.
+ }
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.out b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.out
new file mode 100644
index 0000000000..ffdfa56645
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Key "a" was already used in this dictionary (at line 3).
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.gd b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.gd
new file mode 100644
index 0000000000..933e737ac7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.gd
@@ -0,0 +1,6 @@
+func test():
+ var lua_dict_with_string = {
+ a = 1,
+ b = 2,
+ "a" = 3, # Duplicate isn't allowed.
+ }
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.out b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.out
new file mode 100644
index 0000000000..ffdfa56645
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_lua_with_string.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Key "a" was already used in this dictionary (at line 3).
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.gd b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.gd
new file mode 100644
index 0000000000..3b8c83e9cb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.gd
@@ -0,0 +1,6 @@
+func test():
+ var python_dict = {
+ "a": 1,
+ "b": 2,
+ "a": 3, # Duplicate isn't allowed.
+ }
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.out b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.out
new file mode 100644
index 0000000000..ffdfa56645
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/dictionary_duplicate_key_python.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Key "a" was already used in this dictionary (at line 3).
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.gd
new file mode 100644
index 0000000000..cf9a0ce038
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.gd
@@ -0,0 +1,7 @@
+enum Size {
+ # Error here. Enum values must be integers.
+ S = 0.0,
+}
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.out
new file mode 100644
index 0000000000..b315d20508
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_float_value.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Enum values must be integers.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_name_shadows_builtin_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_name_shadows_builtin_type.gd
new file mode 100644
index 0000000000..930f91b389
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_name_shadows_builtin_type.gd
@@ -0,0 +1,4 @@
+enum Vector2 { A, B }
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_name_shadows_builtin_type.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_name_shadows_builtin_type.out
new file mode 100644
index 0000000000..87863baf75
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_name_shadows_builtin_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The member "Vector2" cannot have the same name as a builtin type.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.gd
new file mode 100644
index 0000000000..cd9b8fabc4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.gd
@@ -0,0 +1,7 @@
+enum Size {
+ # Error here. Enum values must be integers.
+ S = "hello",
+}
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.out b/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.out
new file mode 100644
index 0000000000..b315d20508
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/enum_string_value.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Enum values must be integers.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.gd b/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.gd
new file mode 100644
index 0000000000..4346503fc2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.gd
@@ -0,0 +1,6 @@
+func function():
+ pass
+
+
+func test():
+ function = 25
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.out b/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.out
new file mode 100644
index 0000000000..5275183da2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/function_used_as_property.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot assign a new value to a constant.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.gd
new file mode 100644
index 0000000000..b8c0b7a8d3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.gd
@@ -0,0 +1,3 @@
+func test():
+ # Error here. Array indices must be integers.
+ print([0, 1][true])
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out
new file mode 100644
index 0000000000..015ad756f8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Invalid index type "bool" for a base of type "Array".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.gd
new file mode 100644
index 0000000000..c159e03140
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.gd
@@ -0,0 +1,2 @@
+func test():
+ print(true + true)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.out
new file mode 100644
index 0000000000..c1dc7c7d08
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_bool.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Invalid operands to operator +, bool and bool.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.gd
new file mode 100644
index 0000000000..6aec2e0796
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.gd
@@ -0,0 +1,2 @@
+func test():
+ print({"hello": "world"} + {"godot": "engine"})
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.out
new file mode 100644
index 0000000000..1b4451edbe
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_dictionary.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Invalid operands "Dictionary" and "Dictionary" for "+" operator.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.gd
new file mode 100644
index 0000000000..eb2a6a0ce7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.gd
@@ -0,0 +1,2 @@
+func test():
+ print("hello" + ["world"])
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.out
new file mode 100644
index 0000000000..6d44c6c1bd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_concatenation_mixed.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Invalid operands "String" and "Array" for "+" operator.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.gd b/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.gd
new file mode 100644
index 0000000000..a7426e88da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.gd
@@ -0,0 +1,5 @@
+func test():
+ var i = 12
+ # Constants must be made of a constant, deterministic expression.
+ # A constant that depends on a variable's value is not a constant expression.
+ const TEST = 13 + i
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.out
new file mode 100644
index 0000000000..c40830f123
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_constant.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Assigned value for constant "TEST" isn't a constant expression.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.gd b/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.gd
new file mode 100644
index 0000000000..d88c02d6ee
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.gd
@@ -0,0 +1,3 @@
+func test():
+ # Number separators may not be placed at the beginning of a number.
+ var __ = _123
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.out b/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.out
new file mode 100644
index 0000000000..cfb558bf45
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/leading_number_separator.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Identifier "_123" not declared in the current scope.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.gd b/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.gd
new file mode 100644
index 0000000000..70bdadf291
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.gd
@@ -0,0 +1,6 @@
+func args(a, b):
+ print(a)
+ print(b)
+
+func test():
+ args(1,)
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_argument.out b/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.out
index fc2a891109..fc2a891109 100644
--- a/modules/gdscript/tests/scripts/parser/errors/missing_argument.out
+++ b/modules/gdscript/tests/scripts/analyzer/errors/missing_argument.out
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd
new file mode 100644
index 0000000000..f1be6aaa0c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.gd
@@ -0,0 +1,11 @@
+var _prop : int
+
+# Getter function has wrong return type.
+var prop : String:
+ get = get_prop
+
+func get_prop():
+ return _prop
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out
new file mode 100644
index 0000000000..29eec51ef2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_get_type_error.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Function with return type "int" cannot be used as getter for a property of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd
new file mode 100644
index 0000000000..dd190157a1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.gd
@@ -0,0 +1,11 @@
+var _prop : int
+
+# Setter function has wrong argument type.
+var prop : String:
+ set = set_prop
+
+func set_prop(value : int):
+ _prop = value
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out
new file mode 100644
index 0000000000..7a25280d55
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_function_set_type_error.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Function with argument type "int" cannot be used as setter for a property of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd
new file mode 100644
index 0000000000..7f2b29222a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.gd
@@ -0,0 +1,9 @@
+var _prop : int
+
+# Inline getter returns int instead of String.
+var prop : String:
+ get:
+ return _prop
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out
new file mode 100644
index 0000000000..e0adef1bf8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_get_type_error.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot return value of type "int" because the function return type is "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd
new file mode 100644
index 0000000000..0ce239dbbd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.gd
@@ -0,0 +1,9 @@
+var _prop : int
+
+# Inline setter assigns String to int.
+var prop : String:
+ set(value):
+ _prop = value
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out
new file mode 100644
index 0000000000..bbadf1ce27
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_inline_set_type_error.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot assign a value of type "String" to a target of type "int".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.gd b/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.gd
new file mode 100644
index 0000000000..059d774927
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.gd
@@ -0,0 +1,4 @@
+var property = 25
+
+func test():
+ property()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.out b/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.out
new file mode 100644
index 0000000000..94d6c26a1a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/property_used_as_function.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Member "property" is not a function.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.gd b/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.gd
new file mode 100644
index 0000000000..91401d32fc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.gd
@@ -0,0 +1,7 @@
+# See also `parser-warnings/shadowed-constant.gd`.
+const TEST = 25
+
+
+func test():
+ # Error here (trying to set a new value to a constant).
+ TEST = 50
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.out b/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.out
new file mode 100644
index 0000000000..5275183da2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/redefine_class_constant.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot assign a new value to a constant.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.gd b/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.gd
new file mode 100644
index 0000000000..97f3e55e81
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.gd
@@ -0,0 +1,5 @@
+func test():
+ const TEST = 25
+
+ # Error here (can't assign a new value to a constant).
+ TEST = 50
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.out b/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.out
new file mode 100644
index 0000000000..5275183da2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/redefine_local_constant.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot assign a new value to a constant.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd
new file mode 100644
index 0000000000..3bbee5f5f7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.gd
@@ -0,0 +1,8 @@
+var with_setter := 0:
+ set(val):
+ var x: String = val
+ with_setter = val
+
+func test():
+ with_setter = 1
+ print(with_setter)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out
new file mode 100644
index 0000000000..9eb2a42ccd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/setter_parameter_uses_property_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Value of type "int" cannot be assigned to a variable of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.gd b/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.gd
new file mode 100644
index 0000000000..722a8fcdb7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.gd
@@ -0,0 +1,11 @@
+# `class` extends RefCounted by default.
+class Say:
+ func say():
+ super()
+ print("say something")
+
+
+func test():
+ # RefCounted doesn't have a `say()` method, so the `super()` call in the method
+ # definition will cause a run-time error.
+ Say.new().say()
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.out b/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.out
new file mode 100644
index 0000000000..e3dbf81850
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/super_nonexistent_base_method.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Function "say()" not found in base RefCounted.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/variable_name_shadows_builtin_type.gd b/modules/gdscript/tests/scripts/analyzer/errors/variable_name_shadows_builtin_type.gd
new file mode 100644
index 0000000000..7cba29884c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/variable_name_shadows_builtin_type.gd
@@ -0,0 +1,4 @@
+var Vector2
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/variable_name_shadows_builtin_type.out b/modules/gdscript/tests/scripts/analyzer/errors/variable_name_shadows_builtin_type.out
new file mode 100644
index 0000000000..87863baf75
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/variable_name_shadows_builtin_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+The member "Vector2" cannot have the same name as a builtin type.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/as.gd b/modules/gdscript/tests/scripts/analyzer/features/as.gd
new file mode 100644
index 0000000000..13a36147c0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/as.gd
@@ -0,0 +1,16 @@
+func test():
+ var some_bool = 5 as bool
+ var some_int = 5 as int
+ var some_float = 5 as float
+ print(typeof(some_bool))
+ print(typeof(some_int))
+ print(typeof(some_float))
+
+ print()
+
+ var some_bool_typed := 5 as bool
+ var some_int_typed := 5 as int
+ var some_float_typed := 5 as float
+ print(typeof(some_bool_typed))
+ print(typeof(some_int_typed))
+ print(typeof(some_float_typed))
diff --git a/modules/gdscript/tests/scripts/analyzer/features/as.out b/modules/gdscript/tests/scripts/analyzer/features/as.out
new file mode 100644
index 0000000000..bcf84aa6f6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/as.out
@@ -0,0 +1,8 @@
+GDTEST_OK
+1
+2
+3
+
+1
+2
+3
diff --git a/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.gd b/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.gd
new file mode 100644
index 0000000000..f64dce26c9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.gd
@@ -0,0 +1,9 @@
+func inferred_parameter(param = null):
+ if param == null:
+ param = Node.new()
+ param.name = "Ok"
+ print(param.name)
+ param.free()
+
+func test():
+ inferred_parameter()
diff --git a/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out b/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out
new file mode 100644
index 0000000000..481016138a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/auto_inferred_type_dont_error.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+>> WARNING
+>> Line: 6
+>> UNSAFE_METHOD_ACCESS
+>> The method 'free' is not present on the inferred type 'Variant' (but may be present on a subtype).
+Ok
diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd
new file mode 100644
index 0000000000..630b20c282
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.gd
@@ -0,0 +1,11 @@
+# https://github.com/godotengine/godot/issues/43503
+
+var test_var = null
+
+
+func test():
+ print(test_var.x)
+
+
+func _init():
+ test_var = Vector3()
diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out
new file mode 100644
index 0000000000..94e2ec2af8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+0
diff --git a/modules/gdscript/tests/scripts/analyzer/features/constants_from_parent.gd b/modules/gdscript/tests/scripts/analyzer/features/constants_from_parent.gd
new file mode 100644
index 0000000000..135b6c3d85
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/constants_from_parent.gd
@@ -0,0 +1,16 @@
+extends Node
+
+const NO_TYPE_CONST = 0
+const TYPE_CONST: int = 1
+const GUESS_TYPE_CONST := 2
+
+class Test:
+ var a = NO_TYPE_CONST
+ var b = TYPE_CONST
+ var c = GUESS_TYPE_CONST
+
+func test():
+ var test_instance = Test.new()
+ prints("a", test_instance.a, test_instance.a == NO_TYPE_CONST)
+ prints("b", test_instance.b, test_instance.b == TYPE_CONST)
+ prints("c", test_instance.c, test_instance.c == GUESS_TYPE_CONST)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/constants_from_parent.out b/modules/gdscript/tests/scripts/analyzer/features/constants_from_parent.out
new file mode 100644
index 0000000000..a96bb84246
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/constants_from_parent.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+a 0 true
+b 1 true
+c 2 true
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_from_parent.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_from_parent.gd
new file mode 100644
index 0000000000..5f57c5b8c2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_from_parent.gd
@@ -0,0 +1,14 @@
+extends Node
+
+enum Named { VALUE_A, VALUE_B, VALUE_C = 42 }
+
+class Test:
+ var a = Named.VALUE_A
+ var b = Named.VALUE_B
+ var c = Named.VALUE_C
+
+func test():
+ var test_instance = Test.new()
+ prints("a", test_instance.a, test_instance.a == Named.VALUE_A)
+ prints("b", test_instance.b, test_instance.b == Named.VALUE_B)
+ prints("c", test_instance.c, test_instance.c == Named.VALUE_C)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_from_parent.out b/modules/gdscript/tests/scripts/analyzer/features/enum_from_parent.out
new file mode 100644
index 0000000000..c160839da3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_from_parent.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+a 0 true
+b 1 true
+c 42 true
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_value_from_parent.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_value_from_parent.gd
new file mode 100644
index 0000000000..26edce353d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_value_from_parent.gd
@@ -0,0 +1,14 @@
+extends Node
+
+enum { VALUE_A, VALUE_B, VALUE_C = 42 }
+
+class Test:
+ var a = VALUE_A
+ var b = VALUE_B
+ var c = VALUE_C
+
+func test():
+ var test_instance = Test.new()
+ prints("a", test_instance.a, test_instance.a == VALUE_A)
+ prints("b", test_instance.b, test_instance.b == VALUE_B)
+ prints("c", test_instance.c, test_instance.c == VALUE_C)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_value_from_parent.out b/modules/gdscript/tests/scripts/analyzer/features/enum_value_from_parent.out
new file mode 100644
index 0000000000..c160839da3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_value_from_parent.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+a 0 true
+b 1 true
+c 42 true
diff --git a/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd
new file mode 100644
index 0000000000..b3784dffa3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.gd
@@ -0,0 +1,14 @@
+# https://github.com/godotengine/godot/issues/41064
+var x = true
+
+func test():
+ var int_var: int = 0
+ var dyn_var = 2
+
+ if x:
+ dyn_var = 5
+ else:
+ dyn_var = Node.new()
+
+ int_var = dyn_var
+ print(int_var)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out
new file mode 100644
index 0000000000..952029f665
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/local_inference_is_weak.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+5
diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd b/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd
new file mode 100644
index 0000000000..1706087f82
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_functions.gd
@@ -0,0 +1,16 @@
+var _prop = 1
+var prop:
+ get = get_prop, set = set_prop
+
+func get_prop():
+ return _prop
+
+func set_prop(value):
+ _prop = value
+
+func test():
+ print(prop)
+
+ prop = 2
+
+ print(prop)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_functions.out b/modules/gdscript/tests/scripts/analyzer/features/property_functions.out
new file mode 100644
index 0000000000..f1253ca57e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_functions.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+1
+2
diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd b/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd
new file mode 100644
index 0000000000..23eb011b23
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_inline.gd
@@ -0,0 +1,46 @@
+# Untyped inline property
+var prop1:
+ get:
+ return prop1
+ set(value):
+ prop1 = value
+
+# Typed inline property
+var prop2 : int:
+ get:
+ return prop2
+ set(value):
+ prop2 = value
+
+# Typed inline property with default value
+var prop3 : int = 1:
+ get:
+ return prop3
+ set(value):
+ prop3 = value
+
+# Typed inline property with backing variable
+var _prop4 : int = 2
+var prop4: int:
+ get:
+ return _prop4
+ set(value):
+ _prop4 = value
+
+func test():
+ print(prop1)
+ print(prop2)
+ print(prop3)
+ print(prop4)
+
+ print()
+
+ prop1 = 1
+ prop2 = 2
+ prop3 = 3
+ prop4 = 4
+
+ print(prop1)
+ print(prop2)
+ print(prop3)
+ print(prop4)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/property_inline.out b/modules/gdscript/tests/scripts/analyzer/features/property_inline.out
new file mode 100644
index 0000000000..5482592e90
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/property_inline.out
@@ -0,0 +1,10 @@
+GDTEST_OK
+null
+0
+1
+2
+
+1
+2
+3
+4
diff --git a/modules/gdscript/tests/scripts/analyzer/features/static_method_builtin_type.gd b/modules/gdscript/tests/scripts/analyzer/features/static_method_builtin_type.gd
new file mode 100644
index 0000000000..569f95850f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/static_method_builtin_type.gd
@@ -0,0 +1,2 @@
+func test():
+ print(Color.html_is_valid("00ffff"))
diff --git a/modules/gdscript/tests/scripts/analyzer/features/static_method_builtin_type.out b/modules/gdscript/tests/scripts/analyzer/features/static_method_builtin_type.out
new file mode 100644
index 0000000000..55482c2b52
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/static_method_builtin_type.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+true
diff --git a/modules/gdscript/tests/scripts/analyzer/features/subscript_self.gd b/modules/gdscript/tests/scripts/analyzer/features/subscript_self.gd
new file mode 100644
index 0000000000..f9a8b23b92
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/subscript_self.gd
@@ -0,0 +1,8 @@
+# https://github.com/godotengine/godot/issues/43221
+extends Node
+
+func test():
+ name = "Node"
+ print(self["name"])
+ self["name"] = "Changed"
+ print(name)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/subscript_self.out b/modules/gdscript/tests/scripts/analyzer/features/subscript_self.out
new file mode 100644
index 0000000000..6417f4f8da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/subscript_self.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+Node
+Changed
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd
new file mode 100644
index 0000000000..9502f6e196
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.gd
@@ -0,0 +1,10 @@
+class Inner:
+ var prop = "Inner"
+
+
+var array: Array[Inner] = [Inner.new()]
+
+
+func test():
+ var element: Inner = array[0]
+ print(element.prop)
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out
new file mode 100644
index 0000000000..8f250d2632
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_with_custom_class.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+Inner
diff --git a/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.gd b/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.gd
new file mode 100644
index 0000000000..b45f99fdd0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.gd
@@ -0,0 +1,3 @@
+func test():
+ # Arrays with consecutive commas are not allowed.
+ var array = ["arrays",,,,]
diff --git a/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.out b/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.out
new file mode 100644
index 0000000000..4ef8526065
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/array_consecutive_commas.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression as array element.
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.gd
new file mode 100644
index 0000000000..17d5e078e5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.gd
@@ -0,0 +1,2 @@
+func test():
+ var hello == "world"
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.out b/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.out
new file mode 100644
index 0000000000..b150fc0d16
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_2_equal_signs.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected end of statement after variable declaration, found "==" instead.
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.gd
new file mode 100644
index 0000000000..8b5f620889
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.gd
@@ -0,0 +1,2 @@
+func test():
+ var hello === "world"
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.out b/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.out
new file mode 100644
index 0000000000..b150fc0d16
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_3_equal_signs.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected end of statement after variable declaration, found "==" instead.
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.gd
new file mode 100644
index 0000000000..8c3a908532
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.gd
@@ -0,0 +1,4 @@
+func test():
+ # Error here.
+ if foo = 25:
+ print(foo)
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.out b/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.out
new file mode 100644
index 0000000000..e8f9130706
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_if.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Assignment is not allowed inside an expression.
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.gd
new file mode 100644
index 0000000000..126a3227ea
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.gd
@@ -0,0 +1,2 @@
+func test():
+ var hello = "world" = "test"
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.out b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.out
new file mode 100644
index 0000000000..e8f9130706
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Assignment is not allowed inside an expression.
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.gd
new file mode 100644
index 0000000000..a99557fa3c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.gd
@@ -0,0 +1,4 @@
+func test():
+ # Error here.
+ if var foo = 25:
+ print(foo)
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.out b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.out
new file mode 100644
index 0000000000..e84f4652ac
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_in_var_if.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected conditional expression after "if".
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.gd b/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.gd
new file mode 100644
index 0000000000..031ea523c8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.gd
@@ -0,0 +1,2 @@
+func test():
+ var = "world"
diff --git a/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.out b/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.out
new file mode 100644
index 0000000000..a4bd8beef1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/assignment_without_identifier.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected variable name after "var".
diff --git a/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.gd b/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.gd
new file mode 100644
index 0000000000..b52a6defcb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.gd
@@ -0,0 +1,2 @@
+func test():
+ print(~)
diff --git a/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.out b/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.out
new file mode 100644
index 0000000000..ceabe42d3c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/binary_complement_without_argument.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression after "~" operator.
diff --git a/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.gd b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.gd
new file mode 100644
index 0000000000..b3ea1ba1f6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.gd
@@ -0,0 +1,2 @@
+func test():
+ print(not)
diff --git a/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.out b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.out
new file mode 100644
index 0000000000..6cf191ea98
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression after "not" operator.
diff --git a/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.gd b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.gd
new file mode 100644
index 0000000000..8a33079193
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.gd
@@ -0,0 +1,2 @@
+func test():
+ print(!)
diff --git a/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.out b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.out
new file mode 100644
index 0000000000..87fcc5e2b0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/boolean_negation_without_argument_using_bang.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression after "!" operator.
diff --git a/modules/gdscript/tests/scripts/parser/errors/brace_syntax.gd b/modules/gdscript/tests/scripts/parser/errors/brace_syntax.gd
new file mode 100644
index 0000000000..ab66537c93
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/brace_syntax.gd
@@ -0,0 +1,3 @@
+func test() {
+ print("Hello world!");
+}
diff --git a/modules/gdscript/tests/scripts/parser/errors/brace_syntax.out b/modules/gdscript/tests/scripts/parser/errors/brace_syntax.out
new file mode 100644
index 0000000000..2f37a740ab
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/brace_syntax.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected ":" after function declaration.
diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd
new file mode 100644
index 0000000000..d13d713454
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd
@@ -0,0 +1,6 @@
+# Error here. `class_name` should be used *before* annotations, not after.
+@icon("res://path/to/optional/icon.svg")
+class_name HelloWorld
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out
new file mode 100644
index 0000000000..0bcc8acc55
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+"class_name" should be used before annotations.
diff --git a/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.gd b/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.gd
new file mode 100644
index 0000000000..49fb4ffedf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.gd
@@ -0,0 +1,3 @@
+func test():
+ var TEST = 50
+ const TEST = 25
diff --git a/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.out b/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.out
new file mode 100644
index 0000000000..407f094ca0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/constant_conflicts_variable.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+There is already a variable named "TEST" declared in this scope.
diff --git a/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.gd b/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.gd
new file mode 100644
index 0000000000..2581d873dd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.gd
@@ -0,0 +1,7 @@
+func hello(arg1):
+ print(arg1)
+
+
+func test():
+ # Error here.
+ hello(arg1 = 25)
diff --git a/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.out b/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.out
new file mode 100644
index 0000000000..e8f9130706
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/default_value_in_function_call.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Assignment is not allowed inside an expression.
diff --git a/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.gd b/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.gd
new file mode 100644
index 0000000000..92dfb2366d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.gd
@@ -0,0 +1,2 @@
+func test():
+ var dictionary = { hello = "world",, }
diff --git a/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.out b/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.out
new file mode 100644
index 0000000000..d1dcd1cb4b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/double_dictionary_comma.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression as dictionary key.
diff --git a/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.gd b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.gd
new file mode 100644
index 0000000000..a8f7cf1810
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.gd
@@ -0,0 +1,5 @@
+const test = 25
+
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.out b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.out
new file mode 100644
index 0000000000..c614acd094
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_constant.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Function "test" has the same name as a previously declared constant.
diff --git a/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.gd b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.gd
new file mode 100644
index 0000000000..5c86710a40
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.gd
@@ -0,0 +1,7 @@
+func test():
+ pass
+
+
+# Error here. The difference with `variable-conflicts-function.gd` is that here,
+# the function is defined *before* the variable.
+var test = 25
diff --git a/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.out b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.out
new file mode 100644
index 0000000000..551db61531
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/function_conflicts_variable.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Variable "test" has the same name as a previously declared function.
diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_escape_sequence.gd b/modules/gdscript/tests/scripts/parser/errors/invalid_escape_sequence.gd
new file mode 100644
index 0000000000..3b52f6e324
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/invalid_escape_sequence.gd
@@ -0,0 +1,2 @@
+func test():
+ var escape = "invalid escape \h <- here"
diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_escape_sequence.out b/modules/gdscript/tests/scripts/parser/errors/invalid_escape_sequence.out
new file mode 100644
index 0000000000..32b4d004db
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/invalid_escape_sequence.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Invalid escape in string.
diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.gd b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.gd
new file mode 100644
index 0000000000..081b9faf4b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.gd
@@ -0,0 +1,3 @@
+func test():
+ # Error here.
+ var 23test = "is not a valid identifier"
diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.out b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.out
new file mode 100644
index 0000000000..a4bd8beef1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_number.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected variable name after "var".
diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.gd b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.gd
new file mode 100644
index 0000000000..fa4d6b5cac
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.gd
@@ -0,0 +1,3 @@
+func test():
+ # Error here.
+ var "yes" = "is not a valid identifier"
diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.out b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.out
new file mode 100644
index 0000000000..a4bd8beef1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/invalid_identifier_string.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected variable name after "var".
diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_ternary_operator.gd b/modules/gdscript/tests/scripts/parser/errors/invalid_ternary_operator.gd
new file mode 100644
index 0000000000..c835ce15e1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/invalid_ternary_operator.gd
@@ -0,0 +1,5 @@
+func test():
+ var amount = 50
+ # C-style ternary operator is invalid in GDScript.
+ # The valid syntax is `"yes" if amount < 60 else "no"`, like in Python.
+ var ternary = amount < 60 ? "yes" : "no"
diff --git a/modules/gdscript/tests/scripts/parser/errors/invalid_ternary_operator.out b/modules/gdscript/tests/scripts/parser/errors/invalid_ternary_operator.out
new file mode 100644
index 0000000000..ac82d691b7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/invalid_ternary_operator.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Unexpected "?" in source. If you want a ternary operator, use "truthy_value if true_condition else falsy_value".
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd b/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd
deleted file mode 100644
index c56ad94095..0000000000
--- a/modules/gdscript/tests/scripts/parser/errors/missing_argument.gd
+++ /dev/null
@@ -1,6 +0,0 @@
-func args(a, b):
- print(a)
- print(b)
-
-func test():
- args(1,)
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd
index a1077e1985..8af5f123cc 100644
--- a/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_closing_expr_paren.gd
@@ -1,2 +1,2 @@
func test():
- var a = ("missing paren ->"
+ var a = ("missing paren ->"
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd
index 62cb633e9e..0e5e5ce060 100644
--- a/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_colon.gd
@@ -1,3 +1,3 @@
func test():
- if true # Missing colon here.
- print("true")
+ if true # Missing colon here.
+ print("true")
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.gd b/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.gd
new file mode 100644
index 0000000000..1f66935329
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.gd
@@ -0,0 +1,4 @@
+func test():
+ var x = 1 if false else
+ print("oops")
+ print(x)
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.out b/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.out
new file mode 100644
index 0000000000..dab6b0a1ad
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_expression_after_ternary_else.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression after "else".
diff --git a/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd
index 116b0151da..7a35bf688c 100644
--- a/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/missing_paren_after_args.gd
@@ -1,6 +1,6 @@
func args(a, b):
- print(a)
- print(b)
+ print(a)
+ print(b)
func test():
- args(1,2
+ args(1,2
diff --git a/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.gd b/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.gd
new file mode 100644
index 0000000000..193f824702
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.gd
@@ -0,0 +1,3 @@
+func test():
+ var a = 0
+ print(a--)
diff --git a/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.out b/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.out
new file mode 100644
index 0000000000..b6b577a277
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/mistaken_decrement_operator.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression after "-" operator.
diff --git a/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.gd b/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.gd
new file mode 100644
index 0000000000..035d27638c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.gd
@@ -0,0 +1,3 @@
+func test():
+ var a = 0
+ print(a++)
diff --git a/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.out b/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.out
new file mode 100644
index 0000000000..24eb76593a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/mistaken_increment_operator.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression after "+" operator.
diff --git a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd
new file mode 100644
index 0000000000..71a03fbc0d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.gd
@@ -0,0 +1,3 @@
+func test():
+ # Number separators may not be placed right next to each other.
+ var __ = 1__23
diff --git a/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out
new file mode 100644
index 0000000000..71a3c2fd6a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/multiple_number_separators.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Only one underscore can be used as a numeric separator.
diff --git a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd
index 3875ce3936..df388a21de 100644
--- a/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/nothing_after_dollar.gd
@@ -1,3 +1,5 @@
extends Node
+
+
func test():
- var a = $ # Expected some node path.
+ var a = $ # Expected some node path.
diff --git a/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.gd b/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.gd
new file mode 100644
index 0000000000..c289c9d976
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.gd
@@ -0,0 +1,2 @@
+func test():
+ var while = "it's been a while"
diff --git a/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.out b/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.out
new file mode 100644
index 0000000000..a4bd8beef1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/redefine_keyword.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected variable name after "var".
diff --git a/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.gd b/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.gd
new file mode 100644
index 0000000000..204259f981
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.gd
@@ -0,0 +1,5 @@
+func test():
+ const TEST = 25
+
+ # Error here (can't redeclare a constant on the same scope).
+ const TEST = 50
diff --git a/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.out b/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.out
new file mode 100644
index 0000000000..d67cc92953
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/redefine_local_constant_with_keyword.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+There is already a constant named "TEST" declared in this scope.
diff --git a/modules/gdscript/tests/scripts/parser/errors/subscript_without_index.gd b/modules/gdscript/tests/scripts/parser/errors/subscript_without_index.gd
new file mode 100644
index 0000000000..c30c05e4da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/subscript_without_index.gd
@@ -0,0 +1,3 @@
+func test():
+ var array = [1, 2, 3]
+ array[] = 4
diff --git a/modules/gdscript/tests/scripts/parser/errors/subscript_without_index.out b/modules/gdscript/tests/scripts/parser/errors/subscript_without_index.out
new file mode 100644
index 0000000000..7017c7b4aa
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/subscript_without_index.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Expected expression after "[".
diff --git a/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.gd b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.gd
new file mode 100644
index 0000000000..0d8843df20
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.gd
@@ -0,0 +1,3 @@
+func test():
+ const TEST = 25
+ var TEST = 50
diff --git a/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.out b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.out
new file mode 100644
index 0000000000..d67cc92953
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_constant.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+There is already a constant named "TEST" declared in this scope.
diff --git a/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.gd b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.gd
new file mode 100644
index 0000000000..ce2c8784d6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.gd
@@ -0,0 +1,6 @@
+var test = 25
+
+# Error here. The difference with `variable-conflicts-function.gd` is that here,
+# the function is defined *before* the variable.
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.out b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.out
new file mode 100644
index 0000000000..daeaca40ec
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/variable_conflicts_function.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Function "test" has the same name as a previously declared variable.
diff --git a/modules/gdscript/tests/scripts/parser/errors/vcs_conflict_marker.gd b/modules/gdscript/tests/scripts/parser/errors/vcs_conflict_marker.gd
new file mode 100644
index 0000000000..8850892f2d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/vcs_conflict_marker.gd
@@ -0,0 +1,13 @@
+# The VCS conflict marker has only 6 `=` signs instead of 7 to prevent editors like
+# Visual Studio Code from recognizing it as an actual VCS conflict marker.
+# Nonetheless, the GDScript parser is still expected to find and report the VCS
+# conflict marker error correctly.
+
+<<<<<<< HEAD
+Hello world
+======
+Goodbye
+>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/vcs_conflict_marker.out b/modules/gdscript/tests/scripts/parser/errors/vcs_conflict_marker.out
new file mode 100644
index 0000000000..df9dab2223
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/vcs_conflict_marker.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Unexpected "VCS conflict marker" in class body.
diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd
index 6fd2692d47..babe39068c 100644
--- a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar.gd
@@ -1,3 +1,5 @@
extends Node
+
+
func test():
- $23 # Can't use number here.
+ $23 # Can't use number here.
diff --git a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd
index 1836d42226..b6b1cf3e52 100644
--- a/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/wrong_value_after_dollar_slash.gd
@@ -1,3 +1,5 @@
extends Node
+
+
func test():
- $MyNode/23 # Can't use number here.
+ $MyNode/23 # Can't use number here.
diff --git a/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.gd b/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.gd
new file mode 100644
index 0000000000..7862eff6ec
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.gd
@@ -0,0 +1,6 @@
+#GDTEST_PARSER_ERROR
+
+signal event
+
+func test():
+ yield("event")
diff --git a/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out b/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out
new file mode 100644
index 0000000000..36cb699e92
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/yield_instead_of_await.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+"yield" was removed in Godot 4.0. Use "await" instead.
diff --git a/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.gd b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.gd
new file mode 100644
index 0000000000..43b513045b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.gd
@@ -0,0 +1,34 @@
+func foo(x):
+ match x:
+ 1 + 1:
+ print("1+1")
+ [1,2,[1,{1:2,2:var z,..}]]:
+ print("[1,2,[1,{1:2,2:var z,..}]]")
+ print(z)
+ 1 if true else 2:
+ print("1 if true else 2")
+ 1 < 2:
+ print("1 < 2")
+ 1 or 2 and 1:
+ print("1 or 2 and 1")
+ 6 | 1:
+ print("1 | 1")
+ 1 >> 1:
+ print("1 >> 1")
+ 1, 2 or 3, 4:
+ print("1, 2 or 3, 4")
+ _:
+ print("wildcard")
+
+func test():
+ foo(6 | 1)
+ foo(1 >> 1)
+ foo(2)
+ foo(1)
+ foo(1+1)
+ foo(1 < 2)
+ foo([2, 1])
+ foo(4)
+ foo([1, 2, [1, {1 : 2, 2:3}]])
+ foo([1, 2, [1, {1 : 2, 2:[1,3,5, "123"], 4:2}]])
+ foo([1, 2, [1, {1 : 2}]])
diff --git a/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out
new file mode 100644
index 0000000000..67c7e28046
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out
@@ -0,0 +1,14 @@
+GDTEST_OK
+1 | 1
+1 >> 1
+1+1
+1 if true else 2
+1+1
+1 < 2
+wildcard
+1, 2 or 3, 4
+[1,2,[1,{1:2,2:var z,..}]]
+3
+[1,2,[1,{1:2,2:var z,..}]]
+[1, 3, 5, 123]
+wildcard
diff --git a/modules/gdscript/tests/scripts/parser/features/array.gd b/modules/gdscript/tests/scripts/parser/features/array.gd
new file mode 100644
index 0000000000..828ce8d134
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/array.gd
@@ -0,0 +1,16 @@
+func test():
+ # Indexing from the beginning:
+ print([1, 2, 3][0])
+ print([1, 2, 3][1])
+ print([1, 2, 3][2])
+
+ # Indexing from the end:
+ print([1, 2, 3][-1])
+ print([1, 2, 3][-2])
+ print([1, 2, 3][-3])
+
+ # Float indices are currently allowed, but should probably be an error?
+ print([1, 2, 3][0.4])
+ print([1, 2, 3][0.8])
+ print([1, 2, 3][1.0])
+ print([1, 2, 3][-1.0])
diff --git a/modules/gdscript/tests/scripts/parser/features/array.out b/modules/gdscript/tests/scripts/parser/features/array.out
new file mode 100644
index 0000000000..cf576c59e0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/array.out
@@ -0,0 +1,11 @@
+GDTEST_OK
+1
+2
+3
+3
+2
+1
+1
+1
+2
+3
diff --git a/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.gd b/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.gd
new file mode 100644
index 0000000000..2b46f1e88a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.gd
@@ -0,0 +1,27 @@
+func foo(x):
+ match x:
+ 1:
+ print("1")
+ 2:
+ print("2")
+ [1, 2]:
+ print("[1, 2]")
+ 3 or 4:
+ print("3 or 4")
+ 4:
+ print("4")
+ {1 : 2, 2 : 3}:
+ print("{1 : 2, 2 : 3}")
+ _:
+ print("wildcard")
+
+func test():
+ foo(0)
+ foo(1)
+ foo(2)
+ foo([1, 2])
+ foo(3)
+ foo(4)
+ foo([4,4])
+ foo({1 : 2, 2 : 3})
+ foo({1 : 2, 4 : 3})
diff --git a/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.out b/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.out
new file mode 100644
index 0000000000..46ee4b04da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/basic_expression_matching.out
@@ -0,0 +1,10 @@
+GDTEST_OK
+wildcard
+1
+2
+[1, 2]
+wildcard
+4
+wildcard
+{1 : 2, 2 : 3}
+wildcard
diff --git a/modules/gdscript/tests/scripts/parser/features/bitwise_operators.gd b/modules/gdscript/tests/scripts/parser/features/bitwise_operators.gd
new file mode 100644
index 0000000000..de502c6ed1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/bitwise_operators.gd
@@ -0,0 +1,50 @@
+enum Flags {
+ FIRE = 1 << 1,
+ ICE = 1 << 2,
+ SLIPPERY = 1 << 3,
+ STICKY = 1 << 4,
+ NONSOLID = 1 << 5,
+
+ ALL = FIRE | ICE | SLIPPERY | STICKY | NONSOLID,
+}
+
+
+func test():
+ var flags = Flags.FIRE | Flags.SLIPPERY
+ print(flags)
+
+ flags = Flags.FIRE & Flags.SLIPPERY
+ print(flags)
+
+ flags = Flags.FIRE ^ Flags.SLIPPERY
+ print(flags)
+
+ flags = Flags.ALL & (Flags.FIRE | Flags.ICE)
+ print(flags)
+
+ flags = (Flags.ALL & Flags.FIRE) | Flags.ICE
+ print(flags)
+
+ flags = Flags.ALL & Flags.FIRE | Flags.ICE
+ print(flags)
+
+ # Enum value must be casted to an integer. Otherwise, a parser error is emitted.
+ flags &= int(Flags.ICE)
+ print(flags)
+
+ flags ^= int(Flags.ICE)
+ print(flags)
+
+ flags |= int(Flags.STICKY | Flags.SLIPPERY)
+ print(flags)
+
+ print()
+
+ var num = 2 << 4
+ print(num)
+
+ num <<= 2
+ print(num)
+
+ num >>= 2
+ print(num)
diff --git a/modules/gdscript/tests/scripts/parser/features/bitwise_operators.out b/modules/gdscript/tests/scripts/parser/features/bitwise_operators.out
new file mode 100644
index 0000000000..410e358a05
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/bitwise_operators.out
@@ -0,0 +1,14 @@
+GDTEST_OK
+10
+0
+10
+6
+6
+6
+4
+0
+24
+
+32
+128
+32
diff --git a/modules/gdscript/tests/scripts/parser/features/class.gd b/modules/gdscript/tests/scripts/parser/features/class.gd
new file mode 100644
index 0000000000..6652f85ad9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/class.gd
@@ -0,0 +1,25 @@
+# Test non-nested/slightly nested class architecture.
+class Test:
+ var number = 25
+ var string = "hello"
+
+
+class TestSub extends Test:
+ var other_string = "bye"
+
+
+class TestConstructor:
+ func _init(argument = 10):
+ print(str("constructor with argument ", argument))
+
+
+func test():
+ var test_instance = Test.new()
+ test_instance.number = 42
+
+ var test_sub = TestSub.new()
+ assert(test_sub.number == 25) # From Test.
+ assert(test_sub.other_string == "bye") # From TestSub.
+
+ TestConstructor.new()
+ TestConstructor.new(500)
diff --git a/modules/gdscript/tests/scripts/parser/features/class.out b/modules/gdscript/tests/scripts/parser/features/class.out
new file mode 100644
index 0000000000..94dc2d6003
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/class.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+constructor with argument 10
+constructor with argument 500
diff --git a/modules/gdscript/tests/scripts/parser/features/class_inheritance.gd b/modules/gdscript/tests/scripts/parser/features/class_inheritance.gd
new file mode 100644
index 0000000000..3f9b4ea86e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/class_inheritance.gd
@@ -0,0 +1,33 @@
+# Test deeply nested class architectures.
+class Test:
+ var depth = 1
+
+ class Nested:
+ var depth_nested = 10
+
+
+class Test2 extends Test:
+ var depth2 = 2
+
+
+class Test3 extends Test2:
+ var depth3 = 3
+
+
+class Test4 extends Test3:
+ var depth4 = 4
+
+ class Nested2:
+ var depth4_nested = 100
+
+
+func test():
+ print(Test.new().depth)
+ print(Test2.new().depth)
+ print(Test2.new().depth2)
+ print(Test3.new().depth)
+ print(Test3.new().depth3)
+ print(Test4.new().depth)
+ print(Test4.new().depth4)
+ print(Test.Nested.new().depth_nested)
+ print(Test4.Nested2.new().depth4_nested)
diff --git a/modules/gdscript/tests/scripts/parser/features/class_inheritance.out b/modules/gdscript/tests/scripts/parser/features/class_inheritance.out
new file mode 100644
index 0000000000..75bdde3d94
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/class_inheritance.out
@@ -0,0 +1,10 @@
+GDTEST_OK
+1
+1
+2
+1
+3
+1
+4
+10
+100
diff --git a/modules/gdscript/tests/scripts/parser/features/class_name.gd b/modules/gdscript/tests/scripts/parser/features/class_name.gd
new file mode 100644
index 0000000000..8bd188e247
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/class_name.gd
@@ -0,0 +1,5 @@
+class_name HelloWorld
+@icon("res://path/to/optional/icon.svg")
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/features/class_name.out b/modules/gdscript/tests/scripts/parser/features/class_name.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/class_name.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/concatenation.gd b/modules/gdscript/tests/scripts/parser/features/concatenation.gd
new file mode 100644
index 0000000000..e8335c9823
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/concatenation.gd
@@ -0,0 +1,4 @@
+func test():
+ print(20 + 20)
+ print("hello" + "world")
+ print([1, 2] + [3, 4])
diff --git a/modules/gdscript/tests/scripts/parser/features/concatenation.out b/modules/gdscript/tests/scripts/parser/features/concatenation.out
new file mode 100644
index 0000000000..23bff08f49
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/concatenation.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+40
+helloworld
+[1, 2, 3, 4]
diff --git a/modules/gdscript/tests/scripts/parser/features/constants.gd b/modules/gdscript/tests/scripts/parser/features/constants.gd
new file mode 100644
index 0000000000..013c9c074f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/constants.gd
@@ -0,0 +1,11 @@
+func test():
+ const _TEST = 12 + 34 - 56 * 78
+ const _STRING = "yes"
+ const _VECTOR = Vector2(5, 6)
+ const _ARRAY = []
+ const _DICTIONARY = {"this": "dictionary"}
+
+ # Create user constants from built-in constants.
+ const _HELLO = PI + TAU
+ const _INFINITY = INF
+ const _NOT_A_NUMBER = NAN
diff --git a/modules/gdscript/tests/scripts/parser/features/constants.out b/modules/gdscript/tests/scripts/parser/features/constants.out
new file mode 100644
index 0000000000..6093e4a6ca
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/constants.out
@@ -0,0 +1,33 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_TEST' is declared but never used in the block. If this is intended, prefix it with an underscore: '__TEST'
+>> WARNING
+>> Line: 3
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_STRING' is declared but never used in the block. If this is intended, prefix it with an underscore: '__STRING'
+>> WARNING
+>> Line: 4
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_VECTOR' is declared but never used in the block. If this is intended, prefix it with an underscore: '__VECTOR'
+>> WARNING
+>> Line: 5
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_ARRAY' is declared but never used in the block. If this is intended, prefix it with an underscore: '__ARRAY'
+>> WARNING
+>> Line: 6
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_DICTIONARY' is declared but never used in the block. If this is intended, prefix it with an underscore: '__DICTIONARY'
+>> WARNING
+>> Line: 9
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_HELLO' is declared but never used in the block. If this is intended, prefix it with an underscore: '__HELLO'
+>> WARNING
+>> Line: 10
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_INFINITY' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INFINITY'
+>> WARNING
+>> Line: 11
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_NOT_A_NUMBER' is declared but never used in the block. If this is intended, prefix it with an underscore: '__NOT_A_NUMBER'
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary.gd b/modules/gdscript/tests/scripts/parser/features/dictionary.gd
new file mode 100644
index 0000000000..99afe166c7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary.gd
@@ -0,0 +1,37 @@
+func test():
+ # Non-string keys are valid.
+ print({ 12: "world" }[12])
+
+ var contents = {
+ 0: "zero",
+ 0.0: "zero point zero",
+ null: "null",
+ false: "false",
+ []: "empty array",
+ Vector2i(): "zero Vector2i",
+ 15: {
+ 22: {
+ 4: ["nesting", "arrays"],
+ },
+ },
+ }
+
+ print(contents[0.0])
+ # Making sure declaration order doesn't affect things...
+ print({ 0.0: "zero point zero", 0: "zero", null: "null", false: "false", []: "empty array" }[0])
+ print({ 0.0: "zero point zero", 0: "zero", null: "null", false: "false", []: "empty array" }[0.0])
+
+ print(contents[null])
+ print(contents[false])
+ print(contents[[]])
+ print(contents[Vector2i()])
+ print(contents[15])
+ print(contents[15][22])
+ print(contents[15][22][4])
+ print(contents[15][22][4][0])
+ print(contents[15][22][4][1])
+
+ # Currently fails with "invalid get index 'hello' on base Dictionary".
+ # Both syntaxes are valid however.
+ #print({ "hello": "world" }["hello"])
+ #print({ "hello": "world" }.hello)
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary.out b/modules/gdscript/tests/scripts/parser/features/dictionary.out
new file mode 100644
index 0000000000..54083c1afc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary.out
@@ -0,0 +1,14 @@
+GDTEST_OK
+world
+zero point zero
+zero
+zero point zero
+null
+false
+empty array
+zero Vector2i
+{22:{4:[nesting, arrays]}}
+{4:[nesting, arrays]}
+[nesting, arrays]
+nesting
+arrays
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.gd b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.gd
new file mode 100644
index 0000000000..fdd6de2348
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.gd
@@ -0,0 +1,9 @@
+func test():
+ var lua_dict = {
+ a = 1,
+ "b" = 2, # Using strings are allowed too.
+ "with spaces" = 3, # Especially useful when key has spaces...
+ "2" = 4, # ... or invalid identifiers.
+ }
+
+ print(lua_dict)
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out
new file mode 100644
index 0000000000..447d7e223c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+{2:4, a:1, b:2, with spaces:3}
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.gd b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.gd
new file mode 100644
index 0000000000..cce8538ddd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.gd
@@ -0,0 +1,12 @@
+func test():
+ # Mixing Python-style and Lua-style syntax in the same dictionary declaration
+ # is allowed.
+ var dict = {
+ "hello": {
+ world = {
+ "is": "beautiful",
+ },
+ },
+ }
+
+ print(dict)
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out
new file mode 100644
index 0000000000..62be807a1f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+{hello:{world:{is:beautiful}}}
diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd
new file mode 100644
index 0000000000..8ba558e91d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.gd
@@ -0,0 +1,20 @@
+extends Node
+
+
+func test():
+ # Create the required node structure.
+ var hello = Node.new()
+ hello.name = "Hello"
+ add_child(hello)
+ var world = Node.new()
+ world.name = "World"
+ hello.add_child(world)
+
+ # All the ways of writing node paths below with the `$` operator are valid.
+ # Results are assigned to variables to avoid warnings.
+ var __ = $Hello
+ __ = $"Hello"
+ __ = $Hello/World
+ __ = $"Hello/World"
+ __ = $"Hello/.."
+ __ = $"Hello/../Hello/World"
diff --git a/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.out b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/dollar_node_paths.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/enum.gd b/modules/gdscript/tests/scripts/parser/features/enum.gd
new file mode 100644
index 0000000000..bbc66f6f3d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/enum.gd
@@ -0,0 +1,14 @@
+enum Size {
+ S = -10,
+ M,
+ L = 0,
+ XL = 10,
+ XXL,
+}
+
+func test():
+ print(Size.S)
+ print(Size.M)
+ print(Size.L)
+ print(Size.XL)
+ print(Size.XXL)
diff --git a/modules/gdscript/tests/scripts/parser/features/enum.out b/modules/gdscript/tests/scripts/parser/features/enum.out
new file mode 100644
index 0000000000..6f3a4a3e49
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/enum.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+-10
+-9
+0
+10
+11
diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.gd b/modules/gdscript/tests/scripts/parser/features/export_variable.gd
new file mode 100644
index 0000000000..1e072728fc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/export_variable.gd
@@ -0,0 +1,18 @@
+@export var example = 99
+@export_range(0, 100) var example_range = 100
+@export_range(0, 100, 1) var example_range_step = 101
+@export_range(0, 100, 1, "or_greater") var example_range_step_or_greater = 102
+
+@export var color: Color
+@export_color_no_alpha var color_no_alpha: Color
+@export_node_path(Sprite2D, Sprite3D, Control, Node) var nodepath := ^"hello"
+
+
+func test():
+ print(example)
+ print(example_range)
+ print(example_range_step)
+ print(example_range_step_or_greater)
+ print(color)
+ print(color_no_alpha)
+ print(nodepath)
diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out
new file mode 100644
index 0000000000..bae35e75c6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out
@@ -0,0 +1,8 @@
+GDTEST_OK
+99
+100
+101
+102
+(0, 0, 0, 1)
+(0, 0, 0, 1)
+hello
diff --git a/modules/gdscript/tests/scripts/parser/features/float_notation.gd b/modules/gdscript/tests/scripts/parser/features/float_notation.gd
new file mode 100644
index 0000000000..b207b88820
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/float_notation.gd
@@ -0,0 +1,24 @@
+func test():
+ # The following floating-point notations are all valid:
+ print(is_equal_approx(123., 123))
+ print(is_equal_approx(.123, 0.123))
+ print(is_equal_approx(.123e4, 1230))
+ print(is_equal_approx(123.e4, 1.23e6))
+ print(is_equal_approx(.123e-1, 0.0123))
+ print(is_equal_approx(123.e-1, 12.3))
+
+ # Same as above, but with negative numbers.
+ print(is_equal_approx(-123., -123))
+ print(is_equal_approx(-.123, -0.123))
+ print(is_equal_approx(-.123e4, -1230))
+ print(is_equal_approx(-123.e4, -1.23e6))
+ print(is_equal_approx(-.123e-1, -0.0123))
+ print(is_equal_approx(-123.e-1, -12.3))
+
+ # Same as above, but with explicit positive numbers (which is redundant).
+ print(is_equal_approx(+123., +123))
+ print(is_equal_approx(+.123, +0.123))
+ print(is_equal_approx(+.123e4, +1230))
+ print(is_equal_approx(+123.e4, +1.23e6))
+ print(is_equal_approx(+.123e-1, +0.0123))
+ print(is_equal_approx(+123.e-1, +12.3))
diff --git a/modules/gdscript/tests/scripts/parser/features/float_notation.out b/modules/gdscript/tests/scripts/parser/features/float_notation.out
new file mode 100644
index 0000000000..041c4439b0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/float_notation.out
@@ -0,0 +1,19 @@
+GDTEST_OK
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/parser/features/for_range.gd b/modules/gdscript/tests/scripts/parser/features/for_range.gd
new file mode 100644
index 0000000000..fd1d002b82
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/for_range.gd
@@ -0,0 +1,39 @@
+func test():
+ for i in range(5):
+ print(i)
+
+ print()
+
+ # Equivalent to the above `for` loop:
+ for i in 5:
+ print(i)
+
+ print()
+
+ for i in range(1, 5):
+ print(i)
+
+ print()
+
+ for i in range(1, -5, -1):
+ print(i)
+
+ print()
+
+ for i in [2, 4, 6, -8]:
+ print(i)
+
+ print()
+
+ for i in [true, false]:
+ print(i)
+
+ print()
+
+ for i in [Vector2i(10, 20), Vector2i(-30, -40)]:
+ print(i)
+
+ print()
+
+ for i in "Hello_Unicôde_world!_🦄":
+ print(i)
diff --git a/modules/gdscript/tests/scripts/parser/features/for_range.out b/modules/gdscript/tests/scripts/parser/features/for_range.out
new file mode 100644
index 0000000000..50b2c856c5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/for_range.out
@@ -0,0 +1,58 @@
+GDTEST_OK
+0
+1
+2
+3
+4
+
+0
+1
+2
+3
+4
+
+1
+2
+3
+4
+
+1
+0
+-1
+-2
+-3
+-4
+
+2
+4
+6
+-8
+
+true
+false
+
+(10, 20)
+(-30, -40)
+
+H
+e
+l
+l
+o
+_
+U
+n
+i
+c
+d
+e
+_
+w
+o
+r
+l
+d
+!
+_
+🦄
diff --git a/modules/gdscript/tests/scripts/parser/features/function_default_parameter_type_inference.gd b/modules/gdscript/tests/scripts/parser/features/function_default_parameter_type_inference.gd
new file mode 100644
index 0000000000..f5098b00ae
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/function_default_parameter_type_inference.gd
@@ -0,0 +1,5 @@
+func example(_number: int, _number2: int = 5, number3 := 10):
+ return number3
+
+func test():
+ print(example(3))
diff --git a/modules/gdscript/tests/scripts/parser/features/function_default_parameter_type_inference.out b/modules/gdscript/tests/scripts/parser/features/function_default_parameter_type_inference.out
new file mode 100644
index 0000000000..404cd41fe5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/function_default_parameter_type_inference.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+10
diff --git a/modules/gdscript/tests/scripts/parser/features/function_many_parameters.gd b/modules/gdscript/tests/scripts/parser/features/function_many_parameters.gd
new file mode 100644
index 0000000000..01edb37cec
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/function_many_parameters.gd
@@ -0,0 +1,5 @@
+func example(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48 = false, arg49 = true, arg50 = null):
+ print(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20, arg21, arg22, arg23, arg24, arg25, arg26, arg27, arg28, arg29, arg30, arg31, arg32, arg33, arg34, arg35, arg36, arg37, arg38, arg39, arg40, arg41, arg42, arg43, arg44, arg45, arg46, arg47, arg48, arg49, arg50)
+
+func test():
+ example(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47)
diff --git a/modules/gdscript/tests/scripts/parser/features/function_many_parameters.out b/modules/gdscript/tests/scripts/parser/features/function_many_parameters.out
new file mode 100644
index 0000000000..3a979227d4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/function_many_parameters.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+123456789101112131415161718192212223242526272829303132333435363738394041424344454647falsetruenull
diff --git a/modules/gdscript/tests/scripts/parser/features/in.gd b/modules/gdscript/tests/scripts/parser/features/in.gd
new file mode 100644
index 0000000000..f7296017c5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/in.gd
@@ -0,0 +1,14 @@
+func test():
+ print("dot" in "Godot")
+ print(not "i" in "team")
+
+ print(true in [true, false])
+ print(not null in [true, false])
+ print(null in [null])
+
+ print(26 in [8, 26, 64, 100])
+ print(not Vector2i(10, 20) in [Vector2i(20, 10)])
+
+ print("apple" in { "apple": "fruit" })
+ print("apple" in { "apple": null })
+ print(not "apple" in { "fruit": "apple" })
diff --git a/modules/gdscript/tests/scripts/parser/features/in.out b/modules/gdscript/tests/scripts/parser/features/in.out
new file mode 100644
index 0000000000..7533f6ff54
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/in.out
@@ -0,0 +1,11 @@
+GDTEST_OK
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_callable.gd b/modules/gdscript/tests/scripts/parser/features/lambda_callable.gd
new file mode 100644
index 0000000000..c3b2506156
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_callable.gd
@@ -0,0 +1,4 @@
+func test():
+ var my_lambda = func(x):
+ print(x)
+ my_lambda.call("hello")
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_callable.out b/modules/gdscript/tests/scripts/parser/features/lambda_callable.out
new file mode 100644
index 0000000000..58774d2d3f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_callable.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+hello
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_capture_callable.gd b/modules/gdscript/tests/scripts/parser/features/lambda_capture_callable.gd
new file mode 100644
index 0000000000..f081a0b6a7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_capture_callable.gd
@@ -0,0 +1,4 @@
+func test():
+ var x = 42
+ var my_lambda = func(): print(x)
+ my_lambda.call() # Prints "42".
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_capture_callable.out b/modules/gdscript/tests/scripts/parser/features/lambda_capture_callable.out
new file mode 100644
index 0000000000..0982f3718c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_capture_callable.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+42
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_named_callable.gd b/modules/gdscript/tests/scripts/parser/features/lambda_named_callable.gd
new file mode 100644
index 0000000000..7971ca72a6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_named_callable.gd
@@ -0,0 +1,10 @@
+func i_take_lambda(lambda: Callable, param: String):
+ lambda.call(param)
+
+
+func test():
+ var my_lambda := func this_is_lambda(x):
+ print("Hello")
+ print("This is %s" % x)
+
+ i_take_lambda(my_lambda, "a lambda")
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_named_callable.out b/modules/gdscript/tests/scripts/parser/features/lambda_named_callable.out
new file mode 100644
index 0000000000..c627187d82
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_named_callable.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+Hello
+This is a lambda
diff --git a/modules/gdscript/tests/scripts/parser/features/match.gd b/modules/gdscript/tests/scripts/parser/features/match.gd
new file mode 100644
index 0000000000..4d05490aa5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match.gd
@@ -0,0 +1,18 @@
+func test():
+ var i = "Hello"
+ match i:
+ "Hello":
+ print("hello")
+ # This will fall through to the default case below.
+ continue
+ "Good bye":
+ print("bye")
+ _:
+ print("default")
+
+ var j = 25
+ match j:
+ 26:
+ print("This won't match")
+ _:
+ print("This will match")
diff --git a/modules/gdscript/tests/scripts/parser/features/match.out b/modules/gdscript/tests/scripts/parser/features/match.out
new file mode 100644
index 0000000000..732885c7a2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+hello
+default
+This will match
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_arrays.gd b/modules/gdscript/tests/scripts/parser/features/multiline_arrays.gd
new file mode 100644
index 0000000000..3b30998853
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_arrays.gd
@@ -0,0 +1,7 @@
+func test():
+ var __ = [
+ "this",
+ "is", "a","multiline",
+
+ "array", "with mixed indentation and trailing comma",
+ ]
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_arrays.out b/modules/gdscript/tests/scripts/parser/features/multiline_arrays.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_arrays.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.gd b/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.gd
new file mode 100644
index 0000000000..e108cd23d4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.gd
@@ -0,0 +1,10 @@
+func test():
+ var __ = {
+ "multiline": "dictionary","should": "work",
+ "even with": "a trailing comma",
+ }
+
+ __ = {
+ this_also_applies = "to the",
+ lua_style_syntax = null, foo = null,
+ }
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.out b/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_dictionaries.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_if.gd b/modules/gdscript/tests/scripts/parser/features/multiline_if.gd
new file mode 100644
index 0000000000..86152f4543
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_if.gd
@@ -0,0 +1,14 @@
+func test():
+ # Line breaks are allowed within parentheses.
+ if (
+ 1 == 1
+ and 2 == 2 and
+ 3 == 3
+ ):
+ pass
+
+ # Alternatively, backslashes can be used.
+ if 1 == 1 \
+ and 2 == 2 and \
+ 3 == 3:
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_if.out b/modules/gdscript/tests/scripts/parser/features/multiline_if.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_if.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_strings.gd b/modules/gdscript/tests/scripts/parser/features/multiline_strings.gd
new file mode 100644
index 0000000000..7f5bba85e7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_strings.gd
@@ -0,0 +1,15 @@
+func test():
+ var __ = """
+ This is a standalone string, not a multiline comment.
+ Writing both "double" quotes and 'simple' quotes is fine as
+ long as there is only ""one"" or ''two'' of those in a row, not more.
+
+ If you have more quotes, they need to be escaped like this: \"\"\"
+ """
+ __ = '''
+ Another standalone string, this time with single quotes.
+ Writing both "double" quotes and 'simple' quotes is fine as
+ long as there is only ""one"" or ''two'' of those in a row, not more.
+
+ If you have more quotes, they need to be escaped like this: \'\'\'
+ '''
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_strings.out b/modules/gdscript/tests/scripts/parser/features/multiline_strings.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_strings.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_vector.gd b/modules/gdscript/tests/scripts/parser/features/multiline_vector.gd
new file mode 100644
index 0000000000..11a40fc00e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_vector.gd
@@ -0,0 +1,17 @@
+func test():
+ Vector2(
+ 1,
+ 2
+ )
+
+ Vector3(
+ 3,
+ 3.5,
+ 4, # Trailing comma should work.
+ )
+
+ Vector2i(1, 2,) # Trailing comma should work.
+
+ Vector3i(6,
+ 9,
+ 12)
diff --git a/modules/gdscript/tests/scripts/parser/features/multiline_vector.out b/modules/gdscript/tests/scripts/parser/features/multiline_vector.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/multiline_vector.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.gd b/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.gd
new file mode 100644
index 0000000000..b9bd19c9c5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.gd
@@ -0,0 +1,22 @@
+func test():
+ print(+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++2.718)
+
+ print()
+
+ print(------------------------------------------------------------------2.718)
+ print(-------------------------------------------------------------------2.718)
+
+ print()
+
+ print(~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~999)
+
+ print()
+
+ print(+-+-+-----+------------+++++++---++--++--+--+---+--++2.718)
+
+ print()
+
+ print(2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 2 / 0.444)
+ print(153023902390239 % 550 % 29 % 27 % 23 % 17)
+ print(2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 << 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2 >> 2)
+ print(8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8 ^ -8 ^ 8 ^ 8 ^ 8 ^ 8 ^ 8)
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.out b/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.out
new file mode 100644
index 0000000000..048cfbdfae
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_arithmetic.out
@@ -0,0 +1,82 @@
+GDTEST_OK
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+>> WARNING
+>> Line: 19
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
+2.718
+
+2.718
+-2.718
+
+-1000
+
+-2.718
+
+36900.9009009009
+2
+8192
+-8
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_array.gd b/modules/gdscript/tests/scripts/parser/features/nested_array.gd
new file mode 100644
index 0000000000..3caef96391
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_array.gd
@@ -0,0 +1,5 @@
+func test():
+ var array = [[[[[[[[[[15]]]]]]]]]]
+ print(array[0][0][0][0][0][0][0][0])
+ print(array[0][0][0][0][0][0][0][0][0])
+ print(array[0][0][0][0][0][0][0][0][0][0])
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_array.out b/modules/gdscript/tests/scripts/parser/features/nested_array.out
new file mode 100644
index 0000000000..46c6ce3874
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_array.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+[[15]]
+[15]
+15
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.gd b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.gd
new file mode 100644
index 0000000000..d67e142156
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.gd
@@ -0,0 +1,6 @@
+func test():
+ var dictionary = {1: {2: {3: {4: {5: {6: {7: {8: {"key": "value"}}}}}}}}}
+ print(dictionary[1][2][3][4][5][6][7])
+ print(dictionary[1][2][3][4][5][6][7][8])
+ print(dictionary[1][2][3][4][5][6][7][8].key)
+ print(dictionary[1][2][3][4][5][6][7][8]["key"])
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out
new file mode 100644
index 0000000000..4009160439
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+{8:{key:value}}
+{key:value}
+value
+value
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd b/modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd
new file mode 100644
index 0000000000..59cdc7d6c2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_function_calls.gd
@@ -0,0 +1,5 @@
+func foo(x):
+ return x + 1
+
+func test():
+ print(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(foo(0)))))))))))))))))))))))))
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_function_calls.out b/modules/gdscript/tests/scripts/parser/features/nested_function_calls.out
new file mode 100644
index 0000000000..28a6636a7b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_function_calls.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+24
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_if.gd b/modules/gdscript/tests/scripts/parser/features/nested_if.gd
new file mode 100644
index 0000000000..7282d08497
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_if.gd
@@ -0,0 +1,57 @@
+func test():
+ # 20 levels of nesting (and then some).
+ if true:
+ print("1")
+ if true:
+ print("2")
+ if true:
+ print("3")
+ if true:
+ print("4")
+ if true:
+ print("5")
+ if true:
+ print("6")
+ if true:
+ print("7")
+ if true:
+ print("8")
+ if true:
+ print("9")
+ if true:
+ print("10")
+ if true:
+ print("11")
+ if true:
+ print("12")
+ if true:
+ print("13")
+ if true:
+ print("14")
+ if true:
+ print("15")
+ if true:
+ print("16")
+ if true:
+ print("17")
+ if true:
+ print("18")
+ if true:
+ print("19")
+ if true:
+ print("20")
+ if false:
+ print("End")
+ if true:
+ if true:
+ if true:
+ if true:
+ if true:
+ if true:
+ if true:
+ if true:
+ if true:
+ if true:
+ if true:
+ if true:
+ print("This won't be printed")
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_if.out b/modules/gdscript/tests/scripts/parser/features/nested_if.out
new file mode 100644
index 0000000000..c2d2e29a06
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_if.out
@@ -0,0 +1,21 @@
+GDTEST_OK
+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_match.gd b/modules/gdscript/tests/scripts/parser/features/nested_match.gd
new file mode 100644
index 0000000000..aaddcc7e83
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_match.gd
@@ -0,0 +1,79 @@
+func test():
+ # 20 levels of nesting (and then some).
+ var number = 1234
+ match number:
+ 1234:
+ print("1")
+ match number:
+ 1234:
+ print("2")
+ match number:
+ 1234:
+ print("3")
+ continue
+ _:
+ print("Should also be printed")
+ match number:
+ 1234:
+ print("4")
+ match number:
+ _:
+ print("5")
+ match number:
+ false:
+ print("Should not be printed")
+ true:
+ print("Should not be printed")
+ "hello":
+ print("Should not be printed")
+ 1234:
+ print("6")
+ match number:
+ _:
+ print("7")
+ match number:
+ 1234:
+ print("8")
+ match number:
+ _:
+ print("9")
+ match number:
+ 1234:
+ print("10")
+ match number:
+ _:
+ print("11")
+ match number:
+ 1234:
+ print("12")
+ match number:
+ _:
+ print("13")
+ match number:
+ 1234:
+ print("14")
+ match number:
+ _:
+ print("15")
+ match number:
+ _:
+ print("16")
+ match number:
+ 1234:
+ print("17")
+ match number:
+ _:
+ print("18")
+ match number:
+ 1234:
+ print("19")
+ match number:
+ _:
+ print("20")
+ match number:
+ []:
+ print("Should not be printed")
+ _:
+ print("Should not be printed")
+ 5678:
+ print("Should not be printed either")
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_match.out b/modules/gdscript/tests/scripts/parser/features/nested_match.out
new file mode 100644
index 0000000000..651d76cc59
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_match.out
@@ -0,0 +1,22 @@
+GDTEST_OK
+1
+2
+3
+Should also be printed
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_parentheses.gd b/modules/gdscript/tests/scripts/parser/features/nested_parentheses.gd
new file mode 100644
index 0000000000..3fef73b9be
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_parentheses.gd
@@ -0,0 +1,65 @@
+func test():
+ (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((print("Hello world!"))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+
+ print(((((((((((((((((((((((((((((((((((((((((((((((((((((((((("Hello world 2!"))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
+
+ print(
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (
+ (2)) + ((4))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_parentheses.out b/modules/gdscript/tests/scripts/parser/features/nested_parentheses.out
new file mode 100644
index 0000000000..27221a56bb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/nested_parentheses.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+Hello world!
+Hello world 2!
+6
diff --git a/modules/gdscript/tests/scripts/parser/features/number_separators.gd b/modules/gdscript/tests/scripts/parser/features/number_separators.gd
new file mode 100644
index 0000000000..f5f5661cae
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/number_separators.gd
@@ -0,0 +1,12 @@
+func test():
+ # `_` can be used as a separator for numbers in GDScript.
+ # It can be placed anywhere in the number, except at the beginning.
+ # Currently, GDScript in the `master` branch only allows using one separator
+ # per number.
+ # Results are assigned to variables to avoid warnings.
+ var __ = 1_23
+ __ = 123_ # Trailing number separators are OK.
+ __ = 12_3
+ __ = 123_456
+ __ = 0x1234_5678
+ __ = 0b1001_0101
diff --git a/modules/gdscript/tests/scripts/parser/features/number_separators.out b/modules/gdscript/tests/scripts/parser/features/number_separators.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/number_separators.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/operator_assign.gd b/modules/gdscript/tests/scripts/parser/features/operator_assign.gd
new file mode 100644
index 0000000000..b5f07675ca
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/operator_assign.gd
@@ -0,0 +1,8 @@
+func test():
+ var i = 0
+ i += 5
+ i -= 4
+ i *= 10
+ i %= 8
+ i /= 0.25
+ print(round(i))
diff --git a/modules/gdscript/tests/scripts/parser/features/operator_assign.out b/modules/gdscript/tests/scripts/parser/features/operator_assign.out
new file mode 100644
index 0000000000..b0cb63ef59
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/operator_assign.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+8
diff --git a/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd
new file mode 100644
index 0000000000..9e4b360fb2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.gd
@@ -0,0 +1,37 @@
+# 4.0+ replacement for `setget`:
+var _backing: int = 0
+var property:
+ get:
+ return _backing + 1000
+ set(value):
+ _backing = value - 1000
+
+
+func test():
+ print("Not using self:")
+ print(property)
+ print(_backing)
+ property = 5000
+ print(property)
+ print(_backing)
+ _backing = -50
+ print(property)
+ print(_backing)
+ property = 5000
+ print(property)
+ print(_backing)
+
+ # In Godot 4.0 and later, using `self` no longer makes a difference for
+ # getter/setter execution in GDScript.
+ print("Using self:")
+ print(self.property)
+ print(self._backing)
+ self.property = 5000
+ print(self.property)
+ print(self._backing)
+ self._backing = -50
+ print(self.property)
+ print(self._backing)
+ self.property = 5000
+ print(self.property)
+ print(self._backing)
diff --git a/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out
new file mode 100644
index 0000000000..560e0c3bd7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/property_setter_getter.out
@@ -0,0 +1,19 @@
+GDTEST_OK
+Not using self:
+1000
+0
+5000
+4000
+950
+-50
+5000
+4000
+Using self:
+5000
+4000
+5000
+4000
+950
+-50
+5000
+4000
diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd
index 08f2eedb2d..d50776c25c 100644
--- a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd
+++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.gd
@@ -1,2 +1,5 @@
func test():
- print("A"); print("B")
+ print("A"); print("B")
+
+ # Multiple semicolons and whitespace between them is also valid.
+ print("A"); ;;;;; ; print("B");;
diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out
index fc03f3efe8..bd7f38f516 100644
--- a/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out
+++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_end_statement.out
@@ -1,3 +1,5 @@
GDTEST_OK
A
B
+A
+B
diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.gd b/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.gd
new file mode 100644
index 0000000000..0f4aebb459
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.gd
@@ -0,0 +1,22 @@
+#GDTEST_OK
+
+func test():
+ a();
+ b();
+ c();
+ d();
+ e();
+
+func a(): print("a");
+
+func b(): print("b1"); print("b2")
+
+func c(): print("c1"); print("c2");
+
+func d():
+ print("d1");
+ print("d2")
+
+func e():
+ print("e1");
+ print("e2");
diff --git a/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.out b/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.out
new file mode 100644
index 0000000000..387cbd8fc2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/semicolon_as_terminator.out
@@ -0,0 +1,10 @@
+GDTEST_OK
+a
+b1
+b2
+c1
+c2
+d1
+d2
+e1
+e2
diff --git a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd
new file mode 100644
index 0000000000..9ad98b78a8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd
@@ -0,0 +1,20 @@
+#GDTEST_OK
+
+# No parentheses.
+signal a
+
+# No parameters.
+signal b()
+
+# With paramters.
+signal c(a, b, c)
+
+# With parameters multiline.
+signal d(
+ a,
+ b,
+ c,
+)
+
+func test():
+ print("Ok")
diff --git a/modules/gdscript/tests/scripts/parser/features/signal_declaration.out b/modules/gdscript/tests/scripts/parser/features/signal_declaration.out
new file mode 100644
index 0000000000..0e9f482af4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/signal_declaration.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+Ok
diff --git a/modules/gdscript/tests/scripts/parser/features/single_line_declaration.gd b/modules/gdscript/tests/scripts/parser/features/single_line_declaration.gd
new file mode 100644
index 0000000000..650500663b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/single_line_declaration.gd
@@ -0,0 +1,11 @@
+#GDTEST_OK
+
+func test(): C.new().test("Ok"); test2()
+
+func test2(): print("Ok 2")
+
+class A: pass
+
+class B extends RefCounted: pass
+
+class C extends RefCounted: func test(x): print(x)
diff --git a/modules/gdscript/tests/scripts/parser/features/single_line_declaration.out b/modules/gdscript/tests/scripts/parser/features/single_line_declaration.out
new file mode 100644
index 0000000000..e021923dc2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/single_line_declaration.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+Ok
+Ok 2
diff --git a/modules/gdscript/tests/scripts/parser/features/space_indentation.gd b/modules/gdscript/tests/scripts/parser/features/space_indentation.gd
new file mode 100644
index 0000000000..0a4887c199
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/space_indentation.gd
@@ -0,0 +1,4 @@
+func test():
+ # 2-space indentation should work, even though the GDScript style guide recommends tabs.
+ if true:
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/features/space_indentation.out b/modules/gdscript/tests/scripts/parser/features/space_indentation.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/space_indentation.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/features/static_typing.gd b/modules/gdscript/tests/scripts/parser/features/static_typing.gd
new file mode 100644
index 0000000000..d42632c82d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/static_typing.gd
@@ -0,0 +1,13 @@
+func test():
+ # The following lines are equivalent:
+ var _integer: int = 1
+ var _integer2 : int = 1
+ var _inferred := 1
+ var _inferred2 : = 1
+
+ # Type inference is automatic for constants.
+ const _INTEGER = 1
+ const _INTEGER_REDUNDANT_TYPED : int = 1
+ const _INTEGER_REDUNDANT_TYPED2 : int = 1
+ const _INTEGER_REDUNDANT_INFERRED := 1
+ const _INTEGER_REDUNDANT_INFERRED2 : = 1
diff --git a/modules/gdscript/tests/scripts/parser/features/static_typing.out b/modules/gdscript/tests/scripts/parser/features/static_typing.out
new file mode 100644
index 0000000000..92ce7bc0e0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/static_typing.out
@@ -0,0 +1,21 @@
+GDTEST_OK
+>> WARNING
+>> Line: 9
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_INTEGER' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER'
+>> WARNING
+>> Line: 10
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_INTEGER_REDUNDANT_TYPED' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER_REDUNDANT_TYPED'
+>> WARNING
+>> Line: 11
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_INTEGER_REDUNDANT_TYPED2' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER_REDUNDANT_TYPED2'
+>> WARNING
+>> Line: 12
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_INTEGER_REDUNDANT_INFERRED' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER_REDUNDANT_INFERRED'
+>> WARNING
+>> Line: 13
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant '_INTEGER_REDUNDANT_INFERRED2' is declared but never used in the block. If this is intended, prefix it with an underscore: '__INTEGER_REDUNDANT_INFERRED2'
diff --git a/modules/gdscript/tests/scripts/parser/features/string_formatting.gd b/modules/gdscript/tests/scripts/parser/features/string_formatting.gd
new file mode 100644
index 0000000000..a91837145d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/string_formatting.gd
@@ -0,0 +1,18 @@
+func test():
+ print("hello %s" % "world" == "hello world")
+ print("hello %s" % true == "hello true")
+ print("hello %s" % false == "hello false")
+
+ print("hello %d" % 25 == "hello 25")
+ print("hello %d %d" % [25, 42] == "hello 25 42")
+ # Pad with spaces.
+ print("hello %3d" % 25 == "hello 25")
+ # Pad with zeroes.
+ print("hello %03d" % 25 == "hello 025")
+
+ print("hello %.02f" % 0.123456 == "hello 0.12")
+
+ # Dynamic padding:
+ # <https://docs.godotengine.org/en/stable/getting_started/scripting/gdscript/gdscript_format_string.html#dynamic-padding>
+ print("hello %*.*f" % [7, 3, 0.123456] == "hello 0.123")
+ print("hello %0*.*f" % [7, 3, 0.123456] == "hello 000.123")
diff --git a/modules/gdscript/tests/scripts/parser/features/string_formatting.out b/modules/gdscript/tests/scripts/parser/features/string_formatting.out
new file mode 100644
index 0000000000..7533f6ff54
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/string_formatting.out
@@ -0,0 +1,11 @@
+GDTEST_OK
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/parser/features/super.gd b/modules/gdscript/tests/scripts/parser/features/super.gd
new file mode 100644
index 0000000000..f5ae2a74a7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/super.gd
@@ -0,0 +1,60 @@
+class Say:
+ var prefix = "S"
+
+ func greet():
+ prefix = "S Greeted"
+ print("hello")
+
+ func say(name):
+ print(prefix, " say something ", name)
+
+
+class SayAnotherThing extends Say:
+ # This currently crashes the engine.
+ #var prefix = "SAT"
+
+ func greet():
+ prefix = "SAT Greeted"
+ print("hi")
+
+ func say(name):
+ print(prefix, " say another thing ", name)
+
+
+class SayNothing extends Say:
+ # This currently crashes the engine.
+ #var prefix = "SN"
+
+ func greet():
+ super()
+ prefix = "SN Greeted"
+ print("howdy, see above")
+
+ func greet_prefix_before_super():
+ prefix = "SN Greeted"
+ super.greet()
+ print("howdy, see above")
+
+ func say(name):
+ super(name + " super'd")
+ print(prefix, " say nothing... or not? ", name)
+
+
+func test():
+ var say = Say.new()
+ say.greet()
+ say.say("foo")
+ print()
+
+ var say_another_thing = SayAnotherThing.new()
+ say_another_thing.greet()
+ say_another_thing.say("bar")
+ print()
+
+ var say_nothing = SayNothing.new()
+ say_nothing.greet()
+ print(say_nothing.prefix)
+ say_nothing.greet_prefix_before_super()
+ print(say_nothing.prefix)
+ # This currently triggers a compiler bug: "compiler bug, function name not found"
+ #say_nothing.say("baz")
diff --git a/modules/gdscript/tests/scripts/parser/features/super.out b/modules/gdscript/tests/scripts/parser/features/super.out
new file mode 100644
index 0000000000..e0d4f4f098
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/super.out
@@ -0,0 +1,13 @@
+GDTEST_OK
+hello
+S Greeted say something foo
+
+hi
+SAT Greeted say another thing bar
+
+hello
+howdy, see above
+SN Greeted
+hello
+howdy, see above
+S Greeted
diff --git a/modules/gdscript/tests/scripts/parser/features/truthiness.gd b/modules/gdscript/tests/scripts/parser/features/truthiness.gd
new file mode 100644
index 0000000000..9c67a152f5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/truthiness.gd
@@ -0,0 +1,30 @@
+func test():
+ # The assertions below should all evaluate to `true` for this test to pass.
+ assert(true)
+ assert(not false)
+ assert(500)
+ assert(not 0)
+ assert(500.5)
+ assert(not 0.0)
+ assert("non-empty string")
+ assert(["non-empty array"])
+ assert({"non-empty": "dictionary"})
+ assert(Vector2(1, 0))
+ assert(Vector2i(-1, -1))
+ assert(Vector3(0, 0, 0.0001))
+ assert(Vector3i(0, 0, 10000))
+
+ # Zero position is `true` only if the Rect2's size is non-zero.
+ assert(Rect2(0, 0, 0, 1))
+
+ # Zero size is `true` only if the position is non-zero.
+ assert(Rect2(1, 1, 0, 0))
+
+ # Zero position is `true` only if the Rect2's size is non-zero.
+ assert(Rect2i(0, 0, 0, 1))
+
+ # Zero size is `true` only if the position is non-zero.
+ assert(Rect2i(1, 1, 0, 0))
+
+ # A fully black color is only truthy if its alpha component is not equal to `1`.
+ assert(Color(0, 0, 0, 0.5))
diff --git a/modules/gdscript/tests/scripts/parser/features/truthiness.out b/modules/gdscript/tests/scripts/parser/features/truthiness.out
new file mode 100644
index 0000000000..705524857b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/truthiness.out
@@ -0,0 +1,65 @@
+GDTEST_OK
+>> WARNING
+>> Line: 3
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 4
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 5
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 6
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 7
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 8
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 9
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 12
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 13
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 14
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 15
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 18
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 21
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 24
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 27
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 30
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
diff --git a/modules/gdscript/tests/scripts/parser/features/typed_arrays.gd b/modules/gdscript/tests/scripts/parser/features/typed_arrays.gd
new file mode 100644
index 0000000000..21bf3fdfcf
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/typed_arrays.gd
@@ -0,0 +1,5 @@
+func test():
+ var my_array: Array[int] = [1, 2, 3]
+ var inferred_array := [1, 2, 3] # This is Array[int].
+ print(my_array)
+ print(inferred_array)
diff --git a/modules/gdscript/tests/scripts/parser/features/typed_arrays.out b/modules/gdscript/tests/scripts/parser/features/typed_arrays.out
new file mode 100644
index 0000000000..953d54d5e0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/typed_arrays.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+[1, 2, 3]
+[1, 2, 3]
diff --git a/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd
index 3b48f10ca7..65013c4301 100644
--- a/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd
+++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.gd
@@ -1,12 +1,20 @@
-var a # No init.
-var b = 42 # Init.
+var m1 # No init.
+var m2 = 22 # Init.
+var m3: String # No init, typed.
+var m4: String = "44" # Init, typed.
+
func test():
- var c # No init, local.
- var d = 23 # Init, local.
+ var loc5 # No init, local.
+ var loc6 = 66 # Init, local.
+ var loc7: String # No init, typed.
+ var loc8: String = "88" # Init, typed.
+
+ m1 = 11
+ m3 = "33"
- a = 1
- c = 2
+ loc5 = 55
+ loc7 = "77"
- prints(a, b, c, d)
+ prints(m1, m2, m3, m4, loc5, loc6, loc7, loc8)
print("OK")
diff --git a/modules/gdscript/tests/scripts/parser/features/variable_declaration.out b/modules/gdscript/tests/scripts/parser/features/variable_declaration.out
index 2e0a63c024..7817dd3169 100644
--- a/modules/gdscript/tests/scripts/parser/features/variable_declaration.out
+++ b/modules/gdscript/tests/scripts/parser/features/variable_declaration.out
@@ -1,7 +1,3 @@
GDTEST_OK
->> WARNING
->> Line: 5
->> UNASSIGNED_VARIABLE
->> The variable 'c' was used but never assigned a value.
-1 42 2 23
+11 22 33 44 55 66 77 88
OK
diff --git a/modules/gdscript/tests/scripts/parser/features/while.gd b/modules/gdscript/tests/scripts/parser/features/while.gd
new file mode 100644
index 0000000000..17dd4fbad2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/while.gd
@@ -0,0 +1,5 @@
+func test():
+ var i = 0
+ while i < 5:
+ print(i)
+ i += 1
diff --git a/modules/gdscript/tests/scripts/parser/features/while.out b/modules/gdscript/tests/scripts/parser/features/while.out
new file mode 100644
index 0000000000..b4a50885c7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/while.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+0
+1
+2
+3
+4
diff --git a/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.gd b/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.gd
new file mode 100644
index 0000000000..8feaed899f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.gd
@@ -0,0 +1,5 @@
+func test():
+ # These statements always evaluate to `true`, and therefore emit a warning.
+ assert(true)
+ assert(-1.234)
+ assert(2 + 3 == 5)
diff --git a/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.out b/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.out
new file mode 100644
index 0000000000..5132792cb7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/assert_always_true.out
@@ -0,0 +1,13 @@
+GDTEST_OK
+>> WARNING
+>> Line: 3
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 4
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
+>> WARNING
+>> Line: 5
+>> ASSERT_ALWAYS_TRUE
+>> Assert statement is redundant because the expression is always true.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.gd b/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.gd
new file mode 100644
index 0000000000..f72b10213f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.gd
@@ -0,0 +1,8 @@
+func test():
+ # `and` should be used instead.
+ if true && true:
+ pass
+
+ # `or` should be used instead.
+ if false || true:
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.out b/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/deprecated_operators.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/warnings/empty_file.notest.gd b/modules/gdscript/tests/scripts/parser/warnings/empty_file.notest.gd
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/empty_file.notest.gd
@@ -0,0 +1 @@
+
diff --git a/modules/gdscript/tests/scripts/parser/warnings/empty_file.notest.out b/modules/gdscript/tests/scripts/parser/warnings/empty_file.notest.out
new file mode 100644
index 0000000000..20eec212ba
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/empty_file.notest.out
@@ -0,0 +1,4 @@
+>> WARNING
+>> Line: 1
+>> EMPTY_FILE
+>> Empty script file.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/empty_file_comment.notest.gd b/modules/gdscript/tests/scripts/parser/warnings/empty_file_comment.notest.gd
new file mode 100644
index 0000000000..15cd95ff2b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/empty_file_comment.notest.gd
@@ -0,0 +1 @@
+#a comment
diff --git a/modules/gdscript/tests/scripts/parser/warnings/empty_file_comment.notest.out b/modules/gdscript/tests/scripts/parser/warnings/empty_file_comment.notest.out
new file mode 100644
index 0000000000..20eec212ba
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/empty_file_comment.notest.out
@@ -0,0 +1,4 @@
+>> WARNING
+>> Line: 1
+>> EMPTY_FILE
+>> Empty script file.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline.notest.gd b/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline.notest.gd
new file mode 100644
index 0000000000..b28b04f643
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline.notest.gd
@@ -0,0 +1,3 @@
+
+
+
diff --git a/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline.notest.out b/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline.notest.out
new file mode 100644
index 0000000000..20eec212ba
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline.notest.out
@@ -0,0 +1,4 @@
+>> WARNING
+>> Line: 1
+>> EMPTY_FILE
+>> Empty script file.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment.notest.gd b/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment.notest.gd
new file mode 100644
index 0000000000..ecdba44d21
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment.notest.gd
@@ -0,0 +1,4 @@
+#a comment, followed by a bunch of newlines
+
+
+
diff --git a/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment.notest.out b/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment.notest.out
new file mode 100644
index 0000000000..20eec212ba
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/empty_file_newline_comment.notest.out
@@ -0,0 +1,4 @@
+>> WARNING
+>> Line: 1
+>> EMPTY_FILE
+>> Empty script file.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.gd b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.gd
new file mode 100644
index 0000000000..a93ecb66b1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.gd
@@ -0,0 +1,8 @@
+func test():
+ # The ternary operator below returns values of different types and the
+ # result is assigned to a typed variable. This will cause a run-time error
+ # if the branch with the incompatible type is picked. Here, it won't happen
+ # since the `false` condition never evaluates to `true`. Instead, a warning
+ # will be emitted.
+ var __: int = 25
+ __ = "hello" if false else -2
diff --git a/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out
new file mode 100644
index 0000000000..7d1558c6fc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/incompatible_ternary.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 8
+>> INCOMPATIBLE_TERNARY
+>> Values of the ternary conditional are not mutually compatible.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/integer_division.gd b/modules/gdscript/tests/scripts/parser/warnings/integer_division.gd
new file mode 100644
index 0000000000..6117425528
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/integer_division.gd
@@ -0,0 +1,10 @@
+func test():
+ # This should emit a warning.
+ var __ = 5 / 2
+
+ # These should not emit warnings.
+ __ = float(5) / 2
+ __ = 5 / float(2)
+ __ = 5.0 / 2
+ __ = 5 / 2.0
+ __ = 5.0 / 2.0
diff --git a/modules/gdscript/tests/scripts/parser/warnings/integer_division.out b/modules/gdscript/tests/scripts/parser/warnings/integer_division.out
new file mode 100644
index 0000000000..40eb63ffcb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/integer_division.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 3
+>> INTEGER_DIVISION
+>> Integer division, decimal part will be discarded.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.gd b/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.gd
new file mode 100644
index 0000000000..1eb54059dd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.gd
@@ -0,0 +1,9 @@
+func test():
+ var i = 25
+ # The default branch (`_`) should be at the end of the `match` statement.
+ # Otherwise, a warning will be emitted
+ match i:
+ _:
+ print("default")
+ 25:
+ print("is 25")
diff --git a/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.out b/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.out
new file mode 100644
index 0000000000..8630fab420
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/match_default_not_at_end.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+>> WARNING
+>> Line: 8
+>> UNREACHABLE_PATTERN
+>> Unreachable pattern (pattern after wildcard or bind).
+default
diff --git a/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.gd b/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.gd
new file mode 100644
index 0000000000..954e697145
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.gd
@@ -0,0 +1,5 @@
+func i_accept_ints_only(_i: int):
+ pass
+
+func test():
+ i_accept_ints_only(12.345)
diff --git a/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.out b/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.out
new file mode 100644
index 0000000000..6fb592117b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/narrowing_conversion.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 5
+>> NARROWING_CONVERSION
+>> Narrowing conversion (float is converted to int and loses precision).
diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd
new file mode 100644
index 0000000000..00598e4d50
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.gd
@@ -0,0 +1,6 @@
+func i_return_int() -> int:
+ return 4
+
+
+func test():
+ i_return_int()
diff --git a/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/return_value_discarded.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.gd
new file mode 100644
index 0000000000..d565d38365
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.gd
@@ -0,0 +1,8 @@
+# See also `parser-errors/redefine-class-constant.gd`.
+const TEST = 25
+
+
+func test():
+ # Warning here. This is not an error because a new constant is created,
+ # rather than attempting to set the value of an existing constant.
+ const TEST = 50
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out
new file mode 100644
index 0000000000..9c9417e11d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out
@@ -0,0 +1,9 @@
+GDTEST_OK
+>> WARNING
+>> Line: 8
+>> UNUSED_LOCAL_CONSTANT
+>> The local constant 'TEST' is declared but never used in the block. If this is intended, prefix it with an underscore: '_TEST'
+>> WARNING
+>> Line: 8
+>> SHADOWED_VARIABLE
+>> The local constant "TEST" is shadowing an already-declared constant at line 2.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.gd
new file mode 100644
index 0000000000..66dcf309e8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.gd
@@ -0,0 +1,8 @@
+var foo = 123
+
+
+func test():
+ # Notice the `var` keyword. Without this keyword, no warning would be emitted
+ # because no new variable would be created. Instead, the class variable's value
+ # would be overwritten.
+ var foo = 456
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out
new file mode 100644
index 0000000000..82e467b368
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out
@@ -0,0 +1,9 @@
+GDTEST_OK
+>> WARNING
+>> Line: 8
+>> UNUSED_VARIABLE
+>> The local variable 'foo' is declared but never used in the block. If this is intended, prefix it with an underscore: '_foo'
+>> WARNING
+>> Line: 8
+>> SHADOWED_VARIABLE
+>> The local variable "foo" is shadowing an already-declared variable at line 1.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.gd
new file mode 100644
index 0000000000..2c55d68be8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.gd
@@ -0,0 +1,2 @@
+func test():
+ var test = "This variable has the same name as the test() function."
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out
new file mode 100644
index 0000000000..26ce0465b1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out
@@ -0,0 +1,9 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> UNUSED_VARIABLE
+>> The local variable 'test' is declared but never used in the block. If this is intended, prefix it with an underscore: '_test'
+>> WARNING
+>> Line: 2
+>> SHADOWED_VARIABLE
+>> The local variable "test" is shadowing an already-declared function at line 1.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd
new file mode 100644
index 0000000000..18ea260fa2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.gd
@@ -0,0 +1,9 @@
+func test():
+ # The following statements should all be reported as standalone expressions:
+ "This is a standalone expression"
+ 1234
+ 0.0 + 0.0
+ Color(1, 1, 1)
+ Vector3.ZERO
+ [true, false]
+ float(125)
diff --git a/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out
new file mode 100644
index 0000000000..99ec87438e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/standalone_expression.out
@@ -0,0 +1,21 @@
+GDTEST_OK
+>> WARNING
+>> Line: 3
+>> STANDALONE_EXPRESSION
+>> Standalone expression (the line has no effect).
+>> WARNING
+>> Line: 4
+>> STANDALONE_EXPRESSION
+>> Standalone expression (the line has no effect).
+>> WARNING
+>> Line: 5
+>> STANDALONE_EXPRESSION
+>> Standalone expression (the line has no effect).
+>> WARNING
+>> Line: 7
+>> STANDALONE_EXPRESSION
+>> Standalone expression (the line has no effect).
+>> WARNING
+>> Line: 8
+>> STANDALONE_EXPRESSION
+>> Standalone expression (the line has no effect).
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.gd b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.gd
new file mode 100644
index 0000000000..afb5059eea
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.gd
@@ -0,0 +1,2 @@
+func test():
+ var __
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.out b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.out
new file mode 100644
index 0000000000..cf14502e9a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> UNASSIGNED_VARIABLE
+>> The variable '__' was used but never assigned a value.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.gd b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.gd
new file mode 100644
index 0000000000..d77791f4c5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.gd
@@ -0,0 +1,4 @@
+func test():
+ var __: int
+ # Variable has no set value at this point (even though it's implicitly `0` here).
+ __ += 15
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.out b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.out
new file mode 100644
index 0000000000..ba55a4e0f8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unassigned_variable_op_assign.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 4
+>> UNASSIGNED_VARIABLE_OP_ASSIGN
+>> Using assignment with operation but the variable '__' was not previously assigned a value.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.gd b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.gd
new file mode 100644
index 0000000000..3311f342ab
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.gd
@@ -0,0 +1,7 @@
+func test():
+ var i = 25
+
+ return
+
+ # This will never be run due to the `return` statement above.
+ print(i)
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.out b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.out
new file mode 100644
index 0000000000..9316abd5eb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unreachable_code_after_return.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 7
+>> UNREACHABLE_CODE
+>> Unreachable code (statement after return) in function 'test()'.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_argument.gd b/modules/gdscript/tests/scripts/parser/warnings/unused_argument.gd
new file mode 100644
index 0000000000..e6e24dc6f2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unused_argument.gd
@@ -0,0 +1,12 @@
+# This should emit a warning since the unused argument is not prefixed with an underscore.
+func function_with_unused_argument(p_arg1, p_arg2):
+ print(p_arg1)
+
+
+# This shouldn't emit a warning since the unused argument is prefixed with an underscore.
+func function_with_ignored_unused_argument(p_arg1, _p_arg2):
+ print(p_arg1)
+
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_argument.out b/modules/gdscript/tests/scripts/parser/warnings/unused_argument.out
new file mode 100644
index 0000000000..92f3308f85
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/unused_argument.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> UNUSED_PARAMETER
+>> The parameter 'p_arg2' is never used in the function 'function_with_unused_argument'. If this is intended, prefix it with an underscore: '_p_arg2'
diff --git a/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd
index 68e3bd424f..013a2e4beb 100644
--- a/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd
+++ b/modules/gdscript/tests/scripts/parser/warnings/unused_variable.gd
@@ -1,2 +1,4 @@
func test():
- var unused = "not used"
+ var unused = "not used"
+
+ var _unused = "not used, but no warning since the variable name starts with an underscore"
diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd
new file mode 100644
index 0000000000..b4a42b3e3d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.gd
@@ -0,0 +1,6 @@
+func i_return_void() -> void:
+ return
+
+
+func test():
+ var __ = i_return_void()
diff --git a/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out
new file mode 100644
index 0000000000..84c9598f9a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/void_assignment.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+>> WARNING
+>> Line: 6
+>> VOID_ASSIGNMENT
+>> Assignment operation, but the function 'i_return_void()' returns void.
diff --git a/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd
new file mode 100644
index 0000000000..f6526aefb4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.gd
@@ -0,0 +1,13 @@
+extends Node
+
+func test():
+ process_priority = 10
+ var change = 20
+
+ print(process_priority)
+ print(change)
+
+ process_priority += change
+
+ print(process_priority)
+ print(change)
diff --git a/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out
new file mode 100644
index 0000000000..c9e6b34c77
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/assign_member_with_operation.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+10
+20
+30
+20
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd
new file mode 100644
index 0000000000..c6645c2c34
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd
@@ -0,0 +1,138 @@
+func test():
+ var value
+
+ # null
+ value = null
+ print(value == null)
+
+ # bool
+ value = false
+ print(value == null)
+
+ # int
+ value = 0
+ print(value == null)
+
+ # float
+ value = 0.0
+ print(value == null)
+
+ # String
+ value = ""
+ print(value == null)
+
+ # Vector2
+ value = Vector2()
+ print(value == null)
+
+ # Vector2i
+ value = Vector2i()
+ print(value == null)
+
+ # Rect2
+ value = Rect2()
+ print(value == null)
+
+ # Rect2i
+ value = Rect2i()
+ print(value == null)
+
+ # Vector3
+ value = Vector3()
+ print(value == null)
+
+ # Vector3i
+ value = Vector3i()
+ print(value == null)
+
+ # Transform2D
+ value = Transform2D()
+ print(value == null)
+
+ # Plane
+ value = Plane()
+ print(value == null)
+
+ # Quaternion
+ value = Quaternion()
+ print(value == null)
+
+ # AABB
+ value = AABB()
+ print(value == null)
+
+ # Basis
+ value = Basis()
+ print(value == null)
+
+ # Transform3D
+ value = Transform3D()
+ print(value == null)
+
+ # Color
+ value = Color()
+ print(value == null)
+
+ # StringName
+ value = &""
+ print(value == null)
+
+ # NodePath
+ value = ^""
+ print(value == null)
+
+ # RID
+ value = RID()
+ print(value == null)
+
+ # Callable
+ value = Callable()
+ print(value == null)
+
+ # Signal
+ value = Signal()
+ print(value == null)
+
+ # Dictionary
+ value = {}
+ print(value == null)
+
+ # Array
+ value = []
+ print(value == null)
+
+ # PackedByteArray
+ value = PackedByteArray()
+ print(value == null)
+
+ # PackedInt32Array
+ value = PackedInt32Array()
+ print(value == null)
+
+ # PackedInt64Array
+ value = PackedInt64Array()
+ print(value == null)
+
+ # PackedFloat32Array
+ value = PackedFloat32Array()
+ print(value == null)
+
+ # PackedFloat64Array
+ value = PackedFloat64Array()
+ print(value == null)
+
+ # PackedStringArray
+ value = PackedStringArray()
+ print(value == null)
+
+ # PackedVector2Array
+ value = PackedVector2Array()
+ print(value == null)
+
+ # PackedVector3Array
+ value = PackedVector3Array()
+ print(value == null)
+
+ # PackedColorArray
+ value = PackedColorArray()
+ print(value == null)
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out
new file mode 100644
index 0000000000..639f6027b9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out
@@ -0,0 +1,35 @@
+GDTEST_OK
+true
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd
new file mode 100644
index 0000000000..ee622bf22f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd
@@ -0,0 +1,138 @@
+func test():
+ var value
+
+ # null
+ value = null
+ print(value != null)
+
+ # bool
+ value = false
+ print(value != null)
+
+ # int
+ value = 0
+ print(value != null)
+
+ # float
+ value = 0.0
+ print(value != null)
+
+ # String
+ value = ""
+ print(value != null)
+
+ # Vector2
+ value = Vector2()
+ print(value != null)
+
+ # Vector2i
+ value = Vector2i()
+ print(value != null)
+
+ # Rect2
+ value = Rect2()
+ print(value != null)
+
+ # Rect2i
+ value = Rect2i()
+ print(value != null)
+
+ # Vector3
+ value = Vector3()
+ print(value != null)
+
+ # Vector3i
+ value = Vector3i()
+ print(value != null)
+
+ # Transform2D
+ value = Transform2D()
+ print(value != null)
+
+ # Plane
+ value = Plane()
+ print(value != null)
+
+ # Quaternion
+ value = Quaternion()
+ print(value != null)
+
+ # AABB
+ value = AABB()
+ print(value != null)
+
+ # Basis
+ value = Basis()
+ print(value != null)
+
+ # Transform3D
+ value = Transform3D()
+ print(value != null)
+
+ # Color
+ value = Color()
+ print(value != null)
+
+ # StringName
+ value = &""
+ print(value != null)
+
+ # NodePath
+ value = ^""
+ print(value != null)
+
+ # RID
+ value = RID()
+ print(value != null)
+
+ # Callable
+ value = Callable()
+ print(value != null)
+
+ # Signal
+ value = Signal()
+ print(value != null)
+
+ # Dictionary
+ value = {}
+ print(value != null)
+
+ # Array
+ value = []
+ print(value != null)
+
+ # PackedByteArray
+ value = PackedByteArray()
+ print(value != null)
+
+ # PackedInt32Array
+ value = PackedInt32Array()
+ print(value != null)
+
+ # PackedInt64Array
+ value = PackedInt64Array()
+ print(value != null)
+
+ # PackedFloat32Array
+ value = PackedFloat32Array()
+ print(value != null)
+
+ # PackedFloat64Array
+ value = PackedFloat64Array()
+ print(value != null)
+
+ # PackedStringArray
+ value = PackedStringArray()
+ print(value != null)
+
+ # PackedVector2Array
+ value = PackedVector2Array()
+ print(value != null)
+
+ # PackedVector3Array
+ value = PackedVector3Array()
+ print(value != null)
+
+ # PackedColorArray
+ value = PackedColorArray()
+ print(value != null)
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out
new file mode 100644
index 0000000000..d1e332afba
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out
@@ -0,0 +1,35 @@
+GDTEST_OK
+false
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd b/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd
new file mode 100644
index 0000000000..7649062fda
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd
@@ -0,0 +1,138 @@
+func test():
+ var value
+
+ # null
+ value = null
+ print(null == value)
+
+ # bool
+ value = false
+ print(null == value)
+
+ # int
+ value = 0
+ print(null == value)
+
+ # float
+ value = 0.0
+ print(null == value)
+
+ # String
+ value = ""
+ print(null == value)
+
+ # Vector2
+ value = Vector2()
+ print(null == value)
+
+ # Vector2i
+ value = Vector2i()
+ print(null == value)
+
+ # Rect2
+ value = Rect2()
+ print(null == value)
+
+ # Rect2i
+ value = Rect2i()
+ print(null == value)
+
+ # Vector3
+ value = Vector3()
+ print(null == value)
+
+ # Vector3i
+ value = Vector3i()
+ print(null == value)
+
+ # Transform2D
+ value = Transform2D()
+ print(null == value)
+
+ # Plane
+ value = Plane()
+ print(null == value)
+
+ # Quaternion
+ value = Quaternion()
+ print(null == value)
+
+ # AABB
+ value = AABB()
+ print(null == value)
+
+ # Basis
+ value = Basis()
+ print(null == value)
+
+ # Transform3D
+ value = Transform3D()
+ print(null == value)
+
+ # Color
+ value = Color()
+ print(null == value)
+
+ # StringName
+ value = &""
+ print(null == value)
+
+ # NodePath
+ value = ^""
+ print(null == value)
+
+ # RID
+ value = RID()
+ print(null == value)
+
+ # Callable
+ value = Callable()
+ print(null == value)
+
+ # Signal
+ value = Signal()
+ print(null == value)
+
+ # Dictionary
+ value = {}
+ print(null == value)
+
+ # Array
+ value = []
+ print(null == value)
+
+ # PackedByteArray
+ value = PackedByteArray()
+ print(null == value)
+
+ # PackedInt32Array
+ value = PackedInt32Array()
+ print(null == value)
+
+ # PackedInt64Array
+ value = PackedInt64Array()
+ print(null == value)
+
+ # PackedFloat32Array
+ value = PackedFloat32Array()
+ print(null == value)
+
+ # PackedFloat64Array
+ value = PackedFloat64Array()
+ print(null == value)
+
+ # PackedStringArray
+ value = PackedStringArray()
+ print(null == value)
+
+ # PackedVector2Array
+ value = PackedVector2Array()
+ print(null == value)
+
+ # PackedVector3Array
+ value = PackedVector3Array()
+ print(null == value)
+
+ # PackedColorArray
+ value = PackedColorArray()
+ print(null == value)
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out b/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out
new file mode 100644
index 0000000000..639f6027b9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out
@@ -0,0 +1,35 @@
+GDTEST_OK
+true
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
+false
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd b/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd
new file mode 100644
index 0000000000..8d5f9df1b8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd
@@ -0,0 +1,138 @@
+func test():
+ var value
+
+ # null
+ value = null
+ print(null != value)
+
+ # bool
+ value = false
+ print(null != value)
+
+ # int
+ value = 0
+ print(null != value)
+
+ # float
+ value = 0.0
+ print(null != value)
+
+ # String
+ value = ""
+ print(null != value)
+
+ # Vector2
+ value = Vector2()
+ print(null != value)
+
+ # Vector2i
+ value = Vector2i()
+ print(null != value)
+
+ # Rect2
+ value = Rect2()
+ print(null != value)
+
+ # Rect2i
+ value = Rect2i()
+ print(null != value)
+
+ # Vector3
+ value = Vector3()
+ print(null != value)
+
+ # Vector3i
+ value = Vector3i()
+ print(null != value)
+
+ # Transform2D
+ value = Transform2D()
+ print(null != value)
+
+ # Plane
+ value = Plane()
+ print(null != value)
+
+ # Quaternion
+ value = Quaternion()
+ print(null != value)
+
+ # AABB
+ value = AABB()
+ print(null != value)
+
+ # Basis
+ value = Basis()
+ print(null != value)
+
+ # Transform3D
+ value = Transform3D()
+ print(null != value)
+
+ # Color
+ value = Color()
+ print(null != value)
+
+ # StringName
+ value = &""
+ print(null != value)
+
+ # NodePath
+ value = ^""
+ print(null != value)
+
+ # RID
+ value = RID()
+ print(null != value)
+
+ # Callable
+ value = Callable()
+ print(null != value)
+
+ # Signal
+ value = Signal()
+ print(null != value)
+
+ # Dictionary
+ value = {}
+ print(null != value)
+
+ # Array
+ value = []
+ print(null != value)
+
+ # PackedByteArray
+ value = PackedByteArray()
+ print(null != value)
+
+ # PackedInt32Array
+ value = PackedInt32Array()
+ print(null != value)
+
+ # PackedInt64Array
+ value = PackedInt64Array()
+ print(null != value)
+
+ # PackedFloat32Array
+ value = PackedFloat32Array()
+ print(null != value)
+
+ # PackedFloat64Array
+ value = PackedFloat64Array()
+ print(null != value)
+
+ # PackedStringArray
+ value = PackedStringArray()
+ print(null != value)
+
+ # PackedVector2Array
+ value = PackedVector2Array()
+ print(null != value)
+
+ # PackedVector3Array
+ value = PackedVector3Array()
+ print(null != value)
+
+ # PackedColorArray
+ value = PackedColorArray()
+ print(null != value)
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out b/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out
new file mode 100644
index 0000000000..d1e332afba
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out
@@ -0,0 +1,35 @@
+GDTEST_OK
+false
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/runtime/features/lua_assign.gd b/modules/gdscript/tests/scripts/runtime/features/lua_assign.gd
new file mode 100644
index 0000000000..c9b5f8481e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/lua_assign.gd
@@ -0,0 +1,4 @@
+func test():
+ var dict = {}
+ dict.test = 1
+ print(dict.test)
diff --git a/modules/gdscript/tests/scripts/runtime/features/lua_assign.out b/modules/gdscript/tests/scripts/runtime/features/lua_assign.out
new file mode 100644
index 0000000000..a7f1357bb2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/lua_assign.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+1
diff --git a/modules/gdscript/tests/scripts/runtime/features/property_with_operator_assignment.gd b/modules/gdscript/tests/scripts/runtime/features/property_with_operator_assignment.gd
new file mode 100644
index 0000000000..3eb02816ed
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/property_with_operator_assignment.gd
@@ -0,0 +1,11 @@
+#GDTEST_OK
+var prop : int = 0:
+ get:
+ return prop
+ set(value):
+ prop = value % 7
+
+func test():
+ for i in 7:
+ prop += 1
+ print(prop)
diff --git a/modules/gdscript/tests/scripts/runtime/features/property_with_operator_assignment.out b/modules/gdscript/tests/scripts/runtime/features/property_with_operator_assignment.out
new file mode 100644
index 0000000000..76157853f2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/property_with_operator_assignment.out
@@ -0,0 +1,8 @@
+GDTEST_OK
+1
+2
+3
+4
+5
+6
+0
diff --git a/modules/gdscript/tests/scripts/runtime/features/recursion.gd b/modules/gdscript/tests/scripts/runtime/features/recursion.gd
new file mode 100644
index 0000000000..a35485022e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/recursion.gd
@@ -0,0 +1,19 @@
+func is_prime(number: int, divisor: int = 2) -> bool:
+ print(divisor)
+ if number <= 2:
+ return (number == 2)
+ elif number % divisor == 0:
+ return false
+ elif divisor * divisor > number:
+ return true
+
+ return is_prime(number, divisor + 1)
+
+func test():
+ # Not a prime number.
+ print(is_prime(989))
+
+ print()
+
+ # Largest prime number below 10000.
+ print(is_prime(9973))
diff --git a/modules/gdscript/tests/scripts/runtime/features/recursion.out b/modules/gdscript/tests/scripts/runtime/features/recursion.out
new file mode 100644
index 0000000000..2bd8f24988
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/recursion.out
@@ -0,0 +1,125 @@
+GDTEST_OK
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+false
+
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+true
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.gd b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
new file mode 100644
index 0000000000..de269b92b3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
@@ -0,0 +1,42 @@
+func test():
+ print(true, false)
+ print(-1, 0, 1)
+ print(-1.25, 0.25, 1.25)
+ print("hello world")
+
+ print(Vector2(0.25, 0.25))
+ print(Vector2i(0, 0))
+
+ print(Rect2(0.25, 0.25, 0.5, 0.5))
+ print(Rect2i(0, 0, 0, 0))
+
+ print(Vector3(0.25, 0.25, 0.25))
+ print(Vector3i(0, 0, 0))
+
+ print(Transform2D.IDENTITY)
+ print(Plane(1, 2, 3, 4))
+ print(Quaternion(1, 2, 3, 4))
+ print(AABB(Vector3.ZERO, Vector3.ONE))
+ print(Basis(Vector3(0, 0, 0)))
+ print(Transform3D.IDENTITY)
+
+ print(Color(1, 2, 3, 4))
+ print(StringName("hello"))
+ print(NodePath("hello/world"))
+ var node := Node.new()
+ print(RID(node))
+ print(node.get_name)
+ print(node.property_list_changed)
+ node.free()
+ print({"hello":123})
+ print(["hello", 123])
+
+ print(PackedByteArray([-1, 0, 1]))
+ print(PackedInt32Array([-1, 0, 1]))
+ print(PackedInt64Array([-1, 0, 1]))
+ print(PackedFloat32Array([-1, 0, 1]))
+ print(PackedFloat64Array([-1, 0, 1]))
+ print(PackedStringArray(["hello", "world"]))
+ print(PackedVector2Array([Vector2.ONE, Vector2.ZERO]))
+ print(PackedVector3Array([Vector3.ONE, Vector3.ZERO]))
+ print(PackedColorArray([Color.RED, Color.BLUE, Color.GREEN]))
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out
new file mode 100644
index 0000000000..7670fc0128
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out
@@ -0,0 +1,34 @@
+GDTEST_OK
+truefalse
+-101
+-1.250.251.25
+hello world
+(0.25, 0.25)
+(0, 0)
+[P: (0.25, 0.25), S: (0.5, 0.5)]
+[P: (0, 0), S: (0, 0)]
+(0.25, 0.25, 0.25)
+(0, 0, 0)
+[X: (1, 0), Y: (0, 1), O: (0, 0)]
+[N: (1, 2, 3), D: 4]
+(1, 2, 3, 4)
+[P: (0, 0, 0), S: (1, 1, 1)]
+[X: (1, 0, 0), Y: (0, 1, 0), Z: (0, 0, 1)]
+[X: (1, 0, 0), Y: (0, 1, 0), Z: (0, 0, 1), O: (0, 0, 0)]
+(1, 2, 3, 4)
+hello
+hello/world
+RID(0)
+Node::get_name
+Node::[signal]property_list_changed
+{hello:123}
+[hello, 123]
+[255, 0, 1]
+[-1, 0, 1]
+[-1, 0, 1]
+[-1, 0, 1]
+[-1, 0, 1]
+[hello, world]
+[(1, 1), (0, 0)]
+[(1, 1, 1), (0, 0, 0)]
+[(1, 0, 0, 1), (0, 0, 1, 1), (0, 1, 0, 1)]
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index e54f055f2b..80eabc1596 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -172,8 +172,8 @@ static void test_compiler(const String &p_code, const String &p_script_path, con
return;
}
- for (const Map<StringName, GDScriptFunction *>::Element *E = script->get_member_functions().front(); E; E = E->next()) {
- const GDScriptFunction *func = E->value();
+ for (const KeyValue<StringName, GDScriptFunction *> &E : script->get_member_functions()) {
+ const GDScriptFunction *func = E.value;
String signature = "Disassembling " + func->get_name().operator String() + "(";
for (int i = 0; i < func->get_argument_count(); i++) {
diff --git a/modules/glslang/SCsub b/modules/glslang/SCsub
index 182272ffc7..1954a32697 100644
--- a/modules/glslang/SCsub
+++ b/modules/glslang/SCsub
@@ -13,46 +13,47 @@ if env["builtin_glslang"]:
thirdparty_dir = "#thirdparty/glslang/"
thirdparty_sources = [
"glslang/CInterface/glslang_c_interface.cpp",
- "glslang/MachineIndependent/RemoveTree.cpp",
- "glslang/MachineIndependent/ParseHelper.cpp",
- "glslang/MachineIndependent/iomapper.cpp",
- "glslang/MachineIndependent/propagateNoContraction.cpp",
- "glslang/MachineIndependent/Intermediate.cpp",
- "glslang/MachineIndependent/linkValidate.cpp",
"glslang/MachineIndependent/attribute.cpp",
- "glslang/MachineIndependent/Scan.cpp",
- "glslang/MachineIndependent/Initialize.cpp",
"glslang/MachineIndependent/Constant.cpp",
- "glslang/MachineIndependent/reflection.cpp",
+ "glslang/MachineIndependent/glslang_tab.cpp",
+ "glslang/MachineIndependent/InfoSink.cpp",
+ "glslang/MachineIndependent/Initialize.cpp",
+ "glslang/MachineIndependent/Intermediate.cpp",
+ "glslang/MachineIndependent/intermOut.cpp",
+ "glslang/MachineIndependent/IntermTraverse.cpp",
+ "glslang/MachineIndependent/iomapper.cpp",
"glslang/MachineIndependent/limits.cpp",
- "glslang/MachineIndependent/preprocessor/PpScanner.cpp",
- "glslang/MachineIndependent/preprocessor/PpTokens.cpp",
+ "glslang/MachineIndependent/linkValidate.cpp",
+ "glslang/MachineIndependent/parseConst.cpp",
+ "glslang/MachineIndependent/ParseContextBase.cpp",
+ "glslang/MachineIndependent/ParseHelper.cpp",
+ "glslang/MachineIndependent/PoolAlloc.cpp",
"glslang/MachineIndependent/preprocessor/PpAtom.cpp",
"glslang/MachineIndependent/preprocessor/PpContext.cpp",
"glslang/MachineIndependent/preprocessor/Pp.cpp",
- "glslang/MachineIndependent/InfoSink.cpp",
- "glslang/MachineIndependent/intermOut.cpp",
+ "glslang/MachineIndependent/preprocessor/PpScanner.cpp",
+ "glslang/MachineIndependent/preprocessor/PpTokens.cpp",
+ "glslang/MachineIndependent/propagateNoContraction.cpp",
+ "glslang/MachineIndependent/reflection.cpp",
+ "glslang/MachineIndependent/RemoveTree.cpp",
+ "glslang/MachineIndependent/Scan.cpp",
+ "glslang/MachineIndependent/ShaderLang.cpp",
+ "glslang/MachineIndependent/SpirvIntrinsics.cpp",
"glslang/MachineIndependent/SymbolTable.cpp",
- "glslang/MachineIndependent/glslang_tab.cpp",
"glslang/MachineIndependent/Versions.cpp",
- "glslang/MachineIndependent/ShaderLang.cpp",
- "glslang/MachineIndependent/parseConst.cpp",
- "glslang/MachineIndependent/PoolAlloc.cpp",
- "glslang/MachineIndependent/ParseContextBase.cpp",
- "glslang/MachineIndependent/IntermTraverse.cpp",
- "glslang/GenericCodeGen/Link.cpp",
"glslang/GenericCodeGen/CodeGen.cpp",
+ "glslang/GenericCodeGen/Link.cpp",
"OGLCompilersDLL/InitializeDll.cpp",
"SPIRV/CInterface/spirv_c_interface.cpp",
- "SPIRV/InReadableOrder.cpp",
- "SPIRV/GlslangToSpv.cpp",
- "SPIRV/SpvBuilder.cpp",
- "SPIRV/SpvTools.cpp",
"SPIRV/disassemble.cpp",
"SPIRV/doc.cpp",
- "SPIRV/SPVRemapper.cpp",
- "SPIRV/SpvPostProcess.cpp",
+ "SPIRV/GlslangToSpv.cpp",
+ "SPIRV/InReadableOrder.cpp",
"SPIRV/Logger.cpp",
+ "SPIRV/SpvBuilder.cpp",
+ "SPIRV/SpvPostProcess.cpp",
+ "SPIRV/SPVRemapper.cpp",
+ "SPIRV/SpvTools.cpp",
"StandAlone/ResourceLimits.cpp",
]
diff --git a/modules/gltf/config.py b/modules/gltf/config.py
index a4ee871eff..a4736321fa 100644
--- a/modules/gltf/config.py
+++ b/modules/gltf/config.py
@@ -1,5 +1,5 @@
def can_build(env, platform):
- return env["tools"] and not env["disable_3d"]
+ return not env["disable_3d"]
def configure(env):
@@ -22,7 +22,8 @@ def get_doc_classes():
"GLTFSpecGloss",
"GLTFState",
"GLTFTexture",
- "PackedSceneGLTF",
+ "GLTFDocumentExtension",
+ "GLTFDocumentExtensionConvertImporterMesh",
]
diff --git a/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml b/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
index e717b30f73..c85fce7b9d 100644
--- a/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
+++ b/modules/gltf/doc_classes/EditorSceneImporterGLTF.xml
@@ -6,8 +6,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFAccessor.xml b/modules/gltf/doc_classes/GLTFAccessor.xml
index 41a318ce19..ae81cae81a 100644
--- a/modules/gltf/doc_classes/GLTFAccessor.xml
+++ b/modules/gltf/doc_classes/GLTFAccessor.xml
@@ -6,8 +6,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="buffer_view" type="int" setter="set_buffer_view" getter="get_buffer_view" default="0">
</member>
@@ -38,6 +36,4 @@
<member name="type" type="int" setter="set_type" getter="get_type" default="0">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFAnimation.xml b/modules/gltf/doc_classes/GLTFAnimation.xml
index 5c1fa02f11..70480c2b38 100644
--- a/modules/gltf/doc_classes/GLTFAnimation.xml
+++ b/modules/gltf/doc_classes/GLTFAnimation.xml
@@ -6,12 +6,8 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="loop" type="bool" setter="set_loop" getter="get_loop" default="false">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFBufferView.xml b/modules/gltf/doc_classes/GLTFBufferView.xml
index edaad85e0a..f58aa46508 100644
--- a/modules/gltf/doc_classes/GLTFBufferView.xml
+++ b/modules/gltf/doc_classes/GLTFBufferView.xml
@@ -6,8 +6,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="buffer" type="int" setter="set_buffer" getter="get_buffer" default="-1">
</member>
@@ -20,6 +18,4 @@
<member name="indices" type="bool" setter="set_indices" getter="get_indices" default="false">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFCamera.xml b/modules/gltf/doc_classes/GLTFCamera.xml
index 0b95f2c802..3682df5951 100644
--- a/modules/gltf/doc_classes/GLTFCamera.xml
+++ b/modules/gltf/doc_classes/GLTFCamera.xml
@@ -6,18 +6,14 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
- <member name="fov_size" type="float" setter="set_fov_size" getter="get_fov_size" default="75.0">
+ <member name="depth_far" type="float" setter="set_depth_far" getter="get_depth_far" default="4000.0">
</member>
- <member name="perspective" type="bool" setter="set_perspective" getter="get_perspective" default="true">
+ <member name="depth_near" type="float" setter="set_depth_near" getter="get_depth_near" default="0.05">
</member>
- <member name="zfar" type="float" setter="set_zfar" getter="get_zfar" default="4000.0">
+ <member name="fov_size" type="float" setter="set_fov_size" getter="get_fov_size" default="75.0">
</member>
- <member name="znear" type="float" setter="set_znear" getter="get_znear" default="0.05">
+ <member name="perspective" type="bool" setter="set_perspective" getter="get_perspective" default="true">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index 04c40dd752..8d8e25e8b3 100644
--- a/modules/gltf/doc_classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
@@ -7,7 +7,31 @@
<tutorials>
</tutorials>
<methods>
+ <method name="import_scene">
+ <return type="Node" />
+ <argument index="0" name="path" type="String" />
+ <argument index="1" name="flags" type="int" default="0" />
+ <argument index="2" name="bake_fps" type="int" default="30" />
+ <argument index="3" name="state" type="GLTFState" default="null" />
+ <description>
+ Import a scene from glTF2 ".gltf" or ".glb" file.
+ </description>
+ </method>
+ <method name="save_scene">
+ <return type="int" enum="Error" />
+ <argument index="0" name="node" type="Node" />
+ <argument index="1" name="path" type="String" />
+ <argument index="2" name="src_path" type="String" />
+ <argument index="3" name="flags" type="int" default="0" />
+ <argument index="4" name="bake_fps" type="float" default="30" />
+ <argument index="5" name="state" type="GLTFState" default="null" />
+ <description>
+ Save a scene as a glTF2 ".glb" or ".gltf" file.
+ </description>
+ </method>
</methods>
- <constants>
- </constants>
+ <members>
+ <member name="extensions" type="GLTFDocumentExtension[]" setter="set_extensions" getter="get_extensions" default="[]">
+ </member>
+ </members>
</class>
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
new file mode 100644
index 0000000000..390bd3b30b
--- /dev/null
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="GLTFDocumentExtension" inherits="Resource" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="export_post">
+ <return type="int" enum="Error" />
+ <argument index="0" name="document" type="GLTFDocument" />
+ <description>
+ </description>
+ </method>
+ <method name="export_preflight">
+ <return type="int" enum="Error" />
+ <argument index="0" name="document" type="GLTFDocument" />
+ <argument index="1" name="node" type="Node" />
+ <description>
+ </description>
+ </method>
+ <method name="get_export_setting" qualifiers="const">
+ <return type="Variant" />
+ <argument index="0" name="key" type="StringName" />
+ <description>
+ </description>
+ </method>
+ <method name="get_export_setting_keys" qualifiers="const">
+ <return type="Array" />
+ <description>
+ </description>
+ </method>
+ <method name="get_import_setting" qualifiers="const">
+ <return type="Variant" />
+ <argument index="0" name="key" type="StringName" />
+ <description>
+ </description>
+ </method>
+ <method name="get_import_setting_keys" qualifiers="const">
+ <return type="Array" />
+ <description>
+ </description>
+ </method>
+ <method name="import_post">
+ <return type="int" enum="Error" />
+ <argument index="0" name="document" type="GLTFDocument" />
+ <argument index="1" name="node" type="Node" />
+ <description>
+ </description>
+ </method>
+ <method name="import_preflight">
+ <return type="int" enum="Error" />
+ <argument index="0" name="document" type="GLTFDocument" />
+ <description>
+ </description>
+ </method>
+ <method name="set_export_setting">
+ <return type="void" />
+ <argument index="0" name="key" type="StringName" />
+ <argument index="1" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ <method name="set_import_setting">
+ <return type="void" />
+ <argument index="0" name="key" type="StringName" />
+ <argument index="1" name="value" type="Variant" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/modules/gdnative/doc_classes/PacketPeerGDNative.xml b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml
index ea9869cc58..452eec5f4f 100644
--- a/modules/gdnative/doc_classes/PacketPeerGDNative.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtensionConvertImporterMesh.xml
@@ -1,13 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PacketPeerGDNative" inherits="PacketPeer" version="4.0">
+<class name="GLTFDocumentExtensionConvertImporterMesh" inherits="GLTFDocumentExtension" version="4.0">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFLight.xml b/modules/gltf/doc_classes/GLTFLight.xml
index f51d287685..b4f03cd1ed 100644
--- a/modules/gltf/doc_classes/GLTFLight.xml
+++ b/modules/gltf/doc_classes/GLTFLight.xml
@@ -6,22 +6,26 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
- <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(0, 0, 0, 1)">
+ <member name="color" type="Color" setter="set_color" getter="get_color" default="Color(1, 1, 1, 1)">
+ The [Color] of the light. Defaults to white. A black color causes the light to have no effect.
</member>
<member name="inner_cone_angle" type="float" setter="set_inner_cone_angle" getter="get_inner_cone_angle" default="0.0">
+ The inner angle of the cone in a spotlight. Must be less than or equal to the outer cone angle.
+ Within this angle, the light is at full brightness. Between the inner and outer cone angles, there is a transition from full brightness to zero brightness. When creating a Godot [SpotLight3D], the ratio between the inner and outer cone angles is used to calculate the attenuation of the light.
</member>
- <member name="intensity" type="float" setter="set_intensity" getter="get_intensity" default="0.0">
+ <member name="intensity" type="float" setter="set_intensity" getter="get_intensity" default="1.0">
+ The intensity of the light. This is expressed in candelas (lumens per steradian) for point and spot lights, and lux (lumens per m²) for directional lights. When creating a Godot light, this value is converted to a unitless multiplier.
</member>
- <member name="outer_cone_angle" type="float" setter="set_outer_cone_angle" getter="get_outer_cone_angle" default="0.0">
+ <member name="light_type" type="String" setter="set_light_type" getter="get_light_type" default="&quot;&quot;">
+ The type of the light. The values accepted by Godot are "point", "spot", and "directional", which correspond to Godot's [OmniLight3D], [SpotLight3D], and [DirectionalLight3D] respectively.
</member>
- <member name="range" type="float" setter="set_range" getter="get_range" default="0.0">
+ <member name="outer_cone_angle" type="float" setter="set_outer_cone_angle" getter="get_outer_cone_angle" default="0.785398">
+ The outer angle of the cone in a spotlight. Must be greater than or equal to the inner angle.
+ At this angle, the light drops off to zero brightness. Between the inner and outer cone angles, there is a transition from full brightness to zero brightness. If this angle is a half turn, then the spotlight emits in all directions. When creating a Godot [SpotLight3D], the outer cone angle is used as the angle of the spotlight.
</member>
- <member name="type" type="String" setter="set_type" getter="get_type" default="&quot;&quot;">
+ <member name="range" type="float" setter="set_range" getter="get_range" default="inf">
+ The range of the light, beyond which the light has no effect. GLTF lights with no range defined behave like physical lights (which have infinite range). When creating a Godot light, the range is clamped to 4096.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFMesh.xml b/modules/gltf/doc_classes/GLTFMesh.xml
index fd7e4a169e..1e7199d229 100644
--- a/modules/gltf/doc_classes/GLTFMesh.xml
+++ b/modules/gltf/doc_classes/GLTFMesh.xml
@@ -6,14 +6,10 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="blend_weights" type="PackedFloat32Array" setter="set_blend_weights" getter="get_blend_weights" default="PackedFloat32Array()">
</member>
- <member name="mesh" type="EditorSceneImporterMesh" setter="set_mesh" getter="get_mesh">
+ <member name="mesh" type="ImporterMesh" setter="set_mesh" getter="get_mesh">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFNode.xml b/modules/gltf/doc_classes/GLTFNode.xml
index bfbb12df4d..f27965ea07 100644
--- a/modules/gltf/doc_classes/GLTFNode.xml
+++ b/modules/gltf/doc_classes/GLTFNode.xml
@@ -6,8 +6,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="camera" type="int" setter="set_camera" getter="get_camera" default="-1">
</member>
@@ -23,6 +21,8 @@
</member>
<member name="parent" type="int" setter="set_parent" getter="get_parent" default="-1">
</member>
+ <member name="position" type="Vector3" setter="set_position" getter="get_position" default="Vector3(0, 0, 0)">
+ </member>
<member name="rotation" type="Quaternion" setter="set_rotation" getter="get_rotation" default="Quaternion(0, 0, 0, 1)">
</member>
<member name="scale" type="Vector3" setter="set_scale" getter="get_scale" default="Vector3(1, 1, 1)">
@@ -31,11 +31,7 @@
</member>
<member name="skin" type="int" setter="set_skin" getter="get_skin" default="-1">
</member>
- <member name="translation" type="Vector3" setter="set_translation" getter="get_translation" default="Vector3(0, 0, 0)">
- </member>
<member name="xform" type="Transform3D" setter="set_xform" getter="get_xform" default="Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFSkeleton.xml b/modules/gltf/doc_classes/GLTFSkeleton.xml
index 6e83cec252..037c3545a6 100644
--- a/modules/gltf/doc_classes/GLTFSkeleton.xml
+++ b/modules/gltf/doc_classes/GLTFSkeleton.xml
@@ -52,6 +52,4 @@
<member name="roots" type="PackedInt32Array" setter="set_roots" getter="get_roots" default="PackedInt32Array()">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFSkin.xml b/modules/gltf/doc_classes/GLTFSkin.xml
index 107ca960cd..ad4f017584 100644
--- a/modules/gltf/doc_classes/GLTFSkin.xml
+++ b/modules/gltf/doc_classes/GLTFSkin.xml
@@ -57,6 +57,4 @@
<member name="skin_root" type="int" setter="set_skin_root" getter="get_skin_root" default="-1">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFSpecGloss.xml b/modules/gltf/doc_classes/GLTFSpecGloss.xml
index 6e9c419649..6b8f86ed1c 100644
--- a/modules/gltf/doc_classes/GLTFSpecGloss.xml
+++ b/modules/gltf/doc_classes/GLTFSpecGloss.xml
@@ -6,8 +6,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="diffuse_factor" type="Color" setter="set_diffuse_factor" getter="get_diffuse_factor" default="Color(1, 1, 1, 1)">
</member>
@@ -20,6 +18,4 @@
<member name="specular_factor" type="Color" setter="set_specular_factor" getter="get_specular_factor" default="Color(1, 1, 1, 1)">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFState.xml b/modules/gltf/doc_classes/GLTFState.xml
index ae976fc04c..6d03d0ecf8 100644
--- a/modules/gltf/doc_classes/GLTFState.xml
+++ b/modules/gltf/doc_classes/GLTFState.xml
@@ -209,6 +209,4 @@
<member name="use_named_skin_binds" type="bool" setter="set_use_named_skin_binds" getter="get_use_named_skin_binds" default="false">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/GLTFTexture.xml b/modules/gltf/doc_classes/GLTFTexture.xml
index 33bd8fddeb..7c88d2318e 100644
--- a/modules/gltf/doc_classes/GLTFTexture.xml
+++ b/modules/gltf/doc_classes/GLTFTexture.xml
@@ -6,12 +6,8 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="src_image" type="int" setter="set_src_image" getter="get_src_image" default="0">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gltf/doc_classes/PackedSceneGLTF.xml b/modules/gltf/doc_classes/PackedSceneGLTF.xml
deleted file mode 100644
index d0136c6402..0000000000
--- a/modules/gltf/doc_classes/PackedSceneGLTF.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="PackedSceneGLTF" inherits="PackedScene" version="4.0">
- <brief_description>
- </brief_description>
- <description>
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="export_gltf">
- <return type="int" enum="Error" />
- <argument index="0" name="node" type="Node" />
- <argument index="1" name="path" type="String" />
- <argument index="2" name="flags" type="int" default="0" />
- <argument index="3" name="bake_fps" type="float" default="1000.0" />
- <description>
- </description>
- </method>
- <method name="import_gltf_scene">
- <return type="Node" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="flags" type="int" default="0" />
- <argument index="2" name="bake_fps" type="float" default="1000.0" />
- <argument index="3" name="state" type="GLTFState" default="null" />
- <description>
- </description>
- </method>
- <method name="pack_gltf">
- <return type="void" />
- <argument index="0" name="path" type="String" />
- <argument index="1" name="flags" type="int" default="0" />
- <argument index="2" name="bake_fps" type="float" default="1000.0" />
- <argument index="3" name="state" type="GLTFState" default="null" />
- <description>
- </description>
- </method>
- </methods>
- <members>
- <member name="_bundled" type="Dictionary" setter="_set_bundled_scene" getter="_get_bundled_scene" override="true" default="{&quot;conn_count&quot;: 0,&quot;conns&quot;: PackedInt32Array(),&quot;editable_instances&quot;: [],&quot;names&quot;: PackedStringArray(),&quot;node_count&quot;: 0,&quot;node_paths&quot;: [],&quot;nodes&quot;: PackedInt32Array(),&quot;variants&quot;: [],&quot;version&quot;: 2}" />
- </members>
- <constants>
- </constants>
-</class>
diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
index ae080bcc9a..25fda7ef3b 100644
--- a/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
+++ b/modules/gltf/editor_scene_exporter_gltf_plugin.cpp
@@ -28,11 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#if TOOLS_ENABLED
#include "editor_scene_exporter_gltf_plugin.h"
#include "core/config/project_settings.h"
+#include "core/error/error_list.h"
#include "core/object/object.h"
#include "core/templates/vector.h"
#include "editor/editor_file_system.h"
+#include "gltf_document.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/gui/check_box.h"
#include "scene/main/node.h"
@@ -49,7 +52,6 @@ bool SceneExporterGLTFPlugin::has_main_screen() const {
SceneExporterGLTFPlugin::SceneExporterGLTFPlugin(EditorNode *p_node) {
editor = p_node;
- convert_gltf2.instantiate();
file_export_lib = memnew(EditorFileDialog);
editor->get_gui_base()->add_child(file_export_lib);
file_export_lib->connect("file_selected", callable_mp(this, &SceneExporterGLTFPlugin::_gltf2_dialog_action));
@@ -71,8 +73,12 @@ void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) {
return;
}
List<String> deps;
- convert_gltf2->save_scene(root, p_file, p_file, 0, 1000.0f, &deps);
- EditorFileSystem::get_singleton()->scan_changes();
+ Ref<GLTFDocument> doc;
+ doc.instantiate();
+ Error err = doc->save_scene(root, p_file, p_file, 0, 30.0f, Ref<GLTFState>());
+ if (err != OK) {
+ ERR_PRINT(vformat("glTF2 save scene error %s.", itos(err)));
+ }
}
void SceneExporterGLTFPlugin::convert_scene_to_gltf2() {
@@ -81,10 +87,12 @@ void SceneExporterGLTFPlugin::convert_scene_to_gltf2() {
editor->show_accept(TTR("This operation can't be done without a scene."), TTR("OK"));
return;
}
- String filename = String(root->get_filename().get_file().get_basename());
+ String filename = String(root->get_scene_file_path().get_file().get_basename());
if (filename.is_empty()) {
filename = root->get_name();
}
file_export_lib->set_current_file(filename + String(".gltf"));
file_export_lib->popup_centered_ratio();
}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor_scene_exporter_gltf_plugin.h b/modules/gltf/editor_scene_exporter_gltf_plugin.h
index d952894c16..89a8e27053 100644
--- a/modules/gltf/editor_scene_exporter_gltf_plugin.h
+++ b/modules/gltf/editor_scene_exporter_gltf_plugin.h
@@ -31,13 +31,14 @@
#ifndef EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
#define EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
+#if TOOLS_ENABLED
#include "editor/editor_plugin.h"
+
#include "editor_scene_importer_gltf.h"
class SceneExporterGLTFPlugin : public EditorPlugin {
GDCLASS(SceneExporterGLTFPlugin, EditorPlugin);
- Ref<PackedSceneGLTF> convert_gltf2;
EditorNode *editor = nullptr;
EditorFileDialog *file_export_lib = nullptr;
void _gltf2_dialog_action(String p_file);
@@ -48,5 +49,5 @@ public:
bool has_main_screen() const override;
SceneExporterGLTFPlugin(class EditorNode *p_node);
};
-
+#endif // TOOLS_ENABLED
#endif // EDITOR_SCENE_EXPORTER_GLTF_PLUGIN_H
diff --git a/modules/gltf/editor_scene_importer_gltf.cpp b/modules/gltf/editor_scene_importer_gltf.cpp
index eca1c85bf3..25875e7396 100644
--- a/modules/gltf/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor_scene_importer_gltf.cpp
@@ -28,6 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
+#if TOOLS_ENABLED
#include "editor_scene_importer_gltf.h"
#include "gltf_document.h"
@@ -50,9 +51,9 @@ Node *EditorSceneImporterGLTF::import_scene(const String &p_path,
uint32_t p_flags, int p_bake_fps,
List<String> *r_missing_deps,
Error *r_err) {
- Ref<PackedSceneGLTF> importer;
- importer.instantiate();
- return importer->import_scene(p_path, p_flags, p_bake_fps, r_missing_deps, r_err, Ref<GLTFState>());
+ Ref<GLTFDocument> doc;
+ doc.instantiate();
+ return doc->import_scene_gltf(p_path, p_flags, p_bake_fps, Ref<GLTFState>(), r_missing_deps, r_err);
}
Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path,
@@ -61,113 +62,4 @@ Ref<Animation> EditorSceneImporterGLTF::import_animation(const String &p_path,
return Ref<Animation>();
}
-void PackedSceneGLTF::_bind_methods() {
- ClassDB::bind_method(
- D_METHOD("export_gltf", "node", "path", "flags", "bake_fps"),
- &PackedSceneGLTF::export_gltf, DEFVAL(0), DEFVAL(1000.0f));
- ClassDB::bind_method(D_METHOD("pack_gltf", "path", "flags", "bake_fps", "state"),
- &PackedSceneGLTF::pack_gltf, DEFVAL(0), DEFVAL(1000.0f), DEFVAL(Ref<GLTFState>()));
- ClassDB::bind_method(D_METHOD("import_gltf_scene", "path", "flags", "bake_fps", "state"),
- &PackedSceneGLTF::import_gltf_scene, DEFVAL(0), DEFVAL(1000.0f), DEFVAL(Ref<GLTFState>()));
-}
-Node *PackedSceneGLTF::import_gltf_scene(const String &p_path, uint32_t p_flags, float p_bake_fps, Ref<GLTFState> r_state) {
- Error err = FAILED;
- List<String> deps;
- return import_scene(p_path, p_flags, p_bake_fps, &deps, &err, r_state);
-}
-
-Node *PackedSceneGLTF::import_scene(const String &p_path, uint32_t p_flags,
- int p_bake_fps,
- List<String> *r_missing_deps,
- Error *r_err,
- Ref<GLTFState> r_state) {
- if (r_state == Ref<GLTFState>()) {
- r_state.instantiate();
- }
- r_state->use_named_skin_binds =
- p_flags & EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
-
- Ref<GLTFDocument> gltf_document;
- gltf_document.instantiate();
- Error err = gltf_document->parse(r_state, p_path);
- if (r_err) {
- *r_err = err;
- }
- ERR_FAIL_COND_V(err != Error::OK, nullptr);
-
- Node3D *root = memnew(Node3D);
- for (int32_t root_i = 0; root_i < r_state->root_nodes.size(); root_i++) {
- gltf_document->_generate_scene_node(r_state, root, root, r_state->root_nodes[root_i]);
- }
- gltf_document->_process_mesh_instances(r_state, root);
- if (r_state->animations.size()) {
- AnimationPlayer *ap = memnew(AnimationPlayer);
- root->add_child(ap);
- ap->set_owner(root);
- for (int i = 0; i < r_state->animations.size(); i++) {
- gltf_document->_import_animation(r_state, ap, i, p_bake_fps);
- }
- }
-
- return cast_to<Node3D>(root);
-}
-
-void PackedSceneGLTF::pack_gltf(String p_path, int32_t p_flags,
- real_t p_bake_fps, Ref<GLTFState> r_state) {
- Error err = FAILED;
- List<String> deps;
- Node *root = import_scene(p_path, p_flags, p_bake_fps, &deps, &err, r_state);
- ERR_FAIL_COND(err != OK);
- pack(root);
-}
-
-void PackedSceneGLTF::save_scene(Node *p_node, const String &p_path,
- const String &p_src_path, uint32_t p_flags,
- int p_bake_fps, List<String> *r_missing_deps,
- Error *r_err) {
- Error err = FAILED;
- if (r_err) {
- *r_err = err;
- }
- Ref<GLTFDocument> gltf_document;
- gltf_document.instantiate();
- Ref<GLTFState> state;
- state.instantiate();
- err = gltf_document->serialize(state, p_node, p_path);
- if (r_err) {
- *r_err = err;
- }
-}
-
-void PackedSceneGLTF::_build_parent_hierachy(Ref<GLTFState> state) {
- // build the hierarchy
- for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
- for (int j = 0; j < state->nodes[node_i]->children.size(); j++) {
- GLTFNodeIndex child_i = state->nodes[node_i]->children[j];
- ERR_FAIL_INDEX(child_i, state->nodes.size());
- if (state->nodes.write[child_i]->parent != -1) {
- continue;
- }
- state->nodes.write[child_i]->parent = node_i;
- }
- }
-}
-
-Error PackedSceneGLTF::export_gltf(Node *p_root, String p_path,
- int32_t p_flags,
- real_t p_bake_fps) {
- ERR_FAIL_COND_V(!p_root, FAILED);
- List<String> deps;
- Error err;
- String path = p_path;
- int32_t flags = p_flags;
- real_t baked_fps = p_bake_fps;
- Ref<PackedSceneGLTF> exporter;
- exporter.instantiate();
- exporter->save_scene(p_root, path, "", flags, baked_fps, &deps, &err);
- int32_t error_code = err;
- if (error_code != 0) {
- return Error(error_code);
- }
- return OK;
-}
+#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor_scene_importer_gltf.h b/modules/gltf/editor_scene_importer_gltf.h
index 7bc5f594ed..90663612a1 100644
--- a/modules/gltf/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor_scene_importer_gltf.h
@@ -30,51 +30,26 @@
#ifndef EDITOR_SCENE_IMPORTER_GLTF_H
#define EDITOR_SCENE_IMPORTER_GLTF_H
-
+#ifdef TOOLS_ENABLED
#include "gltf_state.h"
+#include "gltf_document_extension.h"
+
#include "editor/import/resource_importer_scene.h"
#include "scene/main/node.h"
#include "scene/resources/packed_scene.h"
class Animation;
-#ifdef TOOLS_ENABLED
class EditorSceneImporterGLTF : public EditorSceneImporter {
GDCLASS(EditorSceneImporterGLTF, EditorSceneImporter);
public:
virtual uint32_t get_import_flags() const override;
virtual void get_extensions(List<String> *r_extensions) const override;
- virtual Node *import_scene(const String &p_path, uint32_t p_flags,
- int p_bake_fps,
- List<String> *r_missing_deps = nullptr,
- Error *r_err = nullptr) override;
+ virtual Node *import_scene(const String &p_path, uint32_t p_flags, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override;
virtual Ref<Animation> import_animation(const String &p_path,
uint32_t p_flags, int p_bake_fps) override;
};
-#endif
-
-class PackedSceneGLTF : public PackedScene {
- GDCLASS(PackedSceneGLTF, PackedScene);
-
-protected:
- static void _bind_methods();
-
-public:
- virtual void save_scene(Node *p_node, const String &p_path, const String &p_src_path,
- uint32_t p_flags, int p_bake_fps,
- List<String> *r_missing_deps, Error *r_err = nullptr);
- virtual void _build_parent_hierachy(Ref<GLTFState> state);
- virtual Error export_gltf(Node *p_root, String p_path, int32_t p_flags = 0,
- real_t p_bake_fps = 1000.0f);
- virtual Node *import_scene(const String &p_path, uint32_t p_flags,
- int p_bake_fps,
- List<String> *r_missing_deps,
- Error *r_err,
- Ref<GLTFState> r_state);
- virtual Node *import_gltf_scene(const String &p_path, uint32_t p_flags, float p_bake_fps, Ref<GLTFState> r_state = Ref<GLTFState>());
- virtual void pack_gltf(String p_path, int32_t p_flags = 0,
- real_t p_bake_fps = 1000.0f, Ref<GLTFState> r_state = Ref<GLTFState>());
-};
+#endif // TOOLS_ENABLED
#endif // EDITOR_SCENE_IMPORTER_GLTF_H
diff --git a/modules/gltf/gltf_accessor.cpp b/modules/gltf/gltf_accessor.cpp
index daeb084916..85cec3fec4 100644
--- a/modules/gltf/gltf_accessor.cpp
+++ b/modules/gltf/gltf_accessor.cpp
@@ -30,6 +30,8 @@
#include "gltf_accessor.h"
+#include "gltf_document_extension.h"
+
void GLTFAccessor::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_buffer_view"), &GLTFAccessor::get_buffer_view);
ClassDB::bind_method(D_METHOD("set_buffer_view", "buffer_view"), &GLTFAccessor::set_buffer_view);
diff --git a/modules/gltf/gltf_accessor.h b/modules/gltf/gltf_accessor.h
index 949a601730..bec511f974 100644
--- a/modules/gltf/gltf_accessor.h
+++ b/modules/gltf/gltf_accessor.h
@@ -32,7 +32,9 @@
#define GLTF_ACCESSOR_H
#include "core/io/resource.h"
+
#include "gltf_document.h"
+#include "gltf_document_extension.h"
struct GLTFAccessor : public Resource {
GDCLASS(GLTFAccessor, Resource);
@@ -44,8 +46,7 @@ private:
int component_type = 0;
bool normalized = false;
int count = 0;
- GLTFDocument::GLTFType
- type = GLTFDocument::TYPE_SCALAR;
+ GLTFDocument::GLTFType type = GLTFDocument::TYPE_SCALAR;
Vector<double> min;
Vector<double> max;
int sparse_count = 0;
diff --git a/modules/gltf/gltf_animation.h b/modules/gltf/gltf_animation.h
index 216d2161c4..be0ed2d4c6 100644
--- a/modules/gltf/gltf_animation.h
+++ b/modules/gltf/gltf_animation.h
@@ -55,7 +55,7 @@ public:
};
struct Track {
- Channel<Vector3> translation_track;
+ Channel<Vector3> position_track;
Channel<Quaternion> rotation_track;
Channel<Vector3> scale_track;
Vector<Channel<float>> weight_tracks;
diff --git a/modules/gltf/gltf_buffer_view.cpp b/modules/gltf/gltf_buffer_view.cpp
index ba38a11c4c..d00e0f040f 100644
--- a/modules/gltf/gltf_buffer_view.cpp
+++ b/modules/gltf/gltf_buffer_view.cpp
@@ -30,6 +30,8 @@
#include "gltf_buffer_view.h"
+#include "gltf_document_extension.h"
+
void GLTFBufferView::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_buffer"), &GLTFBufferView::get_buffer);
ClassDB::bind_method(D_METHOD("set_buffer", "buffer"), &GLTFBufferView::set_buffer);
diff --git a/modules/gltf/gltf_camera.cpp b/modules/gltf/gltf_camera.cpp
index efa7c5d6d7..0f895fb989 100644
--- a/modules/gltf/gltf_camera.cpp
+++ b/modules/gltf/gltf_camera.cpp
@@ -35,13 +35,13 @@ void GLTFCamera::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_perspective", "perspective"), &GLTFCamera::set_perspective);
ClassDB::bind_method(D_METHOD("get_fov_size"), &GLTFCamera::get_fov_size);
ClassDB::bind_method(D_METHOD("set_fov_size", "fov_size"), &GLTFCamera::set_fov_size);
- ClassDB::bind_method(D_METHOD("get_zfar"), &GLTFCamera::get_zfar);
- ClassDB::bind_method(D_METHOD("set_zfar", "zfar"), &GLTFCamera::set_zfar);
- ClassDB::bind_method(D_METHOD("get_znear"), &GLTFCamera::get_znear);
- ClassDB::bind_method(D_METHOD("set_znear", "znear"), &GLTFCamera::set_znear);
+ ClassDB::bind_method(D_METHOD("get_depth_far"), &GLTFCamera::get_depth_far);
+ ClassDB::bind_method(D_METHOD("set_depth_far", "zdepth_far"), &GLTFCamera::set_depth_far);
+ ClassDB::bind_method(D_METHOD("get_depth_near"), &GLTFCamera::get_depth_near);
+ ClassDB::bind_method(D_METHOD("set_depth_near", "zdepth_near"), &GLTFCamera::set_depth_near);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "perspective"), "set_perspective", "get_perspective"); // bool
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fov_size"), "set_fov_size", "get_fov_size"); // float
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "zfar"), "set_zfar", "get_zfar"); // float
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "znear"), "set_znear", "get_znear"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_far"), "set_depth_far", "get_depth_far"); // float
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "depth_near"), "set_depth_near", "get_depth_near"); // float
}
diff --git a/modules/gltf/gltf_camera.h b/modules/gltf/gltf_camera.h
index bf94b80bef..843ff417a4 100644
--- a/modules/gltf/gltf_camera.h
+++ b/modules/gltf/gltf_camera.h
@@ -39,8 +39,8 @@ class GLTFCamera : public Resource {
private:
bool perspective = true;
float fov_size = 75.0;
- float zfar = 4000.0;
- float znear = 0.05;
+ float depth_far = 4000.0;
+ float depth_near = 0.05;
protected:
static void _bind_methods();
@@ -50,9 +50,9 @@ public:
void set_perspective(bool p_val) { perspective = p_val; }
float get_fov_size() const { return fov_size; }
void set_fov_size(float p_val) { fov_size = p_val; }
- float get_zfar() const { return zfar; }
- void set_zfar(float p_val) { zfar = p_val; }
- float get_znear() const { return znear; }
- void set_znear(float p_val) { znear = p_val; }
+ float get_depth_far() const { return depth_far; }
+ void set_depth_far(float p_val) { depth_far = p_val; }
+ float get_depth_near() const { return depth_near; }
+ void set_depth_near(float p_val) { depth_near = p_val; }
};
#endif // GLTF_CAMERA_H
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index ff0579a11c..ba98592600 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -33,6 +33,8 @@
#include "gltf_accessor.h"
#include "gltf_animation.h"
#include "gltf_camera.h"
+#include "gltf_document_extension.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
#include "gltf_light.h"
#include "gltf_mesh.h"
#include "gltf_node.h"
@@ -48,6 +50,8 @@
#include "core/io/file_access.h"
#include "core/io/json.h"
#include "core/math/disjoint_set.h"
+#include "core/math/vector2.h"
+#include "core/variant/dictionary.h"
#include "core/variant/typed_array.h"
#include "core/variant/variant.h"
#include "core/version.h"
@@ -56,11 +60,16 @@
#include "editor/import/resource_importer_scene.h"
#include "scene/2d/node_2d.h"
#include "scene/3d/camera_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/animation/animation_player.h"
+#include "scene/resources/importer_mesh.h"
+#include "scene/resources/mesh.h"
+#include "scene/resources/multimesh.h"
#include "scene/resources/surface_tool.h"
#include "modules/modules_enabled.gen.h"
+
#ifdef MODULE_CSG_ENABLED
#include "modules/csg/csg_shape.h"
#endif // MODULE_CSG_ENABLED
@@ -70,12 +79,16 @@
#include <stdio.h>
#include <stdlib.h>
+#include <cstdint>
#include <limits>
Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String &p_path) {
uint64_t begin_time = OS::get_singleton()->get_ticks_usec();
- _convert_scene_node(state, p_root, p_root, -1, -1);
+ state->skeleton3d_to_gltf_skeleton.clear();
+ state->skin_and_skeleton3d_to_gltf_skin.clear();
+
+ _convert_scene_node(state, p_root, -1, -1);
if (!state->buffers.size()) {
state->buffers.push_back(Vector<uint8_t>());
}
@@ -94,11 +107,7 @@ Error GLTFDocument::serialize(Ref<GLTFState> state, Node *p_root, const String &
if (err != OK) {
return Error::FAILED;
}
- /* STEP 4 CREATE BONE ATTACHMENTS */
- err = _serialize_bone_attachment(state);
- if (err != OK) {
- return Error::FAILED;
- }
+
/* STEP 5 SERIALIZE MESHES (we have enough info now) */
err = _serialize_meshes(state);
if (err != OK) {
@@ -246,30 +255,6 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
return OK;
}
-Error GLTFDocument::_serialize_bone_attachment(Ref<GLTFState> state) {
- for (int skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) {
- for (int attachment_i = 0; attachment_i < state->skeletons[skeleton_i]->bone_attachments.size(); attachment_i++) {
- BoneAttachment3D *bone_attachment = state->skeletons[skeleton_i]->bone_attachments[attachment_i];
- String bone_name = bone_attachment->get_bone_name();
- bone_name = _sanitize_bone_name(bone_name);
- int32_t bone = state->skeletons[skeleton_i]->godot_skeleton->find_bone(bone_name);
- ERR_CONTINUE(bone == -1);
- for (int skin_i = 0; skin_i < state->skins.size(); skin_i++) {
- if (state->skins[skin_i]->skeleton != skeleton_i) {
- continue;
- }
-
- for (int node_i = 0; node_i < bone_attachment->get_child_count(); node_i++) {
- ERR_CONTINUE(bone >= state->skins[skin_i]->joints.size());
- _convert_scene_node(state, bone_attachment->get_child(node_i), bone_attachment->get_owner(), state->skins[skin_i]->joints[bone], 0);
- }
- break;
- }
- }
- }
- return OK;
-}
-
Error GLTFDocument::_parse_glb(const String &p_path, Ref<GLTFState> state) {
Error err;
FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
@@ -426,8 +411,8 @@ Error GLTFDocument::_serialize_nodes(Ref<GLTFState> state) {
node["scale"] = _vec3_to_arr(n->scale);
}
- if (!n->translation.is_equal_approx(Vector3())) {
- node["translation"] = _vec3_to_arr(n->translation);
+ if (!n->position.is_equal_approx(Vector3())) {
+ node["translation"] = _vec3_to_arr(n->position);
}
if (n->children.size()) {
Array children;
@@ -581,7 +566,7 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) {
node->xform = _arr_to_xform(n["matrix"]);
} else {
if (n.has("translation")) {
- node->translation = _arr_to_vec3(n["translation"]);
+ node->position = _arr_to_vec3(n["translation"]);
}
if (n.has("rotation")) {
node->rotation = _arr_to_quaternion(n["rotation"]);
@@ -591,7 +576,7 @@ Error GLTFDocument::_parse_nodes(Ref<GLTFState> state) {
}
node->xform.basis.set_quaternion_scale(node->rotation, node->scale);
- node->xform.origin = node->translation;
+ node->xform.origin = node->position;
}
if (n.has("extensions")) {
@@ -2123,16 +2108,19 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
Array meshes;
for (GLTFMeshIndex gltf_mesh_i = 0; gltf_mesh_i < state->meshes.size(); gltf_mesh_i++) {
print_verbose("glTF: Serializing mesh: " + itos(gltf_mesh_i));
- Ref<EditorSceneImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh();
+ Ref<ImporterMesh> import_mesh = state->meshes.write[gltf_mesh_i]->get_mesh();
if (import_mesh.is_null()) {
continue;
}
Array primitives;
- Array targets;
Dictionary gltf_mesh;
Array target_names;
Array weights;
+ for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
+ target_names.push_back(import_mesh->get_blend_shape_name(morph_i));
+ }
for (int surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) {
+ Array targets;
Dictionary primitive;
Mesh::PrimitiveType primitive_type = import_mesh->get_surface_primitive_type(surface_i);
switch (primitive_type) {
@@ -2170,11 +2158,14 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
}
Array array = import_mesh->get_surface_arrays(surface_i);
+ uint32_t format = import_mesh->get_surface_format(surface_i);
+ int32_t vertex_num = 0;
Dictionary attributes;
{
Vector<Vector3> a = array[Mesh::ARRAY_VERTEX];
ERR_FAIL_COND_V(!a.size(), ERR_INVALID_DATA);
attributes["POSITION"] = _encode_accessor_as_vec3(state, a, true);
+ vertex_num = a.size();
}
{
Vector<real_t> a = array[Mesh::ARRAY_TANGENT];
@@ -2217,6 +2208,58 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
attributes["TEXCOORD_1"] = _encode_accessor_as_vec2(state, a, true);
}
}
+ for (int custom_i = 0; custom_i < 3; custom_i++) {
+ Vector<float> a = array[Mesh::ARRAY_CUSTOM0 + custom_i];
+ if (a.size()) {
+ int num_channels = 4;
+ int custom_shift = Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT + custom_i * Mesh::ARRAY_FORMAT_CUSTOM_BITS;
+ switch ((format >> custom_shift) & Mesh::ARRAY_FORMAT_CUSTOM_MASK) {
+ case Mesh::ARRAY_CUSTOM_R_FLOAT:
+ num_channels = 1;
+ break;
+ case Mesh::ARRAY_CUSTOM_RG_FLOAT:
+ num_channels = 2;
+ break;
+ case Mesh::ARRAY_CUSTOM_RGB_FLOAT:
+ num_channels = 3;
+ break;
+ case Mesh::ARRAY_CUSTOM_RGBA_FLOAT:
+ num_channels = 4;
+ break;
+ }
+ int texcoord_i = 2 + 2 * custom_i;
+ String gltf_texcoord_key;
+ for (int prev_texcoord_i = 0; prev_texcoord_i < texcoord_i; prev_texcoord_i++) {
+ gltf_texcoord_key = vformat("TEXCOORD_%d", prev_texcoord_i);
+ if (!attributes.has(gltf_texcoord_key)) {
+ Vector<Vector2> empty;
+ empty.resize(vertex_num);
+ attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, empty, true);
+ }
+ }
+
+ LocalVector<Vector2> first_channel;
+ first_channel.resize(vertex_num);
+ LocalVector<Vector2> second_channel;
+ second_channel.resize(vertex_num);
+ for (int32_t vert_i = 0; vert_i < vertex_num; vert_i++) {
+ float u = a[vert_i * num_channels + 0];
+ float v = (num_channels == 1 ? 0.0f : a[vert_i * num_channels + 1]);
+ first_channel[vert_i] = Vector2(u, v);
+ u = 0;
+ v = 0;
+ if (num_channels >= 3) {
+ u = a[vert_i * num_channels + 2];
+ v = (num_channels == 3 ? 0.0f : a[vert_i * num_channels + 3]);
+ second_channel[vert_i] = Vector2(u, v);
+ }
+ }
+ gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i);
+ attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, first_channel, true);
+ gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1);
+ attributes[gltf_texcoord_key] = _encode_accessor_as_vec2(state, second_channel, true);
+ }
+ }
{
Vector<Color> a = array[Mesh::ARRAY_COLOR];
if (a.size()) {
@@ -2252,13 +2295,12 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
}
attributes["JOINTS_0"] = _encode_accessor_as_joints(state, attribs, true);
} else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) {
- int32_t vertex_count = vertex_array.size();
Vector<Color> joints_0;
- joints_0.resize(vertex_count);
+ joints_0.resize(vertex_num);
Vector<Color> joints_1;
- joints_1.resize(vertex_count);
+ joints_1.resize(vertex_num);
int32_t weights_8_count = JOINT_GROUP_SIZE * 2;
- for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
+ for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) {
Color joint_0;
joint_0.r = a[vertex_i * weights_8_count + 0];
joint_0.g = a[vertex_i * weights_8_count + 1];
@@ -2280,21 +2322,20 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
const Array &a = array[Mesh::ARRAY_WEIGHTS];
const Vector<Vector3> &vertex_array = array[Mesh::ARRAY_VERTEX];
if ((a.size() / JOINT_GROUP_SIZE) == vertex_array.size()) {
- const int ret_size = a.size() / JOINT_GROUP_SIZE;
+ int32_t vertex_count = vertex_array.size();
Vector<Color> attribs;
- attribs.resize(ret_size);
- for (int i = 0; i < ret_size; i++) {
+ attribs.resize(vertex_count);
+ for (int i = 0; i < vertex_count; i++) {
attribs.write[i] = Color(a[(i * JOINT_GROUP_SIZE) + 0], a[(i * JOINT_GROUP_SIZE) + 1], a[(i * JOINT_GROUP_SIZE) + 2], a[(i * JOINT_GROUP_SIZE) + 3]);
}
attributes["WEIGHTS_0"] = _encode_accessor_as_weights(state, attribs, true);
} else if ((a.size() / (JOINT_GROUP_SIZE * 2)) >= vertex_array.size()) {
- int32_t vertex_count = vertex_array.size();
Vector<Color> weights_0;
- weights_0.resize(vertex_count);
+ weights_0.resize(vertex_num);
Vector<Color> weights_1;
- weights_1.resize(vertex_count);
+ weights_1.resize(vertex_num);
int32_t weights_8_count = JOINT_GROUP_SIZE * 2;
- for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
+ for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) {
Color weight_0;
weight_0.r = a[vertex_i * weights_8_count + 0];
weight_0.g = a[vertex_i * weights_8_count + 1];
@@ -2354,7 +2395,6 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
ArrayMesh::BlendShapeMode shape_mode = import_mesh->get_blend_shape_mode();
for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
Array array_morph = import_mesh->get_surface_blend_shape_arrays(surface_i, morph_i);
- target_names.push_back(import_mesh->get_blend_shape_name(morph_i));
Dictionary t;
Vector<Vector3> varr = array_morph[Mesh::ARRAY_VERTEX];
Array mesh_arrays = import_mesh->get_surface_arrays(surface_i);
@@ -2371,22 +2411,21 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
}
Vector<Vector3> narr = array_morph[Mesh::ARRAY_NORMAL];
- if (varr.size()) {
+ if (narr.size()) {
t["NORMAL"] = _encode_accessor_as_vec3(state, narr, true);
}
Vector<real_t> tarr = array_morph[Mesh::ARRAY_TANGENT];
if (tarr.size()) {
const int ret_size = tarr.size() / 4;
- Vector<Color> attribs;
+ Vector<Vector3> attribs;
attribs.resize(ret_size);
for (int i = 0; i < ret_size; i++) {
- Color tangent;
- tangent.r = tarr[(i * 4) + 0];
- tangent.g = tarr[(i * 4) + 1];
- tangent.b = tarr[(i * 4) + 2];
- tangent.a = tarr[(i * 4) + 3];
+ Vector3 vec3;
+ vec3.x = tarr[(i * 4) + 0];
+ vec3.y = tarr[(i * 4) + 1];
+ vec3.z = tarr[(i * 4) + 2];
}
- t["TANGENT"] = _encode_accessor_as_color(state, attribs, true);
+ t["TANGENT"] = _encode_accessor_as_vec3(state, attribs, true);
}
targets.push_back(t);
}
@@ -2415,12 +2454,13 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
Dictionary e;
e["targetNames"] = target_names;
- for (int j = 0; j < target_names.size(); j++) {
+ weights.resize(target_names.size());
+ for (int name_i = 0; name_i < target_names.size(); name_i++) {
real_t weight = 0.0;
- if (j < state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) {
- weight = state->meshes.write[gltf_mesh_i]->get_blend_weights()[j];
+ if (name_i < state->meshes.write[gltf_mesh_i]->get_blend_weights().size()) {
+ weight = state->meshes.write[gltf_mesh_i]->get_blend_weights()[name_i];
}
- weights.push_back(weight);
+ weights[name_i] = weight;
}
if (weights.size()) {
gltf_mesh["weights"] = weights;
@@ -2458,8 +2498,9 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
ERR_FAIL_COND_V(!d.has("primitives"), ERR_PARSE_ERROR);
Array primitives = d["primitives"];
- const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] : Dictionary();
- Ref<EditorSceneImporterMesh> import_mesh;
+ const Dictionary &extras = d.has("extras") ? (Dictionary)d["extras"] :
+ Dictionary();
+ Ref<ImporterMesh> import_mesh;
import_mesh.instantiate();
String mesh_name = "mesh";
if (d.has("name") && !String(d["name"]).is_empty()) {
@@ -2468,6 +2509,7 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
import_mesh->set_name(_gen_unique_name(state, vformat("%s_%s", state->scene_name, mesh_name)));
for (int j = 0; j < primitives.size(); j++) {
+ uint32_t flags = 0;
Dictionary p = primitives[j];
Array array;
@@ -2499,8 +2541,11 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
ERR_FAIL_COND_V(!a.has("POSITION"), ERR_PARSE_ERROR);
+ int32_t vertex_num = 0;
if (a.has("POSITION")) {
- array[Mesh::ARRAY_VERTEX] = _decode_accessor_as_vec3(state, a["POSITION"], true);
+ PackedVector3Array vertices = _decode_accessor_as_vec3(state, a["POSITION"], true);
+ array[Mesh::ARRAY_VERTEX] = vertices;
+ vertex_num = vertices.size();
}
if (a.has("NORMAL")) {
array[Mesh::ARRAY_NORMAL] = _decode_accessor_as_vec3(state, a["NORMAL"], true);
@@ -2514,6 +2559,60 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
if (a.has("TEXCOORD_1")) {
array[Mesh::ARRAY_TEX_UV2] = _decode_accessor_as_vec2(state, a["TEXCOORD_1"], true);
}
+ for (int custom_i = 0; custom_i < 3; custom_i++) {
+ Vector<float> cur_custom;
+ Vector<Vector2> texcoord_first;
+ Vector<Vector2> texcoord_second;
+
+ int texcoord_i = 2 + 2 * custom_i;
+ String gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i);
+ int num_channels = 0;
+ if (a.has(gltf_texcoord_key)) {
+ texcoord_first = _decode_accessor_as_vec2(state, a[gltf_texcoord_key], true);
+ num_channels = 2;
+ }
+ gltf_texcoord_key = vformat("TEXCOORD_%d", texcoord_i + 1);
+ if (a.has(gltf_texcoord_key)) {
+ texcoord_second = _decode_accessor_as_vec2(state, a[gltf_texcoord_key], true);
+ num_channels = 4;
+ }
+ if (!num_channels) {
+ break;
+ }
+ if (num_channels == 2 || num_channels == 4) {
+ cur_custom.resize(vertex_num * num_channels);
+ for (int32_t uv_i = 0; uv_i < texcoord_first.size() && uv_i < vertex_num; uv_i++) {
+ cur_custom.write[uv_i * num_channels + 0] = texcoord_first[uv_i].x;
+ cur_custom.write[uv_i * num_channels + 1] = texcoord_first[uv_i].y;
+ }
+ // Vector.resize seems to not zero-initialize. Ensure all unused elements are 0:
+ for (int32_t uv_i = texcoord_first.size(); uv_i < vertex_num; uv_i++) {
+ cur_custom.write[uv_i * num_channels + 0] = 0;
+ cur_custom.write[uv_i * num_channels + 1] = 0;
+ }
+ }
+ if (num_channels == 4) {
+ for (int32_t uv_i = 0; uv_i < texcoord_second.size() && uv_i < vertex_num; uv_i++) {
+ // num_channels must be 4
+ cur_custom.write[uv_i * num_channels + 2] = texcoord_second[uv_i].x;
+ cur_custom.write[uv_i * num_channels + 3] = texcoord_second[uv_i].y;
+ }
+ // Vector.resize seems to not zero-initialize. Ensure all unused elements are 0:
+ for (int32_t uv_i = texcoord_second.size(); uv_i < vertex_num; uv_i++) {
+ cur_custom.write[uv_i * num_channels + 2] = 0;
+ cur_custom.write[uv_i * num_channels + 3] = 0;
+ }
+ }
+ if (cur_custom.size() > 0) {
+ array[Mesh::ARRAY_CUSTOM0 + custom_i] = cur_custom;
+ int custom_shift = Mesh::ARRAY_FORMAT_CUSTOM0_SHIFT + custom_i * Mesh::ARRAY_FORMAT_CUSTOM_BITS;
+ if (num_channels == 2) {
+ flags |= Mesh::ARRAY_CUSTOM_RG_FLOAT << custom_shift;
+ } else {
+ flags |= Mesh::ARRAY_CUSTOM_RGBA_FLOAT << custom_shift;
+ }
+ }
+ }
if (a.has("COLOR_0")) {
array[Mesh::ARRAY_COLOR] = _decode_accessor_as_color(state, a["COLOR_0"], true);
has_vertex_color = true;
@@ -2525,10 +2624,9 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
PackedInt32Array joints_1 = _decode_accessor_as_ints(state, a["JOINTS_1"], true);
ERR_FAIL_COND_V(joints_0.size() != joints_0.size(), ERR_INVALID_DATA);
int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
- int32_t vertex_count = joints_0.size() / JOINT_GROUP_SIZE;
Vector<int> joints;
- joints.resize(vertex_count * weight_8_count);
- for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
+ joints.resize(vertex_num * weight_8_count);
+ for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) {
joints.write[vertex_i * weight_8_count + 0] = joints_0[vertex_i * JOINT_GROUP_SIZE + 0];
joints.write[vertex_i * weight_8_count + 1] = joints_0[vertex_i * JOINT_GROUP_SIZE + 1];
joints.write[vertex_i * weight_8_count + 2] = joints_0[vertex_i * JOINT_GROUP_SIZE + 2];
@@ -2567,9 +2665,8 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
Vector<float> weights;
ERR_FAIL_COND_V(weights_0.size() != weights_1.size(), ERR_INVALID_DATA);
int32_t weight_8_count = JOINT_GROUP_SIZE * 2;
- int32_t vertex_count = weights_0.size() / JOINT_GROUP_SIZE;
- weights.resize(vertex_count * weight_8_count);
- for (int32_t vertex_i = 0; vertex_i < vertex_count; vertex_i++) {
+ weights.resize(vertex_num * weight_8_count);
+ for (int32_t vertex_i = 0; vertex_i < vertex_num; vertex_i++) {
weights.write[vertex_i * weight_8_count + 0] = weights_0[vertex_i * JOINT_GROUP_SIZE + 0];
weights.write[vertex_i * weight_8_count + 1] = weights_0[vertex_i * JOINT_GROUP_SIZE + 1];
weights.write[vertex_i * weight_8_count + 2] = weights_0[vertex_i * JOINT_GROUP_SIZE + 2];
@@ -2642,17 +2739,18 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
bool generate_tangents = (primitive == Mesh::PRIMITIVE_TRIANGLES && !a.has("TANGENT") && a.has("TEXCOORD_0") && a.has("NORMAL"));
+ Ref<SurfaceTool> mesh_surface_tool;
+ mesh_surface_tool.instantiate();
+ mesh_surface_tool->create_from_triangle_arrays(array);
+ if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+ mesh_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
+ }
+ mesh_surface_tool->index();
if (generate_tangents) {
//must generate mikktspace tangents.. ergh..
- Ref<SurfaceTool> st;
- st.instantiate();
- st->create_from_triangle_arrays(array);
- if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
- st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
- }
- st->generate_tangents();
- array = st->commit_to_arrays();
+ mesh_surface_tool->generate_tangents();
}
+ array = mesh_surface_tool->commit_to_arrays();
Array morphs;
//blend shapes
@@ -2682,8 +2780,6 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
array_copy[l] = array[l];
}
- array_copy[Mesh::ARRAY_INDEX] = Variant();
-
if (t.has("POSITION")) {
Vector<Vector3> varr = _decode_accessor_as_vec3(state, t["POSITION"], true);
const Vector<Vector3> src_varr = array[Mesh::ARRAY_VERTEX];
@@ -2762,17 +2858,17 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
array_copy[Mesh::ARRAY_TANGENT] = tangents_v4;
}
+ Ref<SurfaceTool> blend_surface_tool;
+ blend_surface_tool.instantiate();
+ blend_surface_tool->create_from_triangle_arrays(array_copy);
+ if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
+ blend_surface_tool->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
+ }
+ blend_surface_tool->index();
if (generate_tangents) {
- Ref<SurfaceTool> st;
- st.instantiate();
- st->create_from_triangle_arrays(array_copy);
- if (a.has("JOINTS_0") && a.has("JOINTS_1")) {
- st->set_skin_weight_count(SurfaceTool::SKIN_8_WEIGHTS);
- }
- st->deindex();
- st->generate_tangents();
- array_copy = st->commit_to_arrays();
+ blend_surface_tool->generate_tangents();
}
+ array_copy = blend_surface_tool->commit_to_arrays();
morphs.push_back(array_copy);
}
@@ -2785,19 +2881,23 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
const int material = p["material"];
ERR_FAIL_INDEX_V(material, state->materials.size(), ERR_FILE_CORRUPT);
Ref<BaseMaterial3D> mat3d = state->materials[material];
+ ERR_FAIL_NULL_V(mat3d, ERR_FILE_CORRUPT);
if (has_vertex_color) {
mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
}
mat = mat3d;
- } else if (has_vertex_color) {
+ } else {
Ref<StandardMaterial3D> mat3d;
mat3d.instantiate();
- mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ if (has_vertex_color) {
+ mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ }
mat = mat3d;
}
-
- import_mesh->add_surface(primitive, array, morphs, Dictionary(), mat, mat.is_valid() ? mat->get_name() : String());
+ ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT);
+ import_mesh->add_surface(primitive, array, morphs,
+ Dictionary(), mat, mat->get_name(), flags);
}
Vector<float> blend_weights;
@@ -2953,6 +3053,7 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> state, const String &p_base_pat
}
}
} else { // Relative path to an external image file.
+ uri = uri.uri_decode();
uri = p_base_path.plus_file(uri).replace("\\", "/"); // Fix for Windows.
// ResourceLoader will rely on the file extension to use the relevant loader.
// The spec says that if mimeType is defined, it should take precedence (e.g.
@@ -3519,7 +3620,6 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
material->set_cull_mode(BaseMaterial3D::CULL_DISABLED);
}
}
-
if (d.has("alphaMode")) {
const String &am = d["alphaMode"];
if (am == "BLEND") {
@@ -3643,10 +3743,7 @@ void GLTFDocument::spec_gloss_to_metal_base_color(const Color &p_specular_factor
r_base_color.g = Math::lerp(base_color_from_diffuse.g, base_color_from_specular.g, r_metallic * r_metallic);
r_base_color.b = Math::lerp(base_color_from_diffuse.b, base_color_from_specular.b, r_metallic * r_metallic);
r_base_color.a = p_diffuse.a;
- r_base_color.r = CLAMP(r_base_color.r, 0.0f, 1.0f);
- r_base_color.g = CLAMP(r_base_color.g, 0.0f, 1.0f);
- r_base_color.b = CLAMP(r_base_color.b, 0.0f, 1.0f);
- r_base_color.a = CLAMP(r_base_color.a, 0.0f, 1.0f);
+ r_base_color = r_base_color.clamp();
}
GLTFNodeIndex GLTFDocument::_find_highest_node(Ref<GLTFState> state, const Vector<GLTFNodeIndex> &subset) {
@@ -4174,6 +4271,7 @@ Error GLTFDocument::_create_skeletons(Ref<GLTFState> state) {
Skeleton3D *skeleton = memnew(Skeleton3D);
gltf_skeleton->godot_skeleton = skeleton;
+ state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skel_i;
// Make a unique name, no gltf node represents this skeleton
skeleton->set_name(_gen_unique_name(state, "Skeleton3D"));
@@ -4259,6 +4357,16 @@ Error GLTFDocument::_map_skin_joints_indices_to_skeleton_bone_indices(Ref<GLTFSt
Error GLTFDocument::_serialize_skins(Ref<GLTFState> state) {
_remove_duplicate_skins(state);
+ Array json_skins;
+ for (int skin_i = 0; skin_i < state->skins.size(); skin_i++) {
+ Ref<GLTFSkin> gltf_skin = state->skins[skin_i];
+ Dictionary json_skin;
+ json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(state, gltf_skin->inverse_binds, false);
+ json_skin["joints"] = gltf_skin->get_joints();
+ json_skin["name"] = gltf_skin->get_name();
+ json_skins.push_back(json_skin);
+ }
+ state->json["skins"] = json_skins;
return OK;
}
@@ -4356,8 +4464,8 @@ Error GLTFDocument::_serialize_lights(Ref<GLTFState> state) {
color[1] = light->color.g;
color[2] = light->color.b;
d["color"] = color;
- d["type"] = light->type;
- if (light->type == "spot") {
+ d["type"] = light->light_type;
+ if (light->light_type == "spot") {
Dictionary s;
float inner_cone_angle = light->inner_cone_angle;
s["innerConeAngle"] = inner_cone_angle;
@@ -4403,16 +4511,16 @@ Error GLTFDocument::_serialize_cameras(Ref<GLTFState> state) {
Dictionary og;
og["ymag"] = Math::deg2rad(camera->get_fov_size());
og["xmag"] = Math::deg2rad(camera->get_fov_size());
- og["zfar"] = camera->get_zfar();
- og["znear"] = camera->get_znear();
+ og["zfar"] = camera->get_depth_far();
+ og["znear"] = camera->get_depth_near();
d["orthographic"] = og;
d["type"] = "orthographic";
} else if (camera->get_perspective()) {
Dictionary ppt;
// GLTF spec is in radians, Godot's camera is in degrees.
ppt["yfov"] = Math::deg2rad(camera->get_fov_size());
- ppt["zfar"] = camera->get_zfar();
- ppt["znear"] = camera->get_znear();
+ ppt["zfar"] = camera->get_depth_far();
+ ppt["znear"] = camera->get_depth_near();
d["perspective"] = ppt;
d["type"] = "perspective";
}
@@ -4452,7 +4560,7 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
light.instantiate();
ERR_FAIL_COND_V(!d.has("type"), ERR_PARSE_ERROR);
const String &type = d["type"];
- light->type = type;
+ light->light_type = type;
if (d.has("color")) {
const Array &arr = d["color"];
@@ -4503,8 +4611,8 @@ Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) {
const Dictionary &og = d["orthographic"];
// GLTF spec is in radians, Godot's camera is in degrees.
camera->set_fov_size(Math::rad2deg(real_t(og["ymag"])));
- camera->set_zfar(og["zfar"]);
- camera->set_znear(og["znear"]);
+ camera->set_depth_far(og["zfar"]);
+ camera->set_depth_near(og["znear"]);
} else {
camera->set_fov_size(10);
}
@@ -4514,8 +4622,8 @@ Error GLTFDocument::_parse_cameras(Ref<GLTFState> state) {
const Dictionary &ppt = d["perspective"];
// GLTF spec is in radians, Godot's camera is in degrees.
camera->set_fov_size(Math::rad2deg(real_t(ppt["yfov"])));
- camera->set_zfar(ppt["zfar"]);
- camera->set_znear(ppt["znear"]);
+ camera->set_depth_far(ppt["zfar"]);
+ camera->set_depth_near(ppt["znear"]);
} else {
camera->set_fov_size(10);
}
@@ -4574,24 +4682,24 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
Array channels;
Array samplers;
- for (Map<int, GLTFAnimation::Track>::Element *track_i = gltf_animation->get_tracks().front(); track_i; track_i = track_i->next()) {
- GLTFAnimation::Track track = track_i->get();
- if (track.translation_track.times.size()) {
+ for (KeyValue<int, GLTFAnimation::Track> &track_i : gltf_animation->get_tracks()) {
+ GLTFAnimation::Track track = track_i.value;
+ if (track.position_track.times.size()) {
Dictionary t;
t["sampler"] = samplers.size();
Dictionary s;
- s["interpolation"] = interpolation_to_string(track.translation_track.interpolation);
- Vector<real_t> times = Variant(track.translation_track.times);
+ s["interpolation"] = interpolation_to_string(track.position_track.interpolation);
+ Vector<real_t> times = Variant(track.position_track.times);
s["input"] = _encode_accessor_as_floats(state, times, false);
- Vector<Vector3> values = Variant(track.translation_track.values);
+ Vector<Vector3> values = Variant(track.position_track.values);
s["output"] = _encode_accessor_as_vec3(state, values, false);
samplers.push_back(s);
Dictionary target;
target["path"] = "translation";
- target["node"] = track_i->key();
+ target["node"] = track_i.key;
t["target"] = target;
channels.push_back(t);
@@ -4611,7 +4719,7 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
Dictionary target;
target["path"] = "rotation";
- target["node"] = track_i->key();
+ target["node"] = track_i.key;
t["target"] = target;
channels.push_back(t);
@@ -4631,42 +4739,86 @@ Error GLTFDocument::_serialize_animations(Ref<GLTFState> state) {
Dictionary target;
target["path"] = "scale";
- target["node"] = track_i->key();
+ target["node"] = track_i.key;
t["target"] = target;
channels.push_back(t);
}
if (track.weight_tracks.size()) {
+ double length = 0.0f;
+
+ for (int32_t track_idx = 0; track_idx < track.weight_tracks.size(); track_idx++) {
+ int32_t last_time_index = track.weight_tracks[track_idx].times.size() - 1;
+ length = MAX(length, track.weight_tracks[track_idx].times[last_time_index]);
+ }
+
Dictionary t;
t["sampler"] = samplers.size();
Dictionary s;
-
Vector<real_t> times;
- Vector<real_t> values;
+ const double increment = 1.0 / BAKE_FPS;
+ {
+ double time = 0.0;
+ bool last = false;
+ while (true) {
+ times.push_back(time);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= length) {
+ last = true;
+ time = length;
+ }
+ }
+ }
- for (int32_t times_i = 0; times_i < track.weight_tracks[0].times.size(); times_i++) {
- real_t time = track.weight_tracks[0].times[times_i];
- times.push_back(time);
+ for (int32_t track_idx = 0; track_idx < track.weight_tracks.size(); track_idx++) {
+ double time = 0.0;
+ bool last = false;
+ Vector<real_t> weight_track;
+ while (true) {
+ float weight = _interpolate_track<float>(track.weight_tracks[track_idx].times,
+ track.weight_tracks[track_idx].values,
+ time,
+ track.weight_tracks[track_idx].interpolation);
+ weight_track.push_back(weight);
+ if (last) {
+ break;
+ }
+ time += increment;
+ if (time >= length) {
+ last = true;
+ time = length;
+ }
+ }
+ track.weight_tracks.write[track_idx].times = times;
+ track.weight_tracks.write[track_idx].values = weight_track;
}
- values.resize(times.size() * track.weight_tracks.size());
- // TODO Sort by order in blend shapes
+ Vector<real_t> all_track_times = times;
+ Vector<real_t> all_track_values;
+ int32_t values_size = track.weight_tracks[0].values.size();
+ int32_t weight_tracks_size = track.weight_tracks.size();
+ all_track_values.resize(weight_tracks_size * values_size);
for (int k = 0; k < track.weight_tracks.size(); k++) {
Vector<float> wdata = track.weight_tracks[k].values;
for (int l = 0; l < wdata.size(); l++) {
- values.write[l * track.weight_tracks.size() + k] = wdata.write[l];
+ int32_t index = l * weight_tracks_size + k;
+ ERR_BREAK(index >= all_track_values.size());
+ all_track_values.write[index] = wdata.write[l];
}
}
s["interpolation"] = interpolation_to_string(track.weight_tracks[track.weight_tracks.size() - 1].interpolation);
- s["input"] = _encode_accessor_as_floats(state, times, false);
- s["output"] = _encode_accessor_as_floats(state, values, false);
+ s["input"] = _encode_accessor_as_floats(state, all_track_times, false);
+ s["output"] = _encode_accessor_as_floats(state, all_track_values, false);
samplers.push_back(s);
Dictionary target;
target["path"] = "weights";
- target["node"] = track_i->key();
+ target["node"] = track_i.key;
t["target"] = target;
channels.push_back(t);
@@ -4769,10 +4921,10 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
const Vector<float> times = _decode_accessor_as_floats(state, input, false);
if (path == "translation") {
- const Vector<Vector3> translations = _decode_accessor_as_vec3(state, output, false);
- track->translation_track.interpolation = interp;
- track->translation_track.times = Variant(times); //convert via variant
- track->translation_track.values = Variant(translations); //convert via variant
+ const Vector<Vector3> positions = _decode_accessor_as_vec3(state, output, false);
+ track->position_track.interpolation = interp;
+ track->position_track.times = Variant(times); //convert via variant
+ track->position_track.values = Variant(positions); //convert via variant
} else if (path == "rotation") {
const Vector<Quaternion> rotations = _decode_accessor_as_quaternion(state, output, false);
track->rotation_track.interpolation = interp;
@@ -4794,7 +4946,7 @@ Error GLTFDocument::_parse_animations(Ref<GLTFState> state) {
track->weight_tracks.resize(wc);
const int expected_value_count = times.size() * output_count * wc;
- ERR_FAIL_COND_V_MSG(weights.size() != expected_value_count, ERR_PARSE_ERROR, "Invalid weight data, expected " + itos(expected_value_count) + " weight values, got " + itos(weights.size()) + " instead.");
+ ERR_CONTINUE_MSG(weights.size() != expected_value_count, "Invalid weight data, expected " + itos(expected_value_count) + " weight values, got " + itos(weights.size()) + " instead.");
const int wlen = weights.size() / wc;
for (int k = 0; k < wc; k++) { //separate tracks, having them together is not such a good idea
@@ -4859,77 +5011,70 @@ BoneAttachment3D *GLTFDocument::_generate_bone_attachment(Ref<GLTFState> state,
return bone_attachment;
}
-GLTFMeshIndex GLTFDocument::_convert_mesh_instance(Ref<GLTFState> state, MeshInstance3D *p_mesh_instance) {
+GLTFMeshIndex GLTFDocument::_convert_mesh_to_gltf(Ref<GLTFState> state, MeshInstance3D *p_mesh_instance) {
ERR_FAIL_NULL_V(p_mesh_instance, -1);
if (p_mesh_instance->get_mesh().is_null()) {
return -1;
}
- Ref<EditorSceneImporterMesh> import_mesh;
- import_mesh.instantiate();
- Ref<Mesh> godot_mesh = p_mesh_instance->get_mesh();
- if (godot_mesh.is_null()) {
- return -1;
- }
+ Ref<ImporterMesh> current_mesh;
+ current_mesh.instantiate();
Vector<float> blend_weights;
- Vector<String> blend_names;
- int32_t blend_count = godot_mesh->get_blend_shape_count();
- blend_names.resize(blend_count);
- blend_weights.resize(blend_count);
- for (int32_t blend_i = 0; blend_i < godot_mesh->get_blend_shape_count(); blend_i++) {
- String blend_name = godot_mesh->get_blend_shape_name(blend_i);
- blend_names.write[blend_i] = blend_name;
- import_mesh->add_blend_shape(blend_name);
- }
- for (int32_t surface_i = 0; surface_i < godot_mesh->get_surface_count(); surface_i++) {
- Mesh::PrimitiveType primitive_type = godot_mesh->surface_get_primitive_type(surface_i);
- Array arrays = godot_mesh->surface_get_arrays(surface_i);
- Array blend_shape_arrays = godot_mesh->surface_get_blend_shape_arrays(surface_i);
- Ref<Material> mat = godot_mesh->surface_get_material(surface_i);
- Ref<ArrayMesh> godot_array_mesh = godot_mesh;
- String surface_name;
- if (godot_array_mesh.is_valid()) {
- surface_name = godot_array_mesh->surface_get_name(surface_i);
- }
- if (p_mesh_instance->get_surface_override_material(surface_i).is_valid()) {
- mat = p_mesh_instance->get_surface_override_material(surface_i);
- }
- if (p_mesh_instance->get_material_override().is_valid()) {
- mat = p_mesh_instance->get_material_override();
- }
- import_mesh->add_surface(primitive_type, arrays, blend_shape_arrays, Dictionary(), mat, surface_name);
- }
- for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) {
- blend_weights.write[blend_i] = 0.0f;
+ {
+ Ref<Mesh> import_mesh = p_mesh_instance->get_mesh();
+ Ref<ArrayMesh> import_array_mesh = p_mesh_instance->get_mesh();
+ if (import_mesh->get_blend_shape_count()) {
+ ArrayMesh::BlendShapeMode shape_mode = ArrayMesh::BLEND_SHAPE_MODE_NORMALIZED;
+ if (import_array_mesh.is_valid()) {
+ shape_mode = import_array_mesh->get_blend_shape_mode();
+ }
+ current_mesh->set_blend_shape_mode(shape_mode);
+ for (int morph_i = 0; morph_i < import_mesh->get_blend_shape_count(); morph_i++) {
+ current_mesh->add_blend_shape(import_mesh->get_blend_shape_name(morph_i));
+ }
+ }
+ for (int32_t surface_i = 0; surface_i < import_mesh->get_surface_count(); surface_i++) {
+ Array array = import_mesh->surface_get_arrays(surface_i);
+ Ref<Material> mat = import_mesh->surface_get_material(surface_i);
+ String mat_name;
+ if (mat.is_valid()) {
+ mat_name = mat->get_name();
+ }
+ current_mesh->add_surface(import_mesh->surface_get_primitive_type(surface_i),
+ array, import_mesh->surface_get_blend_shape_arrays(surface_i), import_mesh->surface_get_lods(surface_i), mat,
+ mat_name, import_mesh->surface_get_format(surface_i));
+ }
+ int32_t blend_count = import_mesh->get_blend_shape_count();
+ blend_weights.resize(blend_count);
+ for (int32_t blend_i = 0; blend_i < blend_count; blend_i++) {
+ blend_weights.write[blend_i] = 0.0f;
+ }
}
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
- gltf_mesh->set_mesh(import_mesh);
+ gltf_mesh->set_mesh(current_mesh);
gltf_mesh->set_blend_weights(blend_weights);
GLTFMeshIndex mesh_i = state->meshes.size();
state->meshes.push_back(gltf_mesh);
return mesh_i;
}
-EditorSceneImporterMeshNode3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
+ImporterMeshInstance3D *GLTFDocument::_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index) {
Ref<GLTFNode> gltf_node = state->nodes[node_index];
ERR_FAIL_INDEX_V(gltf_node->mesh, state->meshes.size(), nullptr);
- EditorSceneImporterMeshNode3D *mi = memnew(EditorSceneImporterMeshNode3D);
+ ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D);
print_verbose("glTF: Creating mesh for: " + gltf_node->get_name());
Ref<GLTFMesh> mesh = state->meshes.write[gltf_node->mesh];
if (mesh.is_null()) {
return mi;
}
- Ref<EditorSceneImporterMesh> import_mesh = mesh->get_mesh();
+ Ref<ImporterMesh> import_mesh = mesh->get_mesh();
if (import_mesh.is_null()) {
return mi;
}
mi->set_mesh(import_mesh);
- for (int i = 0; i < mesh->get_blend_weights().size(); i++) {
- mi->set("blend_shapes/" + mesh->get_mesh()->get_blend_shape_name(i), mesh->get_blend_weights()[i]);
- }
return mi;
}
@@ -4950,7 +5095,7 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent,
intensity /= 100;
}
- if (l->type == "directional") {
+ if (l->light_type == "directional") {
DirectionalLight3D *light = memnew(DirectionalLight3D);
light->set_param(Light3D::PARAM_ENERGY, intensity);
light->set_color(l->color);
@@ -4960,15 +5105,15 @@ Node3D *GLTFDocument::_generate_light(Ref<GLTFState> state, Node *scene_parent,
const float range = CLAMP(l->range, 0, 4096);
// Doubling the range will double the effective brightness, so we need double attenuation (half brightness).
// We want to have double intensity give double brightness, so we need half the attenuation.
- const float attenuation = range / intensity;
- if (l->type == "point") {
+ const float attenuation = range / (intensity * 2048);
+ if (l->light_type == "point") {
OmniLight3D *light = memnew(OmniLight3D);
light->set_param(OmniLight3D::PARAM_ATTENUATION, attenuation);
light->set_param(OmniLight3D::PARAM_RANGE, range);
light->set_color(l->color);
return light;
}
- if (l->type == "spot") {
+ if (l->light_type == "spot") {
SpotLight3D *light = memnew(SpotLight3D);
light->set_param(SpotLight3D::PARAM_ATTENUATION, attenuation);
light->set_param(SpotLight3D::PARAM_RANGE, range);
@@ -4995,9 +5140,9 @@ Camera3D *GLTFDocument::_generate_camera(Ref<GLTFState> state, Node *scene_paren
Ref<GLTFCamera> c = state->cameras[gltf_node->camera];
if (c->get_perspective()) {
- camera->set_perspective(c->get_fov_size(), c->get_znear(), c->get_zfar());
+ camera->set_perspective(c->get_fov_size(), c->get_depth_near(), c->get_depth_far());
} else {
- camera->set_orthogonal(c->get_fov_size(), c->get_znear(), c->get_zfar());
+ camera->set_orthogonal(c->get_fov_size(), c->get_depth_near(), c->get_depth_far());
}
return camera;
@@ -5011,14 +5156,10 @@ GLTFCameraIndex GLTFDocument::_convert_camera(Ref<GLTFState> state, Camera3D *p_
if (p_camera->get_projection() == Camera3D::Projection::PROJECTION_PERSPECTIVE) {
c->set_perspective(true);
- c->set_fov_size(p_camera->get_fov());
- c->set_zfar(p_camera->get_far());
- c->set_znear(p_camera->get_near());
- } else {
- c->set_fov_size(p_camera->get_fov());
- c->set_zfar(p_camera->get_far());
- c->set_znear(p_camera->get_near());
}
+ c->set_fov_size(p_camera->get_fov());
+ c->set_depth_far(p_camera->get_far());
+ c->set_depth_near(p_camera->get_near());
GLTFCameraIndex camera_index = state->cameras.size();
state->cameras.push_back(c);
return camera_index;
@@ -5031,22 +5172,22 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_lig
l.instantiate();
l->color = p_light->get_color();
if (cast_to<DirectionalLight3D>(p_light)) {
- l->type = "directional";
+ l->light_type = "directional";
DirectionalLight3D *light = cast_to<DirectionalLight3D>(p_light);
l->intensity = light->get_param(DirectionalLight3D::PARAM_ENERGY);
l->range = FLT_MAX; // Range for directional lights is infinite in Godot.
} else if (cast_to<OmniLight3D>(p_light)) {
- l->type = "point";
+ l->light_type = "point";
OmniLight3D *light = cast_to<OmniLight3D>(p_light);
l->range = light->get_param(OmniLight3D::PARAM_RANGE);
float attenuation = p_light->get_param(OmniLight3D::PARAM_ATTENUATION);
- l->intensity = l->range / attenuation;
+ l->intensity = l->range / (attenuation * 2048);
} else if (cast_to<SpotLight3D>(p_light)) {
- l->type = "spot";
+ l->light_type = "spot";
SpotLight3D *light = cast_to<SpotLight3D>(p_light);
l->range = light->get_param(SpotLight3D::PARAM_RANGE);
float attenuation = light->get_param(SpotLight3D::PARAM_ATTENUATION);
- l->intensity = l->range / attenuation;
+ l->intensity = l->range / (attenuation * 2048);
l->outer_cone_angle = Math::deg2rad(light->get_param(SpotLight3D::PARAM_SPOT_ANGLE));
// This equation is the inverse of the import equation (which has a desmos link).
@@ -5060,22 +5201,11 @@ GLTFLightIndex GLTFDocument::_convert_light(Ref<GLTFState> state, Light3D *p_lig
return light_index;
}
-GLTFSkeletonIndex GLTFDocument::_convert_skeleton(Ref<GLTFState> state, Skeleton3D *p_skeleton) {
- print_verbose("glTF: Converting skeleton: " + p_skeleton->get_name());
- Ref<GLTFSkeleton> gltf_skeleton;
- gltf_skeleton.instantiate();
- gltf_skeleton->set_name(_gen_unique_name(state, p_skeleton->get_name()));
- gltf_skeleton->godot_skeleton = p_skeleton;
- GLTFSkeletonIndex skeleton_i = state->skeletons.size();
- state->skeletons.push_back(gltf_skeleton);
- return skeleton_i;
-}
-
void GLTFDocument::_convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node) {
Transform3D xform = p_spatial->get_transform();
p_node->scale = xform.basis.get_scale();
p_node->rotation = xform.basis.get_rotation_quaternion();
- p_node->translation = xform.origin;
+ p_node->position = xform.origin;
}
Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index) {
@@ -5086,7 +5216,7 @@ Node3D *GLTFDocument::_generate_spatial(Ref<GLTFState> state, Node *scene_parent
return spatial;
}
-void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, Node *p_root, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) {
+void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, const GLTFNodeIndex p_gltf_parent, const GLTFNodeIndex p_gltf_root) {
bool retflag = true;
_check_visibility(p_current, retflag);
if (retflag) {
@@ -5100,37 +5230,41 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, No
_convert_spatial(state, spatial, gltf_node);
}
if (cast_to<MeshInstance3D>(p_current)) {
- Node3D *spatial = cast_to<Node3D>(p_current);
- _convert_mesh_to_gltf(p_current, state, spatial, gltf_node);
+ MeshInstance3D *mi = cast_to<MeshInstance3D>(p_current);
+ _convert_mesh_instance_to_gltf(mi, state, gltf_node);
} else if (cast_to<BoneAttachment3D>(p_current)) {
- _convert_bone_attachment_to_gltf(p_current, state, gltf_node, retflag);
- // TODO 2020-12-21 iFire Handle the case of objects under the bone attachment.
+ BoneAttachment3D *bone = cast_to<BoneAttachment3D>(p_current);
+ _convert_bone_attachment_to_gltf(bone, state, p_gltf_parent, p_gltf_root, gltf_node);
return;
} else if (cast_to<Skeleton3D>(p_current)) {
- _convert_skeleton_to_gltf(p_current, state, p_gltf_parent, p_gltf_root, gltf_node, p_root);
+ Skeleton3D *skel = cast_to<Skeleton3D>(p_current);
+ _convert_skeleton_to_gltf(skel, state, p_gltf_parent, p_gltf_root, gltf_node);
// We ignore the Godot Engine node that is the skeleton.
return;
} else if (cast_to<MultiMeshInstance3D>(p_current)) {
- _convert_mult_mesh_instance_to_gltf(p_current, p_gltf_parent, p_gltf_root, gltf_node, state, p_root);
+ MultiMeshInstance3D *multi = cast_to<MultiMeshInstance3D>(p_current);
+ _convert_multi_mesh_instance_to_gltf(multi, p_gltf_parent, p_gltf_root, gltf_node, state);
#ifdef MODULE_CSG_ENABLED
} else if (cast_to<CSGShape3D>(p_current)) {
- if (p_current->get_parent() && cast_to<CSGShape3D>(p_current)->is_root_shape()) {
- _convert_csg_shape_to_gltf(p_current, p_gltf_parent, gltf_node, state);
+ CSGShape3D *shape = cast_to<CSGShape3D>(p_current);
+ if (shape->get_parent() && shape->is_root_shape()) {
+ _convert_csg_shape_to_gltf(shape, p_gltf_parent, gltf_node, state);
}
#endif // MODULE_CSG_ENABLED
#ifdef MODULE_GRIDMAP_ENABLED
} else if (cast_to<GridMap>(p_current)) {
- _convert_grid_map_to_gltf(p_current, p_gltf_parent, p_gltf_root, gltf_node, state, p_root);
+ GridMap *gridmap = Object::cast_to<GridMap>(p_current);
+ _convert_grid_map_to_gltf(gridmap, p_gltf_parent, p_gltf_root, gltf_node, state);
#endif // MODULE_GRIDMAP_ENABLED
} else if (cast_to<Camera3D>(p_current)) {
Camera3D *camera = Object::cast_to<Camera3D>(p_current);
- _convert_camera_to_gltf(camera, state, camera, gltf_node);
+ _convert_camera_to_gltf(camera, state, gltf_node);
} else if (cast_to<Light3D>(p_current)) {
Light3D *light = Object::cast_to<Light3D>(p_current);
- _convert_light_to_gltf(light, state, light, gltf_node);
+ _convert_light_to_gltf(light, state, gltf_node);
} else if (cast_to<AnimationPlayer>(p_current)) {
AnimationPlayer *animation_player = Object::cast_to<AnimationPlayer>(p_current);
- _convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current, p_root);
+ _convert_animation_player_to_gltf(animation_player, state, p_gltf_parent, p_gltf_root, gltf_node, p_current);
}
GLTFNodeIndex current_node_i = state->nodes.size();
GLTFNodeIndex gltf_root = p_gltf_root;
@@ -5142,13 +5276,13 @@ void GLTFDocument::_convert_scene_node(Ref<GLTFState> state, Node *p_current, No
}
_create_gltf_node(state, p_current, current_node_i, p_gltf_parent, gltf_root, gltf_node);
for (int node_i = 0; node_i < p_current->get_child_count(); node_i++) {
- _convert_scene_node(state, p_current->get_child(node_i), p_root, current_node_i, gltf_root);
+ _convert_scene_node(state, p_current->get_child(node_i), current_node_i, gltf_root);
}
}
#ifdef MODULE_CSG_ENABLED
-void GLTFDocument::_convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
- CSGShape3D *csg = Object::cast_to<CSGShape3D>(p_current);
+void GLTFDocument::_convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+ CSGShape3D *csg = p_current;
csg->call("_update_shape");
Array meshes = csg->get_meshes();
if (meshes.size() != 2) {
@@ -5160,13 +5294,8 @@ void GLTFDocument::_convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_g
}
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
- Ref<EditorSceneImporterMesh> import_mesh;
- import_mesh.instantiate();
- Ref<ArrayMesh> array_mesh = csg->get_meshes()[1];
- for (int32_t surface_i = 0; surface_i < array_mesh->get_surface_count(); surface_i++) {
- import_mesh->add_surface(Mesh::PrimitiveType::PRIMITIVE_TRIANGLES, array_mesh->surface_get_arrays(surface_i), Array(), Dictionary(), mat, array_mesh->surface_get_name(surface_i));
- }
- gltf_mesh->set_mesh(import_mesh);
+ Ref<ImporterMesh> array_mesh = csg->get_meshes()[1];
+ gltf_mesh->set_mesh(array_mesh);
GLTFMeshIndex mesh_i = state->meshes.size();
state->meshes.push_back(gltf_mesh);
gltf_node->mesh = mesh_i;
@@ -5179,16 +5308,15 @@ void GLTFDocument::_create_gltf_node(Ref<GLTFState> state, Node *p_scene_parent,
GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_gltf_node, Ref<GLTFNode> gltf_node) {
state->scene_nodes.insert(current_node_i, p_scene_parent);
state->nodes.push_back(gltf_node);
- if (current_node_i == p_parent_node_index) {
- return;
- }
+ ERR_FAIL_COND(current_node_i == p_parent_node_index);
+ state->nodes.write[current_node_i]->parent = p_parent_node_index;
if (p_parent_node_index == -1) {
return;
}
state->nodes.write[p_parent_node_index]->children.push_back(current_node_i);
}
-void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *animation_player, Ref<GLTFState> state, const GLTFNodeIndex &p_gltf_current, const GLTFNodeIndex &p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent, Node *p_root) {
+void GLTFDocument::_convert_animation_player_to_gltf(AnimationPlayer *animation_player, Ref<GLTFState> state, GLTFNodeIndex p_gltf_current, GLTFNodeIndex p_gltf_root_index, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent) {
ERR_FAIL_COND(!animation_player);
state->animation_players.push_back(animation_player);
print_verbose(String("glTF: Converting animation player: ") + animation_player->get_name());
@@ -5207,7 +5335,7 @@ void GLTFDocument::_check_visibility(Node *p_node, bool &retflag) {
retflag = false;
}
-void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) {
+void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) {
ERR_FAIL_COND(!camera);
GLTFCameraIndex camera_index = _convert_camera(state, camera);
if (camera_index != -1) {
@@ -5215,7 +5343,7 @@ void GLTFDocument::_convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> stat
}
}
-void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) {
+void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) {
ERR_FAIL_COND(!light);
GLTFLightIndex light_index = _convert_light(state, light);
if (light_index != -1) {
@@ -5224,131 +5352,196 @@ void GLTFDocument::_convert_light_to_gltf(Light3D *light, Ref<GLTFState> state,
}
#ifdef MODULE_GRIDMAP_ENABLED
-void GLTFDocument::_convert_grid_map_to_gltf(Node *p_scene_parent, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state, Node *p_root_node) {
- GridMap *grid_map = Object::cast_to<GridMap>(p_scene_parent);
- ERR_FAIL_COND(!grid_map);
- Array cells = grid_map->get_used_cells();
+void GLTFDocument::_convert_grid_map_to_gltf(GridMap *p_grid_map, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+ Array cells = p_grid_map->get_used_cells();
for (int32_t k = 0; k < cells.size(); k++) {
GLTFNode *new_gltf_node = memnew(GLTFNode);
gltf_node->children.push_back(state->nodes.size());
state->nodes.push_back(new_gltf_node);
Vector3 cell_location = cells[k];
- int32_t cell = grid_map->get_cell_item(
+ int32_t cell = p_grid_map->get_cell_item(
Vector3(cell_location.x, cell_location.y, cell_location.z));
- EditorSceneImporterMeshNode3D *import_mesh_node = memnew(EditorSceneImporterMeshNode3D);
- import_mesh_node->set_mesh(grid_map->get_mesh_library()->get_item_mesh(cell));
+ ImporterMeshInstance3D *import_mesh_node = memnew(ImporterMeshInstance3D);
+ import_mesh_node->set_mesh(p_grid_map->get_mesh_library()->get_item_mesh(cell));
Transform3D cell_xform;
cell_xform.basis.set_orthogonal_index(
- grid_map->get_cell_item_orientation(
+ p_grid_map->get_cell_item_orientation(
Vector3(cell_location.x, cell_location.y, cell_location.z)));
- cell_xform.basis.scale(Vector3(grid_map->get_cell_scale(),
- grid_map->get_cell_scale(),
- grid_map->get_cell_scale()));
- cell_xform.set_origin(grid_map->map_to_world(
+ cell_xform.basis.scale(Vector3(p_grid_map->get_cell_scale(),
+ p_grid_map->get_cell_scale(),
+ p_grid_map->get_cell_scale()));
+ cell_xform.set_origin(p_grid_map->map_to_world(
Vector3(cell_location.x, cell_location.y, cell_location.z)));
Ref<GLTFMesh> gltf_mesh;
gltf_mesh.instantiate();
gltf_mesh = import_mesh_node;
new_gltf_node->mesh = state->meshes.size();
state->meshes.push_back(gltf_mesh);
- new_gltf_node->xform = cell_xform * grid_map->get_transform();
- new_gltf_node->set_name(_gen_unique_name(state, grid_map->get_mesh_library()->get_item_name(cell)));
+ new_gltf_node->xform = cell_xform * p_grid_map->get_transform();
+ new_gltf_node->set_name(_gen_unique_name(state, p_grid_map->get_mesh_library()->get_item_name(cell)));
}
}
#endif // MODULE_GRIDMAP_ENABLED
-void GLTFDocument::_convert_mult_mesh_instance_to_gltf(Node *p_scene_parent, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref<GLTFNode> gltf_node, Ref<GLTFState> state, Node *p_root_node) {
- MultiMeshInstance3D *multi_mesh_instance = Object::cast_to<MultiMeshInstance3D>(p_scene_parent);
- ERR_FAIL_COND(!multi_mesh_instance);
- Ref<MultiMesh> multi_mesh = multi_mesh_instance->get_multimesh();
- if (multi_mesh.is_valid()) {
- for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
- instance_i++) {
- GLTFNode *new_gltf_node = memnew(GLTFNode);
- Transform3D transform;
- if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) {
- Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i);
- transform.origin =
- Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y);
- real_t rotation = xform_2d.get_rotation();
- Quaternion quaternion(Vector3(0, 1, 0), rotation);
- Size2 scale = xform_2d.get_scale();
- transform.basis.set_quaternion_scale(quaternion,
- Vector3(scale.x, 0, scale.y));
- transform =
- multi_mesh_instance->get_transform() * transform;
- } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) {
- transform = multi_mesh_instance->get_transform() *
- multi_mesh->get_instance_transform(instance_i);
- }
- Ref<ArrayMesh> mm = multi_mesh->get_mesh();
- if (mm.is_valid()) {
- Ref<EditorSceneImporterMesh> mesh;
- mesh.instantiate();
- for (int32_t surface_i = 0; surface_i < mm->get_surface_count(); surface_i++) {
- Array surface = mm->surface_get_arrays(surface_i);
- mesh->add_surface(mm->surface_get_primitive_type(surface_i), surface, Array(), Dictionary(),
- mm->surface_get_material(surface_i), mm->get_name());
- }
- Ref<GLTFMesh> gltf_mesh;
- gltf_mesh.instantiate();
- gltf_mesh->set_name(multi_mesh->get_name());
- gltf_mesh->set_mesh(mesh);
- new_gltf_node->mesh = state->meshes.size();
- state->meshes.push_back(gltf_mesh);
- }
- new_gltf_node->xform = transform;
- new_gltf_node->set_name(_gen_unique_name(state, multi_mesh_instance->get_name()));
- gltf_node->children.push_back(state->nodes.size());
- state->nodes.push_back(new_gltf_node);
+void GLTFDocument::_convert_multi_mesh_instance_to_gltf(
+ MultiMeshInstance3D *p_multi_mesh_instance,
+ GLTFNodeIndex p_parent_node_index,
+ GLTFNodeIndex p_root_node_index,
+ Ref<GLTFNode> gltf_node, Ref<GLTFState> state) {
+ ERR_FAIL_COND(!p_multi_mesh_instance);
+ Ref<MultiMesh> multi_mesh = p_multi_mesh_instance->get_multimesh();
+ if (multi_mesh.is_null()) {
+ return;
+ }
+ Ref<GLTFMesh> gltf_mesh;
+ gltf_mesh.instantiate();
+ Ref<Mesh> mesh = multi_mesh->get_mesh();
+ if (mesh.is_null()) {
+ return;
+ }
+ gltf_mesh->set_name(multi_mesh->get_name());
+ Ref<ImporterMesh> importer_mesh;
+ importer_mesh.instantiate();
+ Ref<ArrayMesh> array_mesh = multi_mesh->get_mesh();
+ if (array_mesh.is_valid()) {
+ importer_mesh->set_blend_shape_mode(array_mesh->get_blend_shape_mode());
+ for (int32_t blend_i = 0; blend_i < array_mesh->get_blend_shape_count(); blend_i++) {
+ importer_mesh->add_blend_shape(array_mesh->get_blend_shape_name(blend_i));
}
}
-}
-
-void GLTFDocument::_convert_skeleton_to_gltf(Node *p_scene_parent, Ref<GLTFState> state, const GLTFNodeIndex &p_parent_node_index, const GLTFNodeIndex &p_root_node_index, Ref<GLTFNode> gltf_node, Node *p_root_node) {
- Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_scene_parent);
- if (skeleton) {
- // Remove placeholder skeleton3d node by not creating the gltf node
- // Skins are per mesh
- for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) {
- _convert_scene_node(state, skeleton->get_child(node_i), p_root_node, p_parent_node_index, p_root_node_index);
+ for (int32_t surface_i = 0; surface_i < mesh->get_surface_count(); surface_i++) {
+ Ref<Material> mat = mesh->surface_get_material(surface_i);
+ String material_name;
+ if (mat.is_valid()) {
+ material_name = mat->get_name();
}
+ Array blend_arrays;
+ if (array_mesh.is_valid()) {
+ blend_arrays = array_mesh->surface_get_blend_shape_arrays(surface_i);
+ }
+ importer_mesh->add_surface(mesh->surface_get_primitive_type(surface_i), mesh->surface_get_arrays(surface_i),
+ blend_arrays, mesh->surface_get_lods(surface_i), mat, material_name, mesh->surface_get_format(surface_i));
+ }
+ gltf_mesh->set_mesh(importer_mesh);
+ GLTFMeshIndex mesh_index = state->meshes.size();
+ state->meshes.push_back(gltf_mesh);
+ for (int32_t instance_i = 0; instance_i < multi_mesh->get_instance_count();
+ instance_i++) {
+ Transform3D transform;
+ if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_2D) {
+ Transform2D xform_2d = multi_mesh->get_instance_transform_2d(instance_i);
+ transform.origin =
+ Vector3(xform_2d.get_origin().x, 0, xform_2d.get_origin().y);
+ real_t rotation = xform_2d.get_rotation();
+ Quaternion quaternion(Vector3(0, 1, 0), rotation);
+ Size2 scale = xform_2d.get_scale();
+ transform.basis.set_quaternion_scale(quaternion,
+ Vector3(scale.x, 0, scale.y));
+ transform = p_multi_mesh_instance->get_transform() * transform;
+ } else if (multi_mesh->get_transform_format() == MultiMesh::TRANSFORM_3D) {
+ transform = p_multi_mesh_instance->get_transform() *
+ multi_mesh->get_instance_transform(instance_i);
+ }
+ Ref<GLTFNode> new_gltf_node;
+ new_gltf_node.instantiate();
+ new_gltf_node->mesh = mesh_index;
+ new_gltf_node->xform = transform;
+ new_gltf_node->set_name(_gen_unique_name(state, p_multi_mesh_instance->get_name()));
+ gltf_node->children.push_back(state->nodes.size());
+ state->nodes.push_back(new_gltf_node);
}
}
-void GLTFDocument::_convert_bone_attachment_to_gltf(Node *p_scene_parent, Ref<GLTFState> state, Ref<GLTFNode> gltf_node, bool &retflag) {
- retflag = true;
- BoneAttachment3D *bone_attachment = Object::cast_to<BoneAttachment3D>(p_scene_parent);
- if (bone_attachment) {
- Node *node = bone_attachment->get_parent();
- while (node) {
- Skeleton3D *bone_attachment_skeleton = Object::cast_to<Skeleton3D>(node);
- if (bone_attachment_skeleton) {
- for (GLTFSkeletonIndex skeleton_i = 0; skeleton_i < state->skeletons.size(); skeleton_i++) {
- if (state->skeletons[skeleton_i]->godot_skeleton != bone_attachment_skeleton) {
- continue;
- }
- state->skeletons.write[skeleton_i]->bone_attachments.push_back(bone_attachment);
- break;
- }
- break;
+void GLTFDocument::_convert_skeleton_to_gltf(Skeleton3D *p_skeleton3d, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) {
+ Skeleton3D *skeleton = p_skeleton3d;
+ Ref<GLTFSkeleton> gltf_skeleton;
+ gltf_skeleton.instantiate();
+ // GLTFSkeleton is only used to hold internal state data. It will not be written to the document.
+ //
+ gltf_skeleton->godot_skeleton = skeleton;
+ GLTFSkeletonIndex skeleton_i = state->skeletons.size();
+ state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()] = skeleton_i;
+ state->skeletons.push_back(gltf_skeleton);
+
+ BoneId bone_count = skeleton->get_bone_count();
+ for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) {
+ Ref<GLTFNode> joint_node;
+ joint_node.instantiate();
+ // Note that we cannot use _gen_unique_bone_name here, because glTF spec requires all node
+ // names to be unique regardless of whether or not they are used as joints.
+ joint_node->set_name(_gen_unique_name(state, skeleton->get_bone_name(bone_i)));
+ Transform3D xform = skeleton->get_bone_rest(bone_i) * skeleton->get_bone_pose(bone_i);
+ joint_node->scale = xform.basis.get_scale();
+ joint_node->rotation = xform.basis.get_rotation_quaternion();
+ joint_node->position = xform.origin;
+ joint_node->joint = true;
+ GLTFNodeIndex current_node_i = state->nodes.size();
+ state->scene_nodes.insert(current_node_i, skeleton);
+ state->nodes.push_back(joint_node);
+
+ gltf_skeleton->joints.push_back(current_node_i);
+ if (skeleton->get_bone_parent(bone_i) == -1) {
+ gltf_skeleton->roots.push_back(current_node_i);
+ }
+ gltf_skeleton->godot_bone_node.insert(bone_i, current_node_i);
+ }
+ for (BoneId bone_i = 0; bone_i < bone_count; bone_i++) {
+ GLTFNodeIndex current_node_i = gltf_skeleton->godot_bone_node[bone_i];
+ BoneId parent_bone_id = skeleton->get_bone_parent(bone_i);
+ if (parent_bone_id == -1) {
+ if (p_parent_node_index != -1) {
+ state->nodes.write[current_node_i]->parent = p_parent_node_index;
+ state->nodes.write[p_parent_node_index]->children.push_back(current_node_i);
}
- node = node->get_parent();
+ } else {
+ GLTFNodeIndex parent_node_i = gltf_skeleton->godot_bone_node[parent_bone_id];
+ state->nodes.write[current_node_i]->parent = parent_node_i;
+ state->nodes.write[parent_node_i]->children.push_back(current_node_i);
}
- gltf_node.unref();
- return;
}
- retflag = false;
+ // Remove placeholder skeleton3d node by not creating the gltf node
+ // Skins are per mesh
+ for (int node_i = 0; node_i < skeleton->get_child_count(); node_i++) {
+ _convert_scene_node(state, skeleton->get_child(node_i), p_parent_node_index, p_root_node_index);
+ }
}
-void GLTFDocument::_convert_mesh_to_gltf(Node *p_scene_parent, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node) {
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(p_scene_parent);
- if (mi) {
- GLTFMeshIndex gltf_mesh_index = _convert_mesh_instance(state, mi);
- if (gltf_mesh_index != -1) {
- gltf_node->mesh = gltf_mesh_index;
+void GLTFDocument::_convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment, Ref<GLTFState> state, GLTFNodeIndex p_parent_node_index, GLTFNodeIndex p_root_node_index, Ref<GLTFNode> gltf_node) {
+ Skeleton3D *skeleton;
+ // Note that relative transforms to external skeletons and pose overrides are not supported.
+ if (p_bone_attachment->get_use_external_skeleton()) {
+ skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_node_or_null(p_bone_attachment->get_external_skeleton()));
+ } else {
+ skeleton = cast_to<Skeleton3D>(p_bone_attachment->get_parent());
+ }
+ GLTFSkeletonIndex skel_gltf_i = -1;
+ if (skeleton != nullptr && state->skeleton3d_to_gltf_skeleton.has(skeleton->get_instance_id())) {
+ skel_gltf_i = state->skeleton3d_to_gltf_skeleton[skeleton->get_instance_id()];
+ }
+ int bone_idx = -1;
+ if (skeleton != nullptr) {
+ bone_idx = p_bone_attachment->get_bone_idx();
+ if (bone_idx == -1) {
+ bone_idx = skeleton->find_bone(p_bone_attachment->get_bone_name());
}
}
+ GLTFNodeIndex par_node_index = p_parent_node_index;
+ if (skeleton != nullptr && bone_idx != -1 && skel_gltf_i != -1) {
+ Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_gltf_i];
+ gltf_skeleton->bone_attachments.push_back(p_bone_attachment);
+ par_node_index = gltf_skeleton->joints[bone_idx];
+ }
+
+ for (int node_i = 0; node_i < p_bone_attachment->get_child_count(); node_i++) {
+ _convert_scene_node(state, p_bone_attachment->get_child(node_i), par_node_index, p_root_node_index);
+ }
+}
+
+void GLTFDocument::_convert_mesh_instance_to_gltf(MeshInstance3D *p_scene_parent, Ref<GLTFState> state, Ref<GLTFNode> gltf_node) {
+ GLTFMeshIndex gltf_mesh_index = _convert_mesh_to_gltf(state, p_scene_parent);
+ if (gltf_mesh_index != -1) {
+ gltf_node->mesh = gltf_mesh_index;
+ }
}
void GLTFDocument::_generate_scene_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index) {
@@ -5627,16 +5820,16 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
float length = 0.0;
- for (Map<int, GLTFAnimation::Track>::Element *track_i = anim->get_tracks().front(); track_i; track_i = track_i->next()) {
- const GLTFAnimation::Track &track = track_i->get();
+ for (const KeyValue<int, GLTFAnimation::Track> &track_i : anim->get_tracks()) {
+ const GLTFAnimation::Track &track = track_i.value;
//need to find the path: for skeletons, weight tracks will affect the mesh
NodePath node_path;
//for skeletons, transform tracks always affect bones
NodePath transform_node_path;
- GLTFNodeIndex node_index = track_i->key();
+ GLTFNodeIndex node_index = track_i.key;
- const Ref<GLTFNode> gltf_node = state->nodes[track_i->key()];
+ const Ref<GLTFNode> gltf_node = state->nodes[track_i.key];
Node *root = ap->get_parent();
ERR_FAIL_COND(root == nullptr);
@@ -5658,8 +5851,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
for (int i = 0; i < track.rotation_track.times.size(); i++) {
length = MAX(length, track.rotation_track.times[i]);
}
- for (int i = 0; i < track.translation_track.times.size(); i++) {
- length = MAX(length, track.translation_track.times[i]);
+ for (int i = 0; i < track.position_track.times.size(); i++) {
+ length = MAX(length, track.position_track.times[i]);
}
for (int i = 0; i < track.scale_track.times.size(); i++) {
length = MAX(length, track.scale_track.times[i]);
@@ -5673,7 +5866,7 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
// Animated TRS properties will not affect a skinned mesh.
const bool transform_affects_skinned_mesh_instance = gltf_node->skeleton < 0 && gltf_node->skin >= 0;
- if ((track.rotation_track.values.size() || track.translation_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) {
+ if ((track.rotation_track.values.size() || track.position_track.values.size() || track.scale_track.values.size()) && !transform_affects_skinned_mesh_instance) {
//make transform track
int track_idx = animation->get_track_count();
animation->add_track(Animation::TYPE_TRANSFORM3D);
@@ -5688,15 +5881,15 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
Vector3 base_scale = Vector3(1, 1, 1);
if (!track.rotation_track.values.size()) {
- base_rot = state->nodes[track_i->key()]->rotation.normalized();
+ base_rot = state->nodes[track_i.key]->rotation.normalized();
}
- if (!track.translation_track.values.size()) {
- base_pos = state->nodes[track_i->key()]->translation;
+ if (!track.position_track.values.size()) {
+ base_pos = state->nodes[track_i.key]->position;
}
if (!track.scale_track.values.size()) {
- base_scale = state->nodes[track_i->key()]->scale;
+ base_scale = state->nodes[track_i.key]->scale;
}
bool last = false;
@@ -5705,8 +5898,8 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
Quaternion rot = base_rot;
Vector3 scale = base_scale;
- if (track.translation_track.times.size()) {
- pos = _interpolate_track<Vector3>(track.translation_track.times, track.translation_track.values, time, track.translation_track.interpolation);
+ if (track.position_track.times.size()) {
+ pos = _interpolate_track<Vector3>(track.position_track.times, track.position_track.values, time, track.position_track.interpolation);
}
if (track.rotation_track.times.size()) {
@@ -5801,10 +5994,6 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
if (node->mesh < 0) {
continue;
}
- Array json_skins;
- if (state->json.has("skins")) {
- json_skins = state->json["skins"];
- }
Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(mi_node_i);
if (!mi_element) {
continue;
@@ -5814,9 +6003,8 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
Transform3D mi_xform = mi->get_transform();
node->scale = mi_xform.basis.get_scale();
node->rotation = mi_xform.basis.get_rotation_quaternion();
- node->translation = mi_xform.origin;
+ node->position = mi_xform.origin;
- Dictionary json_skin;
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(mi->get_node(mi->get_skeleton_path()));
if (!skeleton) {
continue;
@@ -5825,121 +6013,75 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
continue;
}
Ref<Skin> skin = mi->get_skin();
- if (skin.is_null()) {
- skin = skeleton->register_skin(nullptr)->get_skin();
- }
Ref<GLTFSkin> gltf_skin;
gltf_skin.instantiate();
Array json_joints;
- GLTFSkeletonIndex skeleton_gltf_i = -1;
NodePath skeleton_path = mi->get_skeleton_path();
- bool is_unique = true;
- for (int32_t skin_i = 0; skin_i < state->skins.size(); skin_i++) {
- Ref<GLTFSkin> prev_gltf_skin = state->skins.write[skin_i];
- if (gltf_skin.is_null()) {
- continue;
- }
- GLTFSkeletonIndex prev_skeleton = prev_gltf_skin->get_skeleton();
- if (prev_skeleton == -1 || prev_skeleton >= state->skeletons.size()) {
- continue;
- }
- if (prev_gltf_skin->get_godot_skin() == skin && state->skeletons[prev_skeleton]->godot_skeleton == skeleton) {
- node->skin = skin_i;
- node->skeleton = prev_skeleton;
- is_unique = false;
- break;
- }
- }
- if (!is_unique) {
- continue;
- }
- GLTFSkeletonIndex skeleton_i = _convert_skeleton(state, skeleton);
- skeleton_gltf_i = skeleton_i;
- ERR_CONTINUE(skeleton_gltf_i == -1);
- gltf_skin->skeleton = skeleton_gltf_i;
- Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skeleton_gltf_i];
- for (int32_t bind_i = 0; bind_i < skin->get_bind_count(); bind_i++) {
- String godot_bone_name = skin->get_bind_name(bind_i);
- if (godot_bone_name.is_empty()) {
- int32_t bone = skin->get_bind_bone(bind_i);
- godot_bone_name = skeleton->get_bone_name(bone);
- }
- if (skeleton->find_bone(godot_bone_name) == -1) {
- godot_bone_name = skeleton->get_bone_name(0);
- }
- BoneId bone_index = skeleton->find_bone(godot_bone_name);
- ERR_CONTINUE(bone_index == -1);
- Ref<GLTFNode> joint_node;
- joint_node.instantiate();
- String gltf_bone_name = _gen_unique_bone_name(state, skeleton_gltf_i, godot_bone_name);
- joint_node->set_name(gltf_bone_name);
-
- Transform3D bone_rest_xform = skeleton->get_bone_rest(bone_index);
- joint_node->scale = bone_rest_xform.basis.get_scale();
- joint_node->rotation = bone_rest_xform.basis.get_rotation_quaternion();
- joint_node->translation = bone_rest_xform.origin;
- joint_node->joint = true;
-
- int32_t joint_node_i = state->nodes.size();
- state->nodes.push_back(joint_node);
- gltf_skeleton->godot_bone_node.insert(bone_index, joint_node_i);
- int32_t joint_index = gltf_skin->joints.size();
- gltf_skin->joint_i_to_bone_i.insert(joint_index, bone_index);
- gltf_skin->joints.push_back(joint_node_i);
- gltf_skin->joints_original.push_back(joint_node_i);
- gltf_skin->inverse_binds.push_back(skin->get_bind_pose(bind_i));
- json_joints.push_back(joint_node_i);
- for (Map<GLTFNodeIndex, Node *>::Element *skin_scene_node_i = state->scene_nodes.front(); skin_scene_node_i; skin_scene_node_i = skin_scene_node_i->next()) {
- if (skin_scene_node_i->get() == skeleton) {
- gltf_skin->skin_root = skin_scene_node_i->key();
- json_skin["skeleton"] = skin_scene_node_i->key();
- }
- }
- gltf_skin->godot_skin = skin;
- gltf_skin->set_name(_gen_unique_name(state, skin->get_name()));
- }
- for (int32_t bind_i = 0; bind_i < skin->get_bind_count(); bind_i++) {
- String bone_name = skeleton->get_bone_name(bind_i);
- String godot_bone_name = skin->get_bind_name(bind_i);
- int32_t bone = -1;
- if (skin->get_bind_bone(bind_i) != -1) {
- bone = skin->get_bind_bone(bind_i);
- godot_bone_name = skeleton->get_bone_name(bone);
- }
- bone = skeleton->find_bone(godot_bone_name);
- if (bone == -1) {
- continue;
- }
- BoneId bone_parent = skeleton->get_bone_parent(bone);
- GLTFNodeIndex joint_node_i = gltf_skeleton->godot_bone_node[bone];
- ERR_CONTINUE(joint_node_i >= state->nodes.size());
- if (bone_parent != -1) {
- GLTFNodeIndex parent_joint_gltf_node = gltf_skin->joints[bone_parent];
- Ref<GLTFNode> parent_joint_node = state->nodes.write[parent_joint_gltf_node];
- parent_joint_node->children.push_back(joint_node_i);
+ Node *skel_node = mi->get_node_or_null(skeleton_path);
+ Skeleton3D *godot_skeleton = nullptr;
+ if (skel_node != nullptr) {
+ godot_skeleton = cast_to<Skeleton3D>(skel_node);
+ }
+ if (godot_skeleton != nullptr && state->skeleton3d_to_gltf_skeleton.has(godot_skeleton->get_instance_id())) {
+ // This is a skinned mesh. If the mesh has no ARRAY_WEIGHTS or ARRAY_BONES, it will be invisible.
+ const GLTFSkeletonIndex skeleton_gltf_i = state->skeleton3d_to_gltf_skeleton[godot_skeleton->get_instance_id()];
+ Ref<GLTFSkeleton> gltf_skeleton = state->skeletons[skeleton_gltf_i];
+ int bone_cnt = skeleton->get_bone_count();
+ ERR_FAIL_COND(bone_cnt != gltf_skeleton->joints.size());
+
+ ObjectID gltf_skin_key = skin->get_instance_id();
+ ObjectID gltf_skel_key = godot_skeleton->get_instance_id();
+ GLTFSkinIndex skin_gltf_i = -1;
+ GLTFNodeIndex root_gltf_i = -1;
+ if (!gltf_skeleton->roots.is_empty()) {
+ root_gltf_i = gltf_skeleton->roots[0];
+ }
+ if (state->skin_and_skeleton3d_to_gltf_skin.has(gltf_skin_key) && state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key].has(gltf_skel_key)) {
+ skin_gltf_i = state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key];
} else {
- Node *node_parent = skeleton->get_parent();
- ERR_CONTINUE(!node_parent);
- for (Map<GLTFNodeIndex, Node *>::Element *E = state->scene_nodes.front(); E; E = E->next()) {
- if (E->get() == node_parent) {
- GLTFNodeIndex gltf_node_i = E->key();
- Ref<GLTFNode> gltf_node = state->nodes.write[gltf_node_i];
- gltf_node->children.push_back(joint_node_i);
- break;
+ if (skin.is_null()) {
+ // Note that gltf_skin_key should remain null, so these can share a reference.
+ skin = skeleton->register_skin(nullptr)->get_skin();
+ }
+ gltf_skin.instantiate();
+ gltf_skin->godot_skin = skin;
+ gltf_skin->set_name(skin->get_name());
+ gltf_skin->skeleton = skeleton_gltf_i;
+ gltf_skin->skin_root = root_gltf_i;
+ //gltf_state->godot_to_gltf_node[skel_node]
+ HashMap<StringName, int> bone_name_to_idx;
+ for (int bone_i = 0; bone_i < bone_cnt; bone_i++) {
+ bone_name_to_idx[skeleton->get_bone_name(bone_i)] = bone_i;
+ }
+ for (int bind_i = 0, cnt = skin->get_bind_count(); bind_i < cnt; bind_i++) {
+ int bone_i = skin->get_bind_bone(bind_i);
+ Transform3D bind_pose = skin->get_bind_pose(bind_i);
+ StringName bind_name = skin->get_bind_name(bind_i);
+ if (bind_name != StringName()) {
+ bone_i = bone_name_to_idx[bind_name];
}
+ ERR_CONTINUE(bone_i < 0 || bone_i >= bone_cnt);
+ if (bind_name == StringName()) {
+ bind_name = skeleton->get_bone_name(bone_i);
+ }
+ GLTFNodeIndex skeleton_bone_i = gltf_skeleton->joints[bone_i];
+ gltf_skin->joints_original.push_back(skeleton_bone_i);
+ gltf_skin->joints.push_back(skeleton_bone_i);
+ gltf_skin->inverse_binds.push_back(bind_pose);
+ if (skeleton->get_bone_parent(bone_i) == -1) {
+ gltf_skin->roots.push_back(skeleton_bone_i);
+ }
+ gltf_skin->joint_i_to_bone_i[bind_i] = bone_i;
+ gltf_skin->joint_i_to_name[bind_i] = bind_name;
}
+ skin_gltf_i = state->skins.size();
+ state->skins.push_back(gltf_skin);
+ state->skin_and_skeleton3d_to_gltf_skin[gltf_skin_key][gltf_skel_key] = skin_gltf_i;
}
+ node->skin = skin_gltf_i;
+ node->skeleton = skeleton_gltf_i;
}
- _expand_skin(state, gltf_skin);
- node->skin = state->skins.size();
- state->skins.push_back(gltf_skin);
-
- json_skin["inverseBindMatrices"] = _encode_accessor_as_xform(state, gltf_skin->inverse_binds, false);
- json_skin["joints"] = json_joints;
- json_skin["name"] = gltf_skin->get_name();
- json_skins.push_back(json_skin);
- state->json["skins"] = json_skins;
}
}
@@ -5984,8 +6126,8 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo
Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(node_i);
ERR_CONTINUE_MSG(mi_element == nullptr, vformat("Unable to find node %d", node_i));
- EditorSceneImporterMeshNode3D *mi = Object::cast_to<EditorSceneImporterMeshNode3D>(mi_element->get());
- ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to EditorSceneImporterMeshNode3D", node_i, mi_element->get()->get_class_name()));
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->get());
+ ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->get()->get_class_name()));
const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton;
Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
@@ -6022,10 +6164,9 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
for (int32_t key_i = 0; key_i < key_count; key_i++) {
times.write[key_i] = p_animation->track_get_key_time(p_track_i, key_i);
}
- const float BAKE_FPS = 30.0f;
if (track_type == Animation::TYPE_TRANSFORM3D) {
- p_track.translation_track.times = times;
- p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.position_track.times = times;
+ p_track.position_track.interpolation = gltf_interpolation;
p_track.rotation_track.times = times;
p_track.rotation_track.interpolation = gltf_interpolation;
p_track.scale_track.times = times;
@@ -6033,27 +6174,27 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
p_track.scale_track.values.resize(key_count);
p_track.scale_track.interpolation = gltf_interpolation;
- p_track.translation_track.values.resize(key_count);
- p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.position_track.values.resize(key_count);
+ p_track.position_track.interpolation = gltf_interpolation;
p_track.rotation_track.values.resize(key_count);
p_track.rotation_track.interpolation = gltf_interpolation;
for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Vector3 translation;
+ Vector3 position;
Quaternion rotation;
Vector3 scale;
- Error err = p_animation->transform_track_get_key(p_track_i, key_i, &translation, &rotation, &scale);
+ Error err = p_animation->transform_track_get_key(p_track_i, key_i, &position, &rotation, &scale);
ERR_CONTINUE(err != OK);
Transform3D xform;
xform.basis.set_quaternion_scale(rotation, scale);
- xform.origin = translation;
+ xform.origin = position;
xform = p_bone_rest * xform;
- p_track.translation_track.values.write[key_i] = xform.get_origin();
+ p_track.position_track.values.write[key_i] = xform.get_origin();
p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion();
p_track.scale_track.values.write[key_i] = xform.basis.get_scale();
}
} else if (path.find(":transform") != -1) {
- p_track.translation_track.times = times;
- p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.position_track.times = times;
+ p_track.position_track.interpolation = gltf_interpolation;
p_track.rotation_track.times = times;
p_track.rotation_track.interpolation = gltf_interpolation;
p_track.scale_track.times = times;
@@ -6061,13 +6202,13 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
p_track.scale_track.values.resize(key_count);
p_track.scale_track.interpolation = gltf_interpolation;
- p_track.translation_track.values.resize(key_count);
- p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.position_track.values.resize(key_count);
+ p_track.position_track.interpolation = gltf_interpolation;
p_track.rotation_track.values.resize(key_count);
p_track.rotation_track.interpolation = gltf_interpolation;
for (int32_t key_i = 0; key_i < key_count; key_i++) {
Transform3D xform = p_animation->track_get_key_value(p_track_i, key_i);
- p_track.translation_track.values.write[key_i] = xform.get_origin();
+ p_track.position_track.values.write[key_i] = xform.get_origin();
p_track.rotation_track.values.write[key_i] = xform.basis.get_rotation_quaternion();
p_track.scale_track.values.write[key_i] = xform.basis.get_scale();
}
@@ -6083,16 +6224,16 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
Quaternion rotation_track = p_animation->track_get_key_value(p_track_i, key_i);
p_track.rotation_track.values.write[key_i] = rotation_track;
}
- } else if (path.find(":translation") != -1) {
- p_track.translation_track.times = times;
- p_track.translation_track.interpolation = gltf_interpolation;
+ } else if (path.find(":position") != -1) {
+ p_track.position_track.times = times;
+ p_track.position_track.interpolation = gltf_interpolation;
- p_track.translation_track.values.resize(key_count);
- p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.position_track.values.resize(key_count);
+ p_track.position_track.interpolation = gltf_interpolation;
for (int32_t key_i = 0; key_i < key_count; key_i++) {
- Vector3 translation = p_animation->track_get_key_value(p_track_i, key_i);
- p_track.translation_track.values.write[key_i] = translation;
+ Vector3 position = p_animation->track_get_key_value(p_track_i, key_i);
+ p_track.position_track.values.write[key_i] = position;
}
} else if (path.find(":rotation") != -1) {
p_track.rotation_track.times = times;
@@ -6151,34 +6292,34 @@ GLTFAnimation::Track GLTFDocument::_convert_animation_track(Ref<GLTFState> state
}
p_track.scale_track.values.write[key_i] = bezier_track;
}
- } else if (path.find("/translation") != -1) {
+ } else if (path.find("/position") != -1) {
const int32_t keys = p_animation->track_get_key_time(p_track_i, key_count - 1) * BAKE_FPS;
- if (!p_track.translation_track.times.size()) {
+ if (!p_track.position_track.times.size()) {
Vector<float> new_times;
new_times.resize(keys);
for (int32_t key_i = 0; key_i < keys; key_i++) {
new_times.write[key_i] = key_i / BAKE_FPS;
}
- p_track.translation_track.times = new_times;
- p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.position_track.times = new_times;
+ p_track.position_track.interpolation = gltf_interpolation;
- p_track.translation_track.values.resize(keys);
- p_track.translation_track.interpolation = gltf_interpolation;
+ p_track.position_track.values.resize(keys);
+ p_track.position_track.interpolation = gltf_interpolation;
}
for (int32_t key_i = 0; key_i < keys; key_i++) {
- Vector3 bezier_track = p_track.translation_track.values[key_i];
- if (path.find("/translation:x") != -1) {
+ Vector3 bezier_track = p_track.position_track.values[key_i];
+ if (path.find("/position:x") != -1) {
bezier_track.x = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
bezier_track.x = p_bone_rest.affine_inverse().origin.x * bezier_track.x;
- } else if (path.find("/translation:y") != -1) {
+ } else if (path.find("/position:y") != -1) {
bezier_track.y = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
bezier_track.y = p_bone_rest.affine_inverse().origin.y * bezier_track.y;
- } else if (path.find("/translation:z") != -1) {
+ } else if (path.find("/position:z") != -1) {
bezier_track.z = p_animation->bezier_track_interpolate(p_track_i, key_i / BAKE_FPS);
bezier_track.z = p_bone_rest.affine_inverse().origin.z * bezier_track.z;
}
- p_track.translation_track.values.write[key_i] = bezier_track;
+ p_track.position_track.values.write[key_i] = bezier_track;
}
}
}
@@ -6197,17 +6338,17 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
continue;
}
String orig_track_path = animation->track_get_path(track_i);
- if (String(orig_track_path).find(":translation") != -1) {
- const Vector<String> node_suffix = String(orig_track_path).split(":translation");
+ if (String(orig_track_path).find(":position") != -1) {
+ const Vector<String> node_suffix = String(orig_track_path).split(":position");
const NodePath path = node_suffix[0];
const Node *node = ap->get_parent()->get_node_or_null(path);
- for (Map<GLTFNodeIndex, Node *>::Element *translation_scene_node_i = state->scene_nodes.front(); translation_scene_node_i; translation_scene_node_i = translation_scene_node_i->next()) {
- if (translation_scene_node_i->get() == node) {
- GLTFNodeIndex node_index = translation_scene_node_i->key();
- Map<int, GLTFAnimation::Track>::Element *translation_track_i = gltf_animation->get_tracks().find(node_index);
+ for (const KeyValue<GLTFNodeIndex, Node *> &position_scene_node_i : state->scene_nodes) {
+ if (position_scene_node_i.value == node) {
+ GLTFNodeIndex node_index = position_scene_node_i.key;
+ Map<int, GLTFAnimation::Track>::Element *position_track_i = gltf_animation->get_tracks().find(node_index);
GLTFAnimation::Track track;
- if (translation_track_i) {
- track = translation_track_i->get();
+ if (position_track_i) {
+ track = position_track_i->get();
}
track = _convert_animation_track(state, track, animation, Transform3D(), track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
@@ -6217,9 +6358,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
const Vector<String> node_suffix = String(orig_track_path).split(":rotation_degrees");
const NodePath path = node_suffix[0];
const Node *node = ap->get_parent()->get_node_or_null(path);
- for (Map<GLTFNodeIndex, Node *>::Element *rotation_degree_scene_node_i = state->scene_nodes.front(); rotation_degree_scene_node_i; rotation_degree_scene_node_i = rotation_degree_scene_node_i->next()) {
- if (rotation_degree_scene_node_i->get() == node) {
- GLTFNodeIndex node_index = rotation_degree_scene_node_i->key();
+ for (const KeyValue<GLTFNodeIndex, Node *> &rotation_degree_scene_node_i : state->scene_nodes) {
+ if (rotation_degree_scene_node_i.value == node) {
+ GLTFNodeIndex node_index = rotation_degree_scene_node_i.key;
Map<int, GLTFAnimation::Track>::Element *rotation_degree_track_i = gltf_animation->get_tracks().find(node_index);
GLTFAnimation::Track track;
if (rotation_degree_track_i) {
@@ -6233,9 +6374,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
const Vector<String> node_suffix = String(orig_track_path).split(":scale");
const NodePath path = node_suffix[0];
const Node *node = ap->get_parent()->get_node_or_null(path);
- for (Map<GLTFNodeIndex, Node *>::Element *scale_scene_node_i = state->scene_nodes.front(); scale_scene_node_i; scale_scene_node_i = scale_scene_node_i->next()) {
- if (scale_scene_node_i->get() == node) {
- GLTFNodeIndex node_index = scale_scene_node_i->key();
+ for (const KeyValue<GLTFNodeIndex, Node *> &scale_scene_node_i : state->scene_nodes) {
+ if (scale_scene_node_i.value == node) {
+ GLTFNodeIndex node_index = scale_scene_node_i.key;
Map<int, GLTFAnimation::Track>::Element *scale_track_i = gltf_animation->get_tracks().find(node_index);
GLTFAnimation::Track track;
if (scale_track_i) {
@@ -6249,80 +6390,69 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
const Vector<String> node_suffix = String(orig_track_path).split(":transform");
const NodePath path = node_suffix[0];
const Node *node = ap->get_parent()->get_node_or_null(path);
- for (Map<GLTFNodeIndex, Node *>::Element *transform_track_i = state->scene_nodes.front(); transform_track_i; transform_track_i = transform_track_i->next()) {
- if (transform_track_i->get() == node) {
+ for (const KeyValue<GLTFNodeIndex, Node *> &transform_track_i : state->scene_nodes) {
+ if (transform_track_i.value == node) {
GLTFAnimation::Track track;
- track = _convert_animation_track(state, track, animation, Transform3D(), track_i, transform_track_i->key());
- gltf_animation->get_tracks().insert(transform_track_i->key(), track);
+ track = _convert_animation_track(state, track, animation, Transform3D(), track_i, transform_track_i.key);
+ gltf_animation->get_tracks().insert(transform_track_i.key, track);
}
}
} else if (String(orig_track_path).find(":blend_shapes/") != -1) {
const Vector<String> node_suffix = String(orig_track_path).split(":blend_shapes/");
const NodePath path = node_suffix[0];
const String suffix = node_suffix[1];
- const Node *node = ap->get_parent()->get_node_or_null(path);
- for (Map<GLTFNodeIndex, Node *>::Element *transform_track_i = state->scene_nodes.front(); transform_track_i; transform_track_i = transform_track_i->next()) {
- if (transform_track_i->get() == node) {
- const MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(node);
- if (!mi) {
+ Node *node = ap->get_parent()->get_node_or_null(path);
+ MeshInstance3D *mi = cast_to<MeshInstance3D>(node);
+ Ref<Mesh> mesh = mi->get_mesh();
+ ERR_CONTINUE(mesh.is_null());
+ int32_t mesh_index = -1;
+ for (const KeyValue<GLTFNodeIndex, Node *> &mesh_track_i : state->scene_nodes) {
+ if (mesh_track_i.value == node) {
+ mesh_index = mesh_track_i.key;
+ }
+ }
+ ERR_CONTINUE(mesh_index == -1);
+ Map<int, GLTFAnimation::Track> &tracks = gltf_animation->get_tracks();
+ GLTFAnimation::Track track = gltf_animation->get_tracks().has(mesh_index) ? gltf_animation->get_tracks()[mesh_index] : GLTFAnimation::Track();
+ if (!tracks.has(mesh_index)) {
+ for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) {
+ String shape_name = mesh->get_blend_shape_name(shape_i);
+ NodePath shape_path = String(path) + ":blend_shapes/" + shape_name;
+ int32_t shape_track_i = animation->find_track(shape_path);
+ if (shape_track_i == -1) {
+ GLTFAnimation::Channel<float> weight;
+ weight.interpolation = GLTFAnimation::INTERP_LINEAR;
+ weight.times.push_back(0.0f);
+ weight.times.push_back(0.0f);
+ weight.values.push_back(0.0f);
+ weight.values.push_back(0.0f);
+ track.weight_tracks.push_back(weight);
continue;
}
- Ref<ArrayMesh> array_mesh = mi->get_mesh();
- if (array_mesh.is_null()) {
- continue;
+ Animation::InterpolationType interpolation = animation->track_get_interpolation_type(track_i);
+ GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) {
+ gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
+ } else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) {
+ gltf_interpolation = GLTFAnimation::INTERP_STEP;
+ } else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) {
+ gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE;
}
- if (node_suffix.size() != 2) {
- continue;
+ int32_t key_count = animation->track_get_key_count(shape_track_i);
+ GLTFAnimation::Channel<float> weight;
+ weight.interpolation = gltf_interpolation;
+ weight.times.resize(key_count);
+ for (int32_t time_i = 0; time_i < key_count; time_i++) {
+ weight.times.write[time_i] = animation->track_get_key_time(shape_track_i, time_i);
}
- GLTFNodeIndex mesh_index = -1;
- for (GLTFNodeIndex node_i = 0; node_i < state->scene_nodes.size(); node_i++) {
- if (state->scene_nodes[node_i] == node) {
- mesh_index = node_i;
- break;
- }
- }
- ERR_CONTINUE(mesh_index == -1);
- Ref<Mesh> mesh = mi->get_mesh();
- ERR_CONTINUE(mesh.is_null());
- for (int32_t shape_i = 0; shape_i < mesh->get_blend_shape_count(); shape_i++) {
- if (mesh->get_blend_shape_name(shape_i) != suffix) {
- continue;
- }
- GLTFAnimation::Track track;
- Map<int, GLTFAnimation::Track>::Element *blend_shape_track_i = gltf_animation->get_tracks().find(mesh_index);
- if (blend_shape_track_i) {
- track = blend_shape_track_i->get();
- }
- Animation::InterpolationType interpolation = animation->track_get_interpolation_type(track_i);
-
- GLTFAnimation::Interpolation gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
- if (interpolation == Animation::InterpolationType::INTERPOLATION_LINEAR) {
- gltf_interpolation = GLTFAnimation::INTERP_LINEAR;
- } else if (interpolation == Animation::InterpolationType::INTERPOLATION_NEAREST) {
- gltf_interpolation = GLTFAnimation::INTERP_STEP;
- } else if (interpolation == Animation::InterpolationType::INTERPOLATION_CUBIC) {
- gltf_interpolation = GLTFAnimation::INTERP_CUBIC_SPLINE;
- }
- Animation::TrackType track_type = animation->track_get_type(track_i);
- if (track_type == Animation::TYPE_VALUE) {
- int32_t key_count = animation->track_get_key_count(track_i);
- GLTFAnimation::Channel<float> weight;
- weight.interpolation = gltf_interpolation;
- weight.times.resize(key_count);
- for (int32_t time_i = 0; time_i < key_count; time_i++) {
- weight.times.write[time_i] = animation->track_get_key_time(track_i, time_i);
- }
- weight.values.resize(key_count);
- for (int32_t value_i = 0; value_i < key_count; value_i++) {
- weight.values.write[value_i] = animation->track_get_key_value(track_i, value_i);
- }
- track.weight_tracks.push_back(weight);
- }
- gltf_animation->get_tracks()[mesh_index] = track;
+ weight.values.resize(key_count);
+ for (int32_t value_i = 0; value_i < key_count; value_i++) {
+ weight.values.write[value_i] = animation->track_get_key_value(shape_track_i, value_i);
}
+ track.weight_tracks.push_back(weight);
}
+ tracks[mesh_index] = track;
}
-
} else if (String(orig_track_path).find(":") != -1) {
//Process skeleton
const Vector<String> node_suffix = String(orig_track_path).split(":");
@@ -6359,9 +6489,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
for (int32_t node_i = 0; node_i < ap->get_parent()->get_child_count(); node_i++) {
const Node *child = ap->get_parent()->get_child(node_i);
const Node *node = child->get_node_or_null(orig_track_path);
- for (Map<GLTFNodeIndex, Node *>::Element *scene_node_i = state->scene_nodes.front(); scene_node_i; scene_node_i = scene_node_i->next()) {
- if (scene_node_i->get() == node) {
- GLTFNodeIndex node_index = scene_node_i->key();
+ for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) {
+ if (scene_node_i.value == node) {
+ GLTFNodeIndex node_index = scene_node_i.key;
Map<int, GLTFAnimation::Track>::Element *node_track_i = gltf_animation->get_tracks().find(node_index);
GLTFAnimation::Track track;
if (node_track_i) {
@@ -6630,3 +6760,138 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
}
return err;
}
+
+Error GLTFDocument::save_scene(Node *p_node, const String &p_path,
+ const String &p_src_path, uint32_t p_flags,
+ float p_bake_fps, Ref<GLTFState> r_state) {
+ ERR_FAIL_NULL_V(p_node, ERR_INVALID_PARAMETER);
+
+ Ref<GLTFDocument> gltf_document;
+ gltf_document.instantiate();
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ Error err = ext->export_preflight(this, p_node);
+ ERR_FAIL_COND_V(err != OK, err);
+ }
+
+ if (r_state == Ref<GLTFState>()) {
+ r_state.instantiate();
+ }
+ Error err = gltf_document->serialize(r_state, p_node, p_path);
+ ERR_FAIL_COND_V(err != OK, err);
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ err = ext->export_post(this);
+ ERR_FAIL_COND_V(err != OK, err);
+ }
+ return OK;
+}
+
+Node *GLTFDocument::import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err) {
+ // TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire
+ if (r_state == Ref<GLTFState>()) {
+ r_state.instantiate();
+ }
+ r_state->use_named_skin_binds =
+ p_flags & EditorSceneImporter::IMPORT_USE_NAMED_SKIN_BINDS;
+
+ Ref<GLTFDocument> gltf_document;
+ gltf_document.instantiate();
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ Error err = ext->import_preflight(this);
+ if (r_err) {
+ *r_err = err;
+ }
+ ERR_FAIL_COND_V(err != OK, nullptr);
+ }
+ Error err = gltf_document->parse(r_state, p_path);
+ if (r_err) {
+ *r_err = err;
+ }
+ ERR_FAIL_COND_V(err != Error::OK, nullptr);
+
+ Node3D *root = memnew(Node3D);
+ for (int32_t root_i = 0; root_i < r_state->root_nodes.size(); root_i++) {
+ gltf_document->_generate_scene_node(r_state, root, root, r_state->root_nodes[root_i]);
+ }
+ gltf_document->_process_mesh_instances(r_state, root);
+ if (r_state->animations.size()) {
+ AnimationPlayer *ap = memnew(AnimationPlayer);
+ root->add_child(ap);
+ ap->set_owner(root);
+ for (int i = 0; i < r_state->animations.size(); i++) {
+ gltf_document->_import_animation(r_state, ap, i, p_bake_fps);
+ }
+ }
+ for (int32_t ext_i = 0; ext_i < document_extensions.size(); ext_i++) {
+ Ref<GLTFDocumentExtension> ext = document_extensions[ext_i];
+ ERR_CONTINUE(ext.is_null());
+ err = ext->import_post(this, root);
+ if (r_err) {
+ *r_err = err;
+ }
+ ERR_FAIL_COND_V(err != OK, nullptr);
+ }
+ return root;
+}
+
+void GLTFDocument::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("save_scene", "node", "path", "src_path", "flags", "bake_fps", "state"),
+ &GLTFDocument::save_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>()));
+ ClassDB::bind_method(D_METHOD("import_scene", "path", "flags", "bake_fps", "state"),
+ &GLTFDocument::import_scene, DEFVAL(0), DEFVAL(30), DEFVAL(Ref<GLTFState>()));
+ ClassDB::bind_method(D_METHOD("set_extensions", "extensions"),
+ &GLTFDocument::set_extensions);
+ ClassDB::bind_method(D_METHOD("get_extensions"),
+ &GLTFDocument::get_extensions);
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "extensions", PROPERTY_HINT_ARRAY_TYPE,
+ vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "GLTFDocumentExtension"),
+ PROPERTY_USAGE_DEFAULT),
+ "set_extensions", "get_extensions");
+}
+
+void GLTFDocument::_build_parent_hierachy(Ref<GLTFState> state) {
+ // build the hierarchy
+ for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
+ for (int j = 0; j < state->nodes[node_i]->children.size(); j++) {
+ GLTFNodeIndex child_i = state->nodes[node_i]->children[j];
+ ERR_FAIL_INDEX(child_i, state->nodes.size());
+ if (state->nodes.write[child_i]->parent != -1) {
+ continue;
+ }
+ state->nodes.write[child_i]->parent = node_i;
+ }
+ }
+}
+
+Node *GLTFDocument::import_scene(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state) {
+ Error err = FAILED;
+ List<String> deps;
+ Node *node = import_scene_gltf(p_path, p_flags, p_bake_fps, r_state, &deps, &err);
+ if (err != OK) {
+ return nullptr;
+ }
+ return node;
+}
+
+void GLTFDocument::set_extensions(TypedArray<GLTFDocumentExtension> p_extensions) {
+ document_extensions = p_extensions;
+}
+
+TypedArray<GLTFDocumentExtension> GLTFDocument::get_extensions() const {
+ return document_extensions;
+}
+
+GLTFDocument::GLTFDocument() {
+ bool is_editor = ::Engine::get_singleton()->is_editor_hint();
+ if (is_editor) {
+ return;
+ }
+ Ref<GLTFDocumentExtensionConvertImporterMesh> extension_editor;
+ extension_editor.instantiate();
+ document_extensions.push_back(extension_editor);
+}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 7a826897a9..7317c6a9a3 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -33,8 +33,11 @@
#include "gltf_animation.h"
-#include "editor/import/scene_importer_mesh_node_3d.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/variant.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
#include "scene/3d/bone_attachment_3d.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
#include "scene/3d/light_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/node_3d.h"
@@ -44,12 +47,17 @@
#include "scene/resources/texture.h"
#include "modules/modules_enabled.gen.h"
+#include <cstdint>
class GLTFState;
class GLTFSkin;
class GLTFNode;
class GLTFSpecGloss;
class GLTFSkeleton;
+class CSGShape3D;
+class GridMap;
+class MultiMeshInstance3D;
+class GLTFDocumentExtension;
using GLTFAccessorIndex = int;
using GLTFAnimationIndex = int;
@@ -70,8 +78,13 @@ class GLTFDocument : public Resource {
friend class GLTFState;
friend class GLTFSkin;
friend class GLTFSkeleton;
+ TypedArray<GLTFDocumentExtension> document_extensions;
+
+private:
+ const float BAKE_FPS = 30.0f;
public:
+ GLTFDocument();
const int32_t JOINT_GROUP_SIZE = 4;
enum GLTFType {
TYPE_SCALAR,
@@ -102,6 +115,18 @@ public:
COMPONENT_TYPE_FLOAT = 5126,
};
+protected:
+ static void _bind_methods();
+
+public:
+ Node *import_scene(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state);
+ Node *import_scene_gltf(const String &p_path, uint32_t p_flags, int32_t p_bake_fps, Ref<GLTFState> r_state, List<String> *r_missing_deps, Error *r_err = nullptr);
+ Error save_scene(Node *p_node, const String &p_path,
+ const String &p_src_path, uint32_t p_flags,
+ float p_bake_fps, Ref<GLTFState> r_state);
+ void set_extensions(TypedArray<GLTFDocumentExtension> p_extensions);
+ TypedArray<GLTFDocumentExtension> get_extensions() const;
+
private:
template <class T>
static Array to_array(const Vector<T> &p_inp) {
@@ -155,6 +180,7 @@ private:
r_out[keys[i]] = p_inp[keys[i]];
}
}
+ void _build_parent_hierachy(Ref<GLTFState> state);
double _filter_number(double p_float);
String _get_component_type_name(const uint32_t p_component);
int _get_component_type_size(const int component_type);
@@ -262,12 +288,10 @@ private:
Skeleton3D *skeleton,
const GLTFNodeIndex node_index,
const GLTFNodeIndex bone_index);
- EditorSceneImporterMeshNode3D *_generate_mesh_instance(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
- Camera3D *_generate_camera(Ref<GLTFState> state, Node *scene_parent,
- const GLTFNodeIndex node_index);
- Node3D *_generate_light(Ref<GLTFState> state, Node *scene_parent, const GLTFNodeIndex node_index);
- Node3D *_generate_spatial(Ref<GLTFState> state, Node *scene_parent,
- const GLTFNodeIndex node_index);
+ ImporterMeshInstance3D *_generate_mesh_instance(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+ Camera3D *_generate_camera(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+ Node3D *_generate_light(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
+ Node3D *_generate_spatial(Ref<GLTFState> state, Node *parent_node, const GLTFNodeIndex node_index);
void _assign_scene_names(Ref<GLTFState> state);
template <class T>
T _interpolate_track(const Vector<float> &p_times, const Vector<T> &p_values,
@@ -338,7 +362,6 @@ private:
GLTFNodeIndex p_node_i);
Error _encode_buffer_bins(Ref<GLTFState> state, const String &p_path);
Error _encode_buffer_glb(Ref<GLTFState> state, const String &p_path);
- Error _serialize_bone_attachment(Ref<GLTFState> state);
Dictionary _serialize_texture_transform_uv1(Ref<BaseMaterial3D> p_material);
Dictionary _serialize_texture_transform_uv2(Ref<BaseMaterial3D> p_material);
Error _serialize_version(Ref<GLTFState> state);
@@ -369,20 +392,17 @@ public:
void _generate_skeleton_bone_node(Ref<GLTFState> state, Node *scene_parent, Node3D *scene_root, const GLTFNodeIndex node_index);
void _import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
const GLTFAnimationIndex index, const int bake_fps);
- GLTFMeshIndex _convert_mesh_instance(Ref<GLTFState> state,
- MeshInstance3D *p_mesh_instance);
void _convert_mesh_instances(Ref<GLTFState> state);
GLTFCameraIndex _convert_camera(Ref<GLTFState> state, Camera3D *p_camera);
- void _convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Node3D *spatial, Ref<GLTFNode> gltf_node);
+ void _convert_light_to_gltf(Light3D *light, Ref<GLTFState> state, Ref<GLTFNode> gltf_node);
GLTFLightIndex _convert_light(Ref<GLTFState> state, Light3D *p_light);
- GLTFSkeletonIndex _convert_skeleton(Ref<GLTFState> state, Skeleton3D *p_skeleton);
void _convert_spatial(Ref<GLTFState> state, Node3D *p_spatial, Ref<GLTFNode> p_node);
- void _convert_scene_node(Ref<GLTFState> state, Node *p_current, Node *p_root,
+ void _convert_scene_node(Ref<GLTFState> state, Node *p_current,
const GLTFNodeIndex p_gltf_current,
const GLTFNodeIndex p_gltf_root);
#ifdef MODULE_CSG_ENABLED
- void _convert_csg_shape_to_gltf(Node *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
+ void _convert_csg_shape_to_gltf(CSGShape3D *p_current, GLTFNodeIndex p_gltf_parent, Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
#endif // MODULE_CSG_ENABLED
void _create_gltf_node(Ref<GLTFState> state,
@@ -393,40 +413,39 @@ public:
Ref<GLTFNode> gltf_node);
void _convert_animation_player_to_gltf(
AnimationPlayer *animation_player, Ref<GLTFState> state,
- const GLTFNodeIndex &p_gltf_current,
- const GLTFNodeIndex &p_gltf_root_index,
- Ref<GLTFNode> p_gltf_node, Node *p_scene_parent,
- Node *p_root);
+ GLTFNodeIndex p_gltf_current,
+ GLTFNodeIndex p_gltf_root_index,
+ Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
void _check_visibility(Node *p_node, bool &retflag);
void _convert_camera_to_gltf(Camera3D *camera, Ref<GLTFState> state,
- Node3D *spatial,
Ref<GLTFNode> gltf_node);
#ifdef MODULE_GRIDMAP_ENABLED
void _convert_grid_map_to_gltf(
- Node *p_scene_parent,
- const GLTFNodeIndex &p_parent_node_index,
- const GLTFNodeIndex &p_root_node_index,
- Ref<GLTFNode> gltf_node, Ref<GLTFState> state,
- Node *p_root_node);
+ GridMap *p_grid_map,
+ GLTFNodeIndex p_parent_node_index,
+ GLTFNodeIndex p_root_node_index,
+ Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
#endif // MODULE_GRIDMAP_ENABLED
- void _convert_mult_mesh_instance_to_gltf(
- Node *p_scene_parent,
- const GLTFNodeIndex &p_parent_node_index,
- const GLTFNodeIndex &p_root_node_index,
- Ref<GLTFNode> gltf_node, Ref<GLTFState> state,
- Node *p_root_node);
+ void _convert_multi_mesh_instance_to_gltf(
+ MultiMeshInstance3D *p_multi_mesh_instance,
+ GLTFNodeIndex p_parent_node_index,
+ GLTFNodeIndex p_root_node_index,
+ Ref<GLTFNode> gltf_node, Ref<GLTFState> state);
void _convert_skeleton_to_gltf(
- Node *p_scene_parent, Ref<GLTFState> state,
- const GLTFNodeIndex &p_parent_node_index,
- const GLTFNodeIndex &p_root_node_index,
- Ref<GLTFNode> gltf_node, Node *p_root_node);
- void _convert_bone_attachment_to_gltf(Node *p_scene_parent,
+ Skeleton3D *p_scene_parent, Ref<GLTFState> state,
+ GLTFNodeIndex p_parent_node_index,
+ GLTFNodeIndex p_root_node_index,
+ Ref<GLTFNode> gltf_node);
+ void _convert_bone_attachment_to_gltf(BoneAttachment3D *p_bone_attachment,
+ Ref<GLTFState> state,
+ GLTFNodeIndex p_parent_node_index,
+ GLTFNodeIndex p_root_node_index,
+ Ref<GLTFNode> gltf_node);
+ void _convert_mesh_instance_to_gltf(MeshInstance3D *p_mesh_instance,
Ref<GLTFState> state,
- Ref<GLTFNode> gltf_node,
- bool &retflag);
- void _convert_mesh_to_gltf(Node *p_scene_parent,
- Ref<GLTFState> state, Node3D *spatial,
Ref<GLTFNode> gltf_node);
+ GLTFMeshIndex _convert_mesh_to_gltf(Ref<GLTFState> state,
+ MeshInstance3D *p_mesh_instance);
void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
String p_animation_track_name);
Error serialize(Ref<GLTFState> state, Node *p_root, const String &p_path);
diff --git a/modules/gdnative/net/stream_peer_gdnative.cpp b/modules/gltf/gltf_document_extension.cpp
index 72ab72323d..a423059a9c 100644
--- a/modules/gdnative/net/stream_peer_gdnative.cpp
+++ b/modules/gltf/gltf_document_extension.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* stream_peer_gdnative.cpp */
+/* gltf_document_extension.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,50 +28,61 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "stream_peer_gdnative.h"
+#include "gltf_document_extension.h"
-StreamPeerGDNative::StreamPeerGDNative() {
- interface = nullptr;
-}
-
-StreamPeerGDNative::~StreamPeerGDNative() {
-}
+#include "gltf_document.h"
-void StreamPeerGDNative::set_native_stream_peer(const godot_net_stream_peer *p_interface) {
- interface = p_interface;
+void GLTFDocumentExtension::_bind_methods() {
+ // Import
+ ClassDB::bind_method(D_METHOD("get_import_setting_keys"),
+ &GLTFDocumentExtension::get_import_setting_keys);
+ ClassDB::bind_method(D_METHOD("import_preflight", "document"),
+ &GLTFDocumentExtension::import_preflight);
+ ClassDB::bind_method(D_METHOD("get_import_setting", "key"),
+ &GLTFDocumentExtension::get_import_setting);
+ ClassDB::bind_method(D_METHOD("set_import_setting", "key", "value"),
+ &GLTFDocumentExtension::set_import_setting);
+ ClassDB::bind_method(D_METHOD("import_post", "document", "node"),
+ &GLTFDocumentExtension::import_post);
+ // Export
+ ClassDB::bind_method(D_METHOD("get_export_setting_keys"),
+ &GLTFDocumentExtension::get_export_setting_keys);
+ ClassDB::bind_method(D_METHOD("get_export_setting", "key"),
+ &GLTFDocumentExtension::get_export_setting);
+ ClassDB::bind_method(D_METHOD("set_export_setting", "key", "value"),
+ &GLTFDocumentExtension::set_export_setting);
+ ClassDB::bind_method(D_METHOD("export_preflight", "document", "node"),
+ &GLTFDocumentExtension::export_preflight);
+ ClassDB::bind_method(D_METHOD("export_post", "document"),
+ &GLTFDocumentExtension::export_post);
}
-void StreamPeerGDNative::_bind_methods() {
+Array GLTFDocumentExtension::get_import_setting_keys() const {
+ return import_settings.keys();
}
-Error StreamPeerGDNative::put_data(const uint8_t *p_data, int p_bytes) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)(interface->put_data(interface->data, p_data, p_bytes));
+Variant GLTFDocumentExtension::get_import_setting(const StringName &p_key) const {
+ if (!import_settings.has(p_key)) {
+ return Variant();
+ }
+ return import_settings[p_key];
}
-Error StreamPeerGDNative::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)(interface->put_partial_data(interface->data, p_data, p_bytes, &r_sent));
+void GLTFDocumentExtension::set_import_setting(const StringName &p_key, Variant p_var) {
+ import_settings[p_key] = p_var;
}
-Error StreamPeerGDNative::get_data(uint8_t *p_buffer, int p_bytes) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)(interface->get_data(interface->data, p_buffer, p_bytes));
+Array GLTFDocumentExtension::get_export_setting_keys() const {
+ return import_settings.keys();
}
-Error StreamPeerGDNative::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)(interface->get_partial_data(interface->data, p_buffer, p_bytes, &r_received));
+Variant GLTFDocumentExtension::get_export_setting(const StringName &p_key) const {
+ if (!import_settings.has(p_key)) {
+ return Variant();
+ }
+ return import_settings[p_key];
}
-int StreamPeerGDNative::get_available_bytes() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_available_bytes(interface->data);
-}
-
-extern "C" {
-
-void GDAPI godot_net_bind_stream_peer(godot_object *p_obj, const godot_net_stream_peer *p_interface) {
- ((StreamPeerGDNative *)p_obj)->set_native_stream_peer(p_interface);
-}
+void GLTFDocumentExtension::set_export_setting(const StringName &p_key, Variant p_var) {
+ import_settings[p_key] = p_var;
}
diff --git a/modules/gdnative/net/packet_peer_gdnative.h b/modules/gltf/gltf_document_extension.h
index 29013f9367..622a65708c 100644
--- a/modules/gdnative/net/packet_peer_gdnative.h
+++ b/modules/gltf/gltf_document_extension.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* packet_peer_gdnative.h */
+/* gltf_document_extension.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,32 +28,36 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef PACKET_PEER_GDNATIVE_H
-#define PACKET_PEER_GDNATIVE_H
+#ifndef GLTF_DOCUMENT_EXTENSION_H
+#define GLTF_DOCUMENT_EXTENSION_H
-#include "core/io/packet_peer.h"
-#include "modules/gdnative/gdnative.h"
-#include "modules/gdnative/include/net/godot_net.h"
+#include "core/io/resource.h"
+#include "core/variant/dictionary.h"
+#include "core/variant/typed_array.h"
+#include "core/variant/variant.h"
+class GLTFDocument;
+class GLTFDocumentExtension : public Resource {
+ GDCLASS(GLTFDocumentExtension, Resource);
-class PacketPeerGDNative : public PacketPeer {
- GDCLASS(PacketPeerGDNative, PacketPeer);
+ Dictionary import_settings;
+ Dictionary export_settings;
protected:
static void _bind_methods();
- const godot_net_packet_peer *interface;
public:
- PacketPeerGDNative();
- ~PacketPeerGDNative();
+ virtual Array get_import_setting_keys() const;
+ virtual Variant get_import_setting(const StringName &p_key) const;
+ virtual void set_import_setting(const StringName &p_key, Variant p_var);
+ virtual Error import_preflight(Ref<GLTFDocument> p_document) { return OK; }
+ virtual Error import_post(Ref<GLTFDocument> p_document, Node *p_node) { return OK; }
- /* Sets the interface implementation from GDNative */
- void set_native_packet_peer(const godot_net_packet_peer *p_impl);
-
- /* Specific to PacketPeer */
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size) override;
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size) override;
- virtual int get_max_packet_size() const override;
- virtual int get_available_packet_count() const override;
+public:
+ virtual Array get_export_setting_keys() const;
+ virtual Variant get_export_setting(const StringName &p_key) const;
+ virtual void set_export_setting(const StringName &p_key, Variant p_var);
+ virtual Error export_preflight(Ref<GLTFDocument> p_document, Node *p_node) { return OK; }
+ virtual Error export_post(Ref<GLTFDocument> p_document) { return OK; }
};
-#endif // PACKET_PEER_GDNATIVE_H
+#endif // GLTF_DOCUMENT_EXTENSION_H
diff --git a/modules/gdnative/net/webrtc_gdnative.cpp b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
index 76ccbad009..78a98dfa3e 100644
--- a/modules/gdnative/net/webrtc_gdnative.cpp
+++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.cpp
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* webrtc_gdnative.cpp */
+/* gltf_document_extension_convert_importer_mesh.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,33 +28,52 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "modules/gdnative/gdnative.h"
-#include "modules/gdnative/include/net/godot_net.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/resources/importer_mesh.h"
-#ifdef WEBRTC_GDNATIVE_ENABLED
-#include "modules/webrtc/webrtc_data_channel_gdnative.h"
-#include "modules/webrtc/webrtc_peer_connection_gdnative.h"
-#endif
+#include <cstddef>
-extern "C" {
-
-void GDAPI godot_net_bind_webrtc_peer_connection(godot_object *p_obj, const godot_net_webrtc_peer_connection *p_impl) {
-#ifdef WEBRTC_GDNATIVE_ENABLED
- ((WebRTCPeerConnectionGDNative *)p_obj)->set_native_webrtc_peer_connection(p_impl);
-#endif
-}
-
-void GDAPI godot_net_bind_webrtc_data_channel(godot_object *p_obj, const godot_net_webrtc_data_channel *p_impl) {
-#ifdef WEBRTC_GDNATIVE_ENABLED
- ((WebRTCDataChannelGDNative *)p_obj)->set_native_webrtc_data_channel(p_impl);
-#endif
+void GLTFDocumentExtensionConvertImporterMesh::_bind_methods() {
}
-godot_error GDAPI godot_net_set_webrtc_library(const godot_net_webrtc_library *p_lib) {
-#ifdef WEBRTC_GDNATIVE_ENABLED
- return (godot_error)WebRTCPeerConnectionGDNative::set_default_library(p_lib);
-#else
- return (godot_error)ERR_UNAVAILABLE;
-#endif
-}
+Error GLTFDocumentExtensionConvertImporterMesh::import_post(Ref<GLTFDocument> p_document, Node *p_node) {
+ List<Node *> queue;
+ queue.push_back(p_node);
+ List<Node *> delete_queue;
+ while (!queue.is_empty()) {
+ List<Node *>::Element *E = queue.front();
+ Node *node = E->get();
+ {
+ ImporterMeshInstance3D *mesh_3d = cast_to<ImporterMeshInstance3D>(node);
+ if (mesh_3d) {
+ MeshInstance3D *mesh_instance_node_3d = memnew(MeshInstance3D);
+ Ref<ImporterMesh> mesh = mesh_3d->get_mesh();
+ if (mesh.is_valid()) {
+ Ref<ArrayMesh> array_mesh = mesh->get_mesh();
+ mesh_instance_node_3d->set_name(node->get_name());
+ mesh_instance_node_3d->set_transform(mesh_3d->get_transform());
+ mesh_instance_node_3d->set_mesh(array_mesh);
+ mesh_instance_node_3d->set_skin(mesh_3d->get_skin());
+ mesh_instance_node_3d->set_skeleton_path(mesh_3d->get_skeleton_path());
+ node->replace_by(mesh_instance_node_3d);
+ delete_queue.push_back(node);
+ } else {
+ memdelete(mesh_instance_node_3d);
+ }
+ }
+ }
+ int child_count = node->get_child_count();
+ for (int i = 0; i < child_count; i++) {
+ queue.push_back(node->get_child(i));
+ }
+ queue.pop_front();
+ }
+ while (!queue.is_empty()) {
+ List<Node *>::Element *E = delete_queue.front();
+ Node *node = E->get();
+ memdelete(node);
+ delete_queue.pop_front();
+ }
+ return OK;
}
diff --git a/modules/stb_vorbis/register_types.cpp b/modules/gltf/gltf_document_extension_convert_importer_mesh.h
index bdb1cf69cf..85ddb4d250 100644
--- a/modules/stb_vorbis/register_types.cpp
+++ b/modules/gltf/gltf_document_extension_convert_importer_mesh.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* register_types.cpp */
+/* gltf_document_extension_convert_importer_mesh.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,25 +28,28 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#include "register_types.h"
+#ifndef GLTF_EXTENSION_EDITOR_H
+#define GLTF_EXTENSION_EDITOR_H
-#include "audio_stream_ogg_vorbis.h"
+#include "core/io/resource.h"
+#include "core/variant/dictionary.h"
-#ifdef TOOLS_ENABLED
-#include "core/config/engine.h"
-#include "resource_importer_ogg_vorbis.h"
-#endif
+#include "gltf_document.h"
+#include "gltf_document_extension.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/3d/mesh_instance_3d.h"
+#include "scene/main/node.h"
+#include "scene/resources/importer_mesh.h"
-void register_stb_vorbis_types() {
-#ifdef TOOLS_ENABLED
- if (Engine::get_singleton()->is_editor_hint()) {
- Ref<ResourceImporterOGGVorbis> ogg_import;
- ogg_import.instantiate();
- ResourceFormatImporter::get_singleton()->add_importer(ogg_import);
- }
-#endif
- GDREGISTER_CLASS(AudioStreamOGGVorbis);
-}
+class GLTFDocumentExtension;
+class GLTFDocument;
+class GLTFDocumentExtensionConvertImporterMesh : public GLTFDocumentExtension {
+ GDCLASS(GLTFDocumentExtensionConvertImporterMesh, GLTFDocumentExtension);
-void unregister_stb_vorbis_types() {
-}
+protected:
+ static void _bind_methods();
+
+public:
+ Error import_post(Ref<GLTFDocument> p_document, Node *p_node) override;
+};
+#endif // GLTF_EXTENSION_EDITOR_H
diff --git a/modules/gltf/gltf_light.cpp b/modules/gltf/gltf_light.cpp
index 95cca9cf71..c5aa8d5724 100644
--- a/modules/gltf/gltf_light.cpp
+++ b/modules/gltf/gltf_light.cpp
@@ -35,8 +35,8 @@ void GLTFLight::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_color", "color"), &GLTFLight::set_color);
ClassDB::bind_method(D_METHOD("get_intensity"), &GLTFLight::get_intensity);
ClassDB::bind_method(D_METHOD("set_intensity", "intensity"), &GLTFLight::set_intensity);
- ClassDB::bind_method(D_METHOD("get_type"), &GLTFLight::get_type);
- ClassDB::bind_method(D_METHOD("set_type", "type"), &GLTFLight::set_type);
+ ClassDB::bind_method(D_METHOD("get_light_type"), &GLTFLight::get_light_type);
+ ClassDB::bind_method(D_METHOD("set_light_type", "light_type"), &GLTFLight::set_light_type);
ClassDB::bind_method(D_METHOD("get_range"), &GLTFLight::get_range);
ClassDB::bind_method(D_METHOD("set_range", "range"), &GLTFLight::set_range);
ClassDB::bind_method(D_METHOD("get_inner_cone_angle"), &GLTFLight::get_inner_cone_angle);
@@ -46,7 +46,7 @@ void GLTFLight::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color"); // Color
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "intensity"), "set_intensity", "get_intensity"); // float
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "type"), "set_type", "get_type"); // String
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "light_type"), "set_light_type", "get_light_type"); // String
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "range"), "set_range", "get_range"); // float
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "inner_cone_angle"), "set_inner_cone_angle", "get_inner_cone_angle"); // float
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "outer_cone_angle"), "set_outer_cone_angle", "get_outer_cone_angle"); // float
@@ -68,12 +68,12 @@ void GLTFLight::set_intensity(float p_intensity) {
intensity = p_intensity;
}
-String GLTFLight::get_type() {
- return type;
+String GLTFLight::get_light_type() {
+ return light_type;
}
-void GLTFLight::set_type(String p_type) {
- type = p_type;
+void GLTFLight::set_light_type(String p_light_type) {
+ light_type = p_light_type;
}
float GLTFLight::get_range() {
diff --git a/modules/gltf/gltf_light.h b/modules/gltf/gltf_light.h
index a859ca1833..62a20d2f16 100644
--- a/modules/gltf/gltf_light.h
+++ b/modules/gltf/gltf_light.h
@@ -42,12 +42,12 @@ protected:
static void _bind_methods();
private:
- Color color;
- float intensity = 0.0f;
- String type;
- float range = 0.0f;
+ Color color = Color(1.0f, 1.0f, 1.0f);
+ float intensity = 1.0f;
+ String light_type;
+ float range = INFINITY;
float inner_cone_angle = 0.0f;
- float outer_cone_angle = 0.0f;
+ float outer_cone_angle = Math_TAU / 8.0f;
public:
Color get_color();
@@ -56,8 +56,8 @@ public:
float get_intensity();
void set_intensity(float p_intensity);
- String get_type();
- void set_type(String p_type);
+ String get_light_type();
+ void set_light_type(String p_light_type);
float get_range();
void set_range(float p_range);
diff --git a/modules/gltf/gltf_mesh.cpp b/modules/gltf/gltf_mesh.cpp
index 8c10e42c89..747820521a 100644
--- a/modules/gltf/gltf_mesh.cpp
+++ b/modules/gltf/gltf_mesh.cpp
@@ -29,7 +29,7 @@
/*************************************************************************/
#include "gltf_mesh.h"
-#include "editor/import/scene_importer_mesh.h"
+#include "scene/resources/importer_mesh.h"
void GLTFMesh::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_mesh"), &GLTFMesh::get_mesh);
@@ -41,11 +41,11 @@ void GLTFMesh::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_FLOAT32_ARRAY, "blend_weights"), "set_blend_weights", "get_blend_weights"); // Vector<float>
}
-Ref<EditorSceneImporterMesh> GLTFMesh::get_mesh() {
+Ref<ImporterMesh> GLTFMesh::get_mesh() {
return mesh;
}
-void GLTFMesh::set_mesh(Ref<EditorSceneImporterMesh> p_mesh) {
+void GLTFMesh::set_mesh(Ref<ImporterMesh> p_mesh) {
mesh = p_mesh;
}
diff --git a/modules/gltf/gltf_mesh.h b/modules/gltf/gltf_mesh.h
index 0fc750fc9f..3aba0ede32 100644
--- a/modules/gltf/gltf_mesh.h
+++ b/modules/gltf/gltf_mesh.h
@@ -33,22 +33,23 @@
#include "core/io/resource.h"
#include "editor/import/resource_importer_scene.h"
-#include "editor/import/scene_importer_mesh.h"
+#include "scene/3d/importer_mesh_instance_3d.h"
+#include "scene/resources/importer_mesh.h"
#include "scene/resources/mesh.h"
class GLTFMesh : public Resource {
GDCLASS(GLTFMesh, Resource);
private:
- Ref<EditorSceneImporterMesh> mesh;
+ Ref<ImporterMesh> mesh;
Vector<float> blend_weights;
protected:
static void _bind_methods();
public:
- Ref<EditorSceneImporterMesh> get_mesh();
- void set_mesh(Ref<EditorSceneImporterMesh> p_mesh);
+ Ref<ImporterMesh> get_mesh();
+ void set_mesh(Ref<ImporterMesh> p_mesh);
Vector<float> get_blend_weights();
void set_blend_weights(Vector<float> p_blend_weights);
};
diff --git a/modules/gltf/gltf_node.cpp b/modules/gltf/gltf_node.cpp
index 5db7ad66c3..9f925c7bbc 100644
--- a/modules/gltf/gltf_node.cpp
+++ b/modules/gltf/gltf_node.cpp
@@ -47,8 +47,8 @@ void GLTFNode::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_skeleton", "skeleton"), &GLTFNode::set_skeleton);
ClassDB::bind_method(D_METHOD("get_joint"), &GLTFNode::get_joint);
ClassDB::bind_method(D_METHOD("set_joint", "joint"), &GLTFNode::set_joint);
- ClassDB::bind_method(D_METHOD("get_translation"), &GLTFNode::get_translation);
- ClassDB::bind_method(D_METHOD("set_translation", "translation"), &GLTFNode::set_translation);
+ ClassDB::bind_method(D_METHOD("get_position"), &GLTFNode::get_position);
+ ClassDB::bind_method(D_METHOD("set_position", "position"), &GLTFNode::set_position);
ClassDB::bind_method(D_METHOD("get_rotation"), &GLTFNode::get_rotation);
ClassDB::bind_method(D_METHOD("set_rotation", "rotation"), &GLTFNode::set_rotation);
ClassDB::bind_method(D_METHOD("get_scale"), &GLTFNode::get_scale);
@@ -66,7 +66,7 @@ void GLTFNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "skin"), "set_skin", "get_skin"); // GLTFSkinIndex
ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton"), "set_skeleton", "get_skeleton"); // GLTFSkeletonIndex
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "joint"), "set_joint", "get_joint"); // bool
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "translation"), "set_translation", "get_translation"); // Vector3
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "set_position", "get_position"); // Vector3
ADD_PROPERTY(PropertyInfo(Variant::QUATERNION, "rotation"), "set_rotation", "get_rotation"); // Quaternion
ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "scale"), "set_scale", "get_scale"); // Vector3
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "children"), "set_children", "get_children"); // Vector<int>
@@ -137,12 +137,12 @@ void GLTFNode::set_joint(bool p_joint) {
joint = p_joint;
}
-Vector3 GLTFNode::get_translation() {
- return translation;
+Vector3 GLTFNode::get_position() {
+ return position;
}
-void GLTFNode::set_translation(Vector3 p_translation) {
- translation = p_translation;
+void GLTFNode::set_position(Vector3 p_position) {
+ position = p_position;
}
Quaternion GLTFNode::get_rotation() {
diff --git a/modules/gltf/gltf_node.h b/modules/gltf/gltf_node.h
index 378b6da8bf..3b6e061449 100644
--- a/modules/gltf/gltf_node.h
+++ b/modules/gltf/gltf_node.h
@@ -37,7 +37,6 @@
class GLTFNode : public Resource {
GDCLASS(GLTFNode, Resource);
friend class GLTFDocument;
- friend class PackedSceneGLTF;
private:
// matrices need to be transformed to this
@@ -49,7 +48,7 @@ private:
GLTFSkinIndex skin = -1;
GLTFSkeletonIndex skeleton = -1;
bool joint = false;
- Vector3 translation;
+ Vector3 position;
Quaternion rotation;
Vector3 scale = Vector3(1, 1, 1);
Vector<int> children;
@@ -83,8 +82,8 @@ public:
bool get_joint();
void set_joint(bool p_joint);
- Vector3 get_translation();
- void set_translation(Vector3 p_translation);
+ Vector3 get_position();
+ void set_position(Vector3 p_position);
Quaternion get_rotation();
void set_rotation(Quaternion p_rotation);
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index d8209523c5..61faba0dc5 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -36,6 +36,7 @@
#include "gltf_buffer_view.h"
#include "gltf_camera.h"
#include "gltf_document.h"
+#include "gltf_document_extension.h"
#include "gltf_light.h"
#include "gltf_mesh.h"
#include "gltf_node.h"
@@ -44,6 +45,8 @@
#include "gltf_texture.h"
#include "core/io/resource.h"
+#include "core/templates/map.h"
+#include "core/templates/pair.h"
#include "core/templates/vector.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/texture.h"
@@ -51,7 +54,6 @@
class GLTFState : public Resource {
GDCLASS(GLTFState, Resource);
friend class GLTFDocument;
- friend class PackedSceneGLTF;
String filename;
Dictionary json;
@@ -88,6 +90,9 @@ class GLTFState : public Resource {
Vector<Ref<GLTFAnimation>> animations;
Map<GLTFNodeIndex, Node *> scene_nodes;
+ Map<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton;
+ Map<ObjectID, Map<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin;
+
protected:
static void _bind_methods();
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index 85921490d2..0aceb838f7 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -38,6 +38,8 @@
#include "gltf_buffer_view.h"
#include "gltf_camera.h"
#include "gltf_document.h"
+#include "gltf_document_extension.h"
+#include "gltf_document_extension_convert_importer_mesh.h"
#include "gltf_light.h"
#include "gltf_mesh.h"
#include "gltf_node.h"
@@ -79,8 +81,9 @@ void register_gltf_types() {
GDREGISTER_CLASS(GLTFCamera);
GDREGISTER_CLASS(GLTFLight);
GDREGISTER_CLASS(GLTFState);
+ GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
+ GDREGISTER_CLASS(GLTFDocumentExtension);
GDREGISTER_CLASS(GLTFDocument);
- GDREGISTER_CLASS(PackedSceneGLTF);
#endif
}
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 8e8b6f14ad..c9d8f2b42b 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -377,10 +377,7 @@ int GridMap::get_cell_item_orientation(const Vector3i &p_position) const {
}
Vector3i GridMap::world_to_map(const Vector3 &p_world_position) const {
- Vector3 map_position = p_world_position / cell_size;
- map_position.x = floor(map_position.x);
- map_position.y = floor(map_position.y);
- map_position.z = floor(map_position.z);
+ Vector3 map_position = (p_world_position / cell_size).floor();
return Vector3i(map_position);
}
@@ -423,8 +420,8 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
//erase navigation
- for (Map<IndexKey, Octant::NavMesh>::Element *E = g.navmesh_ids.front(); E; E = E->next()) {
- NavigationServer3D::get_singleton()->free(E->get().region);
+ for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
+ NavigationServer3D::get_singleton()->free(E.value.region);
}
g.navmesh_ids.clear();
@@ -475,7 +472,7 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
Pair<Transform3D, IndexKey> p;
- p.first = xform;
+ p.first = xform * mesh_library->get_item_mesh_transform(c.item);
p.second = E->get();
multimesh_items[c.item].push_back(p);
}
@@ -515,15 +512,15 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
//update multimeshes, only if not baked
if (baked_meshes.size() == 0) {
- for (Map<int, List<Pair<Transform3D, IndexKey>>>::Element *E = multimesh_items.front(); E; E = E->next()) {
+ for (const KeyValue<int, List<Pair<Transform3D, IndexKey>>> &E : multimesh_items) {
Octant::MultimeshInstance mmi;
RID mm = RS::get_singleton()->multimesh_create();
- RS::get_singleton()->multimesh_allocate_data(mm, E->get().size(), RS::MULTIMESH_TRANSFORM_3D);
- RS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E->key())->get_rid());
+ RS::get_singleton()->multimesh_allocate_data(mm, E.value.size(), RS::MULTIMESH_TRANSFORM_3D);
+ RS::get_singleton()->multimesh_set_mesh(mm, mesh_library->get_item_mesh(E.key)->get_rid());
int idx = 0;
- for (const Pair<Transform3D, IndexKey> &F : E->get()) {
+ for (const Pair<Transform3D, IndexKey> &F : E.value) {
RS::get_singleton()->multimesh_instance_set_transform(mm, idx, F.first);
#ifdef TOOLS_ENABLED
@@ -570,9 +567,9 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
}
void GridMap::_reset_physic_bodies_collision_filters() {
- for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
- PhysicsServer3D::get_singleton()->body_set_collision_layer(E->get()->static_body, collision_layer);
- PhysicsServer3D::get_singleton()->body_set_collision_mask(E->get()->static_body, collision_mask);
+ for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
+ PhysicsServer3D::get_singleton()->body_set_collision_layer(E.value->static_body, collision_layer);
+ PhysicsServer3D::get_singleton()->body_set_collision_mask(E.value->static_body, collision_mask);
}
}
@@ -593,17 +590,17 @@ void GridMap::_octant_enter_world(const OctantKey &p_key) {
}
if (bake_navigation && mesh_library.is_valid()) {
- for (Map<IndexKey, Octant::NavMesh>::Element *F = g.navmesh_ids.front(); F; F = F->next()) {
- if (cell_map.has(F->key()) && F->get().region.is_valid() == false) {
- Ref<NavigationMesh> nm = mesh_library->get_item_navmesh(cell_map[F->key()].item);
+ for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) {
+ if (cell_map.has(F.key) && F.value.region.is_valid() == false) {
+ Ref<NavigationMesh> nm = mesh_library->get_item_navmesh(cell_map[F.key].item);
if (nm.is_valid()) {
RID region = NavigationServer3D::get_singleton()->region_create();
NavigationServer3D::get_singleton()->region_set_layers(region, navigation_layers);
NavigationServer3D::get_singleton()->region_set_navmesh(region, nm);
- NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * F->get().xform);
+ NavigationServer3D::get_singleton()->region_set_transform(region, get_global_transform() * F.value.xform);
NavigationServer3D::get_singleton()->region_set_map(region, get_world_3d()->get_navigation_map());
- F->get().region = region;
+ F.value.region = region;
}
}
}
@@ -624,10 +621,10 @@ void GridMap::_octant_exit_world(const OctantKey &p_key) {
RS::get_singleton()->instance_set_scenario(g.multimesh_instances[i].instance, RID());
}
- for (Map<IndexKey, Octant::NavMesh>::Element *F = g.navmesh_ids.front(); F; F = F->next()) {
- if (F->get().region.is_valid()) {
- NavigationServer3D::get_singleton()->free(F->get().region);
- F->get().region = RID();
+ for (KeyValue<IndexKey, Octant::NavMesh> &F : g.navmesh_ids) {
+ if (F.value.region.is_valid()) {
+ NavigationServer3D::get_singleton()->free(F.value.region);
+ F.value.region = RID();
}
}
}
@@ -646,8 +643,8 @@ void GridMap::_octant_clean_up(const OctantKey &p_key) {
PhysicsServer3D::get_singleton()->free(g.static_body);
// Erase navigation
- for (Map<IndexKey, Octant::NavMesh>::Element *E = g.navmesh_ids.front(); E; E = E->next()) {
- NavigationServer3D::get_singleton()->free(E->get().region);
+ for (const KeyValue<IndexKey, Octant::NavMesh> &E : g.navmesh_ids) {
+ NavigationServer3D::get_singleton()->free(E.value.region);
}
g.navmesh_ids.clear();
@@ -665,8 +662,8 @@ void GridMap::_notification(int p_what) {
case NOTIFICATION_ENTER_WORLD: {
last_transform = get_global_transform();
- for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
- _octant_enter_world(E->key());
+ for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
+ _octant_enter_world(E.key);
}
for (int i = 0; i < baked_meshes.size(); i++) {
@@ -681,8 +678,8 @@ void GridMap::_notification(int p_what) {
break;
}
//update run
- for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
- _octant_transform(E->key());
+ for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
+ _octant_transform(E.key);
}
last_transform = new_xform;
@@ -692,8 +689,8 @@ void GridMap::_notification(int p_what) {
}
} break;
case NOTIFICATION_EXIT_WORLD: {
- for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
- _octant_exit_world(E->key());
+ for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
+ _octant_exit_world(E.key);
}
//_queue_octants_dirty(MAP_DIRTY_INSTANCES|MAP_DIRTY_TRANSFORMS);
@@ -715,8 +712,8 @@ void GridMap::_update_visibility() {
return;
}
- for (Map<OctantKey, Octant *>::Element *e = octant_map.front(); e; e = e->next()) {
- Octant *octant = e->value();
+ for (KeyValue<OctantKey, Octant *> &e : octant_map) {
+ Octant *octant = e.value;
for (int i = 0; i < octant->multimesh_instances.size(); i++) {
const Octant::MultimeshInstance &mi = octant->multimesh_instances[i];
RS::get_singleton()->instance_set_visible(mi.instance, is_visible_in_tree());
@@ -741,20 +738,20 @@ void GridMap::_recreate_octant_data() {
recreating_octants = true;
Map<IndexKey, Cell> cell_copy = cell_map;
_clear_internal();
- for (Map<IndexKey, Cell>::Element *E = cell_copy.front(); E; E = E->next()) {
- set_cell_item(Vector3i(E->key()), E->get().item, E->get().rot);
+ for (const KeyValue<IndexKey, Cell> &E : cell_copy) {
+ set_cell_item(Vector3i(E.key), E.value.item, E.value.rot);
}
recreating_octants = false;
}
void GridMap::_clear_internal() {
- for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
+ for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
if (is_inside_world()) {
- _octant_exit_world(E->key());
+ _octant_exit_world(E.key);
}
- _octant_clean_up(E->key());
- memdelete(E->get());
+ _octant_clean_up(E.key);
+ memdelete(E.value);
}
octant_map.clear();
@@ -776,9 +773,9 @@ void GridMap::_update_octants_callback() {
}
List<OctantKey> to_delete;
- for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
- if (_octant_update(E->key())) {
- to_delete.push_back(E->key());
+ for (const KeyValue<OctantKey, Octant *> &E : octant_map) {
+ if (_octant_update(E.key)) {
+ to_delete.push_back(E.key);
}
}
@@ -886,8 +883,8 @@ void GridMap::set_clip(bool p_enabled, bool p_clip_above, int p_floor, Vector3::
clip_above = p_clip_above;
//make it all update
- for (Map<OctantKey, Octant *>::Element *E = octant_map.front(); E; E = E->next()) {
- Octant *g = E->get();
+ for (KeyValue<OctantKey, Octant *> &E : octant_map) {
+ Octant *g = E.value;
g->dirty = true;
}
awaiting_update = true;
@@ -907,8 +904,8 @@ Array GridMap::get_used_cells() const {
Array a;
a.resize(cell_map.size());
int i = 0;
- for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
- Vector3 p(E->key().x, E->key().y, E->key().z);
+ for (const KeyValue<IndexKey, Cell> &E : cell_map) {
+ Vector3 p(E.key.x, E.key.y, E.key.z);
a[i++] = p;
}
@@ -923,8 +920,8 @@ Array GridMap::get_meshes() {
Vector3 ofs = _get_offset();
Array meshes;
- for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
- int id = E->get().item;
+ for (KeyValue<IndexKey, Cell> &E : cell_map) {
+ int id = E.value.item;
if (!mesh_library->has_item(id)) {
continue;
}
@@ -933,13 +930,13 @@ Array GridMap::get_meshes() {
continue;
}
- IndexKey ik = E->key();
+ IndexKey ik = E.key;
Vector3 cellpos = Vector3(ik.x, ik.y, ik.z);
Transform3D xform;
- xform.basis.set_orthogonal_index(E->get().rot);
+ xform.basis.set_orthogonal_index(E.value.rot);
xform.set_origin(cellpos * cell_size + ofs);
xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
@@ -975,10 +972,10 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
//generate
Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>> surface_map;
- for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next()) {
- IndexKey key = E->key();
+ for (KeyValue<IndexKey, Cell> &E : cell_map) {
+ IndexKey key = E.key;
- int item = E->get().item;
+ int item = E.value.item;
if (!mesh_library->has_item(item)) {
continue;
}
@@ -993,7 +990,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
Transform3D xform;
- xform.basis.set_orthogonal_index(E->get().rot);
+ xform.basis.set_orthogonal_index(E.value.rot);
xform.set_origin(cellpos * cell_size + ofs);
xform.basis.scale(Vector3(cell_scale, cell_scale, cell_scale));
@@ -1026,11 +1023,11 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
}
}
- for (Map<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>>::Element *E = surface_map.front(); E; E = E->next()) {
+ for (KeyValue<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>> &E : surface_map) {
Ref<ArrayMesh> mesh;
mesh.instantiate();
- for (Map<Ref<Material>, Ref<SurfaceTool>>::Element *F = E->get().front(); F; F = F->next()) {
- F->get()->commit(mesh);
+ for (KeyValue<Ref<Material>, Ref<SurfaceTool>> &F : E.value) {
+ F.value->commit(mesh);
}
BakedMesh bm;
diff --git a/modules/gridmap/grid_map_editor_plugin.cpp b/modules/gridmap/grid_map_editor_plugin.cpp
index 2331a12d0f..08d55de976 100644
--- a/modules/gridmap/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/grid_map_editor_plugin.cpp
@@ -255,6 +255,12 @@ void GridMapEditor::_update_cursor_transform() {
cursor_transform.basis *= node->get_cell_scale();
cursor_transform = node->get_global_transform() * cursor_transform;
+ if (selected_palette >= 0) {
+ if (node && !node->get_mesh_library().is_null()) {
+ cursor_transform *= node->get_mesh_library()->get_item_mesh_transform(selected_palette);
+ }
+ }
+
if (cursor_instance.is_valid()) {
RenderingServer::get_singleton()->instance_set_transform(cursor_instance, cursor_transform);
RenderingServer::get_singleton()->instance_set_visible(cursor_instance, cursor_visible);
@@ -597,9 +603,9 @@ void GridMapEditor::_do_paste() {
_clear_clipboard_data();
}
-bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
+EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event) {
if (!node) {
- return false;
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
Ref<InputEventMouseButton> mb = p_event;
@@ -610,12 +616,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
floor->set_value(floor->get_value() + mb->get_factor());
}
- return true; // Eaten.
+ return EditorPlugin::AFTER_GUI_INPUT_STOP; // Eaten.
} else if (mb->get_button_index() == MOUSE_BUTTON_WHEEL_DOWN && (mb->is_command_pressed() || mb->is_shift_pressed())) {
if (mb->is_pressed()) {
floor->set_value(floor->get_value() - mb->get_factor());
}
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
if (mb->is_pressed()) {
@@ -642,19 +648,22 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
_clear_clipboard_data();
input_action = INPUT_NONE;
_update_paste_indicator();
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (selection.active) {
_set_selection(false);
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
input_action = INPUT_ERASE;
set_items.clear();
}
} else {
- return false;
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
- return do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true);
+ if (do_input_action(p_camera, Point2(mb->get_position().x, mb->get_position().y), true)) {
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
+ }
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
} else {
if ((mb->get_button_index() == MOUSE_BUTTON_RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_PAINT)) {
if (set_items.size()) {
@@ -671,7 +680,11 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
}
set_items.clear();
input_action = INPUT_NONE;
- return set_items.size() > 0;
+
+ if (set_items.size() > 0) {
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
+ }
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action == INPUT_SELECT) {
@@ -684,11 +697,11 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
if (mb->get_button_index() == MOUSE_BUTTON_LEFT && input_action != INPUT_NONE) {
set_items.clear();
input_action = INPUT_NONE;
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
if (mb->get_button_index() == MOUSE_BUTTON_RIGHT && (input_action == INPUT_ERASE || input_action == INPUT_PASTE)) {
input_action = INPUT_NONE;
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
}
@@ -696,7 +709,10 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- return do_input_action(p_camera, mm->get_position(), false);
+ if (do_input_action(p_camera, mm->get_position(), false)) {
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
+ }
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
Ref<InputEventKey> k = p_event;
@@ -708,16 +724,16 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
_clear_clipboard_data();
input_action = INPUT_NONE;
_update_paste_indicator();
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (selection.active) {
_set_selection(false);
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else {
selected_palette = -1;
mesh_library_palette->deselect_all();
update_palette();
_update_cursor_instance();
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
@@ -725,12 +741,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
if (k->get_keycode() == options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_PREV_LEVEL))) {
selection.click[edit_axis]--;
_validate_selection();
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
if (k->get_keycode() == options->get_popup()->get_item_accelerator(options->get_popup()->get_item_index(MENU_OPTION_NEXT_LEVEL))) {
selection.click[edit_axis]++;
_validate_selection();
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
}
@@ -749,12 +765,12 @@ bool GridMapEditor::forward_spatial_input_event(Camera3D *p_camera, const Ref<In
if (step) {
floor->set_value(floor->get_value() + step);
}
- return true;
+ return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
}
accumulated_floor_delta = 0.0;
- return false;
+ return EditorPlugin::AFTER_GUI_INPUT_PASS;
}
struct _CGMEItemSort {
diff --git a/modules/gridmap/grid_map_editor_plugin.h b/modules/gridmap/grid_map_editor_plugin.h
index 4bc849e071..1a6b1310d8 100644
--- a/modules/gridmap/grid_map_editor_plugin.h
+++ b/modules/gridmap/grid_map_editor_plugin.h
@@ -232,7 +232,7 @@ protected:
static void _bind_methods();
public:
- bool forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event);
+ EditorPlugin::AfterGUIInput forward_spatial_input_event(Camera3D *p_camera, const Ref<InputEvent> &p_event);
void edit(GridMap *p_gridmap);
GridMapEditor() {}
@@ -250,7 +250,7 @@ protected:
void _notification(int p_what);
public:
- virtual bool forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
+ virtual EditorPlugin::AfterGUIInput forward_spatial_gui_input(Camera3D *p_camera, const Ref<InputEvent> &p_event) override { return grid_map_editor->forward_spatial_input_event(p_camera, p_event); }
virtual String get_name() const override { return "GridMap"; }
bool has_main_screen() const override { return false; }
virtual void edit(Object *p_object) override;
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index 9d6a399eff..32a31aa764 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -65,7 +65,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
Vector<uint8_t> imgdata;
- imgdata.resize(height * width * sizeof(uint32_t));
+ imgdata.resize(height * width * (int)sizeof(uint32_t));
{
uint8_t *w = imgdata.ptrw();
@@ -75,7 +75,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
if (width < 8 || width >= 32768) {
// Read flat data
- f->get_buffer(ptr, width * height * 4);
+ f->get_buffer(ptr, (uint64_t)width * height * 4);
} else {
// Read RLE-encoded data
diff --git a/modules/lightmapper_rd/SCsub b/modules/lightmapper_rd/SCsub
index 2f04f1833e..5cc9d8ee8b 100644
--- a/modules/lightmapper_rd/SCsub
+++ b/modules/lightmapper_rd/SCsub
@@ -7,6 +7,9 @@ env_lightmapper_rd = env_modules.Clone()
env_lightmapper_rd.GLSL_HEADER("lm_raster.glsl")
env_lightmapper_rd.GLSL_HEADER("lm_compute.glsl")
env_lightmapper_rd.GLSL_HEADER("lm_blendseams.glsl")
+env_lightmapper_rd.Depends("lm_raster.glsl.gen.h", "lm_common_inc.glsl")
+env_lightmapper_rd.Depends("lm_compute.glsl.gen.h", "lm_common_inc.glsl")
+env_lightmapper_rd.Depends("lm_blendseams.glsl.gen.h", "lm_common_inc.glsl")
# Godot source files
env_lightmapper_rd.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index fe941e25e7..ba4ef3be8d 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -274,13 +274,12 @@ Lightmapper::BakeError LightmapperRD::_blit_meshes_into_atlas(int p_max_texture_
return BAKE_OK;
}
-void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
+void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata) {
HashMap<Vertex, uint32_t, VertexHash> vertex_map;
//fill triangles array and vertex array
LocalVector<Triangle> triangles;
LocalVector<Vertex> vertex_array;
- LocalVector<Box> box_array;
LocalVector<Seam> seams;
slice_triangle_count.resize(atlas_slices);
@@ -387,16 +386,13 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
}
}
- Box box;
- box.min_bounds[0] = taabb.position.x;
- box.min_bounds[1] = taabb.position.y;
- box.min_bounds[2] = taabb.position.z;
- box.max_bounds[0] = taabb.position.x + MAX(taabb.size.x, 0.0001);
- box.max_bounds[1] = taabb.position.y + MAX(taabb.size.y, 0.0001);
- box.max_bounds[2] = taabb.position.z + MAX(taabb.size.z, 0.0001);
- box.pad0 = box.pad1 = 0; //make valgrind not complain
- box_array.push_back(box);
-
+ t.min_bounds[0] = taabb.position.x;
+ t.min_bounds[1] = taabb.position.y;
+ t.min_bounds[2] = taabb.position.z;
+ t.max_bounds[0] = taabb.position.x + MAX(taabb.size.x, 0.0001);
+ t.max_bounds[1] = taabb.position.y + MAX(taabb.size.y, 0.0001);
+ t.max_bounds[2] = taabb.position.z + MAX(taabb.size.z, 0.0001);
+ t.pad0 = t.pad1 = 0; //make valgrind not complain
triangles.push_back(t);
slice_triangle_count.write[t.slice]++;
}
@@ -505,9 +501,6 @@ void LightmapperRD::_create_acceleration_structures(RenderingDevice *rd, Size2i
Vector<uint8_t> tb = triangles.to_byte_array();
triangle_buffer = rd->storage_buffer_create(tb.size(), tb);
- Vector<uint8_t> bb = box_array.to_byte_array();
- box_buffer = rd->storage_buffer_create(bb.size(), bb);
-
Vector<uint8_t> tib = triangle_indices.to_byte_array();
triangle_cell_indices_buffer = rd->storage_buffer_create(tib.size(), tib);
@@ -755,7 +748,6 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
Vector<int> slice_triangle_count;
RID vertex_buffer;
RID triangle_buffer;
- RID box_buffer;
RID lights_buffer;
RID triangle_cell_indices_buffer;
RID grid_texture;
@@ -767,14 +759,13 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
#define FREE_BUFFERS \
rd->free(vertex_buffer); \
rd->free(triangle_buffer); \
- rd->free(box_buffer); \
rd->free(lights_buffer); \
rd->free(triangle_cell_indices_buffer); \
rd->free(grid_texture); \
rd->free(seams_buffer); \
rd->free(probe_positions_buffer);
- _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, box_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, seams_buffer, p_step_function, p_bake_userdata);
+ _create_acceleration_structures(rd, atlas_size, atlas_slices, bounds, grid_size, probe_positions, p_generate_probes, slice_triangle_count, slice_seam_count, vertex_buffer, triangle_buffer, lights_buffer, triangle_cell_indices_buffer, probe_positions_buffer, grid_texture, seams_buffer, p_step_function, p_bake_userdata);
if (p_step_function) {
p_step_function(0.47, TTR("Preparing shaders"), p_bake_userdata, true);
@@ -828,62 +819,55 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.binding = 3;
- u.ids.push_back(box_buffer);
- base_uniforms.push_back(u);
- }
- {
- RD::Uniform u;
- u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 4;
u.ids.push_back(triangle_cell_indices_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 5;
+ u.binding = 4;
u.ids.push_back(lights_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 6;
+ u.binding = 5;
u.ids.push_back(seams_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
- u.binding = 7;
+ u.binding = 6;
u.ids.push_back(probe_positions_buffer);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 8;
+ u.binding = 7;
u.ids.push_back(grid_texture);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 9;
+ u.binding = 8;
u.ids.push_back(albedo_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
- u.binding = 10;
+ u.binding = 9;
u.ids.push_back(emission_array_tex);
base_uniforms.push_back(u);
}
{
RD::Uniform u;
u.uniform_type = RD::UNIFORM_TYPE_SAMPLER;
- u.binding = 11;
+ u.binding = 10;
u.ids.push_back(sampler);
base_uniforms.push_back(u);
}
diff --git a/modules/lightmapper_rd/lightmapper_rd.h b/modules/lightmapper_rd/lightmapper_rd.h
index 7ab7f34464..a6a3740051 100644
--- a/modules/lightmapper_rd/lightmapper_rd.h
+++ b/modules/lightmapper_rd/lightmapper_rd.h
@@ -157,16 +157,13 @@ class LightmapperRD : public Lightmapper {
}
};
- struct Box {
+ struct Triangle {
+ uint32_t indices[3] = {};
+ uint32_t slice = 0;
float min_bounds[3] = {};
float pad0 = 0.0;
float max_bounds[3] = {};
float pad1 = 0.0;
- };
-
- struct Triangle {
- uint32_t indices[3] = {};
- uint32_t slice = 0;
bool operator<(const Triangle &p_triangle) const {
return slice < p_triangle.slice;
}
@@ -231,7 +228,7 @@ class LightmapperRD : public Lightmapper {
Vector<Color> probe_values;
BakeError _blit_meshes_into_atlas(int p_max_texture_size, Vector<Ref<Image>> &albedo_images, Vector<Ref<Image>> &emission_images, AABB &bounds, Size2i &atlas_size, int &atlas_slices, BakeStepFunc p_step_function, void *p_bake_userdata);
- void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &box_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
+ void _create_acceleration_structures(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, AABB &bounds, int grid_size, Vector<Probe> &probe_positions, GenerateProbes p_generate_probes, Vector<int> &slice_triangle_count, Vector<int> &slice_seam_count, RID &vertex_buffer, RID &triangle_buffer, RID &lights_buffer, RID &triangle_cell_indices_buffer, RID &probe_positions_buffer, RID &grid_texture, RID &seams_buffer, BakeStepFunc p_step_function, void *p_bake_userdata);
void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
public:
diff --git a/modules/lightmapper_rd/lm_common_inc.glsl b/modules/lightmapper_rd/lm_common_inc.glsl
index 1581639036..22172d50e4 100644
--- a/modules/lightmapper_rd/lm_common_inc.glsl
+++ b/modules/lightmapper_rd/lm_common_inc.glsl
@@ -16,26 +16,18 @@ vertices;
struct Triangle {
uvec3 indices;
uint slice;
-};
-
-layout(set = 0, binding = 2, std430) restrict readonly buffer Triangles {
- Triangle data[];
-}
-triangles;
-
-struct Box {
vec3 min_bounds;
uint pad0;
vec3 max_bounds;
uint pad1;
};
-layout(set = 0, binding = 3, std430) restrict readonly buffer Boxes {
- Box data[];
+layout(set = 0, binding = 2, std430) restrict readonly buffer Triangles {
+ Triangle data[];
}
-boxes;
+triangles;
-layout(set = 0, binding = 4, std430) restrict readonly buffer GridIndices {
+layout(set = 0, binding = 3, std430) restrict readonly buffer GridIndices {
uint data[];
}
grid_indices;
@@ -63,7 +55,7 @@ struct Light {
uint pad[3];
};
-layout(set = 0, binding = 5, std430) restrict readonly buffer Lights {
+layout(set = 0, binding = 4, std430) restrict readonly buffer Lights {
Light data[];
}
lights;
@@ -73,19 +65,19 @@ struct Seam {
uvec2 b;
};
-layout(set = 0, binding = 6, std430) restrict readonly buffer Seams {
+layout(set = 0, binding = 5, std430) restrict readonly buffer Seams {
Seam data[];
}
seams;
-layout(set = 0, binding = 7, std430) restrict readonly buffer Probes {
+layout(set = 0, binding = 6, std430) restrict readonly buffer Probes {
vec4 data[];
}
probe_positions;
-layout(set = 0, binding = 8) uniform utexture3D grid;
+layout(set = 0, binding = 7) uniform utexture3D grid;
-layout(set = 0, binding = 9) uniform texture2DArray albedo_tex;
-layout(set = 0, binding = 10) uniform texture2DArray emission_tex;
+layout(set = 0, binding = 8) uniform texture2DArray albedo_tex;
+layout(set = 0, binding = 9) uniform texture2DArray emission_tex;
-layout(set = 0, binding = 11) uniform sampler linear_sampler;
+layout(set = 0, binding = 10) uniform sampler linear_sampler;
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index 9ca40535f9..25b334c5eb 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -115,7 +115,12 @@ bool ray_hits_triangle(vec3 from, vec3 dir, float max_dist, vec3 p0, vec3 p1, ve
return (r_distance > params.bias) && (r_distance < max_dist) && all(greaterThanEqual(r_barycentric, vec3(0.0)));
}
-bool trace_ray(vec3 p_from, vec3 p_to
+const uint RAY_MISS = 0;
+const uint RAY_FRONT = 1;
+const uint RAY_BACK = 2;
+const uint RAY_ANY = 3;
+
+uint trace_ray(vec3 p_from, vec3 p_to
#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
,
out uint r_triangle, out vec3 r_barycentric
@@ -125,6 +130,7 @@ bool trace_ray(vec3 p_from, vec3 p_to
out float r_distance, out vec3 r_normal
#endif
) {
+
/* world coords */
vec3 rel = p_to - p_from;
@@ -150,79 +156,66 @@ bool trace_ray(vec3 p_from, vec3 p_to
while (all(greaterThanEqual(icell, ivec3(0))) && all(lessThan(icell, ivec3(params.grid_size))) && iters < 1000) {
uvec2 cell_data = texelFetch(usampler3D(grid, linear_sampler), icell, 0).xy;
if (cell_data.x > 0) { //triangles here
- bool hit = false;
-#if defined(MODE_UNOCCLUDE)
- bool hit_backface = false;
-#endif
+ uint hit = RAY_MISS;
float best_distance = 1e20;
for (uint i = 0; i < cell_data.x; i++) {
uint tidx = grid_indices.data[cell_data.y + i];
//Ray-Box test
- vec3 t0 = (boxes.data[tidx].min_bounds - p_from) * inv_dir;
- vec3 t1 = (boxes.data[tidx].max_bounds - p_from) * inv_dir;
+ Triangle triangle = triangles.data[tidx];
+ vec3 t0 = (triangle.min_bounds - p_from) * inv_dir;
+ vec3 t1 = (triangle.max_bounds - p_from) * inv_dir;
vec3 tmin = min(t0, t1), tmax = max(t0, t1);
- if (max(tmin.x, max(tmin.y, tmin.z)) <= min(tmax.x, min(tmax.y, tmax.z))) {
+ if (max(tmin.x, max(tmin.y, tmin.z)) > min(tmax.x, min(tmax.y, tmax.z))) {
continue; //ray box failed
}
//prepare triangle vertices
- vec3 vtx0 = vertices.data[triangles.data[tidx].indices.x].position;
- vec3 vtx1 = vertices.data[triangles.data[tidx].indices.y].position;
- vec3 vtx2 = vertices.data[triangles.data[tidx].indices.z].position;
-#if defined(MODE_UNOCCLUDE)
+ vec3 vtx0 = vertices.data[triangle.indices.x].position;
+ vec3 vtx1 = vertices.data[triangle.indices.y].position;
+ vec3 vtx2 = vertices.data[triangle.indices.z].position;
+#if defined(MODE_UNOCCLUDE) || defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
vec3 normal = -normalize(cross((vtx0 - vtx1), (vtx0 - vtx2)));
bool backface = dot(normal, dir) >= 0.0;
#endif
+
float distance;
vec3 barycentric;
if (ray_hits_triangle(p_from, dir, rel_len, vtx0, vtx1, vtx2, distance, barycentric)) {
#ifdef MODE_DIRECT_LIGHT
- return true; //any hit good
+ return RAY_ANY; //any hit good
#endif
-#if defined(MODE_UNOCCLUDE)
+#if defined(MODE_UNOCCLUDE) || defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
if (!backface) {
// the case of meshes having both a front and back face in the same plane is more common than
// expected, so if this is a front-face, bias it closer to the ray origin, so it always wins over the back-face
distance = max(params.bias, distance - params.bias);
}
- hit = true;
-
if (distance < best_distance) {
- hit_backface = backface;
+ hit = backface ? RAY_BACK : RAY_FRONT;
best_distance = distance;
+#if defined(MODE_UNOCCLUDE)
r_distance = distance;
r_normal = normal;
- }
-
#endif
-
#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
-
- hit = true;
- if (distance < best_distance) {
- best_distance = distance;
r_triangle = tidx;
r_barycentric = barycentric;
+#endif
}
#endif
}
}
-#if defined(MODE_UNOCCLUDE)
+#if defined(MODE_UNOCCLUDE) || defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
- if (hit) {
- return hit_backface;
- }
-#endif
-#if defined(MODE_BOUNCE_LIGHT) || defined(MODE_LIGHT_PROBES)
- if (hit) {
- return true;
+ if (hit != RAY_MISS) {
+ return hit;
}
#endif
}
@@ -238,7 +231,7 @@ bool trace_ray(vec3 p_from, vec3 p_to
iters++;
}
- return false;
+ return RAY_MISS;
}
const float PI = 3.14159265f;
@@ -338,7 +331,7 @@ void main() {
continue; //no need to do anything
}
- if (!trace_ray(position + light_dir * params.bias, light_pos)) {
+ if (trace_ray(position + light_dir * params.bias, light_pos) == RAY_MISS) {
vec3 light = lights.data[i].color * lights.data[i].energy * attenuation;
if (lights.data[i].static_bake) {
static_light += light;
@@ -409,6 +402,7 @@ void main() {
vec4(0.0, 0.0, 0.0, 1.0));
#endif
vec3 light_average = vec3(0.0);
+ float active_rays = 0.0;
for (uint i = params.ray_from; i < params.ray_to; i++) {
vec3 ray_dir = normal_mat * vogel_hemisphere(i, params.ray_count, quick_hash(vec2(atlas_pos)));
@@ -416,7 +410,8 @@ void main() {
vec3 barycentric;
vec3 light = vec3(0.0);
- if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
+ uint trace_result = trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric);
+ if (trace_result == RAY_FRONT) {
//hit a triangle
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
vec2 uv1 = vertices.data[triangles.data[tidx].indices.y].uv;
@@ -424,7 +419,8 @@ void main() {
vec3 uvw = vec3(barycentric.x * uv0 + barycentric.y * uv1 + barycentric.z * uv2, float(triangles.data[tidx].slice));
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
- } else if (params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
+ active_rays += 1.0;
+ } else if (trace_result == RAY_MISS && params.env_transform[0][3] == 0.0) { // Use env_transform[0][3] to indicate when we are computing the first bounce
// Did not hit a triangle, reach out for the sky
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
@@ -438,6 +434,7 @@ void main() {
st /= vec2(PI * 2.0, PI);
light = textureLod(sampler2D(environment, linear_sampler), st, 0.0).rgb;
+ active_rays += 1.0;
}
light_average += light;
@@ -461,7 +458,9 @@ void main() {
if (params.ray_from == 0) {
light_total = vec3(0.0);
} else {
- light_total = imageLoad(bounce_accum, ivec3(atlas_pos, params.atlas_slice)).rgb;
+ vec4 accum = imageLoad(bounce_accum, ivec3(atlas_pos, params.atlas_slice));
+ light_total = accum.rgb;
+ active_rays += accum.a;
}
light_total += light_average;
@@ -476,7 +475,9 @@ void main() {
#endif
if (params.ray_to == params.ray_count) {
- light_total /= float(params.ray_count);
+ if (active_rays > 0) {
+ light_total /= active_rays;
+ }
imageStore(dest_light, ivec3(atlas_pos, params.atlas_slice), vec4(light_total, 1.0));
#ifndef USE_SH_LIGHTMAPS
vec4 accum = imageLoad(accum_light, ivec3(atlas_pos, params.atlas_slice));
@@ -484,7 +485,7 @@ void main() {
imageStore(accum_light, ivec3(atlas_pos, params.atlas_slice), accum);
#endif
} else {
- imageStore(bounce_accum, ivec3(atlas_pos, params.atlas_slice), vec4(light_total, 1.0));
+ imageStore(bounce_accum, ivec3(atlas_pos, params.atlas_slice), vec4(light_total, active_rays));
}
#endif
@@ -517,7 +518,7 @@ void main() {
float d;
vec3 norm;
- if (trace_ray(base_pos, ray_to, d, norm)) {
+ if (trace_ray(base_pos, ray_to, d, norm) == RAY_BACK) {
if (d < min_d) {
vertex_pos = base_pos + rays[i] * d + norm * params.bias * 10.0; //this bias needs to be greater than the regular bias, because otherwise later, rays will go the other side when pointing back.
min_d = d;
@@ -557,7 +558,8 @@ void main() {
vec3 barycentric;
vec3 light;
- if (trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric)) {
+ uint trace_result = trace_ray(position + ray_dir * params.bias, position + ray_dir * length(params.world_size), tidx, barycentric);
+ if (trace_result == RAY_FRONT) {
vec2 uv0 = vertices.data[triangles.data[tidx].indices.x].uv;
vec2 uv1 = vertices.data[triangles.data[tidx].indices.y].uv;
vec2 uv2 = vertices.data[triangles.data[tidx].indices.z].uv;
@@ -565,7 +567,7 @@ void main() {
light = textureLod(sampler2DArray(source_light, linear_sampler), uvw, 0.0).rgb;
light += textureLod(sampler2DArray(source_direct_light, linear_sampler), uvw, 0.0).rgb;
- } else {
+ } else if (trace_result == RAY_MISS) {
//did not hit a triangle, reach out for the sky
vec3 sky_dir = normalize(mat3(params.env_transform) * ray_dir);
diff --git a/modules/minimp3/audio_stream_mp3.cpp b/modules/minimp3/audio_stream_mp3.cpp
index 7b52ef178a..17ce051b67 100644
--- a/modules/minimp3/audio_stream_mp3.cpp
+++ b/modules/minimp3/audio_stream_mp3.cpp
@@ -112,7 +112,7 @@ void AudioStreamPlaybackMP3::seek(float p_time) {
}
frames_mixed = uint32_t(mp3_stream->sample_rate * p_time);
- mp3dec_ex_seek(mp3d, frames_mixed * mp3_stream->channels);
+ mp3dec_ex_seek(mp3d, (uint64_t)frames_mixed * mp3_stream->channels);
}
AudioStreamPlaybackMP3::~AudioStreamPlaybackMP3() {
diff --git a/modules/minimp3/doc_classes/AudioStreamMP3.xml b/modules/minimp3/doc_classes/AudioStreamMP3.xml
index 5507329a18..e4f56614ee 100644
--- a/modules/minimp3/doc_classes/AudioStreamMP3.xml
+++ b/modules/minimp3/doc_classes/AudioStreamMP3.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()">
Contains the audio data in bytes.
@@ -21,6 +19,4 @@
Time in seconds at which the stream starts after being looped.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/mobile_vr/doc_classes/MobileVRInterface.xml b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
index 120535bd41..04ba82ef51 100644
--- a/modules/mobile_vr/doc_classes/MobileVRInterface.xml
+++ b/modules/mobile_vr/doc_classes/MobileVRInterface.xml
@@ -15,8 +15,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="display_to_lens" type="float" setter="set_display_to_lens" getter="get_display_to_lens" default="4.0">
The distance between the display and the lenses inside of the device in centimeters.
@@ -40,6 +38,4 @@
The oversample setting. Because of the lens distortion we have to render our buffers at a higher resolution then the screen can natively handle. A value between 1.5 and 2.0 often provides good results but at the cost of performance.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index bbf1db689d..fc1a118e4f 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -244,59 +244,59 @@ void MobileVRInterface::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "k2", PROPERTY_HINT_RANGE, "0.1,10.0,0.0001"), "set_k2", "get_k2");
}
-void MobileVRInterface::set_eye_height(const real_t p_eye_height) {
+void MobileVRInterface::set_eye_height(const double p_eye_height) {
eye_height = p_eye_height;
}
-real_t MobileVRInterface::get_eye_height() const {
+double MobileVRInterface::get_eye_height() const {
return eye_height;
}
-void MobileVRInterface::set_iod(const real_t p_iod) {
+void MobileVRInterface::set_iod(const double p_iod) {
intraocular_dist = p_iod;
};
-real_t MobileVRInterface::get_iod() const {
+double MobileVRInterface::get_iod() const {
return intraocular_dist;
};
-void MobileVRInterface::set_display_width(const real_t p_display_width) {
+void MobileVRInterface::set_display_width(const double p_display_width) {
display_width = p_display_width;
};
-real_t MobileVRInterface::get_display_width() const {
+double MobileVRInterface::get_display_width() const {
return display_width;
};
-void MobileVRInterface::set_display_to_lens(const real_t p_display_to_lens) {
+void MobileVRInterface::set_display_to_lens(const double p_display_to_lens) {
display_to_lens = p_display_to_lens;
};
-real_t MobileVRInterface::get_display_to_lens() const {
+double MobileVRInterface::get_display_to_lens() const {
return display_to_lens;
};
-void MobileVRInterface::set_oversample(const real_t p_oversample) {
+void MobileVRInterface::set_oversample(const double p_oversample) {
oversample = p_oversample;
};
-real_t MobileVRInterface::get_oversample() const {
+double MobileVRInterface::get_oversample() const {
return oversample;
};
-void MobileVRInterface::set_k1(const real_t p_k1) {
+void MobileVRInterface::set_k1(const double p_k1) {
k1 = p_k1;
};
-real_t MobileVRInterface::get_k1() const {
+double MobileVRInterface::get_k1() const {
return k1;
};
-void MobileVRInterface::set_k2(const real_t p_k2) {
+void MobileVRInterface::set_k2(const double p_k2) {
k2 = p_k2;
};
-real_t MobileVRInterface::get_k2() const {
+double MobileVRInterface::get_k2() const {
return k2;
};
@@ -422,7 +422,7 @@ Transform3D MobileVRInterface::get_transform_for_view(uint32_t p_view, const Tra
return transform_for_eye;
};
-CameraMatrix MobileVRInterface::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+CameraMatrix MobileVRInterface::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) {
_THREAD_SAFE_METHOD_
CameraMatrix eye;
diff --git a/modules/mobile_vr/mobile_vr_interface.h b/modules/mobile_vr/mobile_vr_interface.h
index 48b76ec187..a843e1188b 100644
--- a/modules/mobile_vr/mobile_vr_interface.h
+++ b/modules/mobile_vr/mobile_vr_interface.h
@@ -56,17 +56,17 @@ private:
Basis orientation;
// Just set some defaults for these. At some point we need to look at adding a lookup table for common device + headset combos and/or support reading cardboard QR codes
- float eye_height = 1.85;
+ double eye_height = 1.85;
uint64_t last_ticks = 0;
- real_t intraocular_dist = 6.0;
- real_t display_width = 14.5;
- real_t display_to_lens = 4.0;
- real_t oversample = 1.5;
+ double intraocular_dist = 6.0;
+ double display_width = 14.5;
+ double display_to_lens = 4.0;
+ double oversample = 1.5;
- real_t k1 = 0.215;
- real_t k2 = 0.215;
- real_t aspect = 1.0;
+ double k1 = 0.215;
+ double k2 = 0.215;
+ double aspect = 1.0;
/*
logic for processing our sensor data, this was originally in our positional tracker logic but I think
@@ -110,26 +110,26 @@ protected:
static void _bind_methods();
public:
- void set_eye_height(const real_t p_eye_height);
- real_t get_eye_height() const;
+ void set_eye_height(const double p_eye_height);
+ double get_eye_height() const;
- void set_iod(const real_t p_iod);
- real_t get_iod() const;
+ void set_iod(const double p_iod);
+ double get_iod() const;
- void set_display_width(const real_t p_display_width);
- real_t get_display_width() const;
+ void set_display_width(const double p_display_width);
+ double get_display_width() const;
- void set_display_to_lens(const real_t p_display_to_lens);
- real_t get_display_to_lens() const;
+ void set_display_to_lens(const double p_display_to_lens);
+ double get_display_to_lens() const;
- void set_oversample(const real_t p_oversample);
- real_t get_oversample() const;
+ void set_oversample(const double p_oversample);
+ double get_oversample() const;
- void set_k1(const real_t p_k1);
- real_t get_k1() const;
+ void set_k1(const double p_k1);
+ double get_k1() const;
- void set_k2(const real_t p_k2);
- real_t get_k2() const;
+ void set_k2(const double p_k2);
+ double get_k2() const;
virtual StringName get_name() const override;
virtual uint32_t get_capabilities() const override;
@@ -144,7 +144,7 @@ public:
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
- virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
+ virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override;
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
virtual void process() override;
diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp
index 47d1fe482c..233c16531a 100644
--- a/modules/mobile_vr/register_types.cpp
+++ b/modules/mobile_vr/register_types.cpp
@@ -32,15 +32,30 @@
#include "mobile_vr_interface.h"
+Ref<MobileVRInterface> mobile_vr;
+
void register_mobile_vr_types() {
GDREGISTER_CLASS(MobileVRInterface);
if (XRServer::get_singleton()) {
- Ref<MobileVRInterface> mobile_vr;
mobile_vr.instantiate();
XRServer::get_singleton()->add_interface(mobile_vr);
}
}
void unregister_mobile_vr_types() {
+ if (mobile_vr.is_valid()) {
+ // uninitialise our interface if it is initialised
+ if (mobile_vr->is_initialized()) {
+ mobile_vr->uninitialize();
+ }
+
+ // unregister our interface from the XR server
+ if (XRServer::get_singleton()) {
+ XRServer::get_singleton()->remove_interface(mobile_vr);
+ }
+
+ // and release
+ mobile_vr.unref();
+ }
}
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 3437dbd194..247eee4280 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -43,8 +43,10 @@
#include "core/os/thread.h"
#ifdef TOOLS_ENABLED
+#include "core/os/keyboard.h"
#include "editor/bindings_generator.h"
#include "editor/editor_node.h"
+#include "editor/editor_settings.h"
#include "editor/node_dock.h"
#endif
@@ -1353,6 +1355,7 @@ void CSharpLanguage::_editor_init_callback() {
// Enable it as a plugin
EditorNode::add_editor_plugin(godotsharp_editor);
+ ED_SHORTCUT("mono/build_solution", TTR("Build Solution"), KEY_MASK_ALT | KEY_B);
godotsharp_editor->enable_plugin();
get_singleton()->godotsharp_editor = godotsharp_editor;
@@ -1861,6 +1864,28 @@ Variant::Type CSharpInstance::get_property_type(const StringName &p_name, bool *
return Variant::NIL;
}
+void CSharpInstance::get_method_list(List<MethodInfo> *p_list) const {
+ if (!script->is_valid() || !script->script_class)
+ return;
+
+ GD_MONO_SCOPE_THREAD_ATTACH;
+
+ // TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls.
+ GDMonoClass *top = script->script_class;
+
+ while (top && top != script->native) {
+ const Vector<GDMonoMethod *> &methods = top->get_all_methods();
+ for (int i = 0; i < methods.size(); ++i) {
+ MethodInfo minfo = methods[i]->get_method_info();
+ if (minfo.name != CACHED_STRING_NAME(dotctor)) {
+ p_list->push_back(minfo);
+ }
+ }
+
+ top = top->get_parent_class();
+ }
+}
+
bool CSharpInstance::has_method(const StringName &p_method) const {
if (!script.is_valid()) {
return false;
@@ -2866,12 +2891,24 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
ERR_FAIL_COND_V_MSG(elem_variant_type == Variant::NIL, -1, "Unknown array element type.");
- int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, /* allow_generics: */ false, elem_hint, elem_hint_string);
+ bool preset_hint = false;
+ if (elem_variant_type == Variant::STRING) {
+ MonoObject *attr = p_member->get_attribute(CACHED_CLASS(ExportAttribute));
+ if (PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr)) == PROPERTY_HINT_ENUM) {
+ r_hint_string = itos(elem_variant_type) + "/" + itos(PROPERTY_HINT_ENUM) + ":" + CACHED_FIELD(ExportAttribute, hintString)->get_string_value(attr);
+ preset_hint = true;
+ }
+ }
+
+ if (!preset_hint) {
+ int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, /* allow_generics: */ false, elem_hint, elem_hint_string);
- ERR_FAIL_COND_V_MSG(hint_res == -1, -1, "Error while trying to determine information about the array element type.");
+ ERR_FAIL_COND_V_MSG(hint_res == -1, -1, "Error while trying to determine information about the array element type.");
+
+ // Format: type/hint:hint_string
+ r_hint_string = itos(elem_variant_type) + "/" + itos(elem_hint) + ":" + elem_hint_string;
+ }
- // Format: type/hint:hint_string
- r_hint_string = itos(elem_variant_type) + "/" + itos(elem_hint) + ":" + elem_hint_string;
r_hint = PROPERTY_HINT_TYPE_STRING;
} else if (p_allow_generics && p_variant_type == Variant::DICTIONARY) {
@@ -3280,10 +3317,19 @@ void CSharpScript::get_script_method_list(List<MethodInfo> *p_list) const {
GD_MONO_SCOPE_THREAD_ATTACH;
- // TODO: Filter out things unsuitable for explicit calls, like constructors.
- const Vector<GDMonoMethod *> &methods = script_class->get_all_methods();
- for (int i = 0; i < methods.size(); ++i) {
- p_list->push_back(methods[i]->get_method_info());
+ // TODO: We're filtering out constructors but there may be other methods unsuitable for explicit calls.
+ GDMonoClass *top = script_class;
+
+ while (top && top != native) {
+ const Vector<GDMonoMethod *> &methods = top->get_all_methods();
+ for (int i = 0; i < methods.size(); ++i) {
+ MethodInfo minfo = methods[i]->get_method_info();
+ if (minfo.name != CACHED_STRING_NAME(dotctor)) {
+ p_list->push_back(methods[i]->get_method_info());
+ }
+ }
+
+ top = top->get_parent_class();
}
}
@@ -3465,10 +3511,10 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
}
Multiplayer::RPCMode CSharpScript::_member_get_rpc_mode(IMonoClassMember *p_member) const {
- if (p_member->has_attribute(CACHED_CLASS(RemoteAttribute))) {
- return Multiplayer::RPC_MODE_ANY;
+ if (p_member->has_attribute(CACHED_CLASS(AnyPeerAttribute))) {
+ return Multiplayer::RPC_MODE_ANY_PEER;
}
- if (p_member->has_attribute(CACHED_CLASS(PuppetAttribute))) {
+ if (p_member->has_attribute(CACHED_CLASS(AuthorityAttribute))) {
return Multiplayer::RPC_MODE_AUTHORITY;
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index e3bbb20dec..afc17f694a 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -293,7 +293,7 @@ public:
void get_property_list(List<PropertyInfo> *p_properties) const override;
Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid) const override;
- /* TODO */ void get_method_list(List<MethodInfo> *p_list) const override {}
+ void get_method_list(List<MethodInfo> *p_list) const override;
bool has_method(const StringName &p_method) const override;
Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
diff --git a/modules/mono/doc_classes/CSharpScript.xml b/modules/mono/doc_classes/CSharpScript.xml
index 45a6f991bf..abd860a55f 100644
--- a/modules/mono/doc_classes/CSharpScript.xml
+++ b/modules/mono/doc_classes/CSharpScript.xml
@@ -8,7 +8,7 @@
See also [GodotSharp].
</description>
<tutorials>
- <link title="C# tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/c_sharp/index.html</link>
+ <link title="C# documentation index">https://docs.godotengine.org/en/latest/tutorials/scripting/c_sharp/index.html</link>
</tutorials>
<methods>
<method name="new" qualifiers="vararg">
diff --git a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
index 0f50c90531..1d7bfaf0a4 100644
--- a/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
+++ b/modules/mono/editor/GodotTools/GodotTools.IdeMessaging/Client.cs
@@ -121,6 +121,7 @@ namespace GodotTools.IdeMessaging
this.messageHandler = messageHandler;
this.logger = logger;
+ // TODO: Need to fetch the project data dir name from ProjectSettings instead of defaulting to ".godot"
string projectMetadataDir = Path.Combine(godotProjectDir, ".godot", "mono", "metadata");
MetaFilePath = Path.Combine(projectMetadataDir, GodotIdeMetadata.DefaultFileName);
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index 73cabf8561..98c6881166 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -418,11 +418,15 @@ namespace GodotTools
AddToolSubmenuItem("C#", _menuPopup);
+ var buildSolutionShortcut = (Shortcut)EditorShortcut("mono/build_solution");
+
_toolBarBuildButton = new Button
{
Text = "Build",
- HintTooltip = "Build solution",
- FocusMode = Control.FocusModeEnum.None
+ HintTooltip = "Build Solution".TTR(),
+ FocusMode = Control.FocusModeEnum.None,
+ Shortcut = buildSolutionShortcut,
+ ShortcutInTooltip = true
};
_toolBarBuildButton.PressedSignal += BuildSolutionPressed;
AddControlToContainer(CustomControlContainer.Toolbar, _toolBarBuildButton);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
index 793f84fd77..5c5ced8c29 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/Globals.cs
@@ -13,6 +13,9 @@ namespace GodotTools.Internals
public static object EditorDef(string setting, object defaultValue, bool restartIfChanged = false) =>
internal_EditorDef(setting, defaultValue, restartIfChanged);
+ public static object EditorShortcut(string setting) =>
+ internal_EditorShortcut(setting);
+
[SuppressMessage("ReSharper", "InconsistentNaming")]
public static string TTR(this string text) => internal_TTR(text);
@@ -28,6 +31,9 @@ namespace GodotTools.Internals
private static extern object internal_EditorDef(string setting, object defaultValue, bool restartIfChanged);
[MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern object internal_EditorShortcut(string setting);
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
private static extern string internal_TTR(string text);
}
}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 67bcb34b1c..e03c5fd248 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -2610,7 +2610,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
Map<StringName, StringName> accessor_methods;
for (const PropertyInfo &property : property_list) {
- if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY) {
+ if (property.usage & PROPERTY_USAGE_GROUP || property.usage & PROPERTY_USAGE_SUBGROUP || property.usage & PROPERTY_USAGE_CATEGORY || (property.type == Variant::NIL && property.usage & PROPERTY_USAGE_ARRAY)) {
continue;
}
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index d911f6461c..7433c865f5 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -123,8 +123,8 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
// AutoLoads
OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
- for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
- const ProjectSettings::AutoloadInfo &info = E.value;
+ for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
+ const ProjectSettings::AutoloadInfo &info = E.value();
suggestions.push_back(quoted("/root/" + String(info.name)));
}
}
diff --git a/modules/mono/editor/editor_internal_calls.cpp b/modules/mono/editor/editor_internal_calls.cpp
index 6692a6efec..9a61b63c12 100644
--- a/modules/mono/editor/editor_internal_calls.cpp
+++ b/modules/mono/editor/editor_internal_calls.cpp
@@ -306,6 +306,12 @@ MonoObject *godot_icall_Globals_EditorDef(MonoString *p_setting, MonoObject *p_d
return GDMonoMarshal::variant_to_mono_object(result);
}
+MonoObject *godot_icall_Globals_EditorShortcut(MonoString *p_setting) {
+ String setting = GDMonoMarshal::mono_string_to_godot(p_setting);
+ Ref<Shortcut> result = ED_GET_SHORTCUT(setting);
+ return GDMonoMarshal::variant_to_mono_object(result);
+}
+
MonoString *godot_icall_Globals_TTR(MonoString *p_text) {
String text = GDMonoMarshal::mono_string_to_godot(p_text);
return GDMonoMarshal::mono_string_from_godot(TTR(text));
@@ -380,6 +386,7 @@ void register_editor_internal_calls() {
GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorScale", godot_icall_Globals_EditorScale);
GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_GlobalDef", godot_icall_Globals_GlobalDef);
GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorDef", godot_icall_Globals_EditorDef);
+ GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_EditorShortcut", godot_icall_Globals_EditorShortcut);
GDMonoUtils::add_internal_call("GodotTools.Internals.Globals::internal_TTR", godot_icall_Globals_TTR);
// Utils.OS
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
index 8b12537f7f..70a2cf5695 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -67,6 +67,16 @@ namespace Godot
}
/// <summary>
+ /// Returns the center of the <see cref="AABB"/>, which is equal
+ /// to <see cref="Position"/> + (<see cref="Size"/> / 2).
+ /// </summary>
+ /// <returns>The center.</returns>
+ public Vector3 GetCenter()
+ {
+ return _position + (_size * 0.5f);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if this <see cref="AABB"/> completely encloses another one.
/// </summary>
/// <param name="with">The other <see cref="AABB"/> that may be enclosed.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
index 2dedba2be3..b8b9bc660c 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Attributes/RPCAttributes.cs
@@ -3,8 +3,8 @@ using System;
namespace Godot
{
[AttributeUsage(AttributeTargets.Method)]
- public class RemoteAttribute : Attribute { }
+ public class AnyPeerAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Method)]
- public class PuppetAttribute : Attribute { }
+ public class AuthorityAttribute : Attribute { }
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
index 658582960f..1dc21b6303 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Extensions/NodeExtensions.cs
@@ -78,7 +78,8 @@ namespace Godot
/// </example>
/// <seealso cref="GetNode{T}(NodePath)"/>
/// <param name="path">The path to the node to fetch.</param>
- /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>/// ///////// <returns>
+ /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
+ /// <returns>
/// The <see cref="Node"/> at the given <paramref name="path"/>, or <see langword="null"/> if not found.
/// </returns>
public T GetNodeOrNull<T>(NodePath path) where T : class
@@ -97,7 +98,8 @@ namespace Godot
/// <exception cref="InvalidCastException">
/// Thrown when the given the fetched node can't be casted to the given type <typeparamref name="T"/>.
/// </exception>
- /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>/// ///////// <returns>
+ /// <typeparam name="T">The type to cast to. Should be a descendant of <see cref="Node"/>.</typeparam>
+ /// <returns>
/// The child <see cref="Node"/> at the given index <paramref name="idx"/>.
/// </returns>
public T GetChild<T>(int idx) where T : class
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
index 53c02feaa2..ef42374041 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/GD.cs
@@ -376,7 +376,7 @@ namespace Godot
/// <example>
/// <code>
/// GD.Print(GD.RandRange(0, 1)); // Prints 0 or 1
- /// GD.Print(GD.RangeRange(-10, 1000)); // Prints any number from -10 to 1000
+ /// GD.Print(GD.RandRange(-10, 1000)); // Prints any number from -10 to 1000
/// </code>
/// </example>
/// <returns>A random <see langword="int"/> number inside the given range.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
index 8fe08e7e1d..746612477d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Object.base.cs
@@ -117,7 +117,7 @@ namespace Godot
/// {
/// for (int i = 0; i &lt; 100; i++)
/// {
- /// await ToSignal(GetTree(), "idle_frame");
+ /// await ToSignal(GetTree(), "process_frame");
/// GD.Print($"Frame {i}");
/// }
/// }
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index 1d001fba2d..af94484577 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -165,6 +165,16 @@ namespace Godot
}
/// <summary>
+ /// Returns the center of the <see cref="Rect2"/>, which is equal
+ /// to <see cref="Position"/> + (<see cref="Size"/> / 2).
+ /// </summary>
+ /// <returns>The center.</returns>
+ public Vector2 GetCenter()
+ {
+ return _position + (_size * 0.5f);
+ }
+
+ /// <summary>
/// Returns a copy of the <see cref="Rect2"/> grown by the specified amount
/// on all sides.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
index 250b0d0baf..03f406a910 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
@@ -151,7 +151,7 @@ namespace Godot
}
/// <summary>
- /// Returns the area of the <see cref="Rect2"/>.
+ /// Returns the area of the <see cref="Rect2i"/>.
/// </summary>
/// <returns>The area.</returns>
public int GetArea()
@@ -160,6 +160,18 @@ namespace Godot
}
/// <summary>
+ /// Returns the center of the <see cref="Rect2i"/>, which is equal
+ /// to <see cref="Position"/> + (<see cref="Size"/> / 2).
+ /// If <see cref="Size"/> is an odd number, the returned center
+ /// value will be rounded towards <see cref="Position"/>.
+ /// </summary>
+ /// <returns>The center.</returns>
+ public Vector2i GetCenter()
+ {
+ return _position + (_size / 2);
+ }
+
+ /// <summary>
/// Returns a copy of the <see cref="Rect2i"/> grown by the specified amount
/// on all sides.
/// </summary>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index daea09ba72..c82c5f4588 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -361,6 +361,7 @@ namespace Godot
/// <seealso cref="XformInv(Vector2)"/>
/// <param name="v">A vector to transform.</param>
/// <returns>The transformed vector.</returns>
+ [Obsolete("Xform is deprecated. Use the multiplication operator (Transform2D * Vector2) instead.")]
public Vector2 Xform(Vector2 v)
{
return new Vector2(Tdotx(v), Tdoty(v)) + origin;
@@ -372,6 +373,7 @@ namespace Godot
/// <seealso cref="Xform(Vector2)"/>
/// <param name="v">A vector to inversely transform.</param>
/// <returns>The inversely transformed vector.</returns>
+ [Obsolete("XformInv is deprecated. Use the multiplication operator (Vector2 * Transform2D) instead.")]
public Vector2 XformInv(Vector2 v)
{
Vector2 vInv = v - origin;
@@ -447,7 +449,7 @@ namespace Godot
public static Transform2D operator *(Transform2D left, Transform2D right)
{
- left.origin = left.Xform(right.origin);
+ left.origin = left * right.origin;
real_t x0 = left.Tdotx(right.x);
real_t x1 = left.Tdoty(right.x);
@@ -462,6 +464,96 @@ namespace Godot
return left;
}
+ /// <summary>
+ /// Returns a Vector2 transformed (multiplied) by transformation matrix.
+ /// </summary>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <param name="vector">A Vector2 to transform.</param>
+ /// <returns>The transformed Vector2.</returns>
+ public static Vector2 operator *(Transform2D transform, Vector2 vector)
+ {
+ return new Vector2(transform.Tdotx(vector), transform.Tdoty(vector)) + transform.origin;
+ }
+
+ /// <summary>
+ /// Returns a Vector2 transformed (multiplied) by the inverse transformation matrix.
+ /// </summary>
+ /// <param name="vector">A Vector2 to inversely transform.</param>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <returns>The inversely transformed Vector2.</returns>
+ public static Vector2 operator *(Vector2 vector, Transform2D transform)
+ {
+ Vector2 vInv = vector - transform.origin;
+ return new Vector2(transform.x.Dot(vInv), transform.y.Dot(vInv));
+ }
+
+ /// <summary>
+ /// Returns a Rect2 transformed (multiplied) by transformation matrix.
+ /// </summary>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <param name="rect">A Rect2 to transform.</param>
+ /// <returns>The transformed Rect2.</returns>
+ public static Rect2 operator *(Transform2D transform, Rect2 rect)
+ {
+ Vector2 pos = transform * rect.Position;
+ Vector2 toX = transform.x * rect.Size.x;
+ Vector2 toY = transform.y * rect.Size.y;
+
+ return new Rect2(pos, rect.Size).Expand(pos + toX).Expand(pos + toY).Expand(pos + toX + toY);
+ }
+
+ /// <summary>
+ /// Returns a Rect2 transformed (multiplied) by the inverse transformation matrix.
+ /// </summary>
+ /// <param name="rect">A Rect2 to inversely transform.</param>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <returns>The inversely transformed Rect2.</returns>
+ public static Rect2 operator *(Rect2 rect, Transform2D transform)
+ {
+ Vector2 pos = rect.Position * transform;
+ Vector2 to1 = new Vector2(rect.Position.x, rect.Position.y + rect.Size.y) * transform;
+ Vector2 to2 = new Vector2(rect.Position.x + rect.Size.x, rect.Position.y + rect.Size.y) * transform;
+ Vector2 to3 = new Vector2(rect.Position.x + rect.Size.x, rect.Position.y) * transform;
+
+ return new Rect2(pos, rect.Size).Expand(to1).Expand(to2).Expand(to3);
+ }
+
+ /// <summary>
+ /// Returns a copy of the given Vector2[] transformed (multiplied) by transformation matrix.
+ /// </summary>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <param name="array">A Vector2[] to transform.</param>
+ /// <returns>The transformed copy of the Vector2[].</returns>
+ public static Vector2[] operator *(Transform2D transform, Vector2[] array)
+ {
+ Vector2[] newArray = new Vector2[array.Length];
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ newArray[i] = transform * array[i];
+ }
+
+ return newArray;
+ }
+
+ /// <summary>
+ /// Returns a copy of the given Vector2[] transformed (multiplied) by the inverse transformation matrix.
+ /// </summary>
+ /// <param name="array">A Vector2[] to inversely transform.</param>
+ /// <param name="transform">The transformation to apply.</param>
+ /// <returns>The inversely transformed copy of the Vector2[].</returns>
+ public static Vector2[] operator *(Vector2[] array, Transform2D transform)
+ {
+ Vector2[] newArray = new Vector2[array.Length];
+
+ for (int i = 0; i < array.Length; i++)
+ {
+ newArray[i] = array[i] * transform;
+ }
+
+ return newArray;
+ }
+
public static bool operator ==(Transform2D left, Transform2D right)
{
return left.Equals(right);
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 375ad413c4..24bd1ed492 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -122,7 +122,7 @@ public:
private:
_GodotSharpDirs() {
- res_data_dir = "res://.godot/mono";
+ res_data_dir = ProjectSettings::get_singleton()->get_project_data_path().plus_file("mono");
res_metadata_dir = res_data_dir.plus_file("metadata");
res_assemblies_base_dir = res_data_dir.plus_file("assemblies");
res_assemblies_dir = res_assemblies_base_dir.plus_file(GDMono::get_expected_api_build_config());
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 8b215a66c2..2bf55493e0 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -140,8 +140,8 @@ void CachedData::clear_godot_api_cache() {
field_ExportAttribute_hintString = nullptr;
class_SignalAttribute = nullptr;
class_ToolAttribute = nullptr;
- class_RemoteAttribute = nullptr;
- class_PuppetAttribute = nullptr;
+ class_AnyPeerAttribute = nullptr;
+ class_AuthorityAttribute = nullptr;
class_GodotMethodAttribute = nullptr;
field_GodotMethodAttribute_methodName = nullptr;
class_ScriptPathAttribute = nullptr;
@@ -265,8 +265,8 @@ void update_godot_api_cache() {
CACHE_FIELD_AND_CHECK(ExportAttribute, hintString, CACHED_CLASS(ExportAttribute)->get_field("hintString"));
CACHE_CLASS_AND_CHECK(SignalAttribute, GODOT_API_CLASS(SignalAttribute));
CACHE_CLASS_AND_CHECK(ToolAttribute, GODOT_API_CLASS(ToolAttribute));
- CACHE_CLASS_AND_CHECK(RemoteAttribute, GODOT_API_CLASS(RemoteAttribute));
- CACHE_CLASS_AND_CHECK(PuppetAttribute, GODOT_API_CLASS(PuppetAttribute));
+ CACHE_CLASS_AND_CHECK(AnyPeerAttribute, GODOT_API_CLASS(AnyPeerAttribute));
+ CACHE_CLASS_AND_CHECK(AuthorityAttribute, GODOT_API_CLASS(AuthorityAttribute));
CACHE_CLASS_AND_CHECK(GodotMethodAttribute, GODOT_API_CLASS(GodotMethodAttribute));
CACHE_FIELD_AND_CHECK(GodotMethodAttribute, methodName, CACHED_CLASS(GodotMethodAttribute)->get_field("methodName"));
CACHE_CLASS_AND_CHECK(ScriptPathAttribute, GODOT_API_CLASS(ScriptPathAttribute));
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index fd28bbda14..4b4688b4d9 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -111,8 +111,8 @@ struct CachedData {
GDMonoField *field_ExportAttribute_hintString;
GDMonoClass *class_SignalAttribute;
GDMonoClass *class_ToolAttribute;
- GDMonoClass *class_RemoteAttribute;
- GDMonoClass *class_PuppetAttribute;
+ GDMonoClass *class_AnyPeerAttribute;
+ GDMonoClass *class_AuthorityAttribute;
GDMonoClass *class_GodotMethodAttribute;
GDMonoField *field_GodotMethodAttribute_methodName;
GDMonoClass *class_ScriptPathAttribute;
diff --git a/modules/mono/utils/mono_reg_utils.cpp b/modules/mono/utils/mono_reg_utils.cpp
index 6b616dd52d..d0a27b27c1 100644
--- a/modules/mono/utils/mono_reg_utils.cpp
+++ b/modules/mono/utils/mono_reg_utils.cpp
@@ -35,7 +35,7 @@
#include "core/os/os.h"
-// Here, after os/os.h
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
namespace MonoRegUtils {
diff --git a/modules/mono/utils/path_utils.cpp b/modules/mono/utils/path_utils.cpp
index ec04d50704..64aec5d359 100644
--- a/modules/mono/utils/path_utils.cpp
+++ b/modules/mono/utils/path_utils.cpp
@@ -36,6 +36,7 @@
#include "core/os/os.h"
#ifdef WINDOWS_ENABLED
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#define ENV_PATH_SEP ";"
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index fd965674d6..f600f07c87 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -133,13 +133,13 @@ RID GodotNavigationServer::map_create() const {
GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
RID rid = map_owner.make_rid();
- NavMap *space = map_owner.getornull(rid);
+ NavMap *space = map_owner.get_or_null(rid);
space->set_self(rid);
return rid;
}
COMMAND_2(map_set_active, RID, p_map, bool, p_active) {
- NavMap *map = map_owner.getornull(p_map);
+ NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND(map == nullptr);
if (p_active) {
@@ -156,84 +156,84 @@ COMMAND_2(map_set_active, RID, p_map, bool, p_active) {
}
bool GodotNavigationServer::map_is_active(RID p_map) const {
- NavMap *map = map_owner.getornull(p_map);
+ NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, false);
return active_maps.find(map) >= 0;
}
COMMAND_2(map_set_up, RID, p_map, Vector3, p_up) {
- NavMap *map = map_owner.getornull(p_map);
+ NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND(map == nullptr);
map->set_up(p_up);
}
Vector3 GodotNavigationServer::map_get_up(RID p_map) const {
- const NavMap *map = map_owner.getornull(p_map);
+ const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector3());
return map->get_up();
}
COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size) {
- NavMap *map = map_owner.getornull(p_map);
+ NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND(map == nullptr);
map->set_cell_size(p_cell_size);
}
real_t GodotNavigationServer::map_get_cell_size(RID p_map) const {
- const NavMap *map = map_owner.getornull(p_map);
+ const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, 0);
return map->get_cell_size();
}
COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin) {
- NavMap *map = map_owner.getornull(p_map);
+ NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND(map == nullptr);
map->set_edge_connection_margin(p_connection_margin);
}
real_t GodotNavigationServer::map_get_edge_connection_margin(RID p_map) const {
- const NavMap *map = map_owner.getornull(p_map);
+ const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, 0);
return map->get_edge_connection_margin();
}
Vector<Vector3> GodotNavigationServer::map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers) const {
- const NavMap *map = map_owner.getornull(p_map);
+ const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector<Vector3>());
return map->get_path(p_origin, p_destination, p_optimize, p_layers);
}
Vector3 GodotNavigationServer::map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision) const {
- const NavMap *map = map_owner.getornull(p_map);
+ const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector3());
return map->get_closest_point_to_segment(p_from, p_to, p_use_collision);
}
Vector3 GodotNavigationServer::map_get_closest_point(RID p_map, const Vector3 &p_point) const {
- const NavMap *map = map_owner.getornull(p_map);
+ const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector3());
return map->get_closest_point(p_point);
}
Vector3 GodotNavigationServer::map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const {
- const NavMap *map = map_owner.getornull(p_map);
+ const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, Vector3());
return map->get_closest_point_normal(p_point);
}
RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const {
- const NavMap *map = map_owner.getornull(p_map);
+ const NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND_V(map == nullptr, RID());
return map->get_closest_point_owner(p_point);
@@ -243,13 +243,13 @@ RID GodotNavigationServer::region_create() const {
GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
RID rid = region_owner.make_rid();
- NavRegion *reg = region_owner.getornull(rid);
+ NavRegion *reg = region_owner.get_or_null(rid);
reg->set_self(rid);
return rid;
}
COMMAND_2(region_set_map, RID, p_region, RID, p_map) {
- NavRegion *region = region_owner.getornull(p_region);
+ NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
if (region->get_map() != nullptr) {
@@ -262,7 +262,7 @@ COMMAND_2(region_set_map, RID, p_region, RID, p_map) {
}
if (p_map.is_valid()) {
- NavMap *map = map_owner.getornull(p_map);
+ NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND(map == nullptr);
map->add_region(region);
@@ -271,28 +271,28 @@ COMMAND_2(region_set_map, RID, p_region, RID, p_map) {
}
COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform) {
- NavRegion *region = region_owner.getornull(p_region);
+ NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
region->set_transform(p_transform);
}
COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers) {
- NavRegion *region = region_owner.getornull(p_region);
+ NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
region->set_layers(p_layers);
}
uint32_t GodotNavigationServer::region_get_layers(RID p_region) const {
- NavRegion *region = region_owner.getornull(p_region);
+ NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND_V(region == nullptr, 0);
return region->get_layers();
}
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh) {
- NavRegion *region = region_owner.getornull(p_region);
+ NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND(region == nullptr);
region->set_mesh(p_nav_mesh);
@@ -309,21 +309,21 @@ void GodotNavigationServer::region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node
}
int GodotNavigationServer::region_get_connections_count(RID p_region) const {
- NavRegion *region = region_owner.getornull(p_region);
+ NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND_V(!region, 0);
return region->get_connections_count();
}
Vector3 GodotNavigationServer::region_get_connection_pathway_start(RID p_region, int p_connection_id) const {
- NavRegion *region = region_owner.getornull(p_region);
+ NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND_V(!region, Vector3());
return region->get_connection_pathway_start(p_connection_id);
}
Vector3 GodotNavigationServer::region_get_connection_pathway_end(RID p_region, int p_connection_id) const {
- NavRegion *region = region_owner.getornull(p_region);
+ NavRegion *region = region_owner.get_or_null(p_region);
ERR_FAIL_COND_V(!region, Vector3());
return region->get_connection_pathway_end(p_connection_id);
@@ -333,13 +333,13 @@ RID GodotNavigationServer::agent_create() const {
GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
RID rid = agent_owner.make_rid();
- RvoAgent *agent = agent_owner.getornull(rid);
+ RvoAgent *agent = agent_owner.get_or_null(rid);
agent->set_self(rid);
return rid;
}
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
if (agent->get_map()) {
@@ -353,7 +353,7 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {
agent->set_map(nullptr);
if (p_map.is_valid()) {
- NavMap *map = map_owner.getornull(p_map);
+ NavMap *map = map_owner.get_or_null(p_map);
ERR_FAIL_COND(map == nullptr);
agent->set_map(map);
@@ -366,77 +366,77 @@ COMMAND_2(agent_set_map, RID, p_agent, RID, p_map) {
}
COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->neighborDist_ = p_dist;
}
COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->maxNeighbors_ = p_count;
}
COMMAND_2(agent_set_time_horizon, RID, p_agent, real_t, p_time) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->timeHorizon_ = p_time;
}
COMMAND_2(agent_set_radius, RID, p_agent, real_t, p_radius) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->radius_ = p_radius;
}
COMMAND_2(agent_set_max_speed, RID, p_agent, real_t, p_max_speed) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->maxSpeed_ = p_max_speed;
}
COMMAND_2(agent_set_velocity, RID, p_agent, Vector3, p_velocity) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->velocity_ = RVO::Vector3(p_velocity.x, p_velocity.y, p_velocity.z);
}
COMMAND_2(agent_set_target_velocity, RID, p_agent, Vector3, p_velocity) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->prefVelocity_ = RVO::Vector3(p_velocity.x, p_velocity.y, p_velocity.z);
}
COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->position_ = RVO::Vector3(p_position.x, p_position.y, p_position.z);
}
COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->get_agent()->ignore_y_ = p_ignore;
}
bool GodotNavigationServer::agent_is_map_changed(RID p_agent) const {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND_V(agent == nullptr, false);
return agent->is_map_changed();
}
COMMAND_4(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata) {
- RvoAgent *agent = agent_owner.getornull(p_agent);
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
ERR_FAIL_COND(agent == nullptr);
agent->set_callback(p_receiver == nullptr ? ObjectID() : p_receiver->get_instance_id(), p_method, p_udata);
@@ -452,7 +452,7 @@ COMMAND_4(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_
COMMAND_1(free, RID, p_object) {
if (map_owner.owns(p_object)) {
- NavMap *map = map_owner.getornull(p_object);
+ NavMap *map = map_owner.get_or_null(p_object);
// Removes any assigned region
std::vector<NavRegion *> regions = map->get_regions();
@@ -474,7 +474,7 @@ COMMAND_1(free, RID, p_object) {
map_owner.free(p_object);
} else if (region_owner.owns(p_object)) {
- NavRegion *region = region_owner.getornull(p_object);
+ NavRegion *region = region_owner.get_or_null(p_object);
// Removes this region from the map if assigned
if (region->get_map() != nullptr) {
@@ -485,7 +485,7 @@ COMMAND_1(free, RID, p_object) {
region_owner.free(p_object);
} else if (agent_owner.owns(p_object)) {
- RvoAgent *agent = agent_owner.getornull(p_object);
+ RvoAgent *agent = agent_owner.get_or_null(p_object);
// Removes this agent from the map if assigned
if (agent->get_map() != nullptr) {
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 3150ca0bc8..0c8f0ed8c9 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -613,17 +613,17 @@ void NavMap::sync() {
}
Vector<gd::Edge::Connection> free_edges;
- for (Map<gd::EdgeKey, Vector<gd::Edge::Connection>>::Element *E = connections.front(); E; E = E->next()) {
- if (E->get().size() == 2) {
+ for (KeyValue<gd::EdgeKey, Vector<gd::Edge::Connection>> &E : connections) {
+ if (E.value.size() == 2) {
// Connect edge that are shared in different polygons.
- gd::Edge::Connection &c1 = E->get().write[0];
- gd::Edge::Connection &c2 = E->get().write[1];
+ gd::Edge::Connection &c1 = E.value.write[0];
+ gd::Edge::Connection &c2 = E.value.write[1];
c1.polygon->edges[c1.edge].connections.push_back(c2);
c2.polygon->edges[c2.edge].connections.push_back(c1);
// Note: The pathway_start/end are full for those connection and do not need to be modified.
} else {
- CRASH_COND_MSG(E->get().size() != 1, vformat("Number of connection != 1. Found: %d", E->get().size()));
- free_edges.push_back(E->get()[0]);
+ CRASH_COND_MSG(E.value.size() != 1, vformat("Number of connection != 1. Found: %d", E.value.size()));
+ free_edges.push_back(E.value[0]);
}
}
@@ -664,7 +664,7 @@ void NavMap::sync() {
} else {
other1 = other_edge_p1.lerp(other_edge_p2, (1.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio));
}
- if ((self1 - other1).length() > edge_connection_margin) {
+ if (other1.distance_to(self1) > edge_connection_margin) {
continue;
}
@@ -675,7 +675,7 @@ void NavMap::sync() {
} else {
other2 = other_edge_p1.lerp(other_edge_p2, (0.0 - projected_p1_ratio) / (projected_p2_ratio - projected_p1_ratio));
}
- if ((self2 - other2).length() > edge_connection_margin) {
+ if (other2.distance_to(self2) > edge_connection_margin) {
continue;
}
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 905d10c9d4..bb6bc578a4 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -45,7 +45,7 @@
#include "scene/resources/primitive_meshes.h"
#include "scene/resources/shape_3d.h"
#include "scene/resources/sphere_shape_3d.h"
-#include "scene/resources/world_margin_shape_3d.h"
+#include "scene/resources/world_boundary_shape_3d.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_node.h"
diff --git a/modules/ogg/config.py b/modules/ogg/config.py
index d22f9454ed..5a417ba8dd 100644
--- a/modules/ogg/config.py
+++ b/modules/ogg/config.py
@@ -4,3 +4,14 @@ def can_build(env, platform):
def configure(env):
pass
+
+
+def get_doc_classes():
+ return [
+ "OGGPacketSequence",
+ "OGGPacketSequencePlayback",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/ogg/doc_classes/OGGPacketSequence.xml b/modules/ogg/doc_classes/OGGPacketSequence.xml
new file mode 100644
index 0000000000..deac5b67e2
--- /dev/null
+++ b/modules/ogg/doc_classes/OGGPacketSequence.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="OGGPacketSequence" inherits="Resource" version="4.0">
+ <brief_description>
+ A sequence of OGG packets.
+ </brief_description>
+ <description>
+ A sequence of OGG packets.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="get_length" qualifiers="const">
+ <return type="float" />
+ <description>
+ The length of this stream, in seconds.
+ </description>
+ </method>
+ </methods>
+ <members>
+ <member name="granule_positions" type="Array" setter="set_packet_granule_positions" getter="get_packet_granule_positions" default="[]">
+ Contains the granule positions for each page in this packet sequence.
+ </member>
+ <member name="packet_data" type="Array" setter="set_packet_data" getter="get_packet_data" default="[]">
+ Contains the raw packets that make up this OGGPacketSequence.
+ </member>
+ <member name="sampling_rate" type="float" setter="set_sampling_rate" getter="get_sampling_rate" default="0.0">
+ Holds sample rate information about this sequence. Must be set by another class that actually understands the codec.
+ </member>
+ </members>
+</class>
diff --git a/modules/gdnative/doc_classes/StreamPeerGDNative.xml b/modules/ogg/doc_classes/OGGPacketSequencePlayback.xml
index de76277fff..86dee15567 100644
--- a/modules/gdnative/doc_classes/StreamPeerGDNative.xml
+++ b/modules/ogg/doc_classes/OGGPacketSequencePlayback.xml
@@ -1,13 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="StreamPeerGDNative" inherits="StreamPeer" version="4.0">
+<class name="OGGPacketSequencePlayback" inherits="RefCounted" version="4.0">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp
new file mode 100644
index 0000000000..b7a3ad2876
--- /dev/null
+++ b/modules/ogg/ogg_packet_sequence.cpp
@@ -0,0 +1,220 @@
+/*************************************************************************/
+/* ogg_packet_sequence.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "ogg_packet_sequence.h"
+#include "core/variant/typed_array.h"
+
+void OGGPacketSequence::push_page(int64_t p_granule_pos, const Vector<PackedByteArray> &p_data) {
+ Vector<PackedByteArray> data_stored;
+ for (int i = 0; i < p_data.size(); i++) {
+ data_stored.push_back(p_data[i]);
+ }
+ page_granule_positions.push_back(p_granule_pos);
+ page_data.push_back(data_stored);
+ data_version++;
+}
+
+void OGGPacketSequence::set_packet_data(const Array &p_data) {
+ data_version++; // Update the data version so old playbacks know that they can't rely on us anymore.
+ page_data.clear();
+ for (int page_idx = 0; page_idx < p_data.size(); page_idx++) {
+ // Push a new page. We cleared the vector so this will be at index `page_idx`.
+ page_data.push_back(Vector<PackedByteArray>());
+ TypedArray<PackedByteArray> this_page_data = p_data[page_idx];
+ for (int packet = 0; packet < this_page_data.size(); packet++) {
+ page_data.write[page_idx].push_back(this_page_data[packet]);
+ }
+ }
+}
+
+Array OGGPacketSequence::get_packet_data() const {
+ Array ret;
+ for (const Vector<PackedByteArray> &page : page_data) {
+ Array page_variant;
+ for (const PackedByteArray &packet : page) {
+ page_variant.push_back(packet);
+ }
+ ret.push_back(page_variant);
+ }
+ return ret;
+}
+
+void OGGPacketSequence::set_packet_granule_positions(const Array &p_granule_positions) {
+ data_version++; // Update the data version so old playbacks know that they can't rely on us anymore.
+ page_granule_positions.clear();
+ for (int page_idx = 0; page_idx < p_granule_positions.size(); page_idx++) {
+ int64_t granule_pos = p_granule_positions[page_idx];
+ page_granule_positions.push_back(granule_pos);
+ }
+}
+
+Array OGGPacketSequence::get_packet_granule_positions() const {
+ Array ret;
+ for (int64_t granule_pos : page_granule_positions) {
+ ret.push_back(granule_pos);
+ }
+ return ret;
+}
+
+void OGGPacketSequence::set_sampling_rate(float p_sampling_rate) {
+ sampling_rate = p_sampling_rate;
+}
+
+float OGGPacketSequence::get_sampling_rate() const {
+ return sampling_rate;
+}
+
+int64_t OGGPacketSequence::get_final_granule_pos() const {
+ if (!page_granule_positions.is_empty()) {
+ return page_granule_positions[page_granule_positions.size() - 1];
+ }
+ return -1;
+}
+
+float OGGPacketSequence::get_length() const {
+ int64_t granule_pos = get_final_granule_pos();
+ if (granule_pos < 0) {
+ return 0;
+ }
+ return granule_pos / sampling_rate;
+}
+
+Ref<OGGPacketSequencePlayback> OGGPacketSequence::instance_playback() {
+ Ref<OGGPacketSequencePlayback> playback;
+ playback.instantiate();
+ playback->ogg_packet_sequence = Ref<OGGPacketSequence>(this);
+ playback->data_version = data_version;
+
+ return playback;
+}
+
+void OGGPacketSequence::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_packet_data", "packet_data"), &OGGPacketSequence::set_packet_data);
+ ClassDB::bind_method(D_METHOD("get_packet_data"), &OGGPacketSequence::get_packet_data);
+
+ ClassDB::bind_method(D_METHOD("set_packet_granule_positions", "granule_positions"), &OGGPacketSequence::set_packet_granule_positions);
+ ClassDB::bind_method(D_METHOD("get_packet_granule_positions"), &OGGPacketSequence::get_packet_granule_positions);
+
+ ClassDB::bind_method(D_METHOD("set_sampling_rate", "sampling_rate"), &OGGPacketSequence::set_sampling_rate);
+ ClassDB::bind_method(D_METHOD("get_sampling_rate"), &OGGPacketSequence::get_sampling_rate);
+
+ ClassDB::bind_method(D_METHOD("get_length"), &OGGPacketSequence::get_length);
+
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "packet_data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_packet_data", "get_packet_data");
+ ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "granule_positions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_packet_granule_positions", "get_packet_granule_positions");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "sampling_rate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_sampling_rate", "get_sampling_rate");
+}
+
+bool OGGPacketSequencePlayback::next_ogg_packet(ogg_packet **p_packet) const {
+ ERR_FAIL_COND_V(data_version != ogg_packet_sequence->data_version, false);
+ ERR_FAIL_COND_V(ogg_packet_sequence->page_data.is_empty(), false);
+ ERR_FAIL_COND_V(ogg_packet_sequence->page_granule_positions.is_empty(), false);
+ // Move on to the next page if need be. This happens first to help simplify seek logic.
+ while (packet_cursor >= ogg_packet_sequence->page_data[page_cursor].size()) {
+ packet_cursor = 0;
+ page_cursor++;
+ if (page_cursor >= ogg_packet_sequence->page_data.size()) {
+ return false;
+ }
+ }
+
+ ERR_FAIL_COND_V(page_cursor >= ogg_packet_sequence->page_data.size(), false);
+
+ packet->b_o_s = page_cursor == 0 && packet_cursor == 0;
+ packet->e_o_s = page_cursor == ogg_packet_sequence->page_data.size() - 1 && packet_cursor == ogg_packet_sequence->page_data[page_cursor].size() - 1;
+ packet->granulepos = packet_cursor == ogg_packet_sequence->page_data[page_cursor].size() - 1 ? ogg_packet_sequence->page_granule_positions[page_cursor] : -1;
+ packet->packetno = packetno++;
+ packet->bytes = ogg_packet_sequence->page_data[page_cursor][packet_cursor].size();
+ packet->packet = (unsigned char *)(ogg_packet_sequence->page_data[page_cursor][packet_cursor].ptr());
+
+ *p_packet = packet;
+
+ packet_cursor++;
+
+ return true;
+}
+
+uint32_t OGGPacketSequencePlayback::seek_page_internal(int64_t granule, uint32_t after_page_inclusive, uint32_t before_page_inclusive) {
+ if (before_page_inclusive == after_page_inclusive) {
+ return before_page_inclusive;
+ }
+ uint32_t actual_middle_page = after_page_inclusive + (before_page_inclusive - after_page_inclusive) / 2;
+ // Complicating the bisection search algorithm, the middle page might not have a packet that ends on it,
+ // which means it might not have a correct granule position. Find a nearby page that does have a packet ending on it.
+ uint32_t bisection_page = -1;
+ for (uint32_t test_page = actual_middle_page; test_page <= before_page_inclusive; test_page++) {
+ if (ogg_packet_sequence->page_data[test_page].size() > 0) {
+ bisection_page = test_page;
+ break;
+ }
+ }
+ // Check if we have to go backwards.
+ if (bisection_page == (unsigned int)-1) {
+ for (uint32_t test_page = actual_middle_page; test_page >= after_page_inclusive; test_page--) {
+ if (ogg_packet_sequence->page_data[test_page].size() > 0) {
+ bisection_page = test_page;
+ break;
+ }
+ }
+ }
+ if (bisection_page == (unsigned int)-1) {
+ return -1;
+ }
+
+ int64_t bisection_granule_pos = ogg_packet_sequence->page_granule_positions[bisection_page];
+ if (granule > bisection_granule_pos) {
+ return seek_page_internal(granule, bisection_page + 1, before_page_inclusive);
+ } else {
+ return seek_page_internal(granule, after_page_inclusive, bisection_page);
+ }
+}
+
+bool OGGPacketSequencePlayback::seek_page(int64_t p_granule_pos) {
+ int correct_page = seek_page_internal(p_granule_pos, 0, ogg_packet_sequence->page_data.size() - 1);
+ if (correct_page == -1) {
+ return false;
+ }
+
+ packet_cursor = 0;
+ page_cursor = correct_page;
+
+ // Don't pretend subsequent packets are contiguous with previous ones.
+ packetno = 0;
+
+ return true;
+}
+
+OGGPacketSequencePlayback::OGGPacketSequencePlayback() {
+ packet = new ogg_packet();
+}
+
+OGGPacketSequencePlayback::~OGGPacketSequencePlayback() {
+ delete packet;
+}
diff --git a/modules/ogg/ogg_packet_sequence.h b/modules/ogg/ogg_packet_sequence.h
new file mode 100644
index 0000000000..b00ada06c1
--- /dev/null
+++ b/modules/ogg/ogg_packet_sequence.h
@@ -0,0 +1,128 @@
+/*************************************************************************/
+/* ogg_packet_sequence.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 OGG_PACKET_SEQUENCE_H
+#define OGG_PACKET_SEQUENCE_H
+
+#include "core/io/resource.h"
+#include "core/object/gdvirtual.gen.inc"
+#include "core/variant/native_ptr.h"
+#include "core/variant/typed_array.h"
+#include "core/variant/variant.h"
+#include "thirdparty/libogg/ogg/ogg.h"
+
+class OGGPacketSequencePlayback;
+
+class OGGPacketSequence : public Resource {
+ GDCLASS(OGGPacketSequence, Resource);
+
+ friend class OGGPacketSequencePlayback;
+
+ // List of pages, each of which is a list of packets on that page. The innermost PackedByteArrays contain complete ogg packets.
+ Vector<Vector<PackedByteArray>> page_data;
+
+ // List of the granule position for each page.
+ Vector<uint64_t> page_granule_positions;
+
+ // The page after the current last page. Similar semantics to an end() iterator.
+ int64_t end_page = 0;
+
+ uint64_t data_version = 0;
+
+ float sampling_rate = 0;
+ float length = 0;
+
+protected:
+ static void _bind_methods();
+
+public:
+ // Pushes information about all the pages that ended on this page.
+ // This should be called for each page, even for pages that no packets ended on.
+ void push_page(int64_t p_granule_pos, const Vector<PackedByteArray> &p_data);
+
+ void set_packet_data(const Array &p_data);
+ Array get_packet_data() const;
+
+ void set_packet_granule_positions(const Array &p_granule_positions);
+ Array get_packet_granule_positions() const;
+
+ // Sets a sampling rate associated with this object. OGGPacketSequence doesn't understand codecs,
+ // so this value is naively stored as a convenience.
+ void set_sampling_rate(float p_sampling_rate);
+
+ // Returns a sampling rate previously set by set_sampling_rate().
+ float get_sampling_rate() const;
+
+ // Returns a length previously set by set_length().
+ float get_length() const;
+
+ // Returns the granule position of the last page in this sequence.
+ int64_t get_final_granule_pos() const;
+
+ Ref<OGGPacketSequencePlayback> instance_playback();
+
+ OGGPacketSequence() {}
+ virtual ~OGGPacketSequence() {}
+};
+
+class OGGPacketSequencePlayback : public RefCounted {
+ GDCLASS(OGGPacketSequencePlayback, RefCounted);
+
+ friend class OGGPacketSequence;
+
+ Ref<OGGPacketSequence> ogg_packet_sequence;
+
+ mutable int64_t page_cursor = 0;
+ mutable int32_t packet_cursor = 0;
+
+ mutable ogg_packet *packet;
+
+ uint64_t data_version;
+
+ mutable int64_t packetno = 0;
+
+ // Recursive bisection search for the correct page.
+ uint32_t seek_page_internal(int64_t granule, uint32_t after_page_inclusive, uint32_t before_page_inclusive);
+
+public:
+ // Calling functions must not modify this packet.
+ // Returns true on success, false on error or if there is no next packet.
+ bool next_ogg_packet(ogg_packet **p_packet) const;
+
+ // Seeks to the page such that the previous page has a granule position less than or equal to this value,
+ // and the current page has a granule position greater than this value.
+ // Returns true on success, false on failure.
+ bool seek_page(int64_t p_granule_pos);
+
+ OGGPacketSequencePlayback();
+ virtual ~OGGPacketSequencePlayback();
+};
+
+#endif // OGG_PACKET_SEQUENCE_H
diff --git a/modules/ogg/register_types.cpp b/modules/ogg/register_types.cpp
index b23ea65378..3448e7063a 100644
--- a/modules/ogg/register_types.cpp
+++ b/modules/ogg/register_types.cpp
@@ -30,8 +30,11 @@
#include "register_types.h"
-// Dummy module as libogg is needed by other modules (vorbis, theora, opus, ...)
+#include "ogg_packet_sequence.h"
-void register_ogg_types() {}
+void register_ogg_types() {
+ GDREGISTER_CLASS(OGGPacketSequence);
+ GDREGISTER_CLASS(OGGPacketSequencePlayback);
+}
void unregister_ogg_types() {}
diff --git a/modules/opensimplex/doc_classes/NoiseTexture.xml b/modules/opensimplex/doc_classes/NoiseTexture.xml
index 2ae7f8cad9..8a10411cf6 100644
--- a/modules/opensimplex/doc_classes/NoiseTexture.xml
+++ b/modules/opensimplex/doc_classes/NoiseTexture.xml
@@ -16,8 +16,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="as_normal_map" type="bool" setter="set_as_normal_map" getter="is_normal_map" default="false">
If [code]true[/code], the resulting texture contains a normal map created from the original noise interpreted as a bump map.
@@ -42,6 +40,4 @@
Width of the generated texture.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
index c470f3e1ab..604b07b645 100644
--- a/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
+++ b/modules/opensimplex/doc_classes/OpenSimplexNoise.xml
@@ -109,6 +109,4 @@
Seed used to generate random values, different seeds will generate different noise maps.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
index 6e7b3e7b8d..ef4c598194 100644
--- a/modules/raycast/SCsub
+++ b/modules/raycast/SCsub
@@ -55,6 +55,9 @@ if env["builtin_embree"]:
"kernels/bvh/bvh_builder_sah_mb.cpp",
"kernels/bvh/bvh_builder_twolevel.cpp",
"kernels/bvh/bvh_intersector1_bvh4.cpp",
+ "kernels/bvh/bvh_intersector_hybrid4_bvh4.cpp",
+ "kernels/bvh/bvh_intersector_stream_bvh4.cpp",
+ "kernels/bvh/bvh_intersector_stream_filters.cpp",
]
thirdparty_sources = [thirdparty_dir + file for file in embree_src]
@@ -76,6 +79,7 @@ if env["builtin_embree"]:
env.Append(LIBS=["psapi"])
env_thirdparty = env_raycast.Clone()
+ env_thirdparty.force_optimization_on_debug()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
@@ -83,6 +87,20 @@ if env["builtin_embree"]:
# Embree needs those, it will automatically use SSE2NEON in ARM
env_thirdparty.Append(CPPDEFINES=["__SSE2__", "__SSE__"])
+ if not env.msvc:
+ env_thirdparty.Append(
+ CPPFLAGS=[
+ "-fno-strict-overflow",
+ "-fno-delete-null-pointer-checks",
+ "-fwrapv",
+ "-fsigned-char",
+ "-fno-strict-aliasing",
+ "-fno-tree-vectorize",
+ "-fvisibility=hidden",
+ "-fvisibility-inlines-hidden",
+ ]
+ )
+
env.modules_sources += thirdparty_obj
diff --git a/modules/raycast/godot_update_embree.py b/modules/raycast/godot_update_embree.py
index 31a25a318f..e31d88b741 100644
--- a/modules/raycast/godot_update_embree.py
+++ b/modules/raycast/godot_update_embree.py
@@ -61,6 +61,11 @@ cpp_files = [
"kernels/bvh/bvh_builder_twolevel.cpp",
"kernels/bvh/bvh_intersector1.cpp",
"kernels/bvh/bvh_intersector1_bvh4.cpp",
+ "kernels/bvh/bvh_intersector_hybrid4_bvh4.cpp",
+ "kernels/bvh/bvh_intersector_stream_bvh4.cpp",
+ "kernels/bvh/bvh_intersector_stream_filters.cpp",
+ "kernels/bvh/bvh_intersector_hybrid.cpp",
+ "kernels/bvh/bvh_intersector_stream.cpp",
]
os.chdir("../../thirdparty")
@@ -117,7 +122,7 @@ with open(os.path.join(dest_dir, "kernels/config.h"), "w") as config_file:
/* #undef EMBREE_GEOMETRY_INSTANCE */
/* #undef EMBREE_GEOMETRY_GRID */
/* #undef EMBREE_GEOMETRY_POINT */
-/* #undef EMBREE_RAY_PACKETS */
+#define EMBREE_RAY_PACKETS
/* #undef EMBREE_COMPACT_POLYS */
#define EMBREE_CURVE_SELF_INTERSECTION_AVOIDANCE_FACTOR 2.0
@@ -249,3 +254,8 @@ with open(os.path.join(dest_dir, "include/embree3/rtcore_config.h"), "w") as con
os.chdir("..")
shutil.rmtree("embree-tmp")
+
+subprocess.run(["git", "restore", "embree/patches"])
+
+for patch in os.listdir("embree/patches"):
+ subprocess.run(["git", "apply", "embree/patches/" + patch])
diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp
index 0583acc119..fdcf509da8 100644
--- a/modules/raycast/lightmap_raycaster.cpp
+++ b/modules/raycast/lightmap_raycaster.cpp
@@ -168,7 +168,7 @@ void LightmapRaycasterEmbree::clear_mesh_filter() {
filter_meshes.clear();
}
-void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str) {
+void embree_lm_error_handler(void *p_user_data, RTCError p_code, const char *p_str) {
print_error("Embree error: " + String(p_str));
}
@@ -179,16 +179,11 @@ LightmapRaycasterEmbree::LightmapRaycasterEmbree() {
#endif
embree_device = rtcNewDevice(nullptr);
- rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr);
+ rtcSetDeviceErrorFunction(embree_device, &embree_lm_error_handler, nullptr);
embree_scene = rtcNewScene(embree_device);
}
LightmapRaycasterEmbree::~LightmapRaycasterEmbree() {
-#ifdef __SSE2__
- _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
- _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
-#endif
-
if (embree_scene != nullptr) {
rtcReleaseScene(embree_scene);
}
diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster.h
index 4c3de27837..290b0a1cf3 100644
--- a/modules/raycast/lightmap_raycaster.h
+++ b/modules/raycast/lightmap_raycaster.h
@@ -30,9 +30,9 @@
#ifdef TOOLS_ENABLED
+#include "core/io/image.h"
#include "core/object/object.h"
#include "scene/3d/lightmapper.h"
-#include "scene/resources/mesh.h"
#include <embree3/rtcore.h>
diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp
index 88c0145ebc..75491c98e5 100644
--- a/modules/raycast/raycast_occlusion_cull.cpp
+++ b/modules/raycast/raycast_occlusion_cull.cpp
@@ -41,9 +41,14 @@ RaycastOcclusionCull *RaycastOcclusionCull::raycast_singleton = nullptr;
void RaycastOcclusionCull::RaycastHZBuffer::clear() {
HZBuffer::clear();
- camera_rays.clear();
+ if (camera_rays_unaligned_buffer) {
+ memfree(camera_rays_unaligned_buffer);
+ camera_rays_unaligned_buffer = nullptr;
+ camera_rays = nullptr;
+ }
camera_ray_masks.clear();
- packs_size = Size2i();
+ camera_rays_tile_count = 0;
+ tile_grid_size = Size2i();
}
void RaycastOcclusionCull::RaycastHZBuffer::resize(const Size2i &p_size) {
@@ -58,100 +63,112 @@ void RaycastOcclusionCull::RaycastHZBuffer::resize(const Size2i &p_size) {
HZBuffer::resize(p_size);
- packs_size = Size2i(Math::ceil(p_size.x / (float)TILE_SIZE), Math::ceil(p_size.y / (float)TILE_SIZE));
- int ray_packets_count = packs_size.x * packs_size.y;
- camera_rays.resize(ray_packets_count);
- camera_ray_masks.resize(ray_packets_count * TILE_SIZE * TILE_SIZE);
+ tile_grid_size = Size2i(Math::ceil(p_size.x / (float)TILE_SIZE), Math::ceil(p_size.y / (float)TILE_SIZE));
+ camera_rays_tile_count = tile_grid_size.x * tile_grid_size.y;
+
+ if (camera_rays_unaligned_buffer) {
+ memfree(camera_rays_unaligned_buffer);
+ }
+
+ const int alignment = 64; // Embree requires ray packets to be 64-aligned
+ camera_rays_unaligned_buffer = (uint8_t *)memalloc(camera_rays_tile_count * sizeof(CameraRayTile) + alignment);
+ camera_rays = (CameraRayTile *)(camera_rays_unaligned_buffer + alignment - (((uint64_t)camera_rays_unaligned_buffer) % alignment));
+
+ camera_ray_masks.resize(camera_rays_tile_count * TILE_RAYS);
+ memset(camera_ray_masks.ptr(), ~0, camera_rays_tile_count * TILE_RAYS * sizeof(uint32_t));
}
void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool) {
CameraRayThreadData td;
- td.camera_matrix = p_cam_projection;
- td.camera_transform = p_cam_transform;
- td.camera_orthogonal = p_cam_orthogonal;
td.thread_count = p_thread_work_pool.get_thread_count();
+ td.z_near = p_cam_projection.get_z_near();
+ td.z_far = p_cam_projection.get_z_far() * 1.05f;
+ td.camera_pos = p_cam_transform.origin;
+ td.camera_dir = -p_cam_transform.basis.get_axis(2);
+ td.camera_orthogonal = p_cam_orthogonal;
+
+ CameraMatrix inv_camera_matrix = p_cam_projection.inverse();
+ Vector3 camera_corner_proj = Vector3(-1.0f, -1.0f, -1.0f);
+ Vector3 camera_corner_view = inv_camera_matrix.xform(camera_corner_proj);
+ td.pixel_corner = p_cam_transform.xform(camera_corner_view);
+
+ Vector3 top_corner_proj = Vector3(-1.0f, 1.0f, -1.0f);
+ Vector3 top_corner_view = inv_camera_matrix.xform(top_corner_proj);
+ Vector3 top_corner_world = p_cam_transform.xform(top_corner_view);
+
+ Vector3 left_corner_proj = Vector3(1.0f, -1.0f, -1.0f);
+ Vector3 left_corner_view = inv_camera_matrix.xform(left_corner_proj);
+ Vector3 left_corner_world = p_cam_transform.xform(left_corner_view);
+
+ td.pixel_u_interp = left_corner_world - td.pixel_corner;
+ td.pixel_v_interp = top_corner_world - td.pixel_corner;
+
+ debug_tex_range = td.z_far;
+
p_thread_work_pool.do_work(td.thread_count, this, &RaycastHZBuffer::_camera_rays_threaded, &td);
}
-void RaycastOcclusionCull::RaycastHZBuffer::_camera_rays_threaded(uint32_t p_thread, RaycastOcclusionCull::RaycastHZBuffer::CameraRayThreadData *p_data) {
- uint32_t packs_total = camera_rays.size();
+void RaycastOcclusionCull::RaycastHZBuffer::_camera_rays_threaded(uint32_t p_thread, const CameraRayThreadData *p_data) {
+ uint32_t total_tiles = camera_rays_tile_count;
uint32_t total_threads = p_data->thread_count;
- uint32_t from = p_thread * packs_total / total_threads;
- uint32_t to = (p_thread + 1 == total_threads) ? packs_total : ((p_thread + 1) * packs_total / total_threads);
- _generate_camera_rays(p_data->camera_transform, p_data->camera_matrix, p_data->camera_orthogonal, from, to);
+ uint32_t from = p_thread * total_tiles / total_threads;
+ uint32_t to = (p_thread + 1 == total_threads) ? total_tiles : ((p_thread + 1) * total_tiles / total_threads);
+ _generate_camera_rays(p_data, from, to);
}
-void RaycastOcclusionCull::RaycastHZBuffer::_generate_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to) {
- Size2i buffer_size = sizes[0];
-
- CameraMatrix inv_camera_matrix = p_cam_projection.inverse();
- float z_far = p_cam_projection.get_z_far() * 1.05f;
- debug_tex_range = z_far;
-
- RayPacket *ray_packets = camera_rays.ptr();
- uint32_t *ray_masks = camera_ray_masks.ptr();
+void RaycastOcclusionCull::RaycastHZBuffer::_generate_camera_rays(const CameraRayThreadData *p_data, int p_from, int p_to) {
+ const Size2i &buffer_size = sizes[0];
for (int i = p_from; i < p_to; i++) {
- RayPacket &packet = ray_packets[i];
- int tile_x = (i % packs_size.x) * TILE_SIZE;
- int tile_y = (i / packs_size.x) * TILE_SIZE;
+ CameraRayTile &tile = camera_rays[i];
+ int tile_x = (i % tile_grid_size.x) * TILE_SIZE;
+ int tile_y = (i / tile_grid_size.x) * TILE_SIZE;
for (int j = 0; j < TILE_RAYS; j++) {
- float x = tile_x + j % TILE_SIZE;
- float y = tile_y + j / TILE_SIZE;
+ int x = tile_x + j % TILE_SIZE;
+ int y = tile_y + j / TILE_SIZE;
- ray_masks[i * TILE_RAYS + j] = ~0U;
+ float u = (float(x) + 0.5f) / buffer_size.x;
+ float v = (float(y) + 0.5f) / buffer_size.y;
+ Vector3 pixel_pos = p_data->pixel_corner + u * p_data->pixel_u_interp + v * p_data->pixel_v_interp;
- if (x >= buffer_size.x || y >= buffer_size.y) {
- ray_masks[i * TILE_RAYS + j] = 0U;
- } else {
- float u = x / (buffer_size.x - 1);
- float v = y / (buffer_size.y - 1);
- u = u * 2.0f - 1.0f;
- v = v * 2.0f - 1.0f;
-
- Plane pixel_proj = Plane(u, v, -1.0, 1.0);
- Plane pixel_view = inv_camera_matrix.xform4(pixel_proj);
- Vector3 pixel_world = p_cam_transform.xform(pixel_view.normal);
-
- Vector3 dir;
- if (p_cam_orthogonal) {
- dir = -p_cam_transform.basis.get_axis(2);
- } else {
- dir = (pixel_world - p_cam_transform.origin).normalized();
- }
-
- packet.ray.org_x[j] = pixel_world.x;
- packet.ray.org_y[j] = pixel_world.y;
- packet.ray.org_z[j] = pixel_world.z;
+ tile.ray.tnear[j] = p_data->z_near;
- packet.ray.dir_x[j] = dir.x;
- packet.ray.dir_y[j] = dir.y;
- packet.ray.dir_z[j] = dir.z;
+ Vector3 dir;
+ if (p_data->camera_orthogonal) {
+ dir = -p_data->camera_dir;
+ tile.ray.org_x[j] = pixel_pos.x - dir.x * p_data->z_near;
+ tile.ray.org_y[j] = pixel_pos.y - dir.y * p_data->z_near;
+ tile.ray.org_z[j] = pixel_pos.z - dir.z * p_data->z_near;
+ } else {
+ dir = (pixel_pos - p_data->camera_pos).normalized();
+ tile.ray.org_x[j] = p_data->camera_pos.x;
+ tile.ray.org_y[j] = p_data->camera_pos.y;
+ tile.ray.org_z[j] = p_data->camera_pos.z;
+ tile.ray.tnear[j] /= dir.dot(p_data->camera_dir);
+ }
- packet.ray.tnear[j] = 0.0f;
+ tile.ray.dir_x[j] = dir.x;
+ tile.ray.dir_y[j] = dir.y;
+ tile.ray.dir_z[j] = dir.z;
- packet.ray.time[j] = 0.0f;
+ tile.ray.tfar[j] = p_data->z_far;
+ tile.ray.time[j] = 0.0f;
- packet.ray.flags[j] = 0;
- packet.ray.mask[j] = -1;
- packet.hit.geomID[j] = RTC_INVALID_GEOMETRY_ID;
- }
-
- packet.ray.tfar[j] = z_far;
+ tile.ray.flags[j] = 0;
+ tile.ray.mask[j] = ~0U;
+ tile.hit.geomID[j] = RTC_INVALID_GEOMETRY_ID;
}
}
}
-void RaycastOcclusionCull::RaycastHZBuffer::sort_rays() {
- if (is_empty()) {
- return;
- }
+void RaycastOcclusionCull::RaycastHZBuffer::sort_rays(const Vector3 &p_camera_dir, bool p_orthogonal) {
+ ERR_FAIL_COND(is_empty());
Size2i buffer_size = sizes[0];
- for (int i = 0; i < packs_size.y; i++) {
- for (int j = 0; j < packs_size.x; j++) {
+ for (int i = 0; i < tile_grid_size.y; i++) {
+ for (int j = 0; j < tile_grid_size.x; j++) {
for (int tile_i = 0; tile_i < TILE_SIZE; tile_i++) {
for (int tile_j = 0; tile_j < TILE_SIZE; tile_j++) {
int x = j * TILE_SIZE + tile_j;
@@ -160,14 +177,30 @@ void RaycastOcclusionCull::RaycastHZBuffer::sort_rays() {
continue;
}
int k = tile_i * TILE_SIZE + tile_j;
- int packet_index = i * packs_size.x + j;
- mips[0][y * buffer_size.x + x] = camera_rays[packet_index].ray.tfar[k];
+ int tile_index = i * tile_grid_size.x + j;
+ float d = camera_rays[tile_index].ray.tfar[k];
+
+ if (!p_orthogonal) {
+ const float &dir_x = camera_rays[tile_index].ray.dir_x[k];
+ const float &dir_y = camera_rays[tile_index].ray.dir_y[k];
+ const float &dir_z = camera_rays[tile_index].ray.dir_z[k];
+ float cos_theta = p_camera_dir.x * dir_x + p_camera_dir.y * dir_y + p_camera_dir.z * dir_z;
+ d *= cos_theta;
+ }
+
+ mips[0][y * buffer_size.x + x] = d;
}
}
}
}
}
+RaycastOcclusionCull::RaycastHZBuffer::~RaycastHZBuffer() {
+ if (camera_rays_unaligned_buffer) {
+ memfree(camera_rays_unaligned_buffer);
+ }
+}
+
////////////////////////////////////////////////////////
bool RaycastOcclusionCull::is_occluder(RID p_rid) {
@@ -184,7 +217,7 @@ void RaycastOcclusionCull::occluder_initialize(RID p_occluder) {
}
void RaycastOcclusionCull::occluder_set_mesh(RID p_occluder, const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices) {
- Occluder *occluder = occluder_owner.getornull(p_occluder);
+ Occluder *occluder = occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
occluder->vertices = p_vertices;
@@ -205,7 +238,7 @@ void RaycastOcclusionCull::occluder_set_mesh(RID p_occluder, const PackedVector3
}
void RaycastOcclusionCull::free_occluder(RID p_occluder) {
- Occluder *occluder = occluder_owner.getornull(p_occluder);
+ Occluder *occluder = occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
memdelete(occluder);
occluder_owner.free(p_occluder);
@@ -245,7 +278,7 @@ void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance,
bool changed = false;
if (instance.occluder != p_occluder) {
- Occluder *old_occluder = occluder_owner.getornull(instance.occluder);
+ Occluder *old_occluder = occluder_owner.get_or_null(instance.occluder);
if (old_occluder) {
old_occluder->users.erase(InstanceID(p_scenario, p_instance));
}
@@ -253,7 +286,7 @@ void RaycastOcclusionCull::scenario_set_instance(RID p_scenario, RID p_instance,
instance.occluder = p_occluder;
if (p_occluder.is_valid()) {
- Occluder *occluder = occluder_owner.getornull(p_occluder);
+ Occluder *occluder = occluder_owner.get_or_null(p_occluder);
ERR_FAIL_COND(!occluder);
occluder->users.insert(InstanceID(p_scenario, p_instance));
}
@@ -285,7 +318,7 @@ void RaycastOcclusionCull::scenario_remove_instance(RID p_scenario, RID p_instan
OccluderInstance &instance = scenario.instances[p_instance];
if (!instance.removed) {
- Occluder *occluder = occluder_owner.getornull(instance.occluder);
+ Occluder *occluder = occluder_owner.get_or_null(instance.occluder);
if (occluder) {
occluder->users.erase(InstanceID(p_scenario, p_instance));
}
@@ -307,7 +340,7 @@ void RaycastOcclusionCull::Scenario::_update_dirty_instance(int p_idx, RID *p_in
return;
}
- Occluder *occ = raycast_singleton->occluder_owner.getornull(occ_inst->occluder);
+ Occluder *occ = raycast_singleton->occluder_owner.get_or_null(occ_inst->occluder);
if (!occ) {
return;
@@ -423,7 +456,7 @@ bool RaycastOcclusionCull::Scenario::update(ThreadWorkPool &p_thread_pool) {
const RID *inst_rid = nullptr;
while ((inst_rid = instances.next(inst_rid))) {
OccluderInstance *occ_inst = instances.getptr(*inst_rid);
- Occluder *occ = raycast_singleton->occluder_owner.getornull(occ_inst->occluder);
+ Occluder *occ = raycast_singleton->occluder_owner.get_or_null(occ_inst->occluder);
if (!occ || !occ_inst->enabled) {
continue;
@@ -451,7 +484,7 @@ void RaycastOcclusionCull::Scenario::_raycast(uint32_t p_idx, const RaycastThrea
rtcIntersect16((const int *)&p_raycast_data->masks[p_idx * TILE_RAYS], ebr_scene[current_scene_idx], &ctx, &p_raycast_data->rays[p_idx]);
}
-void RaycastOcclusionCull::Scenario::raycast(LocalVector<RayPacket> &r_rays, const LocalVector<uint32_t> p_valid_masks, ThreadWorkPool &p_thread_pool) const {
+void RaycastOcclusionCull::Scenario::raycast(CameraRayTile *r_rays, const uint32_t *p_valid_masks, uint32_t p_tile_count, ThreadWorkPool &p_thread_pool) const {
ERR_FAIL_COND(singleton == nullptr);
if (raycast_singleton->ebr_device == nullptr) {
return; // Embree is initialized on demand when there is some scenario with occluders in it.
@@ -462,10 +495,10 @@ void RaycastOcclusionCull::Scenario::raycast(LocalVector<RayPacket> &r_rays, con
}
RaycastThreadData td;
- td.rays = r_rays.ptr();
- td.masks = p_valid_masks.ptr();
+ td.rays = r_rays;
+ td.masks = p_valid_masks;
- p_thread_pool.do_work(r_rays.size(), this, &Scenario::_raycast, &td);
+ p_thread_pool.do_work(p_tile_count, this, &Scenario::_raycast, &td);
}
////////////////////////////////////////////////////////
@@ -513,8 +546,8 @@ void RaycastOcclusionCull::buffer_update(RID p_buffer, const Transform3D &p_cam_
buffer.update_camera_rays(p_cam_transform, p_cam_projection, p_cam_orthogonal, p_thread_pool);
- scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks, p_thread_pool);
- buffer.sort_rays();
+ scenario.raycast(buffer.camera_rays, buffer.camera_ray_masks.ptr(), buffer.camera_rays_tile_count, p_thread_pool);
+ buffer.sort_rays(-p_cam_transform.basis.get_axis(2), p_cam_orthogonal);
buffer.update_mips();
}
@@ -569,13 +602,15 @@ RaycastOcclusionCull::~RaycastOcclusionCull() {
scenario.commit_thread->wait_to_finish();
memdelete(scenario.commit_thread);
}
+
+ for (int i = 0; i < 2; i++) {
+ if (scenario.ebr_scene[i]) {
+ rtcReleaseScene(scenario.ebr_scene[i]);
+ }
+ }
}
if (ebr_device != nullptr) {
-#ifdef __SSE2__
- _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_OFF);
- _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_OFF);
-#endif
rtcReleaseDevice(ebr_device);
}
diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h
index 85710a790c..ea96df5ff6 100644
--- a/modules/raycast/raycast_occlusion_cull.h
+++ b/modules/raycast/raycast_occlusion_cull.h
@@ -43,33 +43,42 @@
#include <embree3/rtcore.h>
class RaycastOcclusionCull : public RendererSceneOcclusionCull {
- typedef RTCRayHit16 RayPacket;
+ typedef RTCRayHit16 CameraRayTile;
public:
class RaycastHZBuffer : public HZBuffer {
private:
- Size2i packs_size;
+ Size2i tile_grid_size;
struct CameraRayThreadData {
- CameraMatrix camera_matrix;
- Transform3D camera_transform;
- bool camera_orthogonal;
int thread_count;
+ float z_near;
+ float z_far;
+ Vector3 camera_dir;
+ Vector3 camera_pos;
+ Vector3 pixel_corner;
+ Vector3 pixel_u_interp;
+ Vector3 pixel_v_interp;
+ bool camera_orthogonal;
Size2i buffer_size;
};
- void _camera_rays_threaded(uint32_t p_thread, CameraRayThreadData *p_data);
- void _generate_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, int p_from, int p_to);
+ void _camera_rays_threaded(uint32_t p_thread, const CameraRayThreadData *p_data);
+ void _generate_camera_rays(const CameraRayThreadData *p_data, int p_from, int p_to);
public:
- LocalVector<RayPacket> camera_rays;
+ unsigned int camera_rays_tile_count = 0;
+ uint8_t *camera_rays_unaligned_buffer = nullptr;
+ CameraRayTile *camera_rays = nullptr;
LocalVector<uint32_t> camera_ray_masks;
RID scenario_rid;
virtual void clear() override;
virtual void resize(const Size2i &p_size) override;
- void sort_rays();
+ void sort_rays(const Vector3 &p_camera_dir, bool p_orthogonal);
void update_camera_rays(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_orthogonal, ThreadWorkPool &p_thread_work_pool);
+
+ ~RaycastHZBuffer();
};
private:
@@ -106,7 +115,7 @@ private:
struct Scenario {
struct RaycastThreadData {
- RayPacket *rays;
+ CameraRayTile *rays;
const uint32_t *masks;
};
@@ -139,7 +148,7 @@ private:
bool update(ThreadWorkPool &p_thread_pool);
void _raycast(uint32_t p_thread, const RaycastThreadData *p_raycast_data) const;
- void raycast(LocalVector<RayPacket> &r_rays, const LocalVector<uint32_t> p_valid_masks, ThreadWorkPool &p_thread_pool) const;
+ void raycast(CameraRayTile *r_rays, const uint32_t *p_valid_masks, uint32_t p_tile_count, ThreadWorkPool &p_thread_pool) const;
};
static RaycastOcclusionCull *raycast_singleton;
diff --git a/modules/raycast/register_types.cpp b/modules/raycast/register_types.cpp
index 78ca91309f..ed99e635e1 100644
--- a/modules/raycast/register_types.cpp
+++ b/modules/raycast/register_types.cpp
@@ -32,12 +32,14 @@
#include "lightmap_raycaster.h"
#include "raycast_occlusion_cull.h"
+#include "static_raycaster.h"
RaycastOcclusionCull *raycast_occlusion_cull = nullptr;
void register_raycast_types() {
#ifdef TOOLS_ENABLED
LightmapRaycasterEmbree::make_default_raycaster();
+ StaticRaycasterEmbree::make_default_raycaster();
#endif
raycast_occlusion_cull = memnew(RaycastOcclusionCull);
}
@@ -46,4 +48,7 @@ void unregister_raycast_types() {
if (raycast_occlusion_cull) {
memdelete(raycast_occlusion_cull);
}
+#ifdef TOOLS_ENABLED
+ StaticRaycasterEmbree::free();
+#endif
}
diff --git a/modules/raycast/static_raycaster.cpp b/modules/raycast/static_raycaster.cpp
new file mode 100644
index 0000000000..2ba65eebf8
--- /dev/null
+++ b/modules/raycast/static_raycaster.cpp
@@ -0,0 +1,137 @@
+/*************************************************************************/
+/* static_raycaster.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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. */
+/*************************************************************************/
+
+#ifdef TOOLS_ENABLED
+
+#include "static_raycaster.h"
+
+#ifdef __SSE2__
+#include <pmmintrin.h>
+#endif
+
+RTCDevice StaticRaycasterEmbree::embree_device;
+
+StaticRaycaster *StaticRaycasterEmbree::create_embree_raycaster() {
+ return memnew(StaticRaycasterEmbree);
+}
+
+void StaticRaycasterEmbree::make_default_raycaster() {
+ create_function = create_embree_raycaster;
+}
+
+void StaticRaycasterEmbree::free() {
+ if (embree_device) {
+ rtcReleaseDevice(embree_device);
+ }
+}
+
+bool StaticRaycasterEmbree::intersect(Ray &r_ray) {
+ RTCIntersectContext context;
+ rtcInitIntersectContext(&context);
+ rtcIntersect1(embree_scene, &context, (RTCRayHit *)&r_ray);
+ return r_ray.geomID != RTC_INVALID_GEOMETRY_ID;
+}
+
+void StaticRaycasterEmbree::intersect(Vector<Ray> &r_rays) {
+ Ray *rays = r_rays.ptrw();
+ for (int i = 0; i < r_rays.size(); ++i) {
+ intersect(rays[i]);
+ }
+}
+
+void StaticRaycasterEmbree::add_mesh(const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices, unsigned int p_id) {
+ RTCGeometry embree_mesh = rtcNewGeometry(embree_device, RTC_GEOMETRY_TYPE_TRIANGLE);
+
+ int vertex_count = p_vertices.size();
+
+ Vector3 *embree_vertices = (Vector3 *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_VERTEX, 0, RTC_FORMAT_FLOAT3, sizeof(Vector3), vertex_count);
+ memcpy(embree_vertices, p_vertices.ptr(), sizeof(Vector3) * vertex_count);
+
+ if (p_indices.is_empty()) {
+ ERR_FAIL_COND(vertex_count % 3 != 0);
+ uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, vertex_count / 3);
+ for (int i = 0; i < vertex_count; i++) {
+ embree_triangles[i] = i;
+ }
+ } else {
+ uint32_t *embree_triangles = (uint32_t *)rtcSetNewGeometryBuffer(embree_mesh, RTC_BUFFER_TYPE_INDEX, 0, RTC_FORMAT_UINT3, sizeof(uint32_t) * 3, p_indices.size() / 3);
+ memcpy(embree_triangles, p_indices.ptr(), sizeof(uint32_t) * p_indices.size());
+ }
+
+ rtcCommitGeometry(embree_mesh);
+ rtcAttachGeometryByID(embree_scene, embree_mesh, p_id);
+ rtcReleaseGeometry(embree_mesh);
+}
+
+void StaticRaycasterEmbree::commit() {
+ rtcCommitScene(embree_scene);
+}
+
+void StaticRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) {
+ for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
+ rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
+ }
+ rtcCommitScene(embree_scene);
+ filter_meshes = p_mesh_ids;
+}
+
+void StaticRaycasterEmbree::clear_mesh_filter() {
+ for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
+ rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
+ }
+ rtcCommitScene(embree_scene);
+ filter_meshes.clear();
+}
+
+void embree_error_handler(void *p_user_data, RTCError p_code, const char *p_str) {
+ print_error("Embree error: " + String(p_str));
+}
+
+StaticRaycasterEmbree::StaticRaycasterEmbree() {
+#ifdef __SSE2__
+ _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
+ _MM_SET_DENORMALS_ZERO_MODE(_MM_DENORMALS_ZERO_ON);
+#endif
+
+ if (!embree_device) {
+ embree_device = rtcNewDevice(nullptr);
+ rtcSetDeviceErrorFunction(embree_device, &embree_error_handler, nullptr);
+ }
+
+ embree_scene = rtcNewScene(embree_device);
+}
+
+StaticRaycasterEmbree::~StaticRaycasterEmbree() {
+ if (embree_scene != nullptr) {
+ rtcReleaseScene(embree_scene);
+ }
+}
+
+#endif
diff --git a/modules/gdnative/text/register_types.h b/modules/raycast/static_raycaster.h
index cd4f2a3089..6b13ecf690 100644
--- a/modules/gdnative/text/register_types.h
+++ b/modules/raycast/static_raycaster.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* register_types.h */
+/* static_raycaster.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,10 +28,37 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef TEXT_REGISTER_TYPES_H
-#define TEXT_REGISTER_TYPES_H
+#ifdef TOOLS_ENABLED
-void register_text_server_gdn_types();
-void unregister_text_server_gdn_types();
+#include "core/math/static_raycaster.h"
-#endif // TEXT_REGISTER_TYPES_H
+#include <embree3/rtcore.h>
+
+class StaticRaycasterEmbree : public StaticRaycaster {
+ GDCLASS(StaticRaycasterEmbree, StaticRaycaster);
+
+private:
+ static RTCDevice embree_device;
+ RTCScene embree_scene;
+
+ Set<int> filter_meshes;
+
+public:
+ virtual bool intersect(Ray &p_ray) override;
+ virtual void intersect(Vector<Ray> &r_rays) override;
+
+ virtual void add_mesh(const PackedVector3Array &p_vertices, const PackedInt32Array &p_indices, unsigned int p_id) override;
+ virtual void commit() override;
+
+ virtual void set_mesh_filter(const Set<int> &p_mesh_ids) override;
+ virtual void clear_mesh_filter() override;
+
+ static StaticRaycaster *create_embree_raycaster();
+ static void make_default_raycaster();
+ static void free();
+
+ StaticRaycasterEmbree();
+ ~StaticRaycasterEmbree();
+};
+
+#endif
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 9c84974ff6..2ae2e53b02 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -116,6 +116,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/regex/doc_classes/RegExMatch.xml b/modules/regex/doc_classes/RegExMatch.xml
index 3cde2836cc..20680b41fd 100644
--- a/modules/regex/doc_classes/RegExMatch.xml
+++ b/modules/regex/doc_classes/RegExMatch.xml
@@ -51,6 +51,4 @@
The source string used with the search pattern to find this matching result.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/stb_vorbis/SCsub b/modules/stb_vorbis/SCsub
deleted file mode 100644
index 8fddb23dc8..0000000000
--- a/modules/stb_vorbis/SCsub
+++ /dev/null
@@ -1,27 +0,0 @@
-#!/usr/bin/env python
-
-Import("env")
-Import("env_modules")
-
-env_stb_vorbis = env_modules.Clone()
-
-# Thirdparty source files
-
-thirdparty_obj = []
-
-thirdparty_sources = ["#thirdparty/misc/stb_vorbis.c"]
-
-env_thirdparty = env_stb_vorbis.Clone()
-env_thirdparty.disable_warnings()
-env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
-env.modules_sources += thirdparty_obj
-
-# Godot source files
-
-module_obj = []
-
-env_stb_vorbis.add_source_files(module_obj, "*.cpp")
-env.modules_sources += module_obj
-
-# Needed to force rebuilding the module files when the thirdparty library is updated.
-env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp b/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
deleted file mode 100644
index 6554c6e274..0000000000
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
+++ /dev/null
@@ -1,278 +0,0 @@
-/*************************************************************************/
-/* audio_stream_ogg_vorbis.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 "audio_stream_ogg_vorbis.h"
-
-#include "core/io/file_access.h"
-
-int AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
- ERR_FAIL_COND_V(!active, 0);
-
- int todo = p_frames;
-
- int start_buffer = 0;
-
- int frames_mixed_this_step = p_frames;
-
- while (todo && active) {
- float *buffer = (float *)p_buffer;
- if (start_buffer > 0) {
- buffer = (buffer + start_buffer * 2);
- }
- int mixed = stb_vorbis_get_samples_float_interleaved(ogg_stream, 2, buffer, todo * 2);
- if (vorbis_stream->channels == 1 && mixed > 0) {
- //mix mono to stereo
- for (int i = start_buffer; i < start_buffer + mixed; i++) {
- p_buffer[i].r = p_buffer[i].l;
- }
- }
- todo -= mixed;
- frames_mixed += mixed;
-
- if (todo) {
- //end of file!
- bool is_not_empty = mixed > 0 || stb_vorbis_stream_length_in_samples(ogg_stream) > 0;
- if (vorbis_stream->loop && is_not_empty) {
- //loop
- seek(vorbis_stream->loop_offset);
- loops++;
- // we still have buffer to fill, start from this element in the next iteration.
- start_buffer = p_frames - todo;
- } else {
- frames_mixed_this_step = p_frames - todo;
- for (int i = p_frames - todo; i < p_frames; i++) {
- p_buffer[i] = AudioFrame(0, 0);
- }
- active = false;
- todo = 0;
- }
- }
- }
- return frames_mixed_this_step;
-}
-
-float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() {
- return vorbis_stream->sample_rate;
-}
-
-void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) {
- active = true;
- seek(p_from_pos);
- loops = 0;
- _begin_resample();
-}
-
-void AudioStreamPlaybackOGGVorbis::stop() {
- active = false;
-}
-
-bool AudioStreamPlaybackOGGVorbis::is_playing() const {
- return active;
-}
-
-int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
- return loops;
-}
-
-float AudioStreamPlaybackOGGVorbis::get_playback_position() const {
- return float(frames_mixed) / vorbis_stream->sample_rate;
-}
-
-void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
- if (!active) {
- return;
- }
-
- if (p_time >= vorbis_stream->get_length()) {
- p_time = 0;
- }
- frames_mixed = uint32_t(vorbis_stream->sample_rate * p_time);
-
- stb_vorbis_seek(ogg_stream, frames_mixed);
-}
-
-AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
- if (ogg_alloc.alloc_buffer) {
- stb_vorbis_close(ogg_stream);
- memfree(ogg_alloc.alloc_buffer);
- }
-}
-
-Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
- Ref<AudioStreamPlaybackOGGVorbis> ovs;
-
- ERR_FAIL_COND_V_MSG(data == nullptr, ovs,
- "This AudioStreamOGGVorbis does not have an audio file assigned "
- "to it. AudioStreamOGGVorbis should not be created from the "
- "inspector or with `.new()`. Instead, load an audio file.");
-
- ovs.instantiate();
- ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this);
- ovs->ogg_alloc.alloc_buffer = (char *)memalloc(decode_mem_size);
- ovs->ogg_alloc.alloc_buffer_length_in_bytes = decode_mem_size;
- ovs->frames_mixed = 0;
- ovs->active = false;
- ovs->loops = 0;
- int error;
- ovs->ogg_stream = stb_vorbis_open_memory((const unsigned char *)data, data_len, &error, &ovs->ogg_alloc);
- if (!ovs->ogg_stream) {
- memfree(ovs->ogg_alloc.alloc_buffer);
- ovs->ogg_alloc.alloc_buffer = nullptr;
- ERR_FAIL_COND_V(!ovs->ogg_stream, Ref<AudioStreamPlaybackOGGVorbis>());
- }
-
- return ovs;
-}
-
-String AudioStreamOGGVorbis::get_stream_name() const {
- return ""; //return stream_name;
-}
-
-void AudioStreamOGGVorbis::clear_data() {
- if (data) {
- memfree(data);
- data = nullptr;
- data_len = 0;
- }
-}
-
-void AudioStreamOGGVorbis::set_data(const Vector<uint8_t> &p_data) {
- int src_data_len = p_data.size();
- uint32_t alloc_try = 1024;
- Vector<char> alloc_mem;
- char *w;
- stb_vorbis *ogg_stream = nullptr;
- stb_vorbis_alloc ogg_alloc;
-
- // Vorbis comments may be up to UINT32_MAX, but that's arguably pretty rare.
- // Let's go with 2^30 so we don't risk going out of bounds.
- const uint32_t MAX_TEST_MEM = 1 << 30;
-
- while (alloc_try < MAX_TEST_MEM) {
- alloc_mem.resize(alloc_try);
- w = alloc_mem.ptrw();
-
- ogg_alloc.alloc_buffer = w;
- ogg_alloc.alloc_buffer_length_in_bytes = alloc_try;
-
- const uint8_t *src_datar = p_data.ptr();
-
- int error;
- ogg_stream = stb_vorbis_open_memory((const unsigned char *)src_datar, src_data_len, &error, &ogg_alloc);
-
- if (!ogg_stream && error == VORBIS_outofmem) {
- alloc_try *= 2;
- } else {
- ERR_FAIL_COND(alloc_try == MAX_TEST_MEM);
- ERR_FAIL_COND(ogg_stream == nullptr);
-
- stb_vorbis_info info = stb_vorbis_get_info(ogg_stream);
-
- channels = info.channels;
- sample_rate = info.sample_rate;
- decode_mem_size = alloc_try;
- //does this work? (it's less mem..)
- //decode_mem_size = ogg_alloc.alloc_buffer_length_in_bytes + info.setup_memory_required + info.temp_memory_required + info.max_frame_size;
-
- length = stb_vorbis_stream_length_in_seconds(ogg_stream);
- stb_vorbis_close(ogg_stream);
-
- // free any existing data
- clear_data();
-
- data = memalloc(src_data_len);
- memcpy(data, src_datar, src_data_len);
- data_len = src_data_len;
-
- break;
- }
- }
-
- ERR_FAIL_COND_MSG(alloc_try == MAX_TEST_MEM, vformat("Couldn't set vorbis data even with an alloc buffer of %d bytes, report bug.", MAX_TEST_MEM));
-}
-
-Vector<uint8_t> AudioStreamOGGVorbis::get_data() const {
- Vector<uint8_t> vdata;
-
- if (data_len && data) {
- vdata.resize(data_len);
- {
- uint8_t *w = vdata.ptrw();
- memcpy(w, data, data_len);
- }
- }
-
- return vdata;
-}
-
-void AudioStreamOGGVorbis::set_loop(bool p_enable) {
- loop = p_enable;
-}
-
-bool AudioStreamOGGVorbis::has_loop() const {
- return loop;
-}
-
-void AudioStreamOGGVorbis::set_loop_offset(float p_seconds) {
- loop_offset = p_seconds;
-}
-
-float AudioStreamOGGVorbis::get_loop_offset() const {
- return loop_offset;
-}
-
-float AudioStreamOGGVorbis::get_length() const {
- return length;
-}
-
-bool AudioStreamOGGVorbis::is_monophonic() const {
- return false;
-}
-
-void AudioStreamOGGVorbis::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_data", "data"), &AudioStreamOGGVorbis::set_data);
- ClassDB::bind_method(D_METHOD("get_data"), &AudioStreamOGGVorbis::get_data);
-
- ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamOGGVorbis::set_loop);
- ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamOGGVorbis::has_loop);
-
- ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamOGGVorbis::set_loop_offset);
- ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset);
-
- ADD_PROPERTY(PropertyInfo(Variant::PACKED_BYTE_ARRAY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_data", "get_data");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset"), "set_loop_offset", "get_loop_offset");
-}
-
-AudioStreamOGGVorbis::AudioStreamOGGVorbis() {}
-
-AudioStreamOGGVorbis::~AudioStreamOGGVorbis() {
- clear_data();
-}
diff --git a/modules/stb_vorbis/config.py b/modules/stb_vorbis/config.py
deleted file mode 100644
index 1eb0a8cf33..0000000000
--- a/modules/stb_vorbis/config.py
+++ /dev/null
@@ -1,16 +0,0 @@
-def can_build(env, platform):
- return True
-
-
-def configure(env):
- pass
-
-
-def get_doc_classes():
- return [
- "AudioStreamOGGVorbis",
- ]
-
-
-def get_doc_path():
- return "doc_classes"
diff --git a/modules/stb_vorbis/register_types.h b/modules/stb_vorbis/register_types.h
deleted file mode 100644
index d36d87606c..0000000000
--- a/modules/stb_vorbis/register_types.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*************************************************************************/
-/* register_types.h */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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 STB_VORBIS_REGISTER_TYPES_H
-#define STB_VORBIS_REGISTER_TYPES_H
-
-void register_stb_vorbis_types();
-void unregister_stb_vorbis_types();
-
-#endif // STB_VORBIS_REGISTER_TYPES_H
diff --git a/modules/text_server_adv/SCsub b/modules/text_server_adv/SCsub
index 6691f86e60..7cd4db6f67 100644
--- a/modules/text_server_adv/SCsub
+++ b/modules/text_server_adv/SCsub
@@ -64,6 +64,7 @@ if env["builtin_harfbuzz"]:
#'src/hb-gobject-structs.cc',
"src/hb-icu.cc",
"src/hb-map.cc",
+ "src/hb-ms-feature-ranges.cc",
"src/hb-number.cc",
"src/hb-ot-cff1-table.cc",
"src/hb-ot-cff2-table.cc",
diff --git a/modules/text_server_adv/config.py b/modules/text_server_adv/config.py
index d22f9454ed..8c8df9b05e 100644
--- a/modules/text_server_adv/config.py
+++ b/modules/text_server_adv/config.py
@@ -4,3 +4,13 @@ def can_build(env, platform):
def configure(env):
pass
+
+
+def get_doc_classes():
+ return [
+ "TextServerAdvanced",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/text_server_adv/doc_classes/TextServerAdvanced.xml b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
new file mode 100644
index 0000000000..eff4aa5fae
--- /dev/null
+++ b/modules/text_server_adv/doc_classes/TextServerAdvanced.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextServerAdvanced" inherits="TextServer" version="4.0">
+ <brief_description>
+ Text Server using HarfBuzz, ICU and SIL Graphite to support BiDi, complex text layouts and contextual OpenType features.
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/text_server_adv/register_types.cpp b/modules/text_server_adv/register_types.cpp
index abefa83b9b..b711d1561f 100644
--- a/modules/text_server_adv/register_types.cpp
+++ b/modules/text_server_adv/register_types.cpp
@@ -33,7 +33,12 @@
#include "text_server_adv.h"
void preregister_text_server_adv_types() {
- TextServerAdvanced::register_server();
+ GDREGISTER_CLASS(TextServerAdvanced);
+ if (TextServerManager::get_singleton()) {
+ Ref<TextServerAdvanced> ts;
+ ts.instantiate();
+ TextServerManager::get_singleton()->add_interface(ts);
+ }
}
void register_text_server_adv_types() {
diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp
index f9bbd25a5f..d1e849def8 100644
--- a/modules/text_server_adv/script_iterator.cpp
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -30,6 +30,8 @@
#include "script_iterator.h"
+// This implementation is derived from ICU: icu4c/source/extra/scrptrun/scrptrun.cpp
+
bool ScriptIterator::same_script(int32_t p_script_one, int32_t p_script_two) {
return p_script_one <= USCRIPT_INHERITED || p_script_two <= USCRIPT_INHERITED || p_script_one == p_script_two;
}
@@ -48,7 +50,8 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
p_start = 0;
}
- ParenStackEntry paren_stack[128];
+ int paren_size = PAREN_STACK_DEPTH;
+ ParenStackEntry *paren_stack = (ParenStackEntry *)memalloc(paren_size * sizeof(ParenStackEntry));
int script_start;
int script_end = p_start;
@@ -64,13 +67,22 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
UChar32 ch = str[script_end];
UScriptCode sc = uscript_getScript(ch, &err);
if (U_FAILURE(err)) {
+ memfree(paren_stack);
ERR_FAIL_MSG(u_errorName(err));
}
if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) != U_BPT_NONE) {
if (u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_OPEN) {
- paren_stack[++paren_sp].pair_index = ch;
+ // If it's an open character, push it onto the stack.
+ paren_sp++;
+ if (unlikely(paren_sp >= paren_size)) {
+ // If the stack is full, allocate more space to handle deeply nested parentheses. This is unlikely to happen with any real text.
+ paren_size += PAREN_STACK_DEPTH;
+ paren_stack = (ParenStackEntry *)memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry));
+ }
+ paren_stack[paren_sp].pair_index = ch;
paren_stack[paren_sp].script_code = script_code;
} else if (paren_sp >= 0) {
+ // If it's a close character, find the matching open on the stack, and use that script code. Any non-matching open characters above it on the stack will be poped.
UChar32 paired_ch = u_getBidiPairedBracket(ch);
while (paren_sp >= 0 && paren_stack[paren_sp].pair_index != paired_ch) {
paren_sp -= 1;
@@ -87,11 +99,13 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
if (same_script(script_code, sc)) {
if (script_code <= USCRIPT_INHERITED && sc > USCRIPT_INHERITED) {
script_code = sc;
+ // Now that we have a final script code, fix any open characters we pushed before we knew the script code.
while (start_sp < paren_sp) {
paren_stack[++start_sp].script_code = script_code;
}
}
if ((u_getIntPropertyValue(ch, UCHAR_BIDI_PAIRED_BRACKET_TYPE) == U_BPT_CLOSE) && paren_sp >= 0) {
+ // If this character is a close paired character pop the matching open character from the stack.
paren_sp -= 1;
if (start_sp >= 0) {
start_sp -= 1;
@@ -109,4 +123,6 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
script_ranges.push_back(rng);
} while (script_end < p_length);
+
+ memfree(paren_stack);
}
diff --git a/modules/text_server_adv/script_iterator.h b/modules/text_server_adv/script_iterator.h
index 896a0e5c15..5efd40f7c4 100644
--- a/modules/text_server_adv/script_iterator.h
+++ b/modules/text_server_adv/script_iterator.h
@@ -43,6 +43,8 @@
#include <hb.h>
class ScriptIterator {
+ static const int PAREN_STACK_DEPTH = 128;
+
public:
struct ScriptRange {
int start = 0;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index 19e94adf68..6c3e53b708 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -30,6 +30,7 @@
#include "text_server_adv.h"
+#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
@@ -45,13 +46,13 @@
#endif
/*************************************************************************/
-/* hb_bmp_font_t HarfBuzz Bitmap font interface */
+/* bmp_font_t HarfBuzz Bitmap font interface */
/*************************************************************************/
hb_font_funcs_t *TextServerAdvanced::funcs = nullptr;
-TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
- hb_bmp_font_t *bm_font = memnew(hb_bmp_font_t);
+TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
+ bmp_font_t *bm_font = memnew(bmp_font_t);
if (!bm_font) {
return nullptr;
@@ -63,13 +64,13 @@ TextServerAdvanced::hb_bmp_font_t *TextServerAdvanced::_hb_bmp_font_create(TextS
return bm_font;
}
-void TextServerAdvanced::_hb_bmp_font_destroy(void *p_data) {
- hb_bmp_font_t *bm_font = reinterpret_cast<hb_bmp_font_t *>(p_data);
+void TextServerAdvanced::_bmp_font_destroy(void *p_data) {
+ bmp_font_t *bm_font = reinterpret_cast<bmp_font_t *>(p_data);
memdelete(bm_font);
}
-hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -88,8 +89,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *
return true;
}
-hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -102,8 +103,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_advance(hb_font_t *p_font,
return bm_font->face->glyph_map[p_glyph].advance.x * 64;
}
-hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -116,8 +117,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_advance(hb_font_t *p_font,
return -bm_font->face->glyph_map[p_glyph].advance.y * 64;
}
-hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -130,22 +131,8 @@ hb_position_t TextServerAdvanced::hb_bmp_get_glyph_h_kerning(hb_font_t *p_font,
return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].x * 64;
}
-hb_position_t TextServerAdvanced::hb_bmp_get_glyph_v_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
-
- if (!bm_font->face) {
- return 0;
- }
-
- if (!bm_font->face->kerning_map.has(Vector2i(p_left_glyph, p_right_glyph))) {
- return 0;
- }
-
- return bm_font->face->kerning_map[Vector2i(p_left_glyph, p_right_glyph)].y * 64;
-}
-
-hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -161,8 +148,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void
return true;
}
-hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -180,8 +167,8 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_glyph_extents(hb_font_t *p_font, void *
return true;
}
-hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) {
- const hb_bmp_font_t *bm_font = reinterpret_cast<const hb_bmp_font_t *>(p_font_data);
+hb_bool_t TextServerAdvanced::_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data) {
+ const bmp_font_t *bm_font = reinterpret_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -194,41 +181,40 @@ hb_bool_t TextServerAdvanced::hb_bmp_get_font_h_extents(hb_font_t *p_font, void
return true;
}
-void TextServerAdvanced::hb_bmp_create_font_funcs() {
+void TextServerAdvanced::_bmp_create_font_funcs() {
if (funcs == nullptr) {
funcs = hb_font_funcs_create();
- hb_font_funcs_set_font_h_extents_func(funcs, hb_bmp_get_font_h_extents, nullptr, nullptr);
- hb_font_funcs_set_nominal_glyph_func(funcs, hb_bmp_get_nominal_glyph, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_advance_func(funcs, hb_bmp_get_glyph_h_advance, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_advance_func(funcs, hb_bmp_get_glyph_v_advance, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_origin_func(funcs, hb_bmp_get_glyph_v_origin, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_kerning_func(funcs, hb_bmp_get_glyph_h_kerning, nullptr, nullptr);
- hb_font_funcs_set_glyph_v_kerning_func(funcs, hb_bmp_get_glyph_v_kerning, nullptr, nullptr);
- hb_font_funcs_set_glyph_extents_func(funcs, hb_bmp_get_glyph_extents, nullptr, nullptr);
+ hb_font_funcs_set_font_h_extents_func(funcs, _bmp_get_font_h_extents, nullptr, nullptr);
+ hb_font_funcs_set_nominal_glyph_func(funcs, _bmp_get_nominal_glyph, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advance_func(funcs, _bmp_get_glyph_h_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_advance_func(funcs, _bmp_get_glyph_v_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_v_origin_func(funcs, _bmp_get_glyph_v_origin, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_kerning_func(funcs, _bmp_get_glyph_h_kerning, nullptr, nullptr);
+ hb_font_funcs_set_glyph_extents_func(funcs, _bmp_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_make_immutable(funcs);
}
}
-void TextServerAdvanced::hb_bmp_free_font_funcs() {
+void TextServerAdvanced::_bmp_free_font_funcs() {
if (funcs != nullptr) {
hb_font_funcs_destroy(funcs);
funcs = nullptr;
}
}
-void TextServerAdvanced::_hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
- hb_font_set_funcs(p_font, funcs, _hb_bmp_font_create(p_face, p_unref), _hb_bmp_font_destroy);
+void TextServerAdvanced::_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref) {
+ hb_font_set_funcs(p_font, funcs, _bmp_font_create(p_face, p_unref), _bmp_font_destroy);
}
-hb_font_t *TextServerAdvanced::hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {
+hb_font_t *TextServerAdvanced::_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy) {
hb_font_t *font;
hb_face_t *face = hb_face_create(nullptr, 0);
font = hb_font_create(face);
hb_face_destroy(face);
- _hb_bmp_font_set_funcs(font, p_face, false);
+ _bmp_font_set_funcs(font, p_face, false);
return font;
}
@@ -336,7 +322,7 @@ _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
String TextServerAdvanced::interface_name = "ICU / HarfBuzz / Graphite";
uint32_t TextServerAdvanced::interface_features = FEATURE_BIDI_LAYOUT | FEATURE_VERTICAL_LAYOUT | FEATURE_SHAPING | FEATURE_KASHIDA_JUSTIFICATION | FEATURE_BREAK_ITERATORS | FEATURE_USE_SUPPORT_DATA | FEATURE_FONT_VARIABLE;
-bool TextServerAdvanced::has_feature(Feature p_feature) {
+bool TextServerAdvanced::has_feature(Feature p_feature) const {
return (interface_features & p_feature) == p_feature;
}
@@ -344,14 +330,18 @@ String TextServerAdvanced::get_name() const {
return interface_name;
}
+uint32_t TextServerAdvanced::get_features() const {
+ return interface_features;
+}
+
void TextServerAdvanced::free(RID p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
- FontDataAdvanced *fd = font_owner.getornull(p_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_rid);
font_owner.free(p_rid);
memdelete(fd);
} else if (shaped_owner.owns(p_rid)) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_rid);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_rid);
shaped_owner.free(p_rid);
memdelete(sd);
}
@@ -408,9 +398,23 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
return true;
}
-#ifdef TOOLS_ENABLED
+String TextServerAdvanced::get_support_data_filename() const {
+#ifdef ICU_STATIC_DATA
+ return _MKSTR(ICU_DATA_NAME);
+#else
+ return String();
+#endif
+}
+
+String TextServerAdvanced::get_support_data_info() const {
+#ifdef ICU_STATIC_DATA
+ return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(").");
+#else
+ return String();
+#endif
+}
-bool TextServerAdvanced::save_support_data(const String &p_filename) {
+bool TextServerAdvanced::save_support_data(const String &p_filename) const {
_THREAD_SAFE_METHOD_
#ifdef ICU_STATIC_DATA
@@ -429,9 +433,7 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) {
#endif
}
-#endif
-
-bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) {
+bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) const {
String l = p_locale.get_slicec('_', 0);
if ((l == "ar") || (l == "dv") || (l == "he") || (l == "fa") || (l == "ff") || (l == "ku") || (l == "ur")) {
return true;
@@ -440,9 +442,7 @@ bool TextServerAdvanced::is_locale_right_to_left(const String &p_locale) {
}
}
-static Map<StringName, int32_t> feature_sets;
-
-static void _insert_feature_sets() {
+void TextServerAdvanced::_insert_feature_sets() {
// Registered OpenType feature tags.
feature_sets.insert("access_all_alternates", HB_TAG('a', 'a', 'l', 't'));
feature_sets.insert("above_base_forms", HB_TAG('a', 'b', 'v', 'f'));
@@ -954,7 +954,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
edgeColoringSimple(shape, 3.0); // Max. angle.
msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
- //msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation.
DistancePixelConversion distancePixelConversion(p_pixel_range);
msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));
@@ -984,10 +983,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
wr[ofs + 2] = (uint8_t)(CLAMP(image(j, i)[2] * 256.f, 0.f, 255.f));
wr[ofs + 3] = (uint8_t)(CLAMP(image(j, i)[3] * 256.f, 0.f, 255.f));
- //wr[ofs + 0] = 100;
- //wr[ofs + 1] = 100;
- //wr[ofs + 2] = 100;
- //wr[ofs + 3] = 100;
}
}
}
@@ -1052,13 +1047,12 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
case FT_PIXEL_MODE_MONO: {
int byte = i * bitmap.pitch + (j >> 3);
int bit = 1 << (7 - (j % 8));
- wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 0] = 255; // grayscale as 1
wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
} break;
case FT_PIXEL_MODE_GRAY:
- wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 0] = 255; // grayscale as 1
wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
- //wr[ofs + 1] = 100;
break;
case FT_PIXEL_MODE_BGRA: {
int ofs_color = i * bitmap.pitch + (j << 2);
@@ -1156,7 +1150,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_glyph(FontDataAdvanced *p_font_d
int error = FT_Load_Glyph(fd->face, p_glyph, flags);
if (error) {
fd->glyph_map[p_glyph] = FontGlyph();
- ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph.");
+ return false;
}
if (!outline) {
@@ -1225,7 +1219,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
int error = 0;
if (!library) {
error = FT_Init_FreeType(&library);
- ERR_FAIL_COND_V_MSG(error != 0, false, TTR("FreeType: Error initializing library:") + " '" + String(FT_Error_String(error)) + "'.");
+ ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
}
memset(&fd->stream, 0, sizeof(FT_StreamRec));
@@ -1243,20 +1237,14 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
- ERR_FAIL_V_MSG(false, TTR("FreeType: Error loading font:") + " '" + String(FT_Error_String(error)) + "'.");
- }
- fd->hb_handle = hb_ft_font_create(fd->face, nullptr);
- if (fd->hb_handle == nullptr) {
- FT_Done_Face(fd->face);
- fd->face = nullptr;
- ERR_FAIL_V_MSG(false, TTR("HarfBuzz: Error creating FreeType font object."));
+ ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
}
if (p_font_data->msdf) {
fd->oversampling = 1.0f;
fd->size.x = p_font_data->msdf_source_size;
} else if (p_font_data->oversampling <= 0.0f) {
- fd->oversampling = TS->font_get_global_oversampling();
+ fd->oversampling = font_get_global_oversampling();
} else {
fd->oversampling = p_font_data->oversampling;
}
@@ -1264,13 +1252,13 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
int best_match = 0;
int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
- fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
+ fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
for (int i = 1; i < fd->face->num_fixed_sizes; i++) {
int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
if (ndiff < diff) {
best_match = i;
diff = ndiff;
- fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
+ fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
}
}
FT_Select_Size(fd->face, best_match);
@@ -1278,6 +1266,8 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
FT_Set_Pixel_Sizes(fd->face, 0, fd->size.x * fd->oversampling);
}
+ fd->hb_handle = hb_ft_font_create(fd->face, nullptr);
+
fd->ascent = (fd->face->size->metrics.ascender / 64.0) / fd->oversampling * fd->scale;
fd->descent = (-fd->face->size->metrics.descender / 64.0) / fd->oversampling * fd->scale;
fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
@@ -1592,22 +1582,19 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
FT_Done_MM_Var(library, amaster);
}
#else
- ERR_FAIL_V_MSG(false, TTR("FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
+ ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
} else {
// Init bitmap font.
- fd->hb_handle = hb_bmp_font_create(fd, nullptr);
- if (!fd->hb_handle) {
- ERR_FAIL_V_MSG(false, TTR("HarfBuzz: Error creating bitmap font object."));
- }
+ fd->hb_handle = _bmp_font_create(fd, nullptr);
}
p_font_data->cache[p_size] = fd;
return true;
}
_FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontDataAdvanced *p_font_data) {
- for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = p_font_data->cache.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : p_font_data->cache) {
+ memdelete(E.value);
}
p_font_data->cache.clear();
p_font_data->face_init = false;
@@ -1617,7 +1604,7 @@ _FORCE_INLINE_ void TextServerAdvanced::_font_clear_cache(FontDataAdvanced *p_fo
}
hb_font_t *TextServerAdvanced::_font_get_hb_handle(RID p_font_rid, int p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, nullptr);
MutexLock lock(fd->mutex);
@@ -1635,7 +1622,7 @@ RID TextServerAdvanced::create_font() {
}
void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_data) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1646,7 +1633,7 @@ void TextServerAdvanced::font_set_data(RID p_font_rid, const PackedByteArray &p_
}
void TextServerAdvanced::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1657,7 +1644,7 @@ void TextServerAdvanced::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data
}
void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1668,7 +1655,7 @@ void TextServerAdvanced::font_set_antialiased(RID p_font_rid, bool p_antialiased
}
bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1676,7 +1663,7 @@ bool TextServerAdvanced::font_is_antialiased(RID p_font_rid) const {
}
void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1687,7 +1674,7 @@ void TextServerAdvanced::font_set_multichannel_signed_distance_field(RID p_font_
}
bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1695,7 +1682,7 @@ bool TextServerAdvanced::font_is_multichannel_signed_distance_field(RID p_font_r
}
void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1706,7 +1693,7 @@ void TextServerAdvanced::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pi
}
int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1714,7 +1701,7 @@ int TextServerAdvanced::font_get_msdf_pixel_range(RID p_font_rid) const {
}
void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1725,7 +1712,7 @@ void TextServerAdvanced::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
}
int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1733,7 +1720,7 @@ int TextServerAdvanced::font_get_msdf_size(RID p_font_rid) const {
}
void TextServerAdvanced::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1743,7 +1730,7 @@ void TextServerAdvanced::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
}
int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1751,7 +1738,7 @@ int TextServerAdvanced::font_get_fixed_size(RID p_font_rid) const {
}
void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1762,7 +1749,7 @@ void TextServerAdvanced::font_set_force_autohinter(RID p_font_rid, bool p_force_
}
bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1770,7 +1757,7 @@ bool TextServerAdvanced::font_is_force_autohinter(RID p_font_rid) const {
}
void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1781,7 +1768,7 @@ void TextServerAdvanced::font_set_hinting(RID p_font_rid, TextServer::Hinting p_
}
TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, HINTING_NONE);
MutexLock lock(fd->mutex);
@@ -1789,7 +1776,7 @@ TextServer::Hinting TextServerAdvanced::font_get_hinting(RID p_font_rid) const {
}
void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1800,15 +1787,15 @@ void TextServerAdvanced::font_set_variation_coordinates(RID p_font_rid, const Di
}
Dictionary TextServerAdvanced::font_get_variation_coordinates(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
MutexLock lock(fd->mutex);
return fd->variation_coordinates;
}
-void TextServerAdvanced::font_set_oversampling(RID p_font_rid, real_t p_oversampling) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+void TextServerAdvanced::font_set_oversampling(RID p_font_rid, float p_oversampling) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1818,8 +1805,8 @@ void TextServerAdvanced::font_set_oversampling(RID p_font_rid, real_t p_oversamp
}
}
-real_t TextServerAdvanced::font_get_oversampling(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+float TextServerAdvanced::font_get_oversampling(RID p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1827,7 +1814,7 @@ real_t TextServerAdvanced::font_get_oversampling(RID p_font_rid) const {
}
Array TextServerAdvanced::font_get_size_cache_list(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
MutexLock lock(fd->mutex);
@@ -1839,18 +1826,18 @@ Array TextServerAdvanced::font_get_size_cache_list(RID p_font_rid) const {
}
void TextServerAdvanced::font_clear_size_cache(RID p_font_rid) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- for (const Map<Vector2i, FontDataForSizeAdvanced *>::Element *E = fd->cache.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) {
+ memdelete(E.value);
}
fd->cache.clear();
}
void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1860,8 +1847,8 @@ void TextServerAdvanced::font_remove_size_cache(RID p_font_rid, const Vector2i &
}
}
-void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1871,8 +1858,8 @@ void TextServerAdvanced::font_set_ascent(RID p_font_rid, int p_size, real_t p_as
fd->cache[size]->ascent = p_ascent;
}
-real_t TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+float TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1881,14 +1868,14 @@ real_t TextServerAdvanced::font_get_ascent(RID p_font_rid, int p_size) const {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->ascent * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->ascent;
}
}
-void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, real_t p_descent) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, float p_descent) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
Vector2i size = _get_size(fd, p_size);
@@ -1897,8 +1884,8 @@ void TextServerAdvanced::font_set_descent(RID p_font_rid, int p_size, real_t p_d
fd->cache[size]->descent = p_descent;
}
-real_t TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+float TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1907,14 +1894,14 @@ real_t TextServerAdvanced::font_get_descent(RID p_font_rid, int p_size) const {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->descent * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->descent;
}
}
-void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1924,8 +1911,8 @@ void TextServerAdvanced::font_set_underline_position(RID p_font_rid, int p_size,
fd->cache[size]->underline_position = p_underline_position;
}
-real_t TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+float TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1934,14 +1921,14 @@ real_t TextServerAdvanced::font_get_underline_position(RID p_font_rid, int p_siz
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->underline_position * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->underline_position;
}
}
-void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1951,8 +1938,8 @@ void TextServerAdvanced::font_set_underline_thickness(RID p_font_rid, int p_size
fd->cache[size]->underline_thickness = p_underline_thickness;
}
-real_t TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+float TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1961,14 +1948,14 @@ real_t TextServerAdvanced::font_get_underline_thickness(RID p_font_rid, int p_si
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->underline_thickness * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->underline_thickness;
}
}
-void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, real_t p_scale) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, float p_scale) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1978,8 +1965,8 @@ void TextServerAdvanced::font_set_scale(RID p_font_rid, int p_size, real_t p_sca
fd->cache[size]->scale = p_scale;
}
-real_t TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+float TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1988,14 +1975,14 @@ real_t TextServerAdvanced::font_get_scale(RID p_font_rid, int p_size) const {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->scale * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->scale / fd->cache[size]->oversampling;
}
}
void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2016,7 +2003,7 @@ void TextServerAdvanced::font_set_spacing(RID p_font_rid, int p_size, TextServer
}
int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
MutexLock lock(fd->mutex);
@@ -2027,14 +2014,14 @@ int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer:
switch (p_spacing) {
case TextServer::SPACING_GLYPH: {
if (fd->msdf) {
- return fd->cache[size]->spacing_glyph * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->spacing_glyph;
}
} break;
case TextServer::SPACING_SPACE: {
if (fd->msdf) {
- return fd->cache[size]->spacing_space * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->spacing_space;
}
@@ -2047,7 +2034,7 @@ int TextServerAdvanced::font_get_spacing(RID p_font_rid, int p_size, TextServer:
}
int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
MutexLock lock(fd->mutex);
@@ -2059,7 +2046,7 @@ int TextServerAdvanced::font_get_texture_count(RID p_font_rid, const Vector2i &p
}
void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
@@ -2069,7 +2056,7 @@ void TextServerAdvanced::font_clear_textures(RID p_font_rid, const Vector2i &p_s
}
void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2081,7 +2068,7 @@ void TextServerAdvanced::font_remove_texture(RID p_font_rid, const Vector2i &p_s
}
void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
ERR_FAIL_COND(p_image.is_null());
@@ -2107,7 +2094,7 @@ void TextServerAdvanced::font_set_texture_image(RID p_font_rid, const Vector2i &
}
Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Ref<Image>());
MutexLock lock(fd->mutex);
@@ -2122,7 +2109,7 @@ Ref<Image> TextServerAdvanced::font_get_texture_image(RID p_font_rid, const Vect
}
void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2137,7 +2124,7 @@ void TextServerAdvanced::font_set_texture_offsets(RID p_font_rid, const Vector2i
}
PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, PackedInt32Array());
MutexLock lock(fd->mutex);
@@ -2150,7 +2137,7 @@ PackedInt32Array TextServerAdvanced::font_get_texture_offsets(RID p_font_rid, co
}
Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
MutexLock lock(fd->mutex);
@@ -2167,7 +2154,7 @@ Array TextServerAdvanced::font_get_glyph_list(RID p_font_rid, const Vector2i &p_
}
void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2178,7 +2165,7 @@ void TextServerAdvanced::font_clear_glyphs(RID p_font_rid, const Vector2i &p_siz
}
void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2189,7 +2176,7 @@ void TextServerAdvanced::font_remove_glyph(RID p_font_rid, const Vector2i &p_siz
}
Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
MutexLock lock(fd->mutex);
@@ -2203,14 +2190,14 @@ Vector2 TextServerAdvanced::font_get_glyph_advance(RID p_font_rid, int p_size, i
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].advance * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return gl[p_glyph].advance * (float)p_size / (float)fd->msdf_source_size;
} else {
return gl[p_glyph].advance;
}
}
void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2225,7 +2212,7 @@ void TextServerAdvanced::font_set_glyph_advance(RID p_font_rid, int p_size, int3
}
Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
MutexLock lock(fd->mutex);
@@ -2239,14 +2226,14 @@ Vector2 TextServerAdvanced::font_get_glyph_offset(RID p_font_rid, const Vector2i
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.position * (real_t)p_size.x / (real_t)fd->msdf_source_size;
+ return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size;
} else {
return gl[p_glyph].rect.position;
}
}
void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2261,7 +2248,7 @@ void TextServerAdvanced::font_set_glyph_offset(RID p_font_rid, const Vector2i &p
}
Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
MutexLock lock(fd->mutex);
@@ -2275,14 +2262,14 @@ Vector2 TextServerAdvanced::font_get_glyph_size(RID p_font_rid, const Vector2i &
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.size * (real_t)p_size.x / (real_t)fd->msdf_source_size;
+ return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size;
} else {
return gl[p_glyph].rect.size;
}
}
void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2297,7 +2284,7 @@ void TextServerAdvanced::font_set_glyph_size(RID p_font_rid, const Vector2i &p_s
}
Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Rect2());
MutexLock lock(fd->mutex);
@@ -2313,7 +2300,7 @@ Rect2 TextServerAdvanced::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i
}
void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2328,7 +2315,7 @@ void TextServerAdvanced::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &
}
int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, -1);
MutexLock lock(fd->mutex);
@@ -2344,7 +2331,7 @@ int TextServerAdvanced::font_get_glyph_texture_idx(RID p_font_rid, const Vector2
}
void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2358,42 +2345,50 @@ void TextServerAdvanced::font_set_glyph_texture_idx(RID p_font_rid, const Vector
gl[p_glyph].found = true;
}
-bool TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
+Dictionary TextServerAdvanced::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Dictionary());
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
+ Vector<Vector3> points;
+ Vector<int32_t> contours;
+ bool orientation;
#ifdef MODULE_FREETYPE_ENABLED
int error = FT_Load_Glyph(fd->cache[size]->face, p_index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
- ERR_FAIL_COND_V(error, false);
+ ERR_FAIL_COND_V(error, Dictionary());
- r_points.clear();
- r_contours.clear();
+ points.clear();
+ contours.clear();
- real_t h = fd->cache[size]->ascent;
- real_t scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
+ float h = fd->cache[size]->ascent;
+ float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
if (fd->msdf) {
- scale = scale * (real_t)p_size / (real_t)fd->msdf_source_size;
+ scale = scale * (float)p_size / (float)fd->msdf_source_size;
}
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) {
- r_points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
+ points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
}
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) {
- r_contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
+ contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
}
- r_orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+ orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
#else
- return false;
+ return Dictionary();
#endif
- return true;
+
+ Dictionary out;
+ out["points"] = points;
+ out["contours"] = contours;
+ out["orientation"] = orientation;
+ return out;
}
Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
MutexLock lock(fd->mutex);
@@ -2409,7 +2404,7 @@ Array TextServerAdvanced::font_get_kerning_list(RID p_font_rid, int p_size) cons
}
void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2420,7 +2415,7 @@ void TextServerAdvanced::font_clear_kerning_map(RID p_font_rid, int p_size) {
}
void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2431,7 +2426,7 @@ void TextServerAdvanced::font_remove_kerning(RID p_font_rid, int p_size, const V
}
void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2442,7 +2437,7 @@ void TextServerAdvanced::font_set_kerning(RID p_font_rid, int p_size, const Vect
}
Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
MutexLock lock(fd->mutex);
@@ -2454,7 +2449,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
- return kern[p_glyph_pair] * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size;
} else {
return kern[p_glyph_pair];
}
@@ -2464,7 +2459,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
FT_Vector delta;
FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);
if (fd->msdf) {
- return Vector2(delta.x, delta.y) * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size;
} else {
return Vector2(delta.x, delta.y);
}
@@ -2475,7 +2470,7 @@ Vector2 TextServerAdvanced::font_get_kerning(RID p_font_rid, int p_size, const V
}
int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
MutexLock lock(fd->mutex);
@@ -2498,7 +2493,7 @@ int32_t TextServerAdvanced::font_get_glyph_index(RID p_font_rid, int p_size, cha
}
bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -2516,7 +2511,7 @@ bool TextServerAdvanced::font_has_char(RID p_font_rid, char32_t p_char) const {
}
String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
MutexLock lock(fd->mutex);
@@ -2550,7 +2545,7 @@ String TextServerAdvanced::font_get_supported_chars(RID p_font_rid) const {
}
void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2568,7 +2563,7 @@ void TextServerAdvanced::font_render_range(RID p_font_rid, const Vector2i &p_siz
}
void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2578,7 +2573,7 @@ void TextServerAdvanced::font_render_glyph(RID p_font_rid, const Vector2i &p_siz
}
void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2603,8 +2598,8 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
- cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size;
- Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size;
+ cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+ Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
Point2i cpos = p_pos;
@@ -2618,7 +2613,7 @@ void TextServerAdvanced::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
}
void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2643,8 +2638,8 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
- cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size;
- Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size;
+ cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+ Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
Point2i cpos = p_pos;
@@ -2658,7 +2653,7 @@ void TextServerAdvanced::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
}
bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String &p_language) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -2670,7 +2665,7 @@ bool TextServerAdvanced::font_is_language_supported(RID p_font_rid, const String
}
void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2678,7 +2673,7 @@ void TextServerAdvanced::font_set_language_support_override(RID p_font_rid, cons
}
bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, const String &p_language) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -2686,7 +2681,7 @@ bool TextServerAdvanced::font_get_language_support_override(RID p_font_rid, cons
}
void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, const String &p_language) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2694,19 +2689,19 @@ void TextServerAdvanced::font_remove_language_support_override(RID p_font_rid, c
}
Vector<String> TextServerAdvanced::font_get_language_support_overrides(RID p_font_rid) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector<String>());
MutexLock lock(fd->mutex);
Vector<String> out;
- for (const Map<String, bool>::Element *E = fd->language_support_overrides.front(); E; E = E->next()) {
- out.push_back(E->key());
+ for (const KeyValue<String, bool> &E : fd->language_support_overrides) {
+ out.push_back(E.key);
}
return out;
}
bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &p_script) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -2715,12 +2710,12 @@ bool TextServerAdvanced::font_is_script_supported(RID p_font_rid, const String &
} else {
Vector2i size = _get_size(fd, 16);
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
- return fd->supported_scripts.has(TS->name_to_tag(p_script));
+ return fd->supported_scripts.has(hb_tag_from_string(p_script.ascii().get_data(), -1));
}
}
void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2728,7 +2723,7 @@ void TextServerAdvanced::font_set_script_support_override(RID p_font_rid, const
}
bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const String &p_script) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -2736,7 +2731,7 @@ bool TextServerAdvanced::font_get_script_support_override(RID p_font_rid, const
}
void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, const String &p_script) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -2744,7 +2739,7 @@ void TextServerAdvanced::font_remove_script_support_override(RID p_font_rid, con
}
Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font_rid) {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector<String>());
MutexLock lock(fd->mutex);
@@ -2756,7 +2751,7 @@ Vector<String> TextServerAdvanced::font_get_script_support_overrides(RID p_font_
}
Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
MutexLock lock(fd->mutex);
@@ -2766,7 +2761,7 @@ Dictionary TextServerAdvanced::font_supported_feature_list(RID p_font_rid) const
}
Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) const {
- FontDataAdvanced *fd = font_owner.getornull(p_font_rid);
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
MutexLock lock(fd->mutex);
@@ -2775,11 +2770,11 @@ Dictionary TextServerAdvanced::font_supported_variation_list(RID p_font_rid) con
return fd->supported_varaitions;
}
-real_t TextServerAdvanced::font_get_global_oversampling() const {
+float TextServerAdvanced::font_get_global_oversampling() const {
return oversampling;
}
-void TextServerAdvanced::font_set_global_oversampling(real_t p_oversampling) {
+void TextServerAdvanced::font_set_global_oversampling(float p_oversampling) {
_THREAD_SAFE_METHOD_
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
@@ -2797,7 +2792,7 @@ void TextServerAdvanced::font_set_global_oversampling(real_t p_oversampling) {
List<RID> text_bufs;
shaped_owner.get_owned_list(&text_bufs);
for (const RID &E : text_bufs) {
- invalidate(shaped_owner.getornull(E));
+ invalidate(shaped_owner.get_or_null(E));
}
}
}
@@ -2858,11 +2853,11 @@ void TextServerAdvanced::invalidate(TextServerAdvanced::ShapedTextDataAdvanced *
}
void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
- ShapedTextDataAdvanced *parent = shaped_owner.getornull(p_shaped->parent);
+ ShapedTextDataAdvanced *parent = shaped_owner.get_or_null(p_shaped->parent);
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = parent->objects.front(); E; E = E->next()) {
- if (E->get().pos >= p_shaped->start && E->get().pos < p_shaped->end) {
- p_shaped->objects[E->key()] = E->get();
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : parent->objects) {
+ if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) {
+ p_shaped->objects[E.key] = E.value;
}
}
@@ -2889,7 +2884,7 @@ RID TextServerAdvanced::create_shaped_text(TextServer::Direction p_direction, Te
}
void TextServerAdvanced::shaped_text_clear(RID p_shaped) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -2904,7 +2899,7 @@ void TextServerAdvanced::shaped_text_clear(RID p_shaped) {
}
void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -2918,27 +2913,30 @@ void TextServerAdvanced::shaped_text_set_direction(RID p_shaped, TextServer::Dir
}
TextServer::Direction TextServerAdvanced::shaped_text_get_direction(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::DIRECTION_LTR);
MutexLock lock(sd->mutex);
return sd->direction;
}
-void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+void TextServerAdvanced::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
if (sd->parent != RID()) {
full_copy(sd);
}
- sd->bidi_override = p_override;
+ sd->bidi_override.clear();
+ for (int i = 0; i < p_override.size(); i++) {
+ sd->bidi_override.push_back(p_override[i]);
+ }
invalidate(sd);
}
void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -2952,7 +2950,7 @@ void TextServerAdvanced::shaped_text_set_orientation(RID p_shaped, TextServer::O
}
void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -2964,7 +2962,7 @@ void TextServerAdvanced::shaped_text_set_preserve_invalid(RID p_shaped, bool p_e
}
bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2972,7 +2970,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_invalid(RID p_shaped) const {
}
void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -2986,7 +2984,7 @@ void TextServerAdvanced::shaped_text_set_preserve_control(RID p_shaped, bool p_e
}
bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2994,7 +2992,7 @@ bool TextServerAdvanced::shaped_text_get_preserve_control(RID p_shaped) const {
}
TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
MutexLock lock(sd->mutex);
@@ -3002,13 +3000,13 @@ TextServer::Orientation TextServerAdvanced::shaped_text_get_orientation(RID p_sh
}
bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
ERR_FAIL_COND_V(p_size <= 0, false);
MutexLock lock(sd->mutex);
for (int i = 0; i < p_fonts.size(); i++) {
- ERR_FAIL_COND_V(!font_owner.getornull(p_fonts[i]), false);
+ ERR_FAIL_COND_V(!font_owner.get_or_null(p_fonts[i]), false);
}
if (p_text.is_empty()) {
@@ -3037,7 +3035,7 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te
bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
ERR_FAIL_COND_V(p_key == Variant(), false);
ERR_FAIL_COND_V(sd->objects.has(p_key), false);
@@ -3066,7 +3064,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con
}
bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -3086,9 +3084,9 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
Glyph gl = sd->glyphs[i];
Variant key;
if (gl.count == 1) {
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if (E->get().pos == gl.start) {
- key = E->key();
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if (E.value.pos == gl.start) {
+ key = E.key;
break;
}
}
@@ -3117,8 +3115,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
- sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -3129,66 +3126,66 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
// Align embedded objects to baseline.
- real_t full_ascent = sd->ascent;
- real_t full_descent = sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -sd->ascent;
+ E.value.rect.position.y = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = sd->descent;
+ E.value.rect.position.y = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -sd->ascent;
+ E.value.rect.position.x = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = sd->descent;
+ E.value.rect.position.x = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
}
@@ -3199,7 +3196,7 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
MutexLock lock(sd->mutex);
@@ -3275,11 +3272,11 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
Variant key;
bool find_embedded = false;
if (gl.count == 1) {
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if (E->get().pos == gl.start) {
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if (E.value.pos == gl.start) {
find_embedded = true;
- key = E->key();
- new_sd->objects[key] = E->get();
+ key = E.key;
+ new_sd->objects[key] = E.value;
break;
}
}
@@ -3304,8 +3301,7 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
- new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -3320,66 +3316,66 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
// Align embedded objects to baseline.
- real_t full_ascent = new_sd->ascent;
- real_t full_descent = new_sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
- if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
+ float full_ascent = new_sd->ascent;
+ float full_descent = new_sd->descent;
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) {
+ if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -new_sd->ascent;
+ E.value.rect.position.y = -new_sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
+ E.value.rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = new_sd->descent;
+ E.value.rect.position.y = new_sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -new_sd->ascent;
+ E.value.rect.position.x = -new_sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
+ E.value.rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = new_sd->descent;
+ E.value.rect.position.x = new_sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
}
@@ -3392,15 +3388,15 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
RID TextServerAdvanced::shaped_text_get_parent(RID p_shaped) const {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
MutexLock lock(sd->mutex);
return sd->parent;
}
-real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -3440,7 +3436,7 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
}
}
- real_t justification_width;
+ float justification_width;
if ((p_jst_flags & JUSTIFICATION_CONSTRAIN_ELLIPSIS) == JUSTIFICATION_CONSTRAIN_ELLIPSIS) {
if (sd->overrun_trim_data.trim_pos >= 0) {
start_pos = sd->overrun_trim_data.trim_pos;
@@ -3480,7 +3476,7 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
}
if ((elongation_count > 0) && ((p_jst_flags & JUSTIFICATION_KASHIDA) == JUSTIFICATION_KASHIDA)) {
- real_t delta_width_per_kashida = (p_width - justification_width) / elongation_count;
+ float delta_width_per_kashida = (p_width - justification_width) / elongation_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
@@ -3495,15 +3491,15 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
}
}
}
- real_t adv_remain = 0;
+ float adv_remain = 0;
if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
- real_t delta_width_per_space = (p_width - justification_width) / space_count;
+ float delta_width_per_space = (p_width - justification_width) / space_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
- real_t old_adv = gl.advance;
- real_t new_advance;
+ float old_adv = gl.advance;
+ float new_advance;
if ((gl.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) {
new_advance = MAX(gl.advance + delta_width_per_space, 0.f);
} else {
@@ -3535,8 +3531,8 @@ real_t TextServerAdvanced::shaped_text_fit_to_width(RID p_shaped, real_t p_width
return sd->width;
}
-real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -3548,7 +3544,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
}
int tab_index = 0;
- real_t off = 0.f;
+ float off = 0.f;
int start, end, delta;
if (sd->para_direction == DIRECTION_LTR) {
@@ -3565,7 +3561,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
for (int i = start; i != end; i += delta) {
if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
- real_t tab_off = 0.f;
+ float tab_off = 0.f;
while (tab_off <= off) {
tab_off += p_tab_stops[tab_index];
tab_index++;
@@ -3573,7 +3569,7 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
tab_index = 0;
}
}
- real_t old_adv = gl[i].advance;
+ float old_adv = gl[i].advance;
gl[i].advance = tab_off - off;
sd->width += gl[i].advance - old_adv;
off = 0;
@@ -3585,8 +3581,8 @@ real_t TextServerAdvanced::shaped_text_tab_align(RID p_shaped, const Vector<real
return 0.f;
}
-void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, real_t p_width, uint8_t p_trim_flags) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped_line);
+void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataAdvanced invalid.");
MutexLock lock(sd->mutex);
@@ -3594,6 +3590,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
shaped_text_shape(p_shaped_line);
}
+ sd->text_trimmed = false;
sd->overrun_trim_data.ellipsis_glyph_buf.clear();
bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
@@ -3627,7 +3624,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
}
int ell_min_characters = 6;
- real_t width = sd->width;
+ float width = sd->width;
bool is_rtl = sd->direction == DIRECTION_RTL || (sd->direction == DIRECTION_AUTO && sd->para_direction == DIRECTION_RTL);
@@ -3683,7 +3680,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
// Insert an additional space when cutting word bound for aesthetics.
if (cut_per_word && (ellipsis_pos > 0)) {
- TextServer::Glyph gl;
+ Glyph gl;
gl.count = 1;
gl.advance = whitespace_adv.x;
gl.index = whitespace_gl_idx;
@@ -3694,7 +3691,7 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
// Add ellipsis dots.
- TextServer::Glyph gl;
+ Glyph gl;
gl.count = 1;
gl.repeat = 3;
gl.advance = dot_adv.x;
@@ -3711,16 +3708,40 @@ void TextServerAdvanced::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
}
}
-TextServer::TrimData TextServerAdvanced::shaped_text_get_trim_data(RID p_shaped) const {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataAdvanced invalid.");
+int TextServerAdvanced::shaped_text_get_trim_pos(RID p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.trim_pos;
+}
+
+int TextServerAdvanced::shaped_text_get_ellipsis_pos(RID p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextDataAdvanced invalid.");
MutexLock lock(sd->mutex);
- return sd->overrun_trim_data;
+ return sd->overrun_trim_data.ellipsis_pos;
+}
+
+const Glyph *TextServerAdvanced::shaped_text_get_ellipsis_glyphs(RID p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextDataAdvanced invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
+}
+
+int TextServerAdvanced::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextDataAdvanced invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.ellipsis_glyph_buf.size();
}
bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -3803,14 +3824,19 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
if (is_whitespace(c)) {
sd_glyphs[i].flags |= GRAPHEME_IS_BREAK_SOFT;
} else {
- TextServer::Glyph gl;
+ Glyph gl;
gl.start = sd_glyphs[i].start;
gl.end = sd_glyphs[i].end;
gl.count = 1;
gl.font_rid = sd_glyphs[i].font_rid;
gl.font_size = sd_glyphs[i].font_size;
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after.
+ if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) {
+ gl.flags |= GRAPHEME_IS_RTL;
+ sd->glyphs.insert(i, gl); // Insert before.
+ } else {
+ sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after.
+ }
// Update write pointer and size.
sd_size = sd->glyphs.size();
@@ -3907,7 +3933,7 @@ _FORCE_INLINE_ int _generate_kashida_justification_opportunies(const String &p_d
}
bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -3979,7 +4005,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
sd->glyphs.write[i].flags |= GRAPHEME_IS_ELONGATION;
} else {
if (sd->glyphs[i].font_rid != RID()) {
- TextServer::Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
+ Glyph gl = _shape_single_glyph(sd, 0x0640, HB_SCRIPT_ARABIC, HB_DIRECTION_RTL, sd->glyphs[i].font_rid, sd->glyphs[i].font_size);
if ((gl.flags & GRAPHEME_IS_VALID) == GRAPHEME_IS_VALID) {
gl.start = sd->glyphs[i].start;
gl.end = sd->glyphs[i].end;
@@ -3997,14 +4023,19 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
}
}
} else if (!is_whitespace(c)) {
- TextServer::Glyph gl;
+ Glyph gl;
gl.start = sd->glyphs[i].start;
gl.end = sd->glyphs[i].end;
gl.count = 1;
gl.font_rid = sd->glyphs[i].font_rid;
gl.font_size = sd->glyphs[i].font_size;
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
- sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after.
+ if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) {
+ gl.flags |= GRAPHEME_IS_RTL;
+ sd->glyphs.insert(i, gl); // Insert before.
+ } else {
+ sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after.
+ }
i += sd->glyphs[i].count;
continue;
}
@@ -4017,9 +4048,9 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
return sd->justification_ops_valid;
}
-TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) {
+Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size) {
hb_font_t *hb_font = _font_get_hb_handle(p_font, p_font_size);
- ERR_FAIL_COND_V(hb_font == nullptr, TextServer::Glyph());
+ ERR_FAIL_COND_V(hb_font == nullptr, Glyph());
hb_buffer_clear_contents(p_sd->hb_buffer);
hb_buffer_set_direction(p_sd->hb_buffer, p_direction);
@@ -4034,7 +4065,7 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
hb_glyph_position_t *glyph_pos = hb_buffer_get_glyph_positions(p_sd->hb_buffer, &glyph_count);
// Process glyphs.
- TextServer::Glyph gl;
+ Glyph gl;
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
gl.flags |= TextServer::GRAPHEME_IS_RTL;
@@ -4044,7 +4075,7 @@ TextServer::Glyph TextServerAdvanced::_shape_single_glyph(ShapedTextDataAdvanced
gl.font_size = p_font_size;
if (glyph_count > 0) {
- real_t scale = font_get_scale(p_font, p_font_size);
+ float scale = font_get_scale(p_font, p_font_size);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = Math::round(glyph_pos[0].x_advance / (64.0 / scale));
} else {
@@ -4069,7 +4100,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
// Add fallback glyphs.
for (int i = p_start; i < p_end; i++) {
if (p_sd->preserve_invalid || (p_sd->preserve_control && is_control(p_sd->text[i]))) {
- TextServer::Glyph gl;
+ Glyph gl;
gl.start = i;
gl.end = i + 1;
gl.count = 1;
@@ -4081,8 +4112,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = get_hex_code_box_size(fs, gl.index).x;
- p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.75f));
- p_sd->descent = MAX(p_sd->descent, Math::round(get_hex_code_box_size(fs, gl.index).y * 0.25f));
+ p_sd->ascent = MAX(p_sd->ascent, get_hex_code_box_size(fs, gl.index).y);
} else {
gl.advance = get_hex_code_box_size(fs, gl.index).y;
p_sd->ascent = MAX(p_sd->ascent, Math::round(get_hex_code_box_size(fs, gl.index).x * 0.5f));
@@ -4136,7 +4166,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
// Process glyphs.
if (glyph_count > 0) {
- TextServer::Glyph *w = (TextServer::Glyph *)memalloc(glyph_count * sizeof(TextServer::Glyph));
+ Glyph *w = (Glyph *)memalloc(glyph_count * sizeof(Glyph));
int end = (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) ? p_end : 0;
uint32_t last_cluster_id = UINT32_MAX;
@@ -4153,7 +4183,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
}
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
- w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL;
+ w[last_cluster_index].flags |= GRAPHEME_IS_RTL;
}
if (last_cluster_valid) {
w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
@@ -4165,8 +4195,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
last_cluster_id = glyph_info[i].cluster;
- TextServer::Glyph &gl = w[i];
- gl = TextServer::Glyph();
+ Glyph &gl = w[i];
+ gl = Glyph();
gl.start = glyph_info[i].cluster;
gl.end = end;
@@ -4175,9 +4205,13 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
gl.font_rid = p_fonts[p_fb_index];
gl.font_size = fs;
+ if (glyph_info[i].mask & HB_GLYPH_FLAG_DEFINED) {
+ gl.flags |= GRAPHEME_IS_CONNECTED;
+ }
+
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
- real_t scale = font_get_scale(f, fs);
+ float scale = font_get_scale(f, fs);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = Math::round(glyph_pos[i].x_advance / (64.0 / scale));
} else {
@@ -4193,9 +4227,9 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
if (p_sd->preserve_control) {
- last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || is_whitespace(p_sd->text[glyph_info[i].cluster]) || is_linebreak(p_sd->text[glyph_info[i].cluster]));
+ last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && is_linebreak(p_sd->text[glyph_info[i].cluster])));
} else {
- last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || !u_isgraph(p_sd->text[glyph_info[i].cluster]));
+ last_cluster_valid = last_cluster_valid && ((glyph_info[i].codepoint != 0) || (p_sd->text[glyph_info[i].cluster] == 0x0009) || (u_isblank(p_sd->text[glyph_info[i].cluster]) && (gl.advance != 0)) || (!u_isblank(p_sd->text[glyph_info[i].cluster]) && !u_isgraph(p_sd->text[glyph_info[i].cluster])));
}
}
if (p_direction == HB_DIRECTION_LTR || p_direction == HB_DIRECTION_TTB) {
@@ -4205,7 +4239,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
w[last_cluster_index].count = glyph_count - last_cluster_index;
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
- w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL;
+ w[last_cluster_index].flags |= GRAPHEME_IS_RTL;
}
if (last_cluster_valid) {
w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
@@ -4255,7 +4289,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
}
bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -4417,65 +4451,65 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
- real_t full_ascent = sd->ascent;
- real_t full_descent = sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -sd->ascent;
+ E.value.rect.position.y = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = sd->descent;
+ E.value.rect.position.y = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -sd->ascent;
+ E.value.rect.position.x = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = sd->descent;
+ E.value.rect.position.x = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
sd->ascent = full_ascent;
@@ -4485,35 +4519,38 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
bool TextServerAdvanced::shaped_text_is_ready(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
return sd->valid;
}
-Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+const Glyph *TextServerAdvanced::shaped_text_get_glyphs(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, nullptr);
MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
}
- return sd->glyphs;
+ return sd->glyphs.ptr();
}
-Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector2i());
+int TextServerAdvanced::shaped_text_get_glyph_count(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0);
MutexLock lock(sd->mutex);
- return Vector2(sd->start, sd->end);
+ if (!sd->valid) {
+ const_cast<TextServerAdvanced *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->glyphs.size();
}
-Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
- ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+const Glyph *TextServerAdvanced::shaped_text_sort_logical(RID p_shaped) {
+ ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, nullptr);
MutexLock lock(sd->mutex);
if (!sd->valid) {
@@ -4522,28 +4559,36 @@ Vector<TextServer::Glyph> TextServerAdvanced::shaped_text_sort_logical(RID p_sha
if (!sd->sort_valid) {
sd->glyphs_logical = sd->glyphs;
- sd->glyphs_logical.sort_custom<TextServer::GlyphCompare>();
+ sd->glyphs_logical.sort_custom<GlyphCompare>();
sd->sort_valid = true;
}
- return sd->glyphs_logical;
+ return sd->glyphs_logical.ptr();
+}
+
+Vector2i TextServerAdvanced::shaped_text_get_range(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector2i());
+
+ MutexLock lock(sd->mutex);
+ return Vector2(sd->start, sd->end);
}
Array TextServerAdvanced::shaped_text_get_objects(RID p_shaped) const {
Array ret;
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, ret);
MutexLock lock(sd->mutex);
- for (const Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ ret.push_back(E.key);
}
return ret;
}
Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Rect2());
MutexLock lock(sd->mutex);
@@ -4555,7 +4600,7 @@ Rect2 TextServerAdvanced::shaped_text_get_object_rect(RID p_shaped, Variant p_ke
}
Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Size2());
MutexLock lock(sd->mutex);
@@ -4569,8 +4614,8 @@ Size2 TextServerAdvanced::shaped_text_get_size(RID p_shaped) const {
}
}
-real_t TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -4580,8 +4625,8 @@ real_t TextServerAdvanced::shaped_text_get_ascent(RID p_shaped) const {
return sd->ascent;
}
-real_t TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -4591,8 +4636,8 @@ real_t TextServerAdvanced::shaped_text_get_descent(RID p_shaped) const {
return sd->descent;
}
-real_t TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -4602,8 +4647,8 @@ real_t TextServerAdvanced::shaped_text_get_width(RID p_shaped) const {
return (sd->text_trimmed ? sd->width_trimmed : sd->width);
}
-real_t TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -4614,8 +4659,8 @@ real_t TextServerAdvanced::shaped_text_get_underline_position(RID p_shaped) cons
return sd->upos;
}
-real_t TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const {
- const ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
+float TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) const {
+ const ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -4626,76 +4671,186 @@ real_t TextServerAdvanced::shaped_text_get_underline_thickness(RID p_shaped) con
return sd->uthk;
}
-struct num_system_data {
- Set<String> lang;
- String digits;
- String percent_sign;
- String exp;
-};
+void TextServerAdvanced::_insert_num_systems_lang() {
+ // Eastern Arabic numerals.
+ {
+ NumSystemData ar;
+ ar.lang.insert(StringName("ar")); // Arabic
+ ar.lang.insert(StringName("ar_AE"));
+ ar.lang.insert(StringName("ar_BH"));
+ ar.lang.insert(StringName("ar_DJ"));
+ ar.lang.insert(StringName("ar_EG"));
+ ar.lang.insert(StringName("ar_ER"));
+ ar.lang.insert(StringName("ar_IL"));
+ ar.lang.insert(StringName("ar_IQ"));
+ ar.lang.insert(StringName("ar_JO"));
+ ar.lang.insert(StringName("ar_KM"));
+ ar.lang.insert(StringName("ar_KW"));
+ ar.lang.insert(StringName("ar_LB"));
+ ar.lang.insert(StringName("ar_MR"));
+ ar.lang.insert(StringName("ar_OM"));
+ ar.lang.insert(StringName("ar_PS"));
+ ar.lang.insert(StringName("ar_QA"));
+ ar.lang.insert(StringName("ar_SA"));
+ ar.lang.insert(StringName("ar_SD"));
+ ar.lang.insert(StringName("ar_SO"));
+ ar.lang.insert(StringName("ar_SS"));
+ ar.lang.insert(StringName("ar_SY"));
+ ar.lang.insert(StringName("ar_TD"));
+ ar.lang.insert(StringName("ar_YE"));
+ ar.lang.insert(StringName("ckb")); // Central Kurdish
+ ar.lang.insert(StringName("ckb_IQ"));
+ ar.lang.insert(StringName("ckb_IR"));
+ ar.lang.insert(StringName("sd")); // Sindhi
+ ar.lang.insert(StringName("sd_PK"));
+ ar.lang.insert(StringName("sd_Arab"));
+ ar.lang.insert(StringName("sd_Arab_PK"));
+ ar.digits = U"٠١٢٣٤٥٦٧٨٩٫";
+ ar.percent_sign = U"٪";
+ ar.exp = U"اس";
+ num_systems.push_back(ar);
+ }
+
+ // Persian and Urdu numerals.
+ {
+ NumSystemData pr;
+ pr.lang.insert(StringName("fa")); // Persian
+ pr.lang.insert(StringName("fa_AF"));
+ pr.lang.insert(StringName("fa_IR"));
+ pr.lang.insert(StringName("ks")); // Kashmiri
+ pr.lang.insert(StringName("ks_IN"));
+ pr.lang.insert(StringName("ks_Arab"));
+ pr.lang.insert(StringName("ks_Arab_IN"));
+ pr.lang.insert(StringName("lrc")); // Northern Luri
+ pr.lang.insert(StringName("lrc_IQ"));
+ pr.lang.insert(StringName("lrc_IR"));
+ pr.lang.insert(StringName("mzn")); // Mazanderani
+ pr.lang.insert(StringName("mzn_IR"));
+ pr.lang.insert(StringName("pa_PK")); // Panjabi
+ pr.lang.insert(StringName("pa_Arab"));
+ pr.lang.insert(StringName("pa_Arab_PK"));
+ pr.lang.insert(StringName("ps")); // Pushto
+ pr.lang.insert(StringName("ps_AF"));
+ pr.lang.insert(StringName("ps_PK"));
+ pr.lang.insert(StringName("ur_IN")); // Urdu
+ pr.lang.insert(StringName("uz_AF")); // Uzbek
+ pr.lang.insert(StringName("uz_Arab"));
+ pr.lang.insert(StringName("uz_Arab_AF"));
+ pr.digits = U"۰۱۲۳۴۵۶۷۸۹٫";
+ pr.percent_sign = U"٪";
+ pr.exp = U"اس";
+ num_systems.push_back(pr);
+ }
+
+ // Bengali numerals.
+ {
+ NumSystemData bn;
+ bn.lang.insert(StringName("as")); // Assamese
+ bn.lang.insert(StringName("as_IN"));
+ bn.lang.insert(StringName("bn")); // Bengali
+ bn.lang.insert(StringName("bn_BD"));
+ bn.lang.insert(StringName("bn_IN"));
+ bn.lang.insert(StringName("mni")); // Manipuri
+ bn.lang.insert(StringName("mni_IN"));
+ bn.lang.insert(StringName("mni_Beng"));
+ bn.lang.insert(StringName("mni_Beng_IN"));
+ bn.digits = U"০১২৩৪৫৬৭৮৯.";
+ bn.percent_sign = U"%";
+ bn.exp = U"e";
+ num_systems.push_back(bn);
+ }
+
+ // Devanagari numerals.
+ {
+ NumSystemData mr;
+ mr.lang.insert(StringName("mr")); // Marathi
+ mr.lang.insert(StringName("mr_IN"));
+ mr.lang.insert(StringName("ne")); // Nepali
+ mr.lang.insert(StringName("ne_IN"));
+ mr.lang.insert(StringName("ne_NP"));
+ mr.lang.insert(StringName("sa")); // Sanskrit
+ mr.lang.insert(StringName("sa_IN"));
+ mr.digits = U"०१२३४५६७८९.";
+ mr.percent_sign = U"%";
+ mr.exp = U"e";
+ num_systems.push_back(mr);
+ }
+
+ // Dzongkha numerals.
+ {
+ NumSystemData dz;
+ dz.lang.insert(StringName("dz")); // Dzongkha
+ dz.lang.insert(StringName("dz_BT"));
+ dz.digits = U"༠༡༢༣༤༥༦༧༨༩.";
+ dz.percent_sign = U"%";
+ dz.exp = U"e";
+ num_systems.push_back(dz);
+ }
-static num_system_data num_systems[]{
- { Set<String>(), U"٠١٢٣٤٥٦٧٨٩٫", U"٪", U"اس" },
- { Set<String>(), U"۰۱۲۳۴۵۶۷۸۹٫", U"٪", U"اس" },
- { Set<String>(), U"০১২৩৪৫৬৭৮৯.", U"%", U"e" },
- { Set<String>(), U"०१२३४५६७८९.", U"%", U"e" },
- { Set<String>(), U"༠༡༢༣༤༥༦༧༨༩.", U"%", U"e" },
- { Set<String>(), U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.", U"%", U"e" },
- { Set<String>(), U"၀၁၂၃၄၅၆၇၈၉.", U"%", U"e" },
- { Set<String>(), String(), String(), String() },
-};
+ // Santali numerals.
+ {
+ NumSystemData sat;
+ sat.lang.insert(StringName("sat")); // Santali
+ sat.lang.insert(StringName("sat_IN"));
+ sat.lang.insert(StringName("sat_Olck"));
+ sat.lang.insert(StringName("sat_Olck_IN"));
+ sat.digits = U"᱐᱑᱒᱓᱔᱕᱖᱗᱘᱙.";
+ sat.percent_sign = U"%";
+ sat.exp = U"e";
+ num_systems.push_back(sat);
+ }
+
+ // Burmese numerals.
+ {
+ NumSystemData my;
+ my.lang.insert(StringName("my")); // Burmese
+ my.lang.insert(StringName("my_MM"));
+ my.digits = U"၀၁၂၃၄၅၆၇၈၉.";
+ my.percent_sign = U"%";
+ my.exp = U"e";
+ num_systems.push_back(my);
+ }
+
+ // Chakma numerals.
+ {
+ NumSystemData ccp;
+ ccp.lang.insert(StringName("ccp")); // Chakma
+ ccp.lang.insert(StringName("ccp_BD"));
+ ccp.lang.insert(StringName("ccp_IN"));
+ ccp.digits = U"𑄶𑄷𑄸𑄹𑄺𑄻𑄼𑄽𑄾𑄿.";
+ ccp.percent_sign = U"%";
+ ccp.exp = U"e";
+ num_systems.push_back(ccp);
+ }
-static void _insert_num_systems_lang() {
- num_systems[0].lang.insert(StringName("ar"));
- num_systems[0].lang.insert(StringName("ar_AR"));
- num_systems[0].lang.insert(StringName("ar_BH"));
- num_systems[0].lang.insert(StringName("ar_DJ"));
- num_systems[0].lang.insert(StringName("ar_EG"));
- num_systems[0].lang.insert(StringName("ar_ER"));
- num_systems[0].lang.insert(StringName("ar_IL"));
- num_systems[0].lang.insert(StringName("ar_IQ"));
- num_systems[0].lang.insert(StringName("ar_JO"));
- num_systems[0].lang.insert(StringName("ar_KM"));
- num_systems[0].lang.insert(StringName("ar_KW"));
- num_systems[0].lang.insert(StringName("ar_LB"));
- num_systems[0].lang.insert(StringName("ar_MR"));
- num_systems[0].lang.insert(StringName("ar_OM"));
- num_systems[0].lang.insert(StringName("ar_PS"));
- num_systems[0].lang.insert(StringName("ar_QA"));
- num_systems[0].lang.insert(StringName("ar_SA"));
- num_systems[0].lang.insert(StringName("ar_SD"));
- num_systems[0].lang.insert(StringName("ar_SO"));
- num_systems[0].lang.insert(StringName("ar_SS"));
- num_systems[0].lang.insert(StringName("ar_SY"));
- num_systems[0].lang.insert(StringName("ar_TD"));
- num_systems[0].lang.insert(StringName("ar_YE"));
-
- num_systems[1].lang.insert(StringName("fa"));
- num_systems[1].lang.insert(StringName("ks"));
- num_systems[1].lang.insert(StringName("pa_Arab"));
- num_systems[1].lang.insert(StringName("ug"));
- num_systems[1].lang.insert(StringName("ur_IN"));
- num_systems[1].lang.insert(StringName("ur"));
- num_systems[1].lang.insert(StringName("uz_Arab"));
-
- num_systems[2].lang.insert(StringName("as"));
- num_systems[2].lang.insert(StringName("bn"));
- num_systems[2].lang.insert(StringName("mni"));
-
- num_systems[3].lang.insert(StringName("mr"));
- num_systems[3].lang.insert(StringName("ne"));
-
- num_systems[4].lang.insert(StringName("dz"));
-
- num_systems[5].lang.insert(StringName("sat"));
-
- num_systems[6].lang.insert(StringName("my"));
+ // Adlam numerals.
+ {
+ NumSystemData ff;
+ ff.lang.insert(StringName("ff")); // Fulah
+ ff.lang.insert(StringName("ff_Adlm_BF"));
+ ff.lang.insert(StringName("ff_Adlm_CM"));
+ ff.lang.insert(StringName("ff_Adlm_GH"));
+ ff.lang.insert(StringName("ff_Adlm_GM"));
+ ff.lang.insert(StringName("ff_Adlm_GN"));
+ ff.lang.insert(StringName("ff_Adlm_GW"));
+ ff.lang.insert(StringName("ff_Adlm_LR"));
+ ff.lang.insert(StringName("ff_Adlm_MR"));
+ ff.lang.insert(StringName("ff_Adlm_NE"));
+ ff.lang.insert(StringName("ff_Adlm_NG"));
+ ff.lang.insert(StringName("ff_Adlm_SL"));
+ ff.lang.insert(StringName("ff_Adlm_SN"));
+ ff.digits = U"𞥐𞥑𞥒𞥓𞥔𞥕𞥖𞥗𞥘𞥙.";
+ ff.percent_sign = U"%";
+ ff.exp = U"e";
+ num_systems.push_back(ff);
+ }
}
String TextServerAdvanced::format_number(const String &p_string, const String &p_language) const {
const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
String res = p_string;
- for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].digits == String()) {
return p_string;
@@ -4720,7 +4875,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_
const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
String res = p_string;
- for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].digits == String()) {
return p_string;
@@ -4747,7 +4902,7 @@ String TextServerAdvanced::parse_number(const String &p_string, const String &p_
String TextServerAdvanced::percent_sign(const String &p_language) const {
const StringName lang = (p_language == "") ? TranslationServer::get_singleton()->get_tool_locale() : p_language;
- for (int i = 0; num_systems[i].lang.size() != 0; i++) {
+ for (int i = 0; i < num_systems.size(); i++) {
if (num_systems[i].lang.has(lang)) {
if (num_systems[i].percent_sign == String()) {
return "%";
@@ -4758,23 +4913,14 @@ String TextServerAdvanced::percent_sign(const String &p_language) const {
return "%";
}
-TextServer *TextServerAdvanced::create_func(Error &r_error, void *p_user_data) {
- r_error = OK;
- return memnew(TextServerAdvanced());
-}
-
-void TextServerAdvanced::register_server() {
- TextServerManager::register_create_function(interface_name, interface_features, create_func, nullptr);
-}
-
TextServerAdvanced::TextServerAdvanced() {
_insert_num_systems_lang();
_insert_feature_sets();
- hb_bmp_create_font_funcs();
+ _bmp_create_font_funcs();
}
TextServerAdvanced::~TextServerAdvanced() {
- hb_bmp_free_font_funcs();
+ _bmp_free_font_funcs();
if (library != nullptr) {
FT_Done_FreeType(library);
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index 5989035800..333b68e074 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -79,6 +79,19 @@ class TextServerAdvanced : public TextServer {
static String interface_name;
static uint32_t interface_features;
+ struct NumSystemData {
+ Set<StringName> lang;
+ String digits;
+ String percent_sign;
+ String exp;
+ };
+
+ Vector<NumSystemData> num_systems;
+ Map<StringName, int32_t> feature_sets;
+
+ void _insert_num_systems_lang();
+ void _insert_feature_sets();
+
// ICU support data.
uint8_t *icu_data = nullptr;
@@ -115,12 +128,12 @@ class TextServerAdvanced : public TextServer {
};
struct FontDataForSizeAdvanced {
- real_t ascent = 0.f;
- real_t descent = 0.f;
- real_t underline_position = 0.f;
- real_t underline_thickness = 0.f;
- real_t scale = 1.f;
- real_t oversampling = 1.f;
+ float ascent = 0.f;
+ float descent = 0.f;
+ float underline_position = 0.f;
+ float underline_thickness = 0.f;
+ float scale = 1.f;
+ float oversampling = 1.f;
int spacing_glyph = 0;
int spacing_space = 0;
@@ -161,7 +174,7 @@ class TextServerAdvanced : public TextServer {
bool force_autohinter = false;
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
Dictionary variation_coordinates;
- real_t oversampling = 0.f;
+ float oversampling = 0.f;
Map<Vector2i, FontDataForSizeAdvanced *> cache;
@@ -245,38 +258,37 @@ class TextServerAdvanced : public TextServer {
// Common data.
- real_t oversampling = 1.f;
+ float oversampling = 1.f;
mutable RID_PtrOwner<FontDataAdvanced> font_owner;
mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner;
int _convert_pos(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
int _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int p_pos) const;
void _shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_start, int32_t p_end, hb_script_t p_script, hb_direction_t p_direction, Vector<RID> p_fonts, int p_span, int p_fb_index);
- TextServer::Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size);
+ Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, RID p_font, int p_font_size);
// HarfBuzz bitmap font interface.
static hb_font_funcs_t *funcs;
- struct hb_bmp_font_t {
+ struct bmp_font_t {
TextServerAdvanced::FontDataForSizeAdvanced *face = nullptr;
bool unref = false; /* Whether to destroy bm_face when done. */
};
- static hb_bmp_font_t *_hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
- static void _hb_bmp_font_destroy(void *p_data);
- static hb_bool_t hb_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data);
- static hb_position_t hb_bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
- static hb_position_t hb_bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
- static hb_position_t hb_bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data);
- static hb_position_t hb_bmp_get_glyph_v_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data);
- static hb_bool_t hb_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data);
- static hb_bool_t hb_bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data);
- static hb_bool_t hb_bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data);
- static void hb_bmp_create_font_funcs();
- static void hb_bmp_free_font_funcs();
- static void _hb_bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
- static hb_font_t *hb_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy);
+ static bmp_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
+ static void _bmp_font_destroy(void *p_data);
+ static hb_bool_t _bmp_get_nominal_glyph(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_unicode, hb_codepoint_t *r_glyph, void *p_user_data);
+ static hb_position_t _bmp_get_glyph_h_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
+ static hb_position_t _bmp_get_glyph_v_advance(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, void *p_user_data);
+ static hb_position_t _bmp_get_glyph_h_kerning(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_left_glyph, hb_codepoint_t p_right_glyph, void *p_user_data);
+ static hb_bool_t _bmp_get_glyph_v_origin(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_position_t *r_x, hb_position_t *r_y, void *p_user_data);
+ static hb_bool_t _bmp_get_glyph_extents(hb_font_t *p_font, void *p_font_data, hb_codepoint_t p_glyph, hb_glyph_extents_t *r_extents, void *p_user_data);
+ static hb_bool_t _bmp_get_font_h_extents(hb_font_t *p_font, void *p_font_data, hb_font_extents_t *r_metrics, void *p_user_data);
+ static void _bmp_create_font_funcs();
+ static void _bmp_free_font_funcs();
+ static void _bmp_font_set_funcs(hb_font_t *p_font, TextServerAdvanced::FontDataForSizeAdvanced *p_face, bool p_unref);
+ static hb_font_t *_bmp_font_create(TextServerAdvanced::FontDataForSizeAdvanced *p_face, hb_destroy_func_t p_destroy);
protected:
static void _bind_methods(){};
@@ -285,20 +297,19 @@ protected:
void invalidate(ShapedTextDataAdvanced *p_shaped);
public:
- virtual bool has_feature(Feature p_feature) override;
+ virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
+ virtual uint32_t get_features() const override;
virtual void free(RID p_rid) override;
virtual bool has(RID p_rid) override;
virtual bool load_support_data(const String &p_filename) override;
-#ifdef TOOLS_ENABLED
- virtual String get_support_data_filename() override { return _MKSTR(ICU_DATA_NAME); };
- virtual String get_support_data_info() override { return String("ICU break iteration data (") + _MKSTR(ICU_DATA_NAME) + String(")."); };
- virtual bool save_support_data(const String &p_filename) override;
-#endif
+ virtual String get_support_data_filename() const override;
+ virtual String get_support_data_info() const override;
+ virtual bool save_support_data(const String &p_filename) const override;
- virtual bool is_locale_right_to_left(const String &p_locale) override;
+ virtual bool is_locale_right_to_left(const String &p_locale) const override;
virtual int32_t name_to_tag(const String &p_name) const override;
virtual String tag_to_name(int32_t p_tag) const override;
@@ -333,8 +344,8 @@ public:
virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
- virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) override;
- virtual real_t font_get_oversampling(RID p_font_rid) const override;
+ virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override;
+ virtual float font_get_oversampling(RID p_font_rid) const override;
virtual Array font_get_size_cache_list(RID p_font_rid) const override;
virtual void font_clear_size_cache(RID p_font_rid) override;
@@ -342,20 +353,20 @@ public:
hb_font_t *_font_get_hb_handle(RID p_font, int p_font_size) const;
- virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) override;
- virtual real_t font_get_ascent(RID p_font_rid, int p_size) const override;
+ virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override;
+ virtual float font_get_ascent(RID p_font_rid, int p_size) const override;
- virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) override;
- virtual real_t font_get_descent(RID p_font_rid, int p_size) const override;
+ virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override;
+ virtual float font_get_descent(RID p_font_rid, int p_size) const override;
- virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) override;
- virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const override;
+ virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override;
+ virtual float font_get_underline_position(RID p_font_rid, int p_size) const override;
- virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) override;
- virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const override;
+ virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override;
+ virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override;
- virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) override;
- virtual real_t font_get_scale(RID p_font_rid, int p_size) const override;
+ virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override;
+ virtual float font_get_scale(RID p_font_rid, int p_size) const override;
virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
@@ -389,7 +400,7 @@ public:
virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
- virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+ virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override;
virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
@@ -424,8 +435,8 @@ public:
virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
- virtual real_t font_get_global_oversampling() const override;
- virtual void font_set_global_oversampling(real_t p_oversampling) override;
+ virtual float font_get_global_oversampling() const override;
+ virtual void font_set_global_oversampling(float p_oversampling) override;
/* Shaped text buffer interface */
@@ -436,7 +447,7 @@ public:
virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
virtual Direction shaped_text_get_direction(RID p_shaped) const override;
- virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) override;
+ virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
@@ -454,41 +465,42 @@ public:
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
- virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
- virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) override;
+ virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+ virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override;
virtual bool shaped_text_shape(RID p_shaped) override;
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) override;
- virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override;
+ virtual int shaped_text_get_trim_pos(RID p_shaped) const override;
+ virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override;
+ virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override;
+
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
- virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override;
+ virtual int shaped_text_get_glyph_count(RID p_shaped) const override;
virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
- virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override;
-
virtual Array shaped_text_get_objects(RID p_shaped) const override;
virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
virtual Size2 shaped_text_get_size(RID p_shaped) const override;
- virtual real_t shaped_text_get_ascent(RID p_shaped) const override;
- virtual real_t shaped_text_get_descent(RID p_shaped) const override;
- virtual real_t shaped_text_get_width(RID p_shaped) const override;
- virtual real_t shaped_text_get_underline_position(RID p_shaped) const override;
- virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const override;
+ virtual float shaped_text_get_ascent(RID p_shaped) const override;
+ virtual float shaped_text_get_descent(RID p_shaped) const override;
+ virtual float shaped_text_get_width(RID p_shaped) const override;
+ virtual float shaped_text_get_underline_position(RID p_shaped) const override;
+ virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
virtual String format_number(const String &p_string, const String &p_language = "") const override;
virtual String parse_number(const String &p_string, const String &p_language = "") const override;
virtual String percent_sign(const String &p_language = "") const override;
- static TextServer *create_func(Error &r_error, void *p_user_data);
- static void register_server();
-
TextServerAdvanced();
~TextServerAdvanced();
};
diff --git a/modules/text_server_fb/config.py b/modules/text_server_fb/config.py
index 7a73080ae9..275c2b4d53 100644
--- a/modules/text_server_fb/config.py
+++ b/modules/text_server_fb/config.py
@@ -9,3 +9,13 @@ def configure(env):
def is_enabled():
# The module is disabled by default. Use module_text_server_fb_enabled=yes to enable it.
return False
+
+
+def get_doc_classes():
+ return [
+ "TextServerFallback",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/text_server_fb/doc_classes/TextServerFallback.xml b/modules/text_server_fb/doc_classes/TextServerFallback.xml
new file mode 100644
index 0000000000..8aadf2b882
--- /dev/null
+++ b/modules/text_server_fb/doc_classes/TextServerFallback.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="TextServerFallback" inherits="TextServer" version="4.0">
+ <brief_description>
+ Fallback implementation of the Text Server, without BiDi and complex text layout support.
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+</class>
diff --git a/modules/text_server_fb/register_types.cpp b/modules/text_server_fb/register_types.cpp
index 87cbd2ac2c..0b59040ce8 100644
--- a/modules/text_server_fb/register_types.cpp
+++ b/modules/text_server_fb/register_types.cpp
@@ -33,7 +33,12 @@
#include "text_server_fb.h"
void preregister_text_server_fb_types() {
- TextServerFallback::register_server();
+ GDREGISTER_CLASS(TextServerFallback);
+ if (TextServerManager::get_singleton()) {
+ Ref<TextServerFallback> ts;
+ ts.instantiate();
+ TextServerManager::get_singleton()->add_interface(ts);
+ }
}
void register_text_server_fb_types() {
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index e4e6797f92..02acd4727c 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -30,6 +30,7 @@
#include "text_server_fb.h"
+#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#ifdef MODULE_MSDFGEN_ENABLED
@@ -68,7 +69,7 @@ _FORCE_INLINE_ bool is_underscore(char32_t p_char) {
String TextServerFallback::interface_name = "Fallback";
uint32_t TextServerFallback::interface_features = 0; // Nothing is supported.
-bool TextServerFallback::has_feature(Feature p_feature) {
+bool TextServerFallback::has_feature(Feature p_feature) const {
return (interface_features & p_feature) == p_feature;
}
@@ -76,14 +77,18 @@ String TextServerFallback::get_name() const {
return interface_name;
}
+uint32_t TextServerFallback::get_features() const {
+ return interface_features;
+}
+
void TextServerFallback::free(RID p_rid) {
_THREAD_SAFE_METHOD_
if (font_owner.owns(p_rid)) {
- FontDataFallback *fd = font_owner.getornull(p_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_rid);
font_owner.free(p_rid);
memdelete(fd);
} else if (shaped_owner.owns(p_rid)) {
- ShapedTextData *sd = shaped_owner.getornull(p_rid);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_rid);
shaped_owner.free(p_rid);
memdelete(sd);
}
@@ -98,34 +103,22 @@ bool TextServerFallback::load_support_data(const String &p_filename) {
return false; // No extra data used.
}
-#ifdef TOOLS_ENABLED
-
-bool TextServerFallback::save_support_data(const String &p_filename) {
+bool TextServerFallback::save_support_data(const String &p_filename) const {
return false; // No extra data used.
}
-#endif
-
-bool TextServerFallback::is_locale_right_to_left(const String &p_locale) {
+bool TextServerFallback::is_locale_right_to_left(const String &p_locale) const {
return false; // No RTL support.
}
-#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | ((uint32_t)(c4)&0xFF)))
-
-struct FeatureInfo {
- int32_t tag;
- String name;
-};
-
-static FeatureInfo feature_set[] = {
- // Registered OpenType variation tags.
- { OT_TAG('i', 't', 'a', 'l'), "italic" },
- { OT_TAG('o', 'p', 's', 'z'), "optical_size" },
- { OT_TAG('s', 'l', 'n', 't'), "slant" },
- { OT_TAG('w', 'd', 't', 'h'), "width" },
- { OT_TAG('w', 'g', 'h', 't'), "weight" },
- { 0, String() },
-};
+void TextServerFallback::_insert_feature_sets() {
+ // Registered OpenType variation tag.
+ feature_sets.insert("italic", OT_TAG('i', 't', 'a', 'l'));
+ feature_sets.insert("optical_size", OT_TAG('o', 'p', 's', 'z'));
+ feature_sets.insert("slant", OT_TAG('s', 'l', 'n', 't'));
+ feature_sets.insert("width", OT_TAG('w', 'd', 't', 'h'));
+ feature_sets.insert("weight", OT_TAG('w', 'g', 'h', 't'));
+}
_FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
char tag[4];
@@ -149,10 +142,8 @@ _FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) {
}
int32_t TextServerFallback::name_to_tag(const String &p_name) const {
- for (int i = 0; feature_set[i].tag != 0; i++) {
- if (feature_set[i].name == p_name) {
- return feature_set[i].tag;
- }
+ if (feature_sets.has(p_name)) {
+ return feature_sets[p_name];
}
// No readable name, use tag string.
@@ -167,9 +158,9 @@ _FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) {
}
String TextServerFallback::tag_to_name(int32_t p_tag) const {
- for (int i = 0; feature_set[i].tag != 0; i++) {
- if (feature_set[i].tag == p_tag) {
- return feature_set[i].name;
+ for (const KeyValue<StringName, int32_t> &E : feature_sets) {
+ if (E.value == p_tag) {
+ return E.key;
}
}
@@ -419,8 +410,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
FontTexture &tex = p_data->textures.write[tex_pos.index];
edgeColoringSimple(shape, 3.0); // Max. angle.
- msdfgen::Bitmap<real_t, 4> image(w, h); // Texture size.
- //msdfgen::generateMTSDF(image, shape, p_pixel_range, 1.0, msdfgen::Vector2(-bounds.l, -bounds.b)); // Range, scale, translation.
+ msdfgen::Bitmap<float, 4> image(w, h); // Texture size.
DistancePixelConversion distancePixelConversion(p_pixel_range);
msdfgen::Projection projection(msdfgen::Vector2(1.0, 1.0), msdfgen::Vector2(-bounds.l, -bounds.b));
@@ -514,11 +504,11 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
case FT_PIXEL_MODE_MONO: {
int byte = i * bitmap.pitch + (j >> 3);
int bit = 1 << (7 - (j % 8));
- wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 0] = 255; // grayscale as 1
wr[ofs + 1] = (bitmap.buffer[byte] & bit) ? 255 : 0;
} break;
case FT_PIXEL_MODE_GRAY:
- wr[ofs + 0] = 255; //grayscale as 1
+ wr[ofs + 0] = 255; // grayscale as 1
wr[ofs + 1] = bitmap.buffer[i * bitmap.pitch + j];
break;
case FT_PIXEL_MODE_BGRA: {
@@ -610,14 +600,16 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_glyph(FontDataFallback *p_font_d
flags |= FT_LOAD_COLOR;
}
+ int32_t glyph_index = FT_Get_Char_Index(fd->face, p_glyph);
+
FT_Fixed v, h;
- FT_Get_Advance(fd->face, p_glyph, flags, &h);
- FT_Get_Advance(fd->face, p_glyph, flags | FT_LOAD_VERTICAL_LAYOUT, &v);
+ FT_Get_Advance(fd->face, glyph_index, flags, &h);
+ FT_Get_Advance(fd->face, glyph_index, flags | FT_LOAD_VERTICAL_LAYOUT, &v);
- int error = FT_Load_Glyph(fd->face, p_glyph, flags);
+ int error = FT_Load_Glyph(fd->face, glyph_index, flags);
if (error) {
fd->glyph_map[p_glyph] = FontGlyph();
- ERR_FAIL_V_MSG(false, "FreeType: Failed to load glyph.");
+ return false;
}
if (!outline) {
@@ -686,7 +678,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
int error = 0;
if (!library) {
error = FT_Init_FreeType(&library);
- ERR_FAIL_COND_V_MSG(error != 0, false, TTR("FreeType: Error initializing library:") + " '" + String(FT_Error_String(error)) + "'.");
+ ERR_FAIL_COND_V_MSG(error != 0, false, "FreeType: Error initializing library: '" + String(FT_Error_String(error)) + "'.");
}
memset(&fd->stream, 0, sizeof(FT_StreamRec));
@@ -704,14 +696,14 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
if (error) {
FT_Done_Face(fd->face);
fd->face = nullptr;
- ERR_FAIL_V_MSG(false, TTR("FreeType: Error loading font:") + " '" + String(FT_Error_String(error)) + "'.");
+ ERR_FAIL_V_MSG(false, "FreeType: Error loading font: '" + String(FT_Error_String(error)) + "'.");
}
if (p_font_data->msdf) {
fd->oversampling = 1.0f;
fd->size.x = p_font_data->msdf_source_size;
} else if (p_font_data->oversampling <= 0.0f) {
- fd->oversampling = TS->font_get_global_oversampling();
+ fd->oversampling = font_get_global_oversampling();
} else {
fd->oversampling = p_font_data->oversampling;
}
@@ -719,13 +711,13 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
if (FT_HAS_COLOR(fd->face) && fd->face->num_fixed_sizes > 0) {
int best_match = 0;
int diff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[0].width));
- fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
+ fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[0].width;
for (int i = 1; i < fd->face->num_fixed_sizes; i++) {
int ndiff = ABS(fd->size.x - ((int64_t)fd->face->available_sizes[i].width));
if (ndiff < diff) {
best_match = i;
diff = ndiff;
- fd->scale = real_t(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
+ fd->scale = float(fd->size.x * fd->oversampling) / fd->face->available_sizes[i].width;
}
}
FT_Select_Size(fd->face, best_match);
@@ -766,7 +758,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
for (FT_UInt i = 0; i < amaster->num_axis; i++) {
// Reset to default.
int32_t var_tag = amaster->axis[i].tag;
- real_t var_value = (double)amaster->axis[i].def / 65536.f;
+ float var_value = (double)amaster->axis[i].def / 65536.f;
coords.write[i] = amaster->axis[i].def;
if (p_font_data->variation_coordinates.has(var_tag)) {
@@ -784,7 +776,7 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
FT_Done_MM_Var(library, amaster);
}
#else
- ERR_FAIL_V_MSG(false, TTR("FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
+ ERR_FAIL_V_MSG(false, "FreeType: Can't load dynamic font, engine is compiled without FreeType support!");
#endif
}
p_font_data->cache[p_size] = fd;
@@ -792,8 +784,8 @@ _FORCE_INLINE_ bool TextServerFallback::_ensure_cache_for_size(FontDataFallback
}
_FORCE_INLINE_ void TextServerFallback::_font_clear_cache(FontDataFallback *p_font_data) {
- for (const Map<Vector2i, FontDataForSizeFallback *>::Element *E = p_font_data->cache.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<Vector2i, FontDataForSizeFallback *> &E : p_font_data->cache) {
+ memdelete(E.value);
}
p_font_data->cache.clear();
@@ -808,7 +800,7 @@ RID TextServerFallback::create_font() {
}
void TextServerFallback::font_set_data(RID p_font_rid, const PackedByteArray &p_data) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -819,7 +811,7 @@ void TextServerFallback::font_set_data(RID p_font_rid, const PackedByteArray &p_
}
void TextServerFallback::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -830,7 +822,7 @@ void TextServerFallback::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data
}
void TextServerFallback::font_set_antialiased(RID p_font_rid, bool p_antialiased) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -841,7 +833,7 @@ void TextServerFallback::font_set_antialiased(RID p_font_rid, bool p_antialiased
}
bool TextServerFallback::font_is_antialiased(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -849,7 +841,7 @@ bool TextServerFallback::font_is_antialiased(RID p_font_rid) const {
}
void TextServerFallback::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -860,7 +852,7 @@ void TextServerFallback::font_set_multichannel_signed_distance_field(RID p_font_
}
bool TextServerFallback::font_is_multichannel_signed_distance_field(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -868,7 +860,7 @@ bool TextServerFallback::font_is_multichannel_signed_distance_field(RID p_font_r
}
void TextServerFallback::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -879,7 +871,7 @@ void TextServerFallback::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pi
}
int TextServerFallback::font_get_msdf_pixel_range(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -887,7 +879,7 @@ int TextServerFallback::font_get_msdf_pixel_range(RID p_font_rid) const {
}
void TextServerFallback::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -898,7 +890,7 @@ void TextServerFallback::font_set_msdf_size(RID p_font_rid, int p_msdf_size) {
}
int TextServerFallback::font_get_msdf_size(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -906,7 +898,7 @@ int TextServerFallback::font_get_msdf_size(RID p_font_rid) const {
}
void TextServerFallback::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -916,7 +908,7 @@ void TextServerFallback::font_set_fixed_size(RID p_font_rid, int p_fixed_size) {
}
int TextServerFallback::font_get_fixed_size(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -924,7 +916,7 @@ int TextServerFallback::font_get_fixed_size(RID p_font_rid) const {
}
void TextServerFallback::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -935,7 +927,7 @@ void TextServerFallback::font_set_force_autohinter(RID p_font_rid, bool p_force_
}
bool TextServerFallback::font_is_force_autohinter(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -943,7 +935,7 @@ bool TextServerFallback::font_is_force_autohinter(RID p_font_rid) const {
}
void TextServerFallback::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -954,7 +946,7 @@ void TextServerFallback::font_set_hinting(RID p_font_rid, TextServer::Hinting p_
}
TextServer::Hinting TextServerFallback::font_get_hinting(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, HINTING_NONE);
MutexLock lock(fd->mutex);
@@ -962,7 +954,7 @@ TextServer::Hinting TextServerFallback::font_get_hinting(RID p_font_rid) const {
}
void TextServerFallback::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -973,15 +965,15 @@ void TextServerFallback::font_set_variation_coordinates(RID p_font_rid, const Di
}
Dictionary TextServerFallback::font_get_variation_coordinates(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
MutexLock lock(fd->mutex);
return fd->variation_coordinates;
}
-void TextServerFallback::font_set_oversampling(RID p_font_rid, real_t p_oversampling) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+void TextServerFallback::font_set_oversampling(RID p_font_rid, float p_oversampling) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -991,8 +983,8 @@ void TextServerFallback::font_set_oversampling(RID p_font_rid, real_t p_oversamp
}
}
-real_t TextServerFallback::font_get_oversampling(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+float TextServerFallback::font_get_oversampling(RID p_font_rid) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1000,30 +992,30 @@ real_t TextServerFallback::font_get_oversampling(RID p_font_rid) const {
}
Array TextServerFallback::font_get_size_cache_list(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
MutexLock lock(fd->mutex);
Array ret;
- for (const Map<Vector2i, FontDataForSizeFallback *>::Element *E = fd->cache.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<Vector2i, FontDataForSizeFallback *> &E : fd->cache) {
+ ret.push_back(E.key);
}
return ret;
}
void TextServerFallback::font_clear_size_cache(RID p_font_rid) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- for (const Map<Vector2i, FontDataForSizeFallback *>::Element *E = fd->cache.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<Vector2i, FontDataForSizeFallback *> &E : fd->cache) {
+ memdelete(E.value);
}
fd->cache.clear();
}
void TextServerFallback::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1033,8 +1025,8 @@ void TextServerFallback::font_remove_size_cache(RID p_font_rid, const Vector2i &
}
}
-void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1044,8 +1036,8 @@ void TextServerFallback::font_set_ascent(RID p_font_rid, int p_size, real_t p_as
fd->cache[size]->ascent = p_ascent;
}
-real_t TextServerFallback::font_get_ascent(RID p_font_rid, int p_size) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+float TextServerFallback::font_get_ascent(RID p_font_rid, int p_size) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1054,14 +1046,14 @@ real_t TextServerFallback::font_get_ascent(RID p_font_rid, int p_size) const {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->ascent * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->ascent * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->ascent;
}
}
-void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, real_t p_descent) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, float p_descent) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
Vector2i size = _get_size(fd, p_size);
@@ -1070,8 +1062,8 @@ void TextServerFallback::font_set_descent(RID p_font_rid, int p_size, real_t p_d
fd->cache[size]->descent = p_descent;
}
-real_t TextServerFallback::font_get_descent(RID p_font_rid, int p_size) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+float TextServerFallback::font_get_descent(RID p_font_rid, int p_size) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1080,14 +1072,14 @@ real_t TextServerFallback::font_get_descent(RID p_font_rid, int p_size) const {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->descent * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->descent * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->descent;
}
}
-void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1097,8 +1089,8 @@ void TextServerFallback::font_set_underline_position(RID p_font_rid, int p_size,
fd->cache[size]->underline_position = p_underline_position;
}
-real_t TextServerFallback::font_get_underline_position(RID p_font_rid, int p_size) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+float TextServerFallback::font_get_underline_position(RID p_font_rid, int p_size) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1107,14 +1099,14 @@ real_t TextServerFallback::font_get_underline_position(RID p_font_rid, int p_siz
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->underline_position * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->underline_position * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->underline_position;
}
}
-void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1124,8 +1116,8 @@ void TextServerFallback::font_set_underline_thickness(RID p_font_rid, int p_size
fd->cache[size]->underline_thickness = p_underline_thickness;
}
-real_t TextServerFallback::font_get_underline_thickness(RID p_font_rid, int p_size) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+float TextServerFallback::font_get_underline_thickness(RID p_font_rid, int p_size) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1134,14 +1126,14 @@ real_t TextServerFallback::font_get_underline_thickness(RID p_font_rid, int p_si
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->underline_thickness * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->underline_thickness * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->underline_thickness;
}
}
-void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, real_t p_scale) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, float p_scale) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1151,8 +1143,8 @@ void TextServerFallback::font_set_scale(RID p_font_rid, int p_size, real_t p_sca
fd->cache[size]->scale = p_scale;
}
-real_t TextServerFallback::font_get_scale(RID p_font_rid, int p_size) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+float TextServerFallback::font_get_scale(RID p_font_rid, int p_size) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0.f);
MutexLock lock(fd->mutex);
@@ -1161,14 +1153,14 @@ real_t TextServerFallback::font_get_scale(RID p_font_rid, int p_size) const {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0.f);
if (fd->msdf) {
- return fd->cache[size]->scale * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->scale * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->scale / fd->cache[size]->oversampling;
}
}
void TextServerFallback::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1189,7 +1181,7 @@ void TextServerFallback::font_set_spacing(RID p_font_rid, int p_size, TextServer
}
int TextServerFallback::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
MutexLock lock(fd->mutex);
@@ -1200,14 +1192,14 @@ int TextServerFallback::font_get_spacing(RID p_font_rid, int p_size, TextServer:
switch (p_spacing) {
case TextServer::SPACING_GLYPH: {
if (fd->msdf) {
- return fd->cache[size]->spacing_glyph * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->spacing_glyph * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->spacing_glyph;
}
} break;
case TextServer::SPACING_SPACE: {
if (fd->msdf) {
- return fd->cache[size]->spacing_space * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return fd->cache[size]->spacing_space * (float)p_size / (float)fd->msdf_source_size;
} else {
return fd->cache[size]->spacing_space;
}
@@ -1220,7 +1212,7 @@ int TextServerFallback::font_get_spacing(RID p_font_rid, int p_size, TextServer:
}
int TextServerFallback::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, 0);
MutexLock lock(fd->mutex);
@@ -1232,7 +1224,7 @@ int TextServerFallback::font_get_texture_count(RID p_font_rid, const Vector2i &p
}
void TextServerFallback::font_clear_textures(RID p_font_rid, const Vector2i &p_size) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
@@ -1242,7 +1234,7 @@ void TextServerFallback::font_clear_textures(RID p_font_rid, const Vector2i &p_s
}
void TextServerFallback::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1254,7 +1246,7 @@ void TextServerFallback::font_remove_texture(RID p_font_rid, const Vector2i &p_s
}
void TextServerFallback::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
ERR_FAIL_COND(p_image.is_null());
@@ -1280,7 +1272,7 @@ void TextServerFallback::font_set_texture_image(RID p_font_rid, const Vector2i &
}
Ref<Image> TextServerFallback::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Ref<Image>());
MutexLock lock(fd->mutex);
@@ -1295,7 +1287,7 @@ Ref<Image> TextServerFallback::font_get_texture_image(RID p_font_rid, const Vect
}
void TextServerFallback::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1310,7 +1302,7 @@ void TextServerFallback::font_set_texture_offsets(RID p_font_rid, const Vector2i
}
PackedInt32Array TextServerFallback::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, PackedInt32Array());
MutexLock lock(fd->mutex);
@@ -1323,7 +1315,7 @@ PackedInt32Array TextServerFallback::font_get_texture_offsets(RID p_font_rid, co
}
Array TextServerFallback::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
MutexLock lock(fd->mutex);
@@ -1340,7 +1332,7 @@ Array TextServerFallback::font_get_glyph_list(RID p_font_rid, const Vector2i &p_
}
void TextServerFallback::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1351,7 +1343,7 @@ void TextServerFallback::font_clear_glyphs(RID p_font_rid, const Vector2i &p_siz
}
void TextServerFallback::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1362,7 +1354,7 @@ void TextServerFallback::font_remove_glyph(RID p_font_rid, const Vector2i &p_siz
}
Vector2 TextServerFallback::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
MutexLock lock(fd->mutex);
@@ -1376,14 +1368,14 @@ Vector2 TextServerFallback::font_get_glyph_advance(RID p_font_rid, int p_size, i
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].advance * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return gl[p_glyph].advance * (float)p_size / (float)fd->msdf_source_size;
} else {
return gl[p_glyph].advance;
}
}
void TextServerFallback::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1398,7 +1390,7 @@ void TextServerFallback::font_set_glyph_advance(RID p_font_rid, int p_size, int3
}
Vector2 TextServerFallback::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
MutexLock lock(fd->mutex);
@@ -1412,14 +1404,14 @@ Vector2 TextServerFallback::font_get_glyph_offset(RID p_font_rid, const Vector2i
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.position * (real_t)p_size.x / (real_t)fd->msdf_source_size;
+ return gl[p_glyph].rect.position * (float)p_size.x / (float)fd->msdf_source_size;
} else {
return gl[p_glyph].rect.position;
}
}
void TextServerFallback::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1434,7 +1426,7 @@ void TextServerFallback::font_set_glyph_offset(RID p_font_rid, const Vector2i &p
}
Vector2 TextServerFallback::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
MutexLock lock(fd->mutex);
@@ -1448,14 +1440,14 @@ Vector2 TextServerFallback::font_get_glyph_size(RID p_font_rid, const Vector2i &
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
if (fd->msdf) {
- return gl[p_glyph].rect.size * (real_t)p_size.x / (real_t)fd->msdf_source_size;
+ return gl[p_glyph].rect.size * (float)p_size.x / (float)fd->msdf_source_size;
} else {
return gl[p_glyph].rect.size;
}
}
void TextServerFallback::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1470,7 +1462,7 @@ void TextServerFallback::font_set_glyph_size(RID p_font_rid, const Vector2i &p_s
}
Rect2 TextServerFallback::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Rect2());
MutexLock lock(fd->mutex);
@@ -1486,7 +1478,7 @@ Rect2 TextServerFallback::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i
}
void TextServerFallback::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1501,7 +1493,7 @@ void TextServerFallback::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &
}
int TextServerFallback::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, -1);
MutexLock lock(fd->mutex);
@@ -1517,7 +1509,7 @@ int TextServerFallback::font_get_glyph_texture_idx(RID p_font_rid, const Vector2
}
void TextServerFallback::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1531,42 +1523,50 @@ void TextServerFallback::font_set_glyph_texture_idx(RID p_font_rid, const Vector
gl[p_glyph].found = true;
}
-bool TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
- ERR_FAIL_COND_V(!fd, false);
+Dictionary TextServerFallback::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Dictionary());
MutexLock lock(fd->mutex);
Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), false);
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
+ Vector<Vector3> points;
+ Vector<int32_t> contours;
+ bool orientation;
#ifdef MODULE_FREETYPE_ENABLED
- int error = FT_Load_Glyph(fd->cache[size]->face, p_index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
- ERR_FAIL_COND_V(error, false);
+ int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, p_index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
+ ERR_FAIL_COND_V(error, Dictionary());
- r_points.clear();
- r_contours.clear();
+ points.clear();
+ contours.clear();
- real_t h = fd->cache[size]->ascent;
- real_t scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
+ float h = fd->cache[size]->ascent;
+ float scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
if (fd->msdf) {
- scale = scale * (real_t)p_size / (real_t)fd->msdf_source_size;
+ scale = scale * (float)p_size / (float)fd->msdf_source_size;
}
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; i++) {
- r_points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
+ points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, h - fd->cache[size]->face->glyph->outline.points[i].y * scale, FT_CURVE_TAG(fd->cache[size]->face->glyph->outline.tags[i])));
}
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_contours; i++) {
- r_contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
+ contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
}
- r_orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
+ orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
#else
- return false;
+ return Dictionary();
#endif
- return true;
+
+ Dictionary out;
+ out["points"] = points;
+ out["contours"] = contours;
+ out["orientation"] = orientation;
+ return out;
}
Array TextServerFallback::font_get_kerning_list(RID p_font_rid, int p_size) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Array());
MutexLock lock(fd->mutex);
@@ -1575,14 +1575,14 @@ Array TextServerFallback::font_get_kerning_list(RID p_font_rid, int p_size) cons
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Array());
Array ret;
- for (const Map<Vector2i, Vector2>::Element *E = fd->cache[size]->kerning_map.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<Vector2i, Vector2> &E : fd->cache[size]->kerning_map) {
+ ret.push_back(E.key);
}
return ret;
}
void TextServerFallback::font_clear_kerning_map(RID p_font_rid, int p_size) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1593,7 +1593,7 @@ void TextServerFallback::font_clear_kerning_map(RID p_font_rid, int p_size) {
}
void TextServerFallback::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1604,7 +1604,7 @@ void TextServerFallback::font_remove_kerning(RID p_font_rid, int p_size, const V
}
void TextServerFallback::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1615,7 +1615,7 @@ void TextServerFallback::font_set_kerning(RID p_font_rid, int p_size, const Vect
}
Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector2());
MutexLock lock(fd->mutex);
@@ -1627,7 +1627,7 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
- return kern[p_glyph_pair] * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return kern[p_glyph_pair] * (float)p_size / (float)fd->msdf_source_size;
} else {
return kern[p_glyph_pair];
}
@@ -1635,9 +1635,11 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
#ifdef MODULE_FREETYPE_ENABLED
if (fd->cache[size]->face) {
FT_Vector delta;
- FT_Get_Kerning(fd->cache[size]->face, p_glyph_pair.x, p_glyph_pair.y, FT_KERNING_DEFAULT, &delta);
+ int32_t glyph_a = FT_Get_Char_Index(fd->cache[size]->face, p_glyph_pair.x);
+ int32_t glyph_b = FT_Get_Char_Index(fd->cache[size]->face, p_glyph_pair.y);
+ FT_Get_Kerning(fd->cache[size]->face, glyph_a, glyph_b, FT_KERNING_DEFAULT, &delta);
if (fd->msdf) {
- return Vector2(delta.x, delta.y) * (real_t)p_size / (real_t)fd->msdf_source_size;
+ return Vector2(delta.x, delta.y) * (float)p_size / (float)fd->msdf_source_size;
} else {
return Vector2(delta.x, delta.y);
}
@@ -1648,30 +1650,11 @@ Vector2 TextServerFallback::font_get_kerning(RID p_font_rid, int p_size, const V
}
int32_t TextServerFallback::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
- ERR_FAIL_COND_V(!fd, 0);
-
- MutexLock lock(fd->mutex);
- Vector2i size = _get_size(fd, p_size);
- ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), 0);
-
-#ifdef MODULE_FREETYPE_ENABLED
- if (fd->cache[size]->face) {
- if (p_variation_selector) {
- return FT_Face_GetCharVariantIndex(fd->cache[size]->face, p_char, p_variation_selector);
- } else {
- return FT_Get_Char_Index(fd->cache[size]->face, p_char);
- }
- } else {
- return 0;
- }
-#else
return (int32_t)p_char;
-#endif
}
bool TextServerFallback::font_has_char(RID p_font_rid, char32_t p_char) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1689,7 +1672,7 @@ bool TextServerFallback::font_has_char(RID p_font_rid, char32_t p_char) const {
}
String TextServerFallback::font_get_supported_chars(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, String());
MutexLock lock(fd->mutex);
@@ -1723,25 +1706,19 @@ String TextServerFallback::font_get_supported_chars(RID p_font_rid) const {
}
void TextServerFallback::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
Vector2i size = _get_size_outline(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
for (char32_t i = p_start; i <= p_end; i++) {
-#ifdef MODULE_FREETYPE_ENABLED
- if (fd->cache[size]->face) {
- _ensure_glyph(fd, size, FT_Get_Char_Index(fd->cache[size]->face, i));
- continue;
- }
-#endif
_ensure_glyph(fd, size, (int32_t)i);
}
}
void TextServerFallback::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1751,7 +1728,7 @@ void TextServerFallback::font_render_glyph(RID p_font_rid, const Vector2i &p_siz
}
void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1776,8 +1753,8 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
- cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size;
- Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size;
+ cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+ Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, 0, fd->msdf_range);
} else {
Point2i cpos = p_pos;
@@ -1791,7 +1768,7 @@ void TextServerFallback::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_siz
}
void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1816,8 +1793,8 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
- cpos += gl.rect.position * (real_t)p_size / (real_t)fd->msdf_source_size;
- Size2 csize = gl.rect.size * (real_t)p_size / (real_t)fd->msdf_source_size;
+ cpos += gl.rect.position * (float)p_size / (float)fd->msdf_source_size;
+ Size2 csize = gl.rect.size * (float)p_size / (float)fd->msdf_source_size;
RenderingServer::get_singleton()->canvas_item_add_msdf_texture_rect_region(p_canvas, Rect2(cpos, csize), texture, gl.uv_rect, modulate, p_outline_size * 2, fd->msdf_range);
} else {
Point2i cpos = p_pos;
@@ -1831,7 +1808,7 @@ void TextServerFallback::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, i
}
bool TextServerFallback::font_is_language_supported(RID p_font_rid, const String &p_language) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1843,7 +1820,7 @@ bool TextServerFallback::font_is_language_supported(RID p_font_rid, const String
}
void TextServerFallback::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1851,7 +1828,7 @@ void TextServerFallback::font_set_language_support_override(RID p_font_rid, cons
}
bool TextServerFallback::font_get_language_support_override(RID p_font_rid, const String &p_language) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1859,7 +1836,7 @@ bool TextServerFallback::font_get_language_support_override(RID p_font_rid, cons
}
void TextServerFallback::font_remove_language_support_override(RID p_font_rid, const String &p_language) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1867,19 +1844,19 @@ void TextServerFallback::font_remove_language_support_override(RID p_font_rid, c
}
Vector<String> TextServerFallback::font_get_language_support_overrides(RID p_font_rid) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector<String>());
MutexLock lock(fd->mutex);
Vector<String> out;
- for (const Map<String, bool>::Element *E = fd->language_support_overrides.front(); E; E = E->next()) {
- out.push_back(E->key());
+ for (const KeyValue<String, bool> &E : fd->language_support_overrides) {
+ out.push_back(E.key);
}
return out;
}
bool TextServerFallback::font_is_script_supported(RID p_font_rid, const String &p_script) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1891,7 +1868,7 @@ bool TextServerFallback::font_is_script_supported(RID p_font_rid, const String &
}
void TextServerFallback::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1899,7 +1876,7 @@ void TextServerFallback::font_set_script_support_override(RID p_font_rid, const
}
bool TextServerFallback::font_get_script_support_override(RID p_font_rid, const String &p_script) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, false);
MutexLock lock(fd->mutex);
@@ -1907,7 +1884,7 @@ bool TextServerFallback::font_get_script_support_override(RID p_font_rid, const
}
void TextServerFallback::font_remove_script_support_override(RID p_font_rid, const String &p_script) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
@@ -1917,13 +1894,13 @@ void TextServerFallback::font_remove_script_support_override(RID p_font_rid, con
}
Vector<String> TextServerFallback::font_get_script_support_overrides(RID p_font_rid) {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Vector<String>());
MutexLock lock(fd->mutex);
Vector<String> out;
- for (const Map<String, bool>::Element *E = fd->script_support_overrides.front(); E; E = E->next()) {
- out.push_back(E->key());
+ for (const KeyValue<String, bool> &E : fd->script_support_overrides) {
+ out.push_back(E.key);
}
return out;
}
@@ -1933,7 +1910,7 @@ Dictionary TextServerFallback::font_supported_feature_list(RID p_font_rid) const
}
Dictionary TextServerFallback::font_supported_variation_list(RID p_font_rid) const {
- FontDataFallback *fd = font_owner.getornull(p_font_rid);
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
MutexLock lock(fd->mutex);
@@ -1942,11 +1919,11 @@ Dictionary TextServerFallback::font_supported_variation_list(RID p_font_rid) con
return fd->supported_varaitions;
}
-real_t TextServerFallback::font_get_global_oversampling() const {
+float TextServerFallback::font_get_global_oversampling() const {
return oversampling;
}
-void TextServerFallback::font_set_global_oversampling(real_t p_oversampling) {
+void TextServerFallback::font_set_global_oversampling(float p_oversampling) {
_THREAD_SAFE_METHOD_
if (oversampling != p_oversampling) {
oversampling = p_oversampling;
@@ -1964,7 +1941,7 @@ void TextServerFallback::font_set_global_oversampling(real_t p_oversampling) {
List<RID> text_bufs;
shaped_owner.get_owned_list(&text_bufs);
for (const RID &E : text_bufs) {
- invalidate(shaped_owner.getornull(E));
+ invalidate(shaped_owner.get_or_null(E));
}
}
}
@@ -1989,11 +1966,11 @@ void TextServerFallback::invalidate(ShapedTextData *p_shaped) {
}
void TextServerFallback::full_copy(ShapedTextData *p_shaped) {
- ShapedTextData *parent = shaped_owner.getornull(p_shaped->parent);
+ ShapedTextData *parent = shaped_owner.get_or_null(p_shaped->parent);
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = parent->objects.front(); E; E = E->next()) {
- if (E->get().pos >= p_shaped->start && E->get().pos < p_shaped->end) {
- p_shaped->objects[E->key()] = E->get();
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : parent->objects) {
+ if (E.value.pos >= p_shaped->start && E.value.pos < p_shaped->end) {
+ p_shaped->objects[E.key] = E.value;
}
}
@@ -2020,7 +1997,7 @@ RID TextServerFallback::create_shaped_text(TextServer::Direction p_direction, Te
}
void TextServerFallback::shaped_text_clear(RID p_shaped) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -2044,7 +2021,7 @@ TextServer::Direction TextServerFallback::shaped_text_get_direction(RID p_shaped
}
void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -2057,12 +2034,12 @@ void TextServerFallback::shaped_text_set_orientation(RID p_shaped, TextServer::O
}
}
-void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) {
+void TextServerFallback::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) {
// No BiDi support, ignore.
}
TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, TextServer::ORIENTATION_HORIZONTAL);
MutexLock lock(sd->mutex);
@@ -2070,7 +2047,7 @@ TextServer::Orientation TextServerFallback::shaped_text_get_orientation(RID p_sh
}
void TextServerFallback::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
MutexLock lock(sd->mutex);
ERR_FAIL_COND(!sd);
@@ -2084,7 +2061,7 @@ void TextServerFallback::shaped_text_set_preserve_invalid(RID p_shaped, bool p_e
}
bool TextServerFallback::shaped_text_get_preserve_invalid(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2092,7 +2069,7 @@ bool TextServerFallback::shaped_text_get_preserve_invalid(RID p_shaped) const {
}
void TextServerFallback::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -2106,7 +2083,7 @@ void TextServerFallback::shaped_text_set_preserve_control(RID p_shaped, bool p_e
}
bool TextServerFallback::shaped_text_get_preserve_control(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2114,14 +2091,14 @@ bool TextServerFallback::shaped_text_get_preserve_control(RID p_shaped) const {
}
bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
ERR_FAIL_COND_V(p_size <= 0, false);
for (int i = 0; i < p_fonts.size(); i++) {
- ERR_FAIL_COND_V(!font_owner.getornull(p_fonts[i]), false);
+ ERR_FAIL_COND_V(!font_owner.get_or_null(p_fonts[i]), false);
}
if (p_text.is_empty()) {
@@ -2161,7 +2138,7 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te
}
bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2192,7 +2169,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con
}
bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2212,9 +2189,9 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
Glyph gl = sd->glyphs[i];
Variant key;
if (gl.count == 1) {
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if (E->get().pos == gl.start) {
- key = E->key();
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if (E.value.pos == gl.start) {
+ key = E.key;
break;
}
}
@@ -2243,8 +2220,7 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
} else if (sd->preserve_invalid || (sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
- sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -2255,66 +2231,66 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
// Align embedded objects to baseline.
- real_t full_ascent = sd->ascent;
- real_t full_descent = sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if ((E.value.pos >= sd->start) && (E.value.pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -sd->ascent;
+ E.value.rect.position.y = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = sd->descent;
+ E.value.rect.position.y = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -sd->ascent;
+ E.value.rect.position.x = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = sd->descent;
+ E.value.rect.position.x = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
}
@@ -2325,7 +2301,7 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_length) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
MutexLock lock(sd->mutex);
@@ -2364,11 +2340,11 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
Variant key;
bool find_embedded = false;
if (gl.count == 1) {
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- if (E->get().pos == gl.start) {
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ if (E.value.pos == gl.start) {
find_embedded = true;
- key = E->key();
- new_sd->objects[key] = E->get();
+ key = E.key;
+ new_sd->objects[key] = E.value;
break;
}
}
@@ -2393,8 +2369,7 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
} else if (new_sd->preserve_invalid || (new_sd->preserve_control && is_control(gl.index))) {
// Glyph not found, replace with hex code box.
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
- new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
- new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ new_sd->ascent = MAX(new_sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
new_sd->ascent = MAX(new_sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
new_sd->descent = MAX(new_sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -2407,66 +2382,66 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
// Align embedded objects to baseline.
- real_t full_ascent = new_sd->ascent;
- real_t full_descent = new_sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
- if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
+ float full_ascent = new_sd->ascent;
+ float full_descent = new_sd->descent;
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : new_sd->objects) {
+ if ((E.value.pos >= new_sd->start) && (E.value.pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -new_sd->ascent;
+ E.value.rect.position.y = -new_sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
+ E.value.rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = new_sd->descent;
+ E.value.rect.position.y = new_sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -new_sd->ascent;
+ E.value.rect.position.x = -new_sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
+ E.value.rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = new_sd->descent;
+ E.value.rect.position.x = new_sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
}
@@ -2479,15 +2454,15 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
RID TextServerFallback::shaped_text_get_parent(RID p_shaped) const {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, RID());
MutexLock lock(sd->mutex);
return sd->parent;
}
-real_t TextServerFallback::shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+float TextServerFallback::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags) {
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -2550,12 +2525,12 @@ real_t TextServerFallback::shaped_text_fit_to_width(RID p_shaped, real_t p_width
}
if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
- real_t delta_width_per_space = (p_width - sd->width) / space_count;
+ float delta_width_per_space = (p_width - sd->width) / space_count;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
if ((gl.flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) {
- real_t old_adv = gl.advance;
+ float old_adv = gl.advance;
gl.advance = MAX(gl.advance + delta_width_per_space, Math::round(0.1 * gl.font_size));
sd->width += (gl.advance - old_adv);
}
@@ -2566,8 +2541,8 @@ real_t TextServerFallback::shaped_text_fit_to_width(RID p_shaped, real_t p_width
return sd->width;
}
-real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+float TextServerFallback::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) {
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -2579,7 +2554,7 @@ real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real
}
int tab_index = 0;
- real_t off = 0.f;
+ float off = 0.f;
int start, end, delta;
if (sd->para_direction == DIRECTION_LTR) {
@@ -2596,7 +2571,7 @@ real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real
for (int i = start; i != end; i += delta) {
if ((gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB) {
- real_t tab_off = 0.f;
+ float tab_off = 0.f;
while (tab_off <= off) {
tab_off += p_tab_stops[tab_index];
tab_index++;
@@ -2604,7 +2579,7 @@ real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real
tab_index = 0;
}
}
- real_t old_adv = gl[i].advance;
+ float old_adv = gl[i].advance;
gl[i].advance = tab_off - off;
sd->width += gl[i].advance - old_adv;
off = 0;
@@ -2617,7 +2592,7 @@ real_t TextServerFallback::shaped_text_tab_align(RID p_shaped, const Vector<real
}
bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2658,7 +2633,7 @@ bool TextServerFallback::shaped_text_update_breaks(RID p_shaped) {
}
bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2673,8 +2648,8 @@ bool TextServerFallback::shaped_text_update_justification_ops(RID p_shaped) {
return true;
}
-void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, real_t p_width, uint8_t p_trim_flags) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped_line);
+void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) {
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped_line);
ERR_FAIL_COND_MSG(!sd, "ShapedTextDataFallback invalid.");
MutexLock lock(sd->mutex);
@@ -2682,6 +2657,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
shaped_text_shape(p_shaped_line);
}
+ sd->text_trimmed = false;
sd->overrun_trim_data.ellipsis_glyph_buf.clear();
bool add_ellipsis = (p_trim_flags & OVERRUN_ADD_ELLIPSIS) == OVERRUN_ADD_ELLIPSIS;
@@ -2715,7 +2691,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
}
int ell_min_characters = 6;
- real_t width = sd->width;
+ float width = sd->width;
int trim_pos = 0;
int ellipsis_pos = (enforce_ellipsis) ? 0 : -1;
@@ -2761,7 +2737,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
if (add_ellipsis && (ellipsis_pos > 0 || enforce_ellipsis)) {
// Insert an additional space when cutting word bound for aesthetics.
if (cut_per_word && (ellipsis_pos > 0)) {
- TextServer::Glyph gl;
+ Glyph gl;
gl.count = 1;
gl.advance = whitespace_adv.x;
gl.index = whitespace_gl_idx;
@@ -2772,7 +2748,7 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
sd->overrun_trim_data.ellipsis_glyph_buf.append(gl);
}
// Add ellipsis dots.
- TextServer::Glyph gl;
+ Glyph gl;
gl.count = 1;
gl.repeat = 3;
gl.advance = dot_adv.x;
@@ -2789,16 +2765,40 @@ void TextServerFallback::shaped_text_overrun_trim_to_width(RID p_shaped_line, re
}
}
-TextServer::TrimData TextServerFallback::shaped_text_get_trim_data(RID p_shaped) const {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V_MSG(!sd, TrimData(), "ShapedTextDataFallback invalid.");
+int TextServerFallback::shaped_text_get_trim_pos(RID p_shaped) const {
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextData invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.trim_pos;
+}
+
+int TextServerFallback::shaped_text_get_ellipsis_pos(RID p_shaped) const {
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, -1, "ShapedTextData invalid.");
MutexLock lock(sd->mutex);
- return sd->overrun_trim_data;
+ return sd->overrun_trim_data.ellipsis_pos;
+}
+
+const Glyph *TextServerFallback::shaped_text_get_ellipsis_glyphs(RID p_shaped) const {
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, nullptr, "ShapedTextData invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.ellipsis_glyph_buf.ptr();
+}
+
+int TextServerFallback::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const {
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V_MSG(!sd, 0, "ShapedTextData invalid.");
+
+ MutexLock lock(sd->mutex);
+ return sd->overrun_trim_data.ellipsis_glyph_buf.size();
}
bool TextServerFallback::shaped_text_shape(RID p_shaped) {
- ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
@@ -2909,8 +2909,7 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
// Glyph not found, replace with hex code box.
if (sd->orientation == ORIENTATION_HORIZONTAL) {
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).x;
- sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.75f));
- sd->descent = MAX(sd->descent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).y * 0.25f));
+ sd->ascent = MAX(sd->ascent, get_hex_code_box_size(gl.font_size, gl.index).y);
} else {
gl.advance = get_hex_code_box_size(gl.font_size, gl.index).y;
sd->ascent = MAX(sd->ascent, Math::round(get_hex_code_box_size(gl.font_size, gl.index).x * 0.5f));
@@ -2924,65 +2923,65 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
- real_t full_ascent = sd->ascent;
- real_t full_descent = sd->descent;
- for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
+ float full_ascent = sd->ascent;
+ float full_descent = sd->descent;
+ for (KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.y = -sd->ascent;
+ E.value.rect.position.y = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.y = 0;
+ E.value.rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.y = sd->descent;
+ E.value.rect.position.y = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.y -= E->get().rect.size.y;
+ E.value.rect.position.y -= E.value.rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.y -= E->get().rect.size.y / 2;
+ E.value.rect.position.y -= E.value.rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.y);
- full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.y);
+ full_descent = MAX(full_descent, E.value.rect.position.y + E.value.rect.size.y);
} else {
- switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
- E->get().rect.position.x = -sd->ascent;
+ E.value.rect.position.x = -sd->ascent;
} break;
case INLINE_ALIGN_TO_CENTER: {
- E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
+ E.value.rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case INLINE_ALIGN_TO_BASELINE: {
- E->get().rect.position.x = 0;
+ E.value.rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
- E->get().rect.position.x = sd->descent;
+ E.value.rect.position.x = sd->descent;
} break;
}
- switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
+ switch (E.value.inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
- E->get().rect.position.x -= E->get().rect.size.x;
+ E.value.rect.position.x -= E.value.rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
- E->get().rect.position.x -= E->get().rect.size.x / 2;
+ E.value.rect.position.x -= E.value.rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
- //NOP
+ // NOP
} break;
}
- full_ascent = MAX(full_ascent, -E->get().rect.position.x);
- full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
+ full_ascent = MAX(full_ascent, -E.value.rect.position.x);
+ full_descent = MAX(full_descent, E.value.rect.position.x + E.value.rect.size.x);
}
}
sd->ascent = full_ascent;
@@ -2992,59 +2991,70 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
}
bool TextServerFallback::shaped_text_is_ready(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, false);
MutexLock lock(sd->mutex);
return sd->valid;
}
-Vector<TextServer::Glyph> TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+const Glyph *TextServerFallback::shaped_text_get_glyphs(RID p_shaped) const {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, nullptr);
MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
}
- return sd->glyphs;
+ return sd->glyphs.ptr();
}
-Vector2i TextServerFallback::shaped_text_get_range(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector2i());
+int TextServerFallback::shaped_text_get_glyph_count(RID p_shaped) const {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, 0);
MutexLock lock(sd->mutex);
- return Vector2(sd->start, sd->end);
+ if (!sd->valid) {
+ const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
+ }
+ return sd->glyphs.size();
}
-Vector<TextServer::Glyph> TextServerFallback::shaped_text_sort_logical(RID p_shaped) {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
- ERR_FAIL_COND_V(!sd, Vector<TextServer::Glyph>());
+const Glyph *TextServerFallback::shaped_text_sort_logical(RID p_shaped) {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, nullptr);
MutexLock lock(sd->mutex);
if (!sd->valid) {
const_cast<TextServerFallback *>(this)->shaped_text_shape(p_shaped);
}
- return sd->glyphs; // Already in the logical order, return as is.
+ return sd->glyphs.ptr(); // Already in the logical order, return as is.
+}
+
+Vector2i TextServerFallback::shaped_text_get_range(RID p_shaped) const {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_V(!sd, Vector2i());
+
+ MutexLock lock(sd->mutex);
+ return Vector2(sd->start, sd->end);
}
Array TextServerFallback::shaped_text_get_objects(RID p_shaped) const {
Array ret;
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, ret);
MutexLock lock(sd->mutex);
- for (const Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
- ret.push_back(E->key());
+ for (const KeyValue<Variant, ShapedTextData::EmbeddedObject> &E : sd->objects) {
+ ret.push_back(E.key);
}
return ret;
}
Rect2 TextServerFallback::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Rect2());
MutexLock lock(sd->mutex);
@@ -3056,7 +3066,7 @@ Rect2 TextServerFallback::shaped_text_get_object_rect(RID p_shaped, Variant p_ke
}
Size2 TextServerFallback::shaped_text_get_size(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, Size2());
MutexLock lock(sd->mutex);
@@ -3070,8 +3080,8 @@ Size2 TextServerFallback::shaped_text_get_size(RID p_shaped) const {
}
}
-real_t TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+float TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -3081,8 +3091,8 @@ real_t TextServerFallback::shaped_text_get_ascent(RID p_shaped) const {
return sd->ascent;
}
-real_t TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+float TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -3092,8 +3102,8 @@ real_t TextServerFallback::shaped_text_get_descent(RID p_shaped) const {
return sd->descent;
}
-real_t TextServerFallback::shaped_text_get_width(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+float TextServerFallback::shaped_text_get_width(RID p_shaped) const {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -3103,8 +3113,8 @@ real_t TextServerFallback::shaped_text_get_width(RID p_shaped) const {
return sd->width;
}
-real_t TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+float TextServerFallback::shaped_text_get_underline_position(RID p_shaped) const {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -3115,8 +3125,8 @@ real_t TextServerFallback::shaped_text_get_underline_position(RID p_shaped) cons
return sd->upos;
}
-real_t TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) const {
- const ShapedTextData *sd = shaped_owner.getornull(p_shaped);
+float TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) const {
+ const ShapedTextData *sd = shaped_owner.get_or_null(p_shaped);
ERR_FAIL_COND_V(!sd, 0.f);
MutexLock lock(sd->mutex);
@@ -3127,16 +3137,9 @@ real_t TextServerFallback::shaped_text_get_underline_thickness(RID p_shaped) con
return sd->uthk;
}
-TextServer *TextServerFallback::create_func(Error &r_error, void *p_user_data) {
- r_error = OK;
- return memnew(TextServerFallback());
-}
-
-void TextServerFallback::register_server() {
- TextServerManager::register_create_function(interface_name, interface_features, create_func, nullptr);
-}
-
-TextServerFallback::TextServerFallback(){};
+TextServerFallback::TextServerFallback() {
+ _insert_feature_sets();
+};
TextServerFallback::~TextServerFallback() {
if (library != nullptr) {
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index fde75e7135..fb7de8f443 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -54,6 +54,8 @@
#include FT_BBOX_H
#endif
+#define OT_TAG(c1, c2, c3, c4) ((int32_t)((((uint32_t)(c1)&0xFF) << 24) | (((uint32_t)(c2)&0xFF) << 16) | (((uint32_t)(c3)&0xFF) << 8) | ((uint32_t)(c4)&0xFF)))
+
class TextServerFallback : public TextServer {
GDCLASS(TextServerFallback, TextServer);
_THREAD_SAFE_CLASS_
@@ -61,6 +63,10 @@ class TextServerFallback : public TextServer {
static String interface_name;
static uint32_t interface_features;
+ Map<StringName, int32_t> feature_sets;
+
+ void _insert_feature_sets();
+
// Font cache data.
#ifdef MODULE_FREETYPE_ENABLED
@@ -93,12 +99,12 @@ class TextServerFallback : public TextServer {
};
struct FontDataForSizeFallback {
- real_t ascent = 0.f;
- real_t descent = 0.f;
- real_t underline_position = 0.f;
- real_t underline_thickness = 0.f;
- real_t scale = 1.f;
- real_t oversampling = 1.f;
+ float ascent = 0.f;
+ float descent = 0.f;
+ float underline_position = 0.f;
+ float underline_thickness = 0.f;
+ float scale = 1.f;
+ float oversampling = 1.f;
int spacing_glyph = 0;
int spacing_space = 0;
@@ -134,7 +140,7 @@ class TextServerFallback : public TextServer {
bool force_autohinter = false;
TextServer::Hinting hinting = TextServer::HINTING_LIGHT;
Dictionary variation_coordinates;
- real_t oversampling = 0.f;
+ float oversampling = 0.f;
Map<Vector2i, FontDataForSizeFallback *> cache;
@@ -194,7 +200,7 @@ class TextServerFallback : public TextServer {
// Common data.
- real_t oversampling = 1.f;
+ float oversampling = 1.f;
mutable RID_PtrOwner<FontDataFallback> font_owner;
mutable RID_PtrOwner<ShapedTextData> shaped_owner;
@@ -205,20 +211,19 @@ protected:
void invalidate(ShapedTextData *p_shaped);
public:
- virtual bool has_feature(Feature p_feature) override;
+ virtual bool has_feature(Feature p_feature) const override;
virtual String get_name() const override;
+ virtual uint32_t get_features() const override;
virtual void free(RID p_rid) override;
virtual bool has(RID p_rid) override;
virtual bool load_support_data(const String &p_filename) override;
-#ifdef TOOLS_ENABLED
- virtual String get_support_data_filename() override { return ""; };
- virtual String get_support_data_info() override { return "Not supported"; };
- virtual bool save_support_data(const String &p_filename) override;
-#endif
+ virtual String get_support_data_filename() const override { return ""; };
+ virtual String get_support_data_info() const override { return "Not supported"; };
+ virtual bool save_support_data(const String &p_filename) const override;
- virtual bool is_locale_right_to_left(const String &p_locale) override;
+ virtual bool is_locale_right_to_left(const String &p_locale) const override;
virtual int32_t name_to_tag(const String &p_name) const override;
virtual String tag_to_name(int32_t p_tag) const override;
@@ -253,27 +258,27 @@ public:
virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override;
virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override;
- virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) override;
- virtual real_t font_get_oversampling(RID p_font_rid) const override;
+ virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override;
+ virtual float font_get_oversampling(RID p_font_rid) const override;
virtual Array font_get_size_cache_list(RID p_font_rid) const override;
virtual void font_clear_size_cache(RID p_font_rid) override;
virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override;
- virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) override;
- virtual real_t font_get_ascent(RID p_font_rid, int p_size) const override;
+ virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override;
+ virtual float font_get_ascent(RID p_font_rid, int p_size) const override;
- virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) override;
- virtual real_t font_get_descent(RID p_font_rid, int p_size) const override;
+ virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override;
+ virtual float font_get_descent(RID p_font_rid, int p_size) const override;
- virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) override;
- virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const override;
+ virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override;
+ virtual float font_get_underline_position(RID p_font_rid, int p_size) const override;
- virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) override;
- virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const override;
+ virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override;
+ virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override;
- virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) override;
- virtual real_t font_get_scale(RID p_font_rid, int p_size) const override;
+ virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override;
+ virtual float font_get_scale(RID p_font_rid, int p_size) const override;
virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override;
virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override;
@@ -307,7 +312,7 @@ public:
virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override;
virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override;
- virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const override;
+ virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override;
virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override;
virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override;
@@ -342,8 +347,8 @@ public:
virtual Dictionary font_supported_feature_list(RID p_font_rid) const override;
virtual Dictionary font_supported_variation_list(RID p_font_rid) const override;
- virtual real_t font_get_global_oversampling() const override;
- virtual void font_set_global_oversampling(real_t p_oversampling) override;
+ virtual float font_get_global_oversampling() const override;
+ virtual void font_set_global_oversampling(float p_oversampling) override;
/* Shaped text buffer interface */
@@ -354,7 +359,7 @@ public:
virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override;
virtual Direction shaped_text_get_direction(RID p_shaped) const override;
- virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) override;
+ virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override;
virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override;
virtual Orientation shaped_text_get_orientation(RID p_shaped) const override;
@@ -372,36 +377,37 @@ public:
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;
- virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
- virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) override;
+ virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override;
+ virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override;
virtual bool shaped_text_shape(RID p_shaped) override;
virtual bool shaped_text_update_breaks(RID p_shaped) override;
virtual bool shaped_text_update_justification_ops(RID p_shaped) override;
- virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) override;
- virtual TrimData shaped_text_get_trim_data(RID p_shaped) const override;
+ virtual int shaped_text_get_trim_pos(RID p_shaped) const override;
+ virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override;
+ virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override;
+
+ virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override;
virtual bool shaped_text_is_ready(RID p_shaped) const override;
- virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override;
+ virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override;
+ virtual int shaped_text_get_glyph_count(RID p_shaped) const override;
virtual Vector2i shaped_text_get_range(RID p_shaped) const override;
- virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) override;
-
virtual Array shaped_text_get_objects(RID p_shaped) const override;
virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override;
virtual Size2 shaped_text_get_size(RID p_shaped) const override;
- virtual real_t shaped_text_get_ascent(RID p_shaped) const override;
- virtual real_t shaped_text_get_descent(RID p_shaped) const override;
- virtual real_t shaped_text_get_width(RID p_shaped) const override;
- virtual real_t shaped_text_get_underline_position(RID p_shaped) const override;
- virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const override;
-
- static TextServer *create_func(Error &r_error, void *p_user_data);
- static void register_server();
+ virtual float shaped_text_get_ascent(RID p_shaped) const override;
+ virtual float shaped_text_get_descent(RID p_shaped) const override;
+ virtual float shaped_text_get_width(RID p_shaped) const override;
+ virtual float shaped_text_get_underline_position(RID p_shaped) const override;
+ virtual float shaped_text_get_underline_thickness(RID p_shaped) const override;
TextServerFallback();
~TextServerFallback();
diff --git a/modules/theora/doc_classes/VideoStreamTheora.xml b/modules/theora/doc_classes/VideoStreamTheora.xml
index e7bf9b202d..2dfcd27dff 100644
--- a/modules/theora/doc_classes/VideoStreamTheora.xml
+++ b/modules/theora/doc_classes/VideoStreamTheora.xml
@@ -24,6 +24,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 2f6faec8ec..8e80dfffca 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -108,7 +108,7 @@ void VideoStreamPlaybackTheora::video_write() {
Ref<Image> img = memnew(Image(size.x, size.y, 0, Image::FORMAT_RGBA8, frame_data)); //zero copy image creation
- texture->update(img); //zero copy send to visual server
+ texture->update(img); //zero copy send to rendering server
frames_pending = 1;
}
diff --git a/modules/upnp/doc_classes/UPNP.xml b/modules/upnp/doc_classes/UPNP.xml
index 5b1d9dbfd1..2cd0b8843a 100644
--- a/modules/upnp/doc_classes/UPNP.xml
+++ b/modules/upnp/doc_classes/UPNP.xml
@@ -16,6 +16,38 @@
[codeblock]
upnp.delete_port_mapping(port)
[/codeblock]
+ [b]Note:[/b] UPnP discovery blocks the current thread. To perform discovery without blocking the main thread, use [Thread]s like this:
+ [codeblock]
+ # Emitted when UPnP port mapping setup is completed (regardless of success or failure).
+ signal upnp_completed(error)
+
+ # Replace this with your own server port number between 1025 and 65535.
+ const SERVER_PORT = 3928
+ var thread = null
+
+ func _upnp_setup(server_port):
+ # UPNP queries take some time.
+ var upnp = UPNP.new()
+ var err = upnp.discover()
+
+ if err != OK:
+ push_error(str(err))
+ emit_signal("upnp_completed", err)
+ return
+
+ if upnp.get_gateway() and upnp.get_gateway().is_valid_gateway():
+ upnp.add_port_mapping(server_port, server_port, ProjectSettings.get_setting("application/config/name"), "UDP")
+ upnp.add_port_mapping(server_port, server_port, ProjectSettings.get_setting("application/config/name"), "TCP")
+ emit_signal("upnp_completed", OK)
+
+ func _ready():
+ thread = Thread.new()
+ thread.start(self, "_upnp_setup", SERVER_PORT)
+
+ func _exit_tree():
+ # Wait for thread finish here to handle game exit while the thread is running.
+ thread.wait_to_finish()
+ [/codeblock]
</description>
<tutorials>
</tutorials>
diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp
index 2b48e94604..54240e66fc 100644
--- a/modules/vhacd/register_types.cpp
+++ b/modules/vhacd/register_types.cpp
@@ -32,48 +32,55 @@
#include "scene/resources/mesh.h"
#include "thirdparty/vhacd/public/VHACD.h"
-static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, int p_max_convex_hulls = -1) {
- Vector<real_t> vertices;
- vertices.resize(p_faces.size() * 9);
- Vector<uint32_t> indices;
- indices.resize(p_faces.size() * 3);
-
- for (int i = 0; i < p_faces.size(); i++) {
- for (int j = 0; j < 3; j++) {
- vertices.write[i * 9 + j * 3 + 0] = p_faces[i].vertex[j].x;
- vertices.write[i * 9 + j * 3 + 1] = p_faces[i].vertex[j].y;
- vertices.write[i * 9 + j * 3 + 2] = p_faces[i].vertex[j].z;
- indices.write[i * 3 + j] = i * 3 + j;
- }
- }
-
+static Vector<Vector<Vector3>> convex_decompose(const real_t *p_vertices, int p_vertex_count, const uint32_t *p_triangles, int p_triangle_count, const Mesh::ConvexDecompositionSettings &p_settings, Vector<Vector<uint32_t>> *r_convex_indices) {
VHACD::IVHACD::Parameters params;
- if (p_max_convex_hulls > 0) {
- params.m_maxConvexHulls = p_max_convex_hulls;
- }
+ params.m_concavity = p_settings.max_concavity;
+ params.m_alpha = p_settings.symmetry_planes_clipping_bias;
+ params.m_beta = p_settings.revolution_axes_clipping_bias;
+ params.m_minVolumePerCH = p_settings.min_volume_per_convex_hull;
+ params.m_resolution = p_settings.resolution;
+ params.m_maxNumVerticesPerCH = p_settings.max_num_vertices_per_convex_hull;
+ params.m_planeDownsampling = p_settings.plane_downsampling;
+ params.m_convexhullDownsampling = p_settings.convexhull_downsampling;
+ params.m_pca = p_settings.normalize_mesh;
+ params.m_mode = p_settings.mode;
+ params.m_convexhullApproximation = p_settings.convexhull_approximation;
+ params.m_oclAcceleration = true;
+ params.m_maxConvexHulls = p_settings.max_convex_hulls;
+ params.m_projectHullVertices = p_settings.project_hull_vertices;
VHACD::IVHACD *decomposer = VHACD::CreateVHACD();
- decomposer->Compute(vertices.ptr(), vertices.size() / 3, indices.ptr(), indices.size() / 3, params);
+ decomposer->Compute(p_vertices, p_vertex_count, p_triangles, p_triangle_count, params);
int hull_count = decomposer->GetNConvexHulls();
- Vector<Vector<Face3>> ret;
+ Vector<Vector<Vector3>> ret;
+ ret.resize(hull_count);
+
+ if (r_convex_indices) {
+ r_convex_indices->resize(hull_count);
+ }
for (int i = 0; i < hull_count; i++) {
- Vector<Face3> triangles;
VHACD::IVHACD::ConvexHull hull;
decomposer->GetConvexHull(i, hull);
- triangles.resize(hull.m_nTriangles);
- for (uint32_t j = 0; j < hull.m_nTriangles; j++) {
- Face3 f;
+
+ Vector<Vector3> &points = ret.write[i];
+ points.resize(hull.m_nPoints);
+
+ Vector3 *w = points.ptrw();
+ for (uint32_t j = 0; j < hull.m_nPoints; ++j) {
for (int k = 0; k < 3; k++) {
- for (int l = 0; l < 3; l++) {
- f.vertex[k][l] = hull.m_points[hull.m_triangles[j * 3 + k] * 3 + l];
- }
+ w[j][k] = hull.m_points[j * 3 + k];
}
- triangles.write[j] = f;
}
- ret.push_back(triangles);
+
+ if (r_convex_indices) {
+ Vector<uint32_t> &indices = r_convex_indices->write[i];
+ indices.resize(hull.m_nTriangles * 3);
+
+ memcpy(indices.ptrw(), hull.m_triangles, hull.m_nTriangles * 3 * sizeof(uint32_t));
+ }
}
decomposer->Clean();
@@ -83,9 +90,9 @@ static Vector<Vector<Face3>> convex_decompose(const Vector<Face3> &p_faces, int
}
void register_vhacd_types() {
- Mesh::convex_composition_function = convex_decompose;
+ Mesh::convex_decomposition_function = convex_decompose;
}
void unregister_vhacd_types() {
- Mesh::convex_composition_function = nullptr;
+ Mesh::convex_decomposition_function = nullptr;
}
diff --git a/modules/visual_script/config.py b/modules/visual_script/config.py
index b15479797c..e8990c43c8 100644
--- a/modules/visual_script/config.py
+++ b/modules/visual_script/config.py
@@ -17,6 +17,7 @@ def get_doc_classes():
"VisualScriptConstant",
"VisualScriptConstructor",
"VisualScriptCustomNode",
+ "VisualScriptCustomNodes",
"VisualScriptDeconstruct",
"VisualScriptEditor",
"VisualScriptEmitSignal",
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 2327fc0009..be6bf00e50 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -9,7 +9,7 @@
You are most likely to use this class via the Visual Script editor or when writing plugins for it.
</description>
<tutorials>
- <link title="VisualScript tutorial index">https://docs.godotengine.org/en/latest/getting_started/scripting/visual_script/index.html</link>
+ <link title="VisualScript documentation index">https://docs.godotengine.org/en/latest/tutorials/scripting/visual_script/index.html</link>
</tutorials>
<methods>
<method name="add_custom_signal">
@@ -354,6 +354,4 @@
</description>
</signal>
</signals>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
index 4d07f878a2..ed5b814bb7 100644
--- a/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBasicTypeConstant.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="basic_type" type="int" setter="set_basic_type" getter="get_basic_type" enum="Variant.Type" default="0">
The type to get the constant from.
@@ -18,6 +16,4 @@
The name of the constant to return.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
index 55d0b392fa..942d92311b 100644
--- a/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
+++ b/modules/visual_script/doc_classes/VisualScriptBuiltinFunc.xml
@@ -9,8 +9,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="function" type="int" setter="set_func" getter="get_func" enum="VisualScriptBuiltinFunc.BuiltinFunc" default="0">
The function to be executed.
@@ -181,32 +179,34 @@
<constant name="TEXT_PRINTRAW" value="55" enum="BuiltinFunc">
Print the given string to the standard output, without adding a newline.
</constant>
- <constant name="VAR_TO_STR" value="56" enum="BuiltinFunc">
+ <constant name="TEXT_PRINT_VERBOSE" value="56" enum="BuiltinFunc">
+ </constant>
+ <constant name="VAR_TO_STR" value="57" enum="BuiltinFunc">
Serialize a [Variant] to a string.
</constant>
- <constant name="STR_TO_VAR" value="57" enum="BuiltinFunc">
+ <constant name="STR_TO_VAR" value="58" enum="BuiltinFunc">
Deserialize a [Variant] from a string serialized using [constant VAR_TO_STR].
</constant>
- <constant name="VAR_TO_BYTES" value="58" enum="BuiltinFunc">
+ <constant name="VAR_TO_BYTES" value="59" enum="BuiltinFunc">
Serialize a [Variant] to a [PackedByteArray].
</constant>
- <constant name="BYTES_TO_VAR" value="59" enum="BuiltinFunc">
+ <constant name="BYTES_TO_VAR" value="60" enum="BuiltinFunc">
Deserialize a [Variant] from a [PackedByteArray] serialized using [constant VAR_TO_BYTES].
</constant>
- <constant name="MATH_SMOOTHSTEP" value="60" enum="BuiltinFunc">
+ <constant name="MATH_SMOOTHSTEP" value="61" enum="BuiltinFunc">
Return a number smoothly interpolated between the first two inputs, based on the third input. Similar to [constant MATH_LERP], but interpolates faster at the beginning and slower at the end. Using Hermite interpolation formula:
[codeblock]
var t = clamp((weight - from) / (to - from), 0.0, 1.0)
return t * t * (3.0 - 2.0 * t)
[/codeblock]
</constant>
- <constant name="MATH_POSMOD" value="61" enum="BuiltinFunc">
+ <constant name="MATH_POSMOD" value="62" enum="BuiltinFunc">
</constant>
- <constant name="MATH_LERP_ANGLE" value="62" enum="BuiltinFunc">
+ <constant name="MATH_LERP_ANGLE" value="63" enum="BuiltinFunc">
</constant>
- <constant name="TEXT_ORD" value="63" enum="BuiltinFunc">
+ <constant name="TEXT_ORD" value="64" enum="BuiltinFunc">
</constant>
- <constant name="FUNC_MAX" value="64" enum="BuiltinFunc">
+ <constant name="FUNC_MAX" value="65" enum="BuiltinFunc">
Represents the size of the [enum BuiltinFunc] enum.
</constant>
</constants>
diff --git a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
index d6b96957f5..ae32500d2f 100644
--- a/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptClassConstant.xml
@@ -12,8 +12,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
The constant's parent class.
@@ -22,6 +20,4 @@
The constant to return. See the given class for its available constants.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptComment.xml b/modules/visual_script/doc_classes/VisualScriptComment.xml
index 02cec97b27..5024aae384 100644
--- a/modules/visual_script/doc_classes/VisualScriptComment.xml
+++ b/modules/visual_script/doc_classes/VisualScriptComment.xml
@@ -9,8 +9,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="description" type="String" setter="set_description" getter="get_description" default="&quot;&quot;">
The text inside the comment node.
@@ -22,6 +20,4 @@
The comment node's title.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptComposeArray.xml b/modules/visual_script/doc_classes/VisualScriptComposeArray.xml
index dec182abf6..ed065759c5 100644
--- a/modules/visual_script/doc_classes/VisualScriptComposeArray.xml
+++ b/modules/visual_script/doc_classes/VisualScriptComposeArray.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptCondition.xml b/modules/visual_script/doc_classes/VisualScriptCondition.xml
index a9981c1f57..a5dd8c7c1b 100644
--- a/modules/visual_script/doc_classes/VisualScriptCondition.xml
+++ b/modules/visual_script/doc_classes/VisualScriptCondition.xml
@@ -15,8 +15,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstant.xml b/modules/visual_script/doc_classes/VisualScriptConstant.xml
index 69676c4bba..388c2bddde 100644
--- a/modules/visual_script/doc_classes/VisualScriptConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptConstant.xml
@@ -12,8 +12,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="type" type="int" setter="set_constant_type" getter="get_constant_type" enum="Variant.Type" default="0">
The constant's type.
@@ -22,6 +20,4 @@
The constant's value.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptConstructor.xml b/modules/visual_script/doc_classes/VisualScriptConstructor.xml
index 4743594ec3..4a3d10aa8e 100644
--- a/modules/visual_script/doc_classes/VisualScriptConstructor.xml
+++ b/modules/visual_script/doc_classes/VisualScriptConstructor.xml
@@ -32,6 +32,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
index b574576856..2c6313c80a 100644
--- a/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptCustomNode.xml
@@ -131,7 +131,7 @@
The [code]inputs[/code] array contains the values of the input ports.
[code]outputs[/code] is an array whose indices should be set to the respective outputs.
The [code]start_mode[/code] is usually [constant START_MODE_BEGIN_SEQUENCE], unless you have used the [code]STEP_*[/code] constants.
- [code]working_mem[/code] is an array which can be used to persist information between runs of the custom node.
+ [code]working_mem[/code] is an array which can be used to persist information between runs of the custom node. The size needs to be predefined using [method _get_working_memory_size].
When returning, you can mask the returned value with one of the [code]STEP_*[/code] constants.
</description>
</method>
diff --git a/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml b/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml
new file mode 100644
index 0000000000..1681da7653
--- /dev/null
+++ b/modules/visual_script/doc_classes/VisualScriptCustomNodes.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="VisualScriptCustomNodes" inherits="Object" version="4.0">
+ <brief_description>
+ Manages custom nodes for the Visual Script editor.
+ </brief_description>
+ <description>
+ This singleton can be used to manage (i.e., add or remove) custom nodes for the Visual Script editor.
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="add_custom_node">
+ <return type="void" />
+ <argument index="0" name="name" type="String" />
+ <argument index="1" name="category" type="String" />
+ <argument index="2" name="script" type="Script" />
+ <description>
+ Add a custom Visual Script node to the editor. It'll be placed under "Custom Nodes" with the [code]category[/code] as the parameter.
+ </description>
+ </method>
+ <method name="remove_custom_node">
+ <return type="void" />
+ <argument index="0" name="name" type="String" />
+ <argument index="1" name="category" type="String" />
+ <description>
+ Remove a custom Visual Script node from the editor. Custom nodes already placed on scripts won't be removed.
+ </description>
+ </method>
+ </methods>
+ <signals>
+ <signal name="custom_nodes_updated">
+ <description>
+ Emitted when a custom Visual Script node is added or removed.
+ </description>
+ </signal>
+ </signals>
+</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
index 530c80530e..fd9a91c2a5 100644
--- a/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
+++ b/modules/visual_script/doc_classes/VisualScriptDeconstruct.xml
@@ -8,13 +8,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="type" type="int" setter="set_deconstruct_type" getter="get_deconstruct_type" enum="Variant.Type" default="0">
The type to deconstruct.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
index df3121d093..e102e02aa9 100644
--- a/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEmitSignal.xml
@@ -12,13 +12,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="signal" type="StringName" setter="set_signal" getter="get_signal" default="&amp;&quot;&quot;">
The signal to emit.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
index 8b7fd3a612..468cae852f 100644
--- a/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
+++ b/modules/visual_script/doc_classes/VisualScriptEngineSingleton.xml
@@ -8,13 +8,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="constant" type="String" setter="set_singleton" getter="get_singleton" default="&quot;&quot;">
The singleton's name.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptExpression.xml b/modules/visual_script/doc_classes/VisualScriptExpression.xml
index 223adbbb96..15e16a15f0 100644
--- a/modules/visual_script/doc_classes/VisualScriptExpression.xml
+++ b/modules/visual_script/doc_classes/VisualScriptExpression.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunction.xml b/modules/visual_script/doc_classes/VisualScriptFunction.xml
index 652418bd64..e0ca9eb280 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunction.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunction.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
index f0b666e57a..a98cb79106 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionCall.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
The script to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE].
diff --git a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
index 18c3826df8..0d7833446d 100644
--- a/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
+++ b/modules/visual_script/doc_classes/VisualScriptFunctionState.xml
@@ -32,6 +32,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
index 87fdfd4e53..c6b5b22590 100644
--- a/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptGlobalConstant.xml
@@ -8,13 +8,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="constant" type="int" setter="set_global_constant" getter="get_global_constant" default="0">
The constant to be used.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
index b348048298..78fd17c5fc 100644
--- a/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIndexGet.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
index d7fe7340ad..0e5e832c65 100644
--- a/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIndexSet.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptInputAction.xml b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
index d6fa111500..eb06d52314 100644
--- a/modules/visual_script/doc_classes/VisualScriptInputAction.xml
+++ b/modules/visual_script/doc_classes/VisualScriptInputAction.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="action" type="StringName" setter="set_action_name" getter="get_action_name" default="&amp;&quot;&quot;">
Name of the action.
diff --git a/modules/visual_script/doc_classes/VisualScriptIterator.xml b/modules/visual_script/doc_classes/VisualScriptIterator.xml
index 1d4ab4daa9..d8305728c6 100644
--- a/modules/visual_script/doc_classes/VisualScriptIterator.xml
+++ b/modules/visual_script/doc_classes/VisualScriptIterator.xml
@@ -15,8 +15,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptLists.xml b/modules/visual_script/doc_classes/VisualScriptLists.xml
index d5bff1341a..373e3c7191 100644
--- a/modules/visual_script/doc_classes/VisualScriptLists.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLists.xml
@@ -74,6 +74,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
index 185f0f1ffb..29dbddcdf4 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVar.xml
@@ -12,8 +12,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0">
The local variable's type.
@@ -22,6 +20,4 @@
The local variable's name.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
index 865f0153c9..96de8ebfdd 100644
--- a/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptLocalVarSet.xml
@@ -14,8 +14,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="type" type="int" setter="set_var_type" getter="get_var_type" enum="Variant.Type" default="0">
The local variable's type.
@@ -24,6 +22,4 @@
The local variable's name.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
index 18a1f030bc..f559083c80 100644
--- a/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
+++ b/modules/visual_script/doc_classes/VisualScriptMathConstant.xml
@@ -12,8 +12,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="constant" type="int" setter="set_math_constant" getter="get_math_constant" enum="VisualScriptMathConstant.MathConstant" default="0">
The math constant.
diff --git a/modules/visual_script/doc_classes/VisualScriptNode.xml b/modules/visual_script/doc_classes/VisualScriptNode.xml
index 23574a5ea8..d080d9eac1 100644
--- a/modules/visual_script/doc_classes/VisualScriptNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptNode.xml
@@ -44,6 +44,4 @@
</description>
</signal>
</signals>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptOperator.xml b/modules/visual_script/doc_classes/VisualScriptOperator.xml
index cbbefa7f71..73d28899f6 100644
--- a/modules/visual_script/doc_classes/VisualScriptOperator.xml
+++ b/modules/visual_script/doc_classes/VisualScriptOperator.xml
@@ -12,8 +12,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="operator" type="int" setter="set_operator" getter="get_operator" enum="Variant.Operator" default="6">
The operation to be performed. See [enum Variant.Operator] for available options.
@@ -22,6 +20,4 @@
The type of the values for this operation. See [enum Variant.Type] for available options.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptPreload.xml b/modules/visual_script/doc_classes/VisualScriptPreload.xml
index e11af6c805..e3d60c77bb 100644
--- a/modules/visual_script/doc_classes/VisualScriptPreload.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPreload.xml
@@ -12,13 +12,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="resource" type="Resource" setter="set_preload" getter="get_preload">
The [Resource] to load.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
index c1bf443ea3..e9f30cb605 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertyGet.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script">
The script to be used when [member set_mode] is set to [constant CALL_MODE_INSTANCE].
diff --git a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
index 75d6a63469..96261d2c5e 100644
--- a/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptPropertySet.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="assign_op" type="int" setter="set_assign_op" getter="get_assign_op" enum="VisualScriptPropertySet.AssignOp" default="0">
The additional operation to perform when assigning. See [enum AssignOp] for options.
diff --git a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
index ea891be05f..77e97a7219 100644
--- a/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
+++ b/modules/visual_script/doc_classes/VisualScriptResourcePath.xml
@@ -6,12 +6,8 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="path" type="String" setter="set_resource_path" getter="get_resource_path" default="&quot;&quot;">
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptReturn.xml b/modules/visual_script/doc_classes/VisualScriptReturn.xml
index 502628925d..2193f45dc8 100644
--- a/modules/visual_script/doc_classes/VisualScriptReturn.xml
+++ b/modules/visual_script/doc_classes/VisualScriptReturn.xml
@@ -13,8 +13,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="return_enabled" type="bool" setter="set_enable_return_value" getter="is_return_value_enabled" default="false">
If [code]true[/code], the [code]return[/code] input port is available.
@@ -23,6 +21,4 @@
The return value's data type.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
index ffe187a00e..ac672d9b3f 100644
--- a/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSceneNode.xml
@@ -12,13 +12,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="node_path" type="NodePath" setter="set_node_path" getter="get_node_path" default="NodePath(&quot;.&quot;)">
The node's path in the scene tree.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
index 8cddd02c77..fc383593c5 100644
--- a/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSceneTree.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelect.xml b/modules/visual_script/doc_classes/VisualScriptSelect.xml
index 1dbc066e32..d536e623f7 100644
--- a/modules/visual_script/doc_classes/VisualScriptSelect.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSelect.xml
@@ -14,13 +14,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="type" type="int" setter="set_typed" getter="get_typed" enum="Variant.Type" default="0">
The input variables' type.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSelf.xml b/modules/visual_script/doc_classes/VisualScriptSelf.xml
index bb24f158c1..3c2bd16302 100644
--- a/modules/visual_script/doc_classes/VisualScriptSelf.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSelf.xml
@@ -12,8 +12,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSequence.xml b/modules/visual_script/doc_classes/VisualScriptSequence.xml
index 664722574d..32dcbb9837 100644
--- a/modules/visual_script/doc_classes/VisualScriptSequence.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSequence.xml
@@ -14,13 +14,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="steps" type="int" setter="set_steps" getter="get_steps" default="1">
The number of steps in the sequence.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSubCall.xml b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
index f54887b09c..fdf0e24d3e 100644
--- a/modules/visual_script/doc_classes/VisualScriptSubCall.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSubCall.xml
@@ -8,8 +8,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptSwitch.xml b/modules/visual_script/doc_classes/VisualScriptSwitch.xml
index 74504948f0..8e176b56f0 100644
--- a/modules/visual_script/doc_classes/VisualScriptSwitch.xml
+++ b/modules/visual_script/doc_classes/VisualScriptSwitch.xml
@@ -17,8 +17,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
index 5dd1ad3421..ee8e2ad31e 100644
--- a/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
+++ b/modules/visual_script/doc_classes/VisualScriptTypeCast.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="base_script" type="String" setter="set_base_script" getter="get_base_script" default="&quot;&quot;">
The target script class to be converted to. If none, only the [member base_type] will be used.
@@ -18,6 +16,4 @@
The target type to be converted to.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
index df20ac53f2..e29765d616 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableGet.xml
@@ -12,13 +12,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&amp;&quot;&quot;">
The variable's name.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
index eb8ebbe338..b2cc70d62e 100644
--- a/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
+++ b/modules/visual_script/doc_classes/VisualScriptVariableSet.xml
@@ -13,13 +13,9 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="var_name" type="StringName" setter="set_variable" getter="get_variable" default="&amp;&quot;&quot;">
The variable's name.
</member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptWhile.xml b/modules/visual_script/doc_classes/VisualScriptWhile.xml
index f187957ad2..f090568608 100644
--- a/modules/visual_script/doc_classes/VisualScriptWhile.xml
+++ b/modules/visual_script/doc_classes/VisualScriptWhile.xml
@@ -14,8 +14,4 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/visual_script/doc_classes/VisualScriptYield.xml b/modules/visual_script/doc_classes/VisualScriptYield.xml
index b04ab7b014..bb7fd8bfb5 100644
--- a/modules/visual_script/doc_classes/VisualScriptYield.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYield.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="mode" type="int" setter="set_yield_mode" getter="get_yield_mode" enum="VisualScriptYield.YieldMode" default="1">
The mode to use for yielding. See [enum YieldMode] for available options.
diff --git a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
index c6c3188d08..ad6a7fb4e2 100644
--- a/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
+++ b/modules/visual_script/doc_classes/VisualScriptYieldSignal.xml
@@ -8,8 +8,6 @@
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
<member name="base_type" type="StringName" setter="set_base_type" getter="get_base_type" default="&amp;&quot;Object&quot;">
The base type to be used when [member call_mode] is set to [constant CALL_MODE_INSTANCE].
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
index 7fb9707fce..890861cf82 100644
--- a/modules/visual_script/register_types.cpp
+++ b/modules/visual_script/register_types.cpp
@@ -117,7 +117,7 @@ void register_visual_script_types() {
GDREGISTER_CLASS(VisualScriptCustomNodes);
ClassDB::set_current_api(ClassDB::API_CORE);
vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes);
- Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptEditor", VisualScriptCustomNodes::get_singleton()));
+ Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton()));
VisualScriptEditor::register_editor();
#endif
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index 4d5f3420b8..54d310e636 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -702,8 +702,8 @@ void VisualScript::rename_custom_signal(const StringName &p_name, const StringNa
}
void VisualScript::get_custom_signal_list(List<StringName> *r_custom_signals) const {
- for (const Map<StringName, Vector<Argument>>::Element *E = custom_signals.front(); E; E = E->next()) {
- r_custom_signals->push_back(E->key());
+ for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) {
+ r_custom_signals->push_back(E.key);
}
r_custom_signals->sort_custom<StringName::AlphCompare>();
@@ -848,13 +848,13 @@ bool VisualScript::has_script_signal(const StringName &p_signal) const {
}
void VisualScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
- for (const Map<StringName, Vector<Argument>>::Element *E = custom_signals.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) {
MethodInfo mi;
- mi.name = E->key();
- for (int i = 0; i < E->get().size(); i++) {
+ mi.name = E.key;
+ for (int i = 0; i < E.value.size(); i++) {
PropertyInfo arg;
- arg.type = E->get()[i].type;
- arg.name = E->get()[i].name;
+ arg.type = E.value[i].type;
+ arg.name = E.value[i].name;
mi.arguments.push_back(arg);
}
@@ -1056,13 +1056,13 @@ Dictionary VisualScript::_get_data() const {
d["variables"] = vars;
Array sigs;
- for (const Map<StringName, Vector<Argument>>::Element *E = custom_signals.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, Vector<Argument>> &E : custom_signals) {
Dictionary cs;
- cs["name"] = E->key();
+ cs["name"] = E.key;
Array args;
- for (int i = 0; i < E->get().size(); i++) {
- args.push_back(E->get()[i].name);
- args.push_back(E->get()[i].type);
+ for (int i = 0; i < E.value.size(); i++) {
+ args.push_back(E.value[i].name);
+ args.push_back(E.value[i].type);
}
cs["arguments"] = args;
@@ -2093,8 +2093,8 @@ VisualScriptInstance::~VisualScriptInstance() {
script->instances.erase(owner);
}
- for (Map<int, VisualScriptNodeInstance *>::Element *E = instances.front(); E; E = E->next()) {
- memdelete(E->get());
+ for (const KeyValue<int, VisualScriptNodeInstance *> &E : instances) {
+ memdelete(E.value);
}
}
@@ -2516,8 +2516,8 @@ Ref<VisualScriptNode> VisualScriptLanguage::create_node_from_name(const String &
}
void VisualScriptLanguage::get_registered_node_names(List<String> *r_names) {
- for (Map<String, VisualScriptNodeRegisterFunc>::Element *E = register_funcs.front(); E; E = E->next()) {
- r_names->push_back(E->key());
+ for (const KeyValue<String, VisualScriptNodeRegisterFunc> &E : register_funcs) {
+ r_names->push_back(E.key);
}
}
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index 2bd7220d15..7e01031128 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -94,6 +94,7 @@ const char *VisualScriptBuiltinFunc::func_name[VisualScriptBuiltinFunc::FUNC_MAX
"print",
"printerr",
"printraw",
+ "print_verbose",
"var2str",
"str2var",
"var2bytes",
@@ -129,6 +130,7 @@ bool VisualScriptBuiltinFunc::has_input_sequence_port() const {
case TEXT_PRINT:
case TEXT_PRINTERR:
case TEXT_PRINTRAW:
+ case TEXT_PRINT_VERBOSE:
case MATH_SEED:
return true;
default:
@@ -177,6 +179,7 @@ int VisualScriptBuiltinFunc::get_func_argument_count(BuiltinFunc p_func) {
case TEXT_PRINT:
case TEXT_PRINTERR:
case TEXT_PRINTRAW:
+ case TEXT_PRINT_VERBOSE:
case VAR_TO_STR:
case STR_TO_VAR:
case TYPE_EXISTS:
@@ -223,6 +226,7 @@ int VisualScriptBuiltinFunc::get_output_value_port_count() const {
case TEXT_PRINT:
case TEXT_PRINTERR:
case TEXT_PRINTRAW:
+ case TEXT_PRINT_VERBOSE:
case MATH_SEED:
return 0;
case MATH_RANDSEED:
@@ -424,7 +428,8 @@ PropertyInfo VisualScriptBuiltinFunc::get_input_value_port_info(int p_idx) const
case TEXT_STR:
case TEXT_PRINT:
case TEXT_PRINTERR:
- case TEXT_PRINTRAW: {
+ case TEXT_PRINTRAW:
+ case TEXT_PRINT_VERBOSE: {
return PropertyInfo(Variant::NIL, "value");
} break;
case STR_TO_VAR: {
@@ -572,6 +577,8 @@ PropertyInfo VisualScriptBuiltinFunc::get_output_value_port_info(int p_idx) cons
} break;
case TEXT_PRINTRAW: {
} break;
+ case TEXT_PRINT_VERBOSE: {
+ } break;
case VAR_TO_STR: {
t = Variant::STRING;
} break;
@@ -1020,6 +1027,10 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
OS::get_singleton()->print("%s", str.utf8().get_data());
} break;
+ case VisualScriptBuiltinFunc::TEXT_PRINT_VERBOSE: {
+ String str = *p_inputs[0];
+ print_verbose(str);
+ } break;
case VisualScriptBuiltinFunc::VAR_TO_STR: {
String vars;
VariantWriter::write_to_string(*p_inputs[0], vars);
@@ -1208,6 +1219,7 @@ void VisualScriptBuiltinFunc::_bind_methods() {
BIND_ENUM_CONSTANT(TEXT_PRINT);
BIND_ENUM_CONSTANT(TEXT_PRINTERR);
BIND_ENUM_CONSTANT(TEXT_PRINTRAW);
+ BIND_ENUM_CONSTANT(TEXT_PRINT_VERBOSE);
BIND_ENUM_CONSTANT(VAR_TO_STR);
BIND_ENUM_CONSTANT(STR_TO_VAR);
BIND_ENUM_CONSTANT(VAR_TO_BYTES);
@@ -1300,6 +1312,7 @@ void register_visual_script_builtin_func_node() {
VisualScriptLanguage::singleton->add_register_func("functions/built_in/print", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/printerr", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTERR>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/printraw", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINTRAW>);
+ VisualScriptLanguage::singleton->add_register_func("functions/built_in/print_verbose", create_builtin_func_node<VisualScriptBuiltinFunc::TEXT_PRINT_VERBOSE>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2str", create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_STR>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/str2var", create_builtin_func_node<VisualScriptBuiltinFunc::STR_TO_VAR>);
VisualScriptLanguage::singleton->add_register_func("functions/built_in/var2bytes", create_builtin_func_node<VisualScriptBuiltinFunc::VAR_TO_BYTES>);
diff --git a/modules/visual_script/visual_script_builtin_funcs.h b/modules/visual_script/visual_script_builtin_funcs.h
index 26abc1e479..f9eb7e983f 100644
--- a/modules/visual_script/visual_script_builtin_funcs.h
+++ b/modules/visual_script/visual_script_builtin_funcs.h
@@ -94,6 +94,7 @@ public:
TEXT_PRINT,
TEXT_PRINTERR,
TEXT_PRINTRAW,
+ TEXT_PRINT_VERBOSE,
VAR_TO_STR,
STR_TO_VAR,
VAR_TO_BYTES,
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index eee9e8f32b..d73b8d3ca0 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -2546,16 +2546,11 @@ void VisualScriptEditor::goto_line(int p_line, bool p_with_error) {
error_line = p_line;
}
- List<StringName> functions;
- script->get_function_list(&functions);
- for (const StringName &E : functions) {
- if (script->has_node(p_line)) {
- _update_graph();
- _update_members();
+ if (script->has_node(p_line)) {
+ _update_graph();
+ _update_members();
- call_deferred(SNAME("call_deferred"), "_center_on_node", E, p_line); //editor might be just created and size might not exist yet
- return;
- }
+ call_deferred(SNAME("call_deferred"), "_center_on_node", p_line); // The editor might be just created and size might not exist yet.
}
}
@@ -3592,6 +3587,11 @@ void VisualScriptEditor::_hide_timer() {
hint_text->hide();
}
+void VisualScriptEditor::_toggle_scripts_pressed() {
+ ScriptEditor::get_singleton()->toggle_scripts_panel();
+ update_toggle_scripts_button();
+}
+
void VisualScriptEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY: {
@@ -3606,6 +3606,8 @@ void VisualScriptEditor::_notification(int p_what) {
return;
}
+ update_toggle_scripts_button();
+
edit_variable_edit->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
edit_signal_edit->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
func_input_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
@@ -3630,17 +3632,17 @@ void VisualScriptEditor::_notification(int p_what) {
node_colors["constants"] = Color(0.94, 0.18, 0.49);
}
- for (Map<StringName, Color>::Element *E = node_colors.front(); E; E = E->next()) {
+ for (const KeyValue<StringName, Color> &E : node_colors) {
const Ref<StyleBoxFlat> sb = tm->get_stylebox(SNAME("frame"), SNAME("GraphNode"));
if (!sb.is_null()) {
Ref<StyleBoxFlat> frame_style = sb->duplicate();
// Adjust the border color to be close to the GraphNode's background color.
// This keeps the node's title area from being too distracting.
- Color color = dark_theme ? E->get().darkened(0.75) : E->get().lightened(0.75);
+ Color color = dark_theme ? E.value.darkened(0.75) : E.value.lightened(0.75);
color.a = 0.9;
frame_style->set_border_color(color);
- node_styles[E->key()] = frame_style;
+ node_styles[E.key] = frame_style;
}
}
@@ -3650,6 +3652,7 @@ void VisualScriptEditor::_notification(int p_what) {
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
+ update_toggle_scripts_button();
members_section->set_visible(is_visible_in_tree());
} break;
}
@@ -3810,15 +3813,15 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
}
- for (Map<int, Ref<VisualScriptNode>>::Element *E = clipboard->nodes.front(); E; E = E->next()) {
- Ref<VisualScriptNode> node = E->get()->duplicate();
+ for (KeyValue<int, Ref<VisualScriptNode>> &E : clipboard->nodes) {
+ Ref<VisualScriptNode> node = E.value->duplicate();
int new_id = idc++;
to_select.insert(new_id);
- remap[E->key()] = new_id;
+ remap[E.key] = new_id;
- Vector2 paste_pos = clipboard->nodes_positions[E->key()];
+ Vector2 paste_pos = clipboard->nodes_positions[E.key];
while (existing_positions.has(paste_pos.snapped(Vector2(2, 2)))) {
paste_pos += Vector2(20, 20) * EDSCALE;
@@ -3903,16 +3906,16 @@ void VisualScriptEditor::_menu_option(int p_what) {
// the user wants to connect the nodes.
int top_nd = -1;
Vector2 top;
- for (Map<int, Ref<VisualScriptNode>>::Element *E = nodes.front(); E; E = E->next()) {
- Ref<VisualScriptNode> nd = script->get_node(E->key());
+ for (const KeyValue<int, Ref<VisualScriptNode>> &E : nodes) {
+ Ref<VisualScriptNode> nd = script->get_node(E.key);
if (nd.is_valid() && nd->has_input_sequence_port()) {
if (top_nd < 0) {
- top_nd = E->key();
+ top_nd = E.key;
top = script->get_node_position(top_nd);
}
- Vector2 pos = script->get_node_position(E->key());
+ Vector2 pos = script->get_node_position(E.key);
if (top.y > pos.y) {
- top_nd = E->key();
+ top_nd = E.key;
top = pos;
}
}
@@ -4232,6 +4235,15 @@ void VisualScriptEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_h
void VisualScriptEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) {
}
+void VisualScriptEditor::update_toggle_scripts_button() {
+ if (is_layout_rtl()) {
+ toggle_scripts_button->set_icon(Control::get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Forward") : SNAME("Back"), SNAME("EditorIcons")));
+ } else {
+ toggle_scripts_button->set_icon(Control::get_theme_icon(ScriptEditor::get_singleton()->is_scripts_panel_toggled() ? SNAME("Back") : SNAME("Forward"), SNAME("EditorIcons")));
+ }
+ toggle_scripts_button->set_tooltip(vformat("%s (%s)", TTR("Toggle Scripts Panel"), ED_GET_SHORTCUT("script_editor/toggle_scripts_panel")->get_as_text()));
+}
+
void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("_move_node", &VisualScriptEditor::_move_node);
ClassDB::bind_method("_update_graph", &VisualScriptEditor::_update_graph, DEFVAL(-1));
@@ -4250,8 +4262,6 @@ void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members);
ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search);
-
- ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &VisualScriptEditor::add_syntax_highlighter);
}
VisualScriptEditor::VisualScriptEditor() {
@@ -4333,6 +4343,16 @@ VisualScriptEditor::VisualScriptEditor() {
graph->hide();
graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed));
+ status_bar = memnew(HBoxContainer);
+ add_child(status_bar);
+ status_bar->set_h_size_flags(SIZE_EXPAND_FILL);
+ status_bar->set_custom_minimum_size(Size2(0, 24 * EDSCALE));
+
+ toggle_scripts_button = memnew(Button);
+ toggle_scripts_button->set_flat(true);
+ toggle_scripts_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_toggle_scripts_pressed));
+ status_bar->add_child(toggle_scripts_button);
+
/// Add Buttons to Top Bar/Zoom bar.
HBoxContainer *graph_hbc = graph->get_zoom_hbox();
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index ab32aae7aa..19f5aabac9 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -93,6 +93,8 @@ class VisualScriptEditor : public ScriptEditorBase {
ConfirmationDialog *function_create_dialog;
GraphEdit *graph;
+ HBoxContainer *status_bar;
+ Button *toggle_scripts_button;
VisualScriptEditorSignalEdit *signal_editor;
@@ -281,6 +283,8 @@ class VisualScriptEditor : public ScriptEditorBase {
void _member_rmb_selected(const Vector2 &p_pos);
void _member_option(int p_option);
+ void _toggle_scripts_pressed();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -330,6 +334,8 @@ public:
static void free_clipboard();
+ void update_toggle_scripts_button() override;
+
VisualScriptEditor();
~VisualScriptEditor();
};
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 6ba5ad4fd6..205918a5f0 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -1010,7 +1010,7 @@ PropertyInfo VisualScriptPropertySet::get_input_value_port_info(int p_idx) const
if (index != StringName()) {
detail_prop_name += "." + String(index);
}
- PropertyInfo pinfo = PropertyInfo(E.type, detail_prop_name, PROPERTY_HINT_TYPE_STRING, E.hint_string);
+ PropertyInfo pinfo = PropertyInfo(E.type, detail_prop_name, E.hint, E.hint_string);
_adjust_input_index(pinfo);
return pinfo;
}
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index cded1e587c..c62de64a85 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -121,7 +121,7 @@ public:
ret = STEP_EXIT_FUNCTION_BIT;
break; //return the yield
case VisualScriptYield::YIELD_FRAME:
- state->connect_to_signal(tree, "idle_frame", Array());
+ state->connect_to_signal(tree, "process_frame", Array());
break;
case VisualScriptYield::YIELD_PHYSICS_FRAME:
state->connect_to_signal(tree, "physics_frame", Array());
diff --git a/modules/vorbis/SCsub b/modules/vorbis/SCsub
index bc31fff066..322314487f 100644
--- a/modules/vorbis/SCsub
+++ b/modules/vorbis/SCsub
@@ -3,9 +3,6 @@
Import("env")
Import("env_modules")
-# Only kept to build the thirdparty library used by the theora and webm
-# modules. We now use stb_vorbis for AudioStreamOGGVorbis.
-
env_vorbis = env_modules.Clone()
# Thirdparty source files
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
new file mode 100644
index 0000000000..e4a80c339f
--- /dev/null
+++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp
@@ -0,0 +1,435 @@
+/*************************************************************************/
+/* audio_stream_ogg_vorbis.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "audio_stream_ogg_vorbis.h"
+
+#include "core/io/file_access.h"
+#include "core/variant/typed_array.h"
+#include "thirdparty/libogg/ogg/ogg.h"
+
+int AudioStreamPlaybackOGGVorbis::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+ ERR_FAIL_COND_V(!ready, 0);
+ ERR_FAIL_COND_V(!active, 0);
+
+ int todo = p_frames;
+
+ int start_buffer = 0;
+
+ int frames_mixed_this_step = p_frames;
+
+ while (todo && active) {
+ AudioFrame *buffer = p_buffer;
+ if (start_buffer > 0) {
+ buffer = buffer + start_buffer;
+ }
+ int mixed = _mix_frames_vorbis(buffer, todo);
+ if (mixed < 0) {
+ return 0;
+ }
+ todo -= mixed;
+ frames_mixed += mixed;
+ start_buffer += mixed;
+ if (!have_packets_left) {
+ //end of file!
+ bool is_not_empty = mixed > 0 || vorbis_stream->get_length() > 0;
+ if (vorbis_stream->loop && is_not_empty) {
+ //loop
+
+ seek(vorbis_stream->loop_offset);
+ loops++;
+ // we still have buffer to fill, start from this element in the next iteration.
+ start_buffer = p_frames - todo;
+ } else {
+ frames_mixed_this_step = p_frames - todo;
+ for (int i = p_frames - todo; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0, 0);
+ }
+ active = false;
+ todo = 0;
+ }
+ }
+ }
+ return frames_mixed_this_step;
+}
+
+int AudioStreamPlaybackOGGVorbis::_mix_frames_vorbis(AudioFrame *p_buffer, int p_frames) {
+ ERR_FAIL_COND_V(!ready, 0);
+ if (!have_samples_left) {
+ ogg_packet *packet = nullptr;
+ int err;
+
+ if (!vorbis_data_playback->next_ogg_packet(&packet)) {
+ have_packets_left = false;
+ WARN_PRINT("ran out of packets in stream");
+ return -1;
+ }
+
+ ERR_FAIL_COND_V_MSG((err = vorbis_synthesis(&block, packet)), 0, "Error during vorbis synthesis " + itos(err));
+ ERR_FAIL_COND_V_MSG((err = vorbis_synthesis_blockin(&dsp_state, &block)), 0, "Error during vorbis block processing " + itos(err));
+
+ have_packets_left = !packet->e_o_s;
+ }
+
+ float **pcm; // Accessed with pcm[channel_idx][sample_idx].
+
+ int frames = vorbis_synthesis_pcmout(&dsp_state, &pcm);
+ if (frames > p_frames) {
+ frames = p_frames;
+ have_samples_left = true;
+ } else {
+ have_samples_left = false;
+ }
+
+ if (info.channels > 1) {
+ for (int frame = 0; frame < frames; frame++) {
+ p_buffer[frame].l = pcm[0][frame];
+ p_buffer[frame].r = pcm[0][frame];
+ }
+ } else {
+ for (int frame = 0; frame < frames; frame++) {
+ p_buffer[frame].l = pcm[0][frame];
+ p_buffer[frame].r = pcm[0][frame];
+ }
+ }
+ vorbis_synthesis_read(&dsp_state, frames);
+ return frames;
+}
+
+float AudioStreamPlaybackOGGVorbis::get_stream_sampling_rate() {
+ return vorbis_data->get_sampling_rate();
+}
+
+bool AudioStreamPlaybackOGGVorbis::_alloc_vorbis() {
+ vorbis_info_init(&info);
+ info_is_allocated = true;
+ vorbis_comment_init(&comment);
+ comment_is_allocated = true;
+
+ ERR_FAIL_COND_V(vorbis_data.is_null(), false);
+ vorbis_data_playback = vorbis_data->instance_playback();
+
+ ogg_packet *packet;
+ int err;
+
+ for (int i = 0; i < 3; i++) {
+ if (!vorbis_data_playback->next_ogg_packet(&packet)) {
+ WARN_PRINT("Not enough packets to parse header");
+ return false;
+ }
+
+ err = vorbis_synthesis_headerin(&info, &comment, packet);
+ ERR_FAIL_COND_V_MSG(err != 0, false, "Error parsing header");
+ }
+
+ err = vorbis_synthesis_init(&dsp_state, &info);
+ ERR_FAIL_COND_V_MSG(err != 0, false, "Error initializing dsp state");
+ dsp_state_is_allocated = true;
+
+ err = vorbis_block_init(&dsp_state, &block);
+ ERR_FAIL_COND_V_MSG(err != 0, false, "Error initializing block");
+ block_is_allocated = true;
+
+ ready = true;
+
+ return true;
+}
+
+void AudioStreamPlaybackOGGVorbis::start(float p_from_pos) {
+ ERR_FAIL_COND(!ready);
+ active = true;
+ seek(p_from_pos);
+ loops = 0;
+ _begin_resample();
+}
+
+void AudioStreamPlaybackOGGVorbis::stop() {
+ active = false;
+}
+
+bool AudioStreamPlaybackOGGVorbis::is_playing() const {
+ return active;
+}
+
+int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
+ return loops;
+}
+
+float AudioStreamPlaybackOGGVorbis::get_playback_position() const {
+ return float(frames_mixed) / vorbis_data->get_sampling_rate();
+}
+
+void AudioStreamPlaybackOGGVorbis::seek(float p_time) {
+ ERR_FAIL_COND(!ready);
+ ERR_FAIL_COND(vorbis_stream.is_null());
+ if (!active) {
+ return;
+ }
+
+ vorbis_synthesis_restart(&dsp_state);
+
+ if (p_time >= vorbis_stream->get_length()) {
+ p_time = 0;
+ }
+ frames_mixed = uint32_t(vorbis_data->get_sampling_rate() * p_time);
+
+ const int64_t desired_sample = p_time * get_stream_sampling_rate();
+
+ if (!vorbis_data_playback->seek_page(desired_sample)) {
+ WARN_PRINT("seek failed");
+ return;
+ }
+
+ ogg_packet *packet;
+ if (!vorbis_data_playback->next_ogg_packet(&packet)) {
+ WARN_PRINT_ONCE("seeking beyond limits");
+ return;
+ }
+
+ // The granule position of the page we're seeking through.
+ int64_t granule_pos = 0;
+
+ int headers_remaining = 0;
+ int samples_in_page = 0;
+ int err;
+ while (true) {
+ if (vorbis_synthesis_idheader(packet)) {
+ headers_remaining = 3;
+ }
+ if (!headers_remaining) {
+ ERR_FAIL_COND_MSG((err = vorbis_synthesis(&block, packet)), "Error during vorbis synthesis " + itos(err));
+ ERR_FAIL_COND_MSG((err = vorbis_synthesis_blockin(&dsp_state, &block)), "Error during vorbis block processing " + itos(err));
+
+ int samples_out = vorbis_synthesis_pcmout(&dsp_state, nullptr);
+ ERR_FAIL_COND_MSG((err = vorbis_synthesis_read(&dsp_state, samples_out)), "Error during vorbis read updating " + itos(err));
+
+ samples_in_page += samples_out;
+
+ } else {
+ headers_remaining--;
+ }
+ if (packet->granulepos != -1 && headers_remaining == 0) {
+ // This indicates the end of the page.
+ granule_pos = packet->granulepos;
+ break;
+ }
+ if (packet->e_o_s) {
+ break;
+ }
+ if (!vorbis_data_playback->next_ogg_packet(&packet)) {
+ // We should get an e_o_s flag before this happens.
+ WARN_PRINT("Vorbis file ended without warning.");
+ break;
+ }
+ }
+
+ int64_t samples_to_burn = samples_in_page - (granule_pos - desired_sample);
+
+ if (samples_to_burn > samples_in_page) {
+ WARN_PRINT("Burning more samples than we have in this page. Check seek algorithm.");
+ } else if (samples_to_burn < 0) {
+ WARN_PRINT("Burning negative samples doesn't make sense. Check seek algorithm.");
+ }
+
+ // Seek again, this time we'll burn a specific number of samples instead of all of them.
+ if (!vorbis_data_playback->seek_page(desired_sample)) {
+ WARN_PRINT("seek failed");
+ return;
+ }
+
+ if (!vorbis_data_playback->next_ogg_packet(&packet)) {
+ WARN_PRINT_ONCE("seeking beyond limits");
+ return;
+ }
+ vorbis_synthesis_restart(&dsp_state);
+
+ while (true) {
+ if (vorbis_synthesis_idheader(packet)) {
+ headers_remaining = 3;
+ }
+ if (!headers_remaining) {
+ ERR_FAIL_COND_MSG((err = vorbis_synthesis(&block, packet)), "Error during vorbis synthesis " + itos(err));
+ ERR_FAIL_COND_MSG((err = vorbis_synthesis_blockin(&dsp_state, &block)), "Error during vorbis block processing " + itos(err));
+
+ int samples_out = vorbis_synthesis_pcmout(&dsp_state, nullptr);
+ int read_samples = samples_to_burn > samples_out ? samples_out : samples_to_burn;
+ ERR_FAIL_COND_MSG((err = vorbis_synthesis_read(&dsp_state, samples_out)), "Error during vorbis read updating " + itos(err));
+ samples_to_burn -= read_samples;
+
+ if (samples_to_burn <= 0) {
+ break;
+ }
+ } else {
+ headers_remaining--;
+ }
+ if (packet->granulepos != -1 && headers_remaining == 0) {
+ // This indicates the end of the page.
+ break;
+ }
+ if (packet->e_o_s) {
+ break;
+ }
+ if (!vorbis_data_playback->next_ogg_packet(&packet)) {
+ // We should get an e_o_s flag before this happens.
+ WARN_PRINT("Vorbis file ended without warning.");
+ break;
+ }
+ }
+}
+
+AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
+ if (block_is_allocated) {
+ vorbis_block_clear(&block);
+ }
+ if (dsp_state_is_allocated) {
+ vorbis_dsp_clear(&dsp_state);
+ }
+ if (comment_is_allocated) {
+ vorbis_comment_clear(&comment);
+ }
+ if (info_is_allocated) {
+ vorbis_info_clear(&info);
+ }
+}
+
+Ref<AudioStreamPlayback> AudioStreamOGGVorbis::instance_playback() {
+ Ref<AudioStreamPlaybackOGGVorbis> ovs;
+
+ ERR_FAIL_COND_V(packet_sequence.is_null(), nullptr);
+
+ ovs.instantiate();
+ ovs->vorbis_stream = Ref<AudioStreamOGGVorbis>(this);
+ ovs->vorbis_data = packet_sequence;
+ ovs->frames_mixed = 0;
+ ovs->active = false;
+ ovs->loops = 0;
+ if (ovs->_alloc_vorbis()) {
+ return ovs;
+ }
+ // Failed to allocate data structures.
+ return nullptr;
+}
+
+String AudioStreamOGGVorbis::get_stream_name() const {
+ return ""; //return stream_name;
+}
+
+void AudioStreamOGGVorbis::maybe_update_info() {
+ ERR_FAIL_COND(packet_sequence.is_null());
+
+ vorbis_info info;
+ vorbis_comment comment;
+ int err;
+
+ vorbis_info_init(&info);
+ vorbis_comment_init(&comment);
+
+ int packet_count = 0;
+ Ref<OGGPacketSequencePlayback> packet_sequence_playback = packet_sequence->instance_playback();
+
+ for (int i = 0; i < 3; i++) {
+ ogg_packet *packet;
+ if (!packet_sequence_playback->next_ogg_packet(&packet)) {
+ WARN_PRINT("Failed to get header packet");
+ break;
+ }
+ if (i == 0) {
+ packet->b_o_s = 1;
+ }
+
+ if (i == 0) {
+ ERR_FAIL_COND(!vorbis_synthesis_idheader(packet));
+ }
+
+ err = vorbis_synthesis_headerin(&info, &comment, packet);
+ ERR_FAIL_COND_MSG(err != 0, "Error parsing header packet " + itos(i) + ": " + itos(err));
+
+ packet_count++;
+ }
+
+ packet_sequence->set_sampling_rate(info.rate);
+
+ vorbis_comment_clear(&comment);
+ vorbis_info_clear(&info);
+}
+
+void AudioStreamOGGVorbis::set_packet_sequence(Ref<OGGPacketSequence> p_packet_sequence) {
+ packet_sequence = p_packet_sequence;
+ if (packet_sequence.is_valid()) {
+ maybe_update_info();
+ }
+}
+
+Ref<OGGPacketSequence> AudioStreamOGGVorbis::get_packet_sequence() const {
+ return packet_sequence;
+}
+
+void AudioStreamOGGVorbis::set_loop(bool p_enable) {
+ loop = p_enable;
+}
+
+bool AudioStreamOGGVorbis::has_loop() const {
+ return loop;
+}
+
+void AudioStreamOGGVorbis::set_loop_offset(float p_seconds) {
+ loop_offset = p_seconds;
+}
+
+float AudioStreamOGGVorbis::get_loop_offset() const {
+ return loop_offset;
+}
+
+float AudioStreamOGGVorbis::get_length() const {
+ ERR_FAIL_COND_V(packet_sequence.is_null(), 0);
+ return packet_sequence->get_length();
+}
+
+bool AudioStreamOGGVorbis::is_monophonic() const {
+ return false;
+}
+
+void AudioStreamOGGVorbis::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_packet_sequence", "packet_sequence"), &AudioStreamOGGVorbis::set_packet_sequence);
+ ClassDB::bind_method(D_METHOD("get_packet_sequence"), &AudioStreamOGGVorbis::get_packet_sequence);
+
+ ClassDB::bind_method(D_METHOD("set_loop", "enable"), &AudioStreamOGGVorbis::set_loop);
+ ClassDB::bind_method(D_METHOD("has_loop"), &AudioStreamOGGVorbis::has_loop);
+
+ ClassDB::bind_method(D_METHOD("set_loop_offset", "seconds"), &AudioStreamOGGVorbis::set_loop_offset);
+ ClassDB::bind_method(D_METHOD("get_loop_offset"), &AudioStreamOGGVorbis::get_loop_offset);
+
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "packet_sequence", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), "set_packet_sequence", "get_packet_sequence");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "loop"), "set_loop", "has_loop");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "loop_offset"), "set_loop_offset", "get_loop_offset");
+}
+
+AudioStreamOGGVorbis::AudioStreamOGGVorbis() {}
+
+AudioStreamOGGVorbis::~AudioStreamOGGVorbis() {}
diff --git a/modules/stb_vorbis/audio_stream_ogg_vorbis.h b/modules/vorbis/audio_stream_ogg_vorbis.h
index 1311c4ce7a..59a1318a6b 100644
--- a/modules/stb_vorbis/audio_stream_ogg_vorbis.h
+++ b/modules/vorbis/audio_stream_ogg_vorbis.h
@@ -28,29 +28,49 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef AUDIO_STREAM_STB_VORBIS_H
-#define AUDIO_STREAM_STB_VORBIS_H
+#ifndef AUDIO_STREAM_LIBVORBIS_H
+#define AUDIO_STREAM_LIBVORBIS_H
-#include "core/io/resource_loader.h"
+#include "core/variant/variant.h"
+#include "modules/ogg/ogg_packet_sequence.h"
#include "servers/audio/audio_stream.h"
-
-#include "thirdparty/misc/stb_vorbis.h"
+#include "thirdparty/libvorbis/vorbis/codec.h"
class AudioStreamOGGVorbis;
class AudioStreamPlaybackOGGVorbis : public AudioStreamPlaybackResampled {
GDCLASS(AudioStreamPlaybackOGGVorbis, AudioStreamPlaybackResampled);
- stb_vorbis *ogg_stream = nullptr;
- stb_vorbis_alloc ogg_alloc;
uint32_t frames_mixed = 0;
bool active = false;
int loops = 0;
+ vorbis_info info;
+ vorbis_comment comment;
+ vorbis_dsp_state dsp_state;
+ vorbis_block block;
+
+ bool info_is_allocated = false;
+ bool comment_is_allocated = false;
+ bool dsp_state_is_allocated = false;
+ bool block_is_allocated = false;
+
+ bool ready = false;
+
+ bool have_samples_left = false;
+ bool have_packets_left = false;
+
friend class AudioStreamOGGVorbis;
+ Ref<OGGPacketSequence> vorbis_data;
+ Ref<OGGPacketSequencePlayback> vorbis_data_playback;
Ref<AudioStreamOGGVorbis> vorbis_stream;
+ int _mix_frames_vorbis(AudioFrame *p_buffer, int p_frames);
+
+ // Allocates vorbis data structures. Returns true upon success, false on failure.
+ bool _alloc_vorbis();
+
protected:
virtual int _mix_internal(AudioFrame *p_buffer, int p_frames) override;
virtual float get_stream_sampling_rate() override;
@@ -72,20 +92,20 @@ public:
class AudioStreamOGGVorbis : public AudioStream {
GDCLASS(AudioStreamOGGVorbis, AudioStream);
OBJ_SAVE_TYPE(AudioStream); // Saves derived classes with common type so they can be interchanged.
- RES_BASE_EXTENSION("oggstr");
+ RES_BASE_EXTENSION("oggvorbisstr");
friend class AudioStreamPlaybackOGGVorbis;
- void *data = nullptr;
- uint32_t data_len = 0;
-
- int decode_mem_size = 0;
- float sample_rate = 1.0;
int channels = 1;
float length = 0.0;
bool loop = false;
float loop_offset = 0.0;
- void clear_data();
+
+ // Performs a seek to the beginning of the stream, should not be called during playback!
+ // Also causes allocation and deallocation.
+ void maybe_update_info();
+
+ Ref<OGGPacketSequence> packet_sequence;
protected:
static void _bind_methods();
@@ -100,8 +120,8 @@ public:
virtual Ref<AudioStreamPlayback> instance_playback() override;
virtual String get_stream_name() const override;
- void set_data(const Vector<uint8_t> &p_data);
- Vector<uint8_t> get_data() const;
+ void set_packet_sequence(Ref<OGGPacketSequence> p_packet_sequence);
+ Ref<OGGPacketSequence> get_packet_sequence() const;
virtual float get_length() const override; //if supported, otherwise return 0
@@ -111,4 +131,4 @@ public:
virtual ~AudioStreamOGGVorbis();
};
-#endif
+#endif // AUDIO_STREAM_LIBVORBIS_H
diff --git a/modules/vorbis/config.py b/modules/vorbis/config.py
index 8a384e3066..978eccb29f 100644
--- a/modules/vorbis/config.py
+++ b/modules/vorbis/config.py
@@ -4,3 +4,14 @@ def can_build(env, platform):
def configure(env):
pass
+
+
+def get_doc_classes():
+ return [
+ "AudioStreamOGGVorbis",
+ "AudioStreamPlaybackOGGVorbis",
+ ]
+
+
+def get_doc_path():
+ return "doc_classes"
diff --git a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml b/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml
index 94fdff5d43..4cd278fe83 100644
--- a/modules/stb_vorbis/doc_classes/AudioStreamOGGVorbis.xml
+++ b/modules/vorbis/doc_classes/AudioStreamOGGVorbis.xml
@@ -1,26 +1,20 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="AudioStreamOGGVorbis" inherits="AudioStream" version="4.0">
<brief_description>
- OGG Vorbis audio stream driver.
</brief_description>
<description>
- OGG Vorbis audio stream driver.
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
<members>
- <member name="data" type="PackedByteArray" setter="set_data" getter="get_data" default="PackedByteArray()">
- Contains the audio data in bytes.
- </member>
<member name="loop" type="bool" setter="set_loop" getter="has_loop" default="false">
If [code]true[/code], the stream will automatically loop when it reaches the end.
</member>
<member name="loop_offset" type="float" setter="set_loop_offset" getter="get_loop_offset" default="0.0">
Time in seconds at which the stream starts after being looped.
</member>
+ <member name="packet_sequence" type="OGGPacketSequence" setter="set_packet_sequence" getter="get_packet_sequence">
+ Contains the raw OGG data for this stream.
+ </member>
</members>
- <constants>
- </constants>
</class>
diff --git a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml b/modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml
index b88f5e7e1e..05c70d88da 100644
--- a/modules/gdnative/doc_classes/MultiplayerPeerGDNative.xml
+++ b/modules/vorbis/doc_classes/AudioStreamPlaybackOGGVorbis.xml
@@ -1,13 +1,9 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="MultiplayerPeerGDNative" inherits="MultiplayerPeer" version="4.0">
+<class name="AudioStreamPlaybackOGGVorbis" inherits="AudioStreamPlaybackResampled" version="4.0">
<brief_description>
</brief_description>
<description>
</description>
<tutorials>
</tutorials>
- <methods>
- </methods>
- <constants>
- </constants>
</class>
diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp
index d3e77ea629..de3f41afdd 100644
--- a/modules/vorbis/register_types.cpp
+++ b/modules/vorbis/register_types.cpp
@@ -30,8 +30,19 @@
#include "register_types.h"
-// Dummy module as libvorbis is needed by other modules (theora ...)
+#include "audio_stream_ogg_vorbis.h"
+#include "resource_importer_ogg_vorbis.h"
-void register_vorbis_types() {}
+void register_vorbis_types() {
+#ifdef TOOLS_ENABLED
+ if (Engine::get_singleton()->is_editor_hint()) {
+ Ref<ResourceImporterOGGVorbis> ogg_vorbis_importer;
+ ogg_vorbis_importer.instantiate();
+ ResourceFormatImporter::get_singleton()->add_importer(ogg_vorbis_importer);
+ }
+#endif
+ GDREGISTER_CLASS(AudioStreamOGGVorbis);
+ GDREGISTER_CLASS(AudioStreamPlaybackOGGVorbis);
+}
void unregister_vorbis_types() {}
diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp
index 85de698efd..33ee6cf359 100644
--- a/modules/stb_vorbis/resource_importer_ogg_vorbis.cpp
+++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp
@@ -30,16 +30,19 @@
#include "resource_importer_ogg_vorbis.h"
+#include "audio_stream_ogg_vorbis.h"
#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
#include "scene/resources/texture.h"
+#include "thirdparty/libogg/ogg/ogg.h"
+#include "thirdparty/libvorbis/vorbis/codec.h"
String ResourceImporterOGGVorbis::get_importer_name() const {
- return "ogg_vorbis";
+ return "oggvorbisstr";
}
String ResourceImporterOGGVorbis::get_visible_name() const {
- return "OGGVorbis";
+ return "oggvorbisstr";
}
void ResourceImporterOGGVorbis::get_recognized_extensions(List<String> *p_extensions) const {
@@ -47,7 +50,7 @@ void ResourceImporterOGGVorbis::get_recognized_extensions(List<String> *p_extens
}
String ResourceImporterOGGVorbis::get_save_extension() const {
- return "oggstr";
+ return "oggvorbisstr";
}
String ResourceImporterOGGVorbis::get_resource_type() const {
@@ -81,23 +84,106 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin
uint64_t len = f->get_length();
- Vector<uint8_t> data;
- data.resize(len);
- uint8_t *w = data.ptrw();
+ Vector<uint8_t> file_data;
+ file_data.resize(len);
+ uint8_t *w = file_data.ptrw();
f->get_buffer(w, len);
memdelete(f);
- Ref<AudioStreamOGGVorbis> ogg_stream;
- ogg_stream.instantiate();
-
- ogg_stream->set_data(data);
- ERR_FAIL_COND_V(!ogg_stream->get_data().size(), ERR_FILE_CORRUPT);
- ogg_stream->set_loop(loop);
- ogg_stream->set_loop_offset(loop_offset);
-
- return ResourceSaver::save(p_save_path + ".oggstr", ogg_stream);
+ Ref<AudioStreamOGGVorbis> ogg_vorbis_stream;
+ ogg_vorbis_stream.instantiate();
+
+ Ref<OGGPacketSequence> ogg_packet_sequence;
+ ogg_packet_sequence.instantiate();
+
+ ogg_stream_state stream_state;
+ ogg_sync_state sync_state;
+ ogg_page page;
+ ogg_packet packet;
+ bool initialized_stream = false;
+
+ ogg_sync_init(&sync_state);
+ int err;
+ size_t cursor = 0;
+ size_t packet_count = 0;
+ bool done = false;
+ while (!done) {
+ ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err));
+ while (ogg_sync_pageout(&sync_state, &page) != 1) {
+ if (cursor >= len) {
+ done = true;
+ break;
+ }
+ ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err));
+ char *sync_buf = ogg_sync_buffer(&sync_state, OGG_SYNC_BUFFER_SIZE);
+ ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err));
+ ERR_FAIL_COND_V(cursor > len, Error::ERR_INVALID_DATA);
+ size_t copy_size = len - cursor;
+ if (copy_size > OGG_SYNC_BUFFER_SIZE) {
+ copy_size = OGG_SYNC_BUFFER_SIZE;
+ }
+ memcpy(sync_buf, &file_data[cursor], copy_size);
+ ogg_sync_wrote(&sync_state, copy_size);
+ cursor += copy_size;
+ ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err));
+ }
+ if (done) {
+ break;
+ }
+ ERR_FAIL_COND_V_MSG((err = ogg_sync_check(&sync_state)), Error::ERR_INVALID_DATA, "Ogg sync error " + itos(err));
+
+ // Have a page now.
+ if (!initialized_stream) {
+ ogg_stream_init(&stream_state, ogg_page_serialno(&page));
+ ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Error::ERR_INVALID_DATA, "Ogg stream error " + itos(err));
+ initialized_stream = true;
+ }
+ ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Error::ERR_INVALID_DATA, "Ogg stream error " + itos(err));
+ ogg_stream_pagein(&stream_state, &page);
+ ERR_FAIL_COND_V_MSG((err = ogg_stream_check(&stream_state)), Error::ERR_INVALID_DATA, "Ogg stream error " + itos(err));
+ int desync_iters = 0;
+
+ Vector<Vector<uint8_t>> packet_data;
+ int64_t granule_pos = 0;
+
+ while (true) {
+ err = ogg_stream_packetout(&stream_state, &packet);
+ if (err == -1) {
+ // According to the docs this is usually recoverable, but don't sit here spinning forever.
+ desync_iters++;
+ ERR_FAIL_COND_V_MSG(desync_iters > 100, Error::ERR_INVALID_DATA, "Packet sync issue during ogg import");
+ continue;
+ } else if (err == 0) {
+ // Not enough data to fully reconstruct a packet. Go on to the next page.
+ break;
+ }
+ if (packet_count == 0 && vorbis_synthesis_idheader(&packet) == 0) {
+ WARN_PRINT("Found a non-vorbis-header packet in a header position");
+ // Clearly this logical stream is not a vorbis stream, so destroy it and try again with the next page.
+ ogg_stream_destroy(&stream_state);
+ initialized_stream = false;
+ break;
+ }
+ granule_pos = packet.granulepos;
+
+ PackedByteArray data;
+ data.resize(packet.bytes);
+ memcpy(data.ptrw(), packet.packet, packet.bytes);
+ packet_data.push_back(data);
+ packet_count++;
+ }
+ if (initialized_stream) {
+ ogg_packet_sequence->push_page(granule_pos, packet_data);
+ }
+ }
+
+ ogg_vorbis_stream->set_packet_sequence(ogg_packet_sequence);
+ ogg_vorbis_stream->set_loop(loop);
+ ogg_vorbis_stream->set_loop_offset(loop_offset);
+
+ return ResourceSaver::save(p_save_path + ".oggvorbisstr", ogg_vorbis_stream);
}
ResourceImporterOGGVorbis::ResourceImporterOGGVorbis() {
diff --git a/modules/stb_vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h
index 60fe3381fb..acdc1a3d38 100644
--- a/modules/stb_vorbis/resource_importer_ogg_vorbis.h
+++ b/modules/vorbis/resource_importer_ogg_vorbis.h
@@ -28,25 +28,29 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef RESOURCEIMPORTEROGGVORBIS_H
-#define RESOURCEIMPORTEROGGVORBIS_H
+#ifndef RESOURCE_IMPORTER_OGG_VORBIS_H
+#define RESOURCE_IMPORTER_OGG_VORBIS_H
-#include "audio_stream_ogg_vorbis.h"
#include "core/io/resource_importer.h"
class ResourceImporterOGGVorbis : public ResourceImporter {
GDCLASS(ResourceImporterOGGVorbis, ResourceImporter);
+ enum {
+ OGG_SYNC_BUFFER_SIZE = 8192,
+ };
+
+private:
+ // virtual int get_samples_in_packet(Vector<uint8_t> p_packet) = 0;
+
public:
- virtual String get_importer_name() const override;
- virtual String get_visible_name() const override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
virtual String get_save_extension() const override;
virtual String get_resource_type() const override;
-
+ virtual String get_importer_name() const override;
+ virtual String get_visible_name() const override;
virtual int get_preset_count() const override;
virtual String get_preset_name(int p_idx) const override;
-
virtual void get_import_options(List<ImportOption> *r_options, int p_preset = 0) const override;
virtual bool get_option_visibility(const String &p_option, const Map<StringName, Variant> &p_options) const override;
@@ -55,4 +59,4 @@ public:
ResourceImporterOGGVorbis();
};
-#endif // RESOURCEIMPORTEROGGVORBIS_H
+#endif // RESOURCE_IMPORTER_OGG_VORBIS_H
diff --git a/modules/webm/doc_classes/VideoStreamWebm.xml b/modules/webm/doc_classes/VideoStreamWebm.xml
index 3b9acfd873..e04d02d6ab 100644
--- a/modules/webm/doc_classes/VideoStreamWebm.xml
+++ b/modules/webm/doc_classes/VideoStreamWebm.xml
@@ -25,6 +25,4 @@
</description>
</method>
</methods>
- <constants>
- </constants>
</class>
diff --git a/modules/webm/video_stream_webm.cpp b/modules/webm/video_stream_webm.cpp
index 12e0f5bd25..187a27b6c2 100644
--- a/modules/webm/video_stream_webm.cpp
+++ b/modules/webm/video_stream_webm.cpp
@@ -311,7 +311,7 @@ void VideoStreamPlaybackWebm::update(float p_delta) {
if (converted) {
Ref<Image> img = memnew(Image(image.w, image.h, 0, Image::FORMAT_RGBA8, frame_data));
- texture->update(img); //Zero copy send to visual server
+ texture->update(img); //Zero copy send to rendering server
video_frame_done = true;
}
}
diff --git a/modules/webrtc/SCsub b/modules/webrtc/SCsub
index 31b8a73bf2..e6b9959840 100644
--- a/modules/webrtc/SCsub
+++ b/modules/webrtc/SCsub
@@ -4,11 +4,6 @@ Import("env")
Import("env_modules")
env_webrtc = env_modules.Clone()
-use_gdnative = env_webrtc["module_gdnative_enabled"]
-
-if use_gdnative: # GDNative is retained in Javascript for export compatibility
- env_webrtc.Append(CPPDEFINES=["WEBRTC_GDNATIVE_ENABLED"])
- env_webrtc.Prepend(CPPPATH=["#modules/gdnative/include/"])
if env["platform"] == "javascript":
# Our JavaScript/C++ interface.
diff --git a/modules/webrtc/config.py b/modules/webrtc/config.py
index 3281415f38..4ad918833a 100644
--- a/modules/webrtc/config.py
+++ b/modules/webrtc/config.py
@@ -11,6 +11,8 @@ def get_doc_classes():
"WebRTCPeerConnection",
"WebRTCDataChannel",
"WebRTCMultiplayerPeer",
+ "WebRTCPeerConnectionExtension",
+ "WebRTCDataChannelExtension",
]
diff --git a/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
new file mode 100644
index 0000000000..746fabd6e5
--- /dev/null
+++ b/modules/webrtc/doc_classes/WebRTCDataChannelExtension.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="WebRTCDataChannelExtension" inherits="WebRTCDataChannel" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_close" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_available_packet_count" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_buffered_amount" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_id" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_label" qualifiers="virtual const">
+ <return type="String" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_max_packet_life_time" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_max_packet_size" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_max_retransmits" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_packet" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="r_buffer" type="const uint8_t **" />
+ <argument index="1" name="r_buffer_size" type="int32_t*" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_protocol" qualifiers="virtual const">
+ <return type="String" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_ready_state" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_write_mode" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_is_negotiated" qualifiers="virtual const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_is_ordered" qualifiers="virtual const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
+ <method name="_poll" qualifiers="virtual">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_put_packet" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="p_buffer" type="const uint8_t*" />
+ <argument index="1" name="p_buffer_size" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_write_mode" qualifiers="virtual">
+ <return type="void" />
+ <argument index="0" name="p_write_mode" type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_was_string_packet" qualifiers="virtual const">
+ <return type="bool" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
index 43a8e20ef7..a8360a4d45 100644
--- a/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
+++ b/modules/webrtc/doc_classes/WebRTCMultiplayerPeer.xml
@@ -7,6 +7,7 @@
This class constructs a full mesh of [WebRTCPeerConnection] (one connection for each peer) that can be used as a [member MultiplayerAPI.multiplayer_peer].
You can add each [WebRTCPeerConnection] via [method add_peer] or remove them via [method remove_peer]. Peers must be added in [constant WebRTCPeerConnection.STATE_NEW] state to allow it to create the appropriate channels. This class will not create offers nor set descriptions, it will only poll them, and notify connections and disconnections.
[signal MultiplayerPeer.connection_succeeded] and [signal MultiplayerPeer.server_disconnected] will not be emitted unless [code]server_compatibility[/code] is [code]true[/code] in [method initialize]. Beside that data transfer works like in a [MultiplayerPeer].
+ [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
</tutorials>
@@ -67,10 +68,4 @@
</description>
</method>
</methods>
- <members>
- <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" />
- <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" />
- </members>
- <constants>
- </constants>
</class>
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
index f6f360503f..618fe14137 100644
--- a/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnection.xml
@@ -26,7 +26,8 @@
<method name="close">
<return type="void" />
<description>
- Close the peer connection and all data channels associated with it. Note, you cannot reuse this object for a new connection unless you call [method initialize].
+ Close the peer connection and all data channels associated with it.
+ [b]Note:[/b] You cannot reuse this object for a new connection unless you call [method initialize].
</description>
</method>
<method name="create_data_channel">
diff --git a/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
new file mode 100644
index 0000000000..d296fcd6e7
--- /dev/null
+++ b/modules/webrtc/doc_classes/WebRTCPeerConnectionExtension.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<class name="WebRTCPeerConnectionExtension" inherits="WebRTCPeerConnection" version="4.0">
+ <brief_description>
+ </brief_description>
+ <description>
+ </description>
+ <tutorials>
+ </tutorials>
+ <methods>
+ <method name="_add_ice_candidate" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="p_sdp_mid_name" type="String" />
+ <argument index="1" name="p_sdp_mline_index" type="int" />
+ <argument index="2" name="p_sdp_name" type="String" />
+ <description>
+ </description>
+ </method>
+ <method name="_close" qualifiers="virtual">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ <method name="_create_data_channel" qualifiers="virtual">
+ <return type="Object" />
+ <argument index="0" name="p_label" type="String" />
+ <argument index="1" name="p_config" type="Dictionary" />
+ <description>
+ </description>
+ </method>
+ <method name="_create_offer" qualifiers="virtual">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_get_connection_state" qualifiers="virtual const">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_initialize" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="p_config" type="Dictionary" />
+ <description>
+ </description>
+ </method>
+ <method name="_poll" qualifiers="virtual">
+ <return type="int" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_local_description" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="p_type" type="String" />
+ <argument index="1" name="p_sdp" type="String" />
+ <description>
+ </description>
+ </method>
+ <method name="_set_remote_description" qualifiers="virtual">
+ <return type="int" />
+ <argument index="0" name="p_type" type="String" />
+ <argument index="1" name="p_sdp" type="String" />
+ <description>
+ </description>
+ </method>
+ <method name="make_default">
+ <return type="void" />
+ <description>
+ </description>
+ </method>
+ </methods>
+</class>
diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp
index 63ecc03a4c..8110e4a048 100644
--- a/modules/webrtc/register_types.cpp
+++ b/modules/webrtc/register_types.cpp
@@ -31,17 +31,11 @@
#include "register_types.h"
#include "core/config/project_settings.h"
#include "webrtc_data_channel.h"
+#include "webrtc_multiplayer_peer.h"
#include "webrtc_peer_connection.h"
-#ifdef JAVASCRIPT_ENABLED
-#include "emscripten.h"
-#include "webrtc_peer_connection_js.h"
-#endif
-#ifdef WEBRTC_GDNATIVE_ENABLED
-#include "webrtc_data_channel_gdnative.h"
-#include "webrtc_peer_connection_gdnative.h"
-#endif
-#include "webrtc_multiplayer_peer.h"
+#include "webrtc_data_channel_extension.h"
+#include "webrtc_peer_connection_extension.h"
void register_webrtc_types() {
#define _SET_HINT(NAME, _VAL_, _MAX_) \
@@ -50,18 +44,12 @@ void register_webrtc_types() {
_SET_HINT(WRTC_IN_BUF, 64, 4096);
-#ifdef JAVASCRIPT_ENABLED
- WebRTCPeerConnectionJS::make_default();
-#elif defined(WEBRTC_GDNATIVE_ENABLED)
- WebRTCPeerConnectionGDNative::make_default();
-#endif
-
ClassDB::register_custom_instance_class<WebRTCPeerConnection>();
-#ifdef WEBRTC_GDNATIVE_ENABLED
- GDREGISTER_CLASS(WebRTCPeerConnectionGDNative);
- GDREGISTER_CLASS(WebRTCDataChannelGDNative);
-#endif
+ GDREGISTER_CLASS(WebRTCPeerConnectionExtension);
+
GDREGISTER_VIRTUAL_CLASS(WebRTCDataChannel);
+ GDREGISTER_CLASS(WebRTCDataChannelExtension);
+
GDREGISTER_CLASS(WebRTCMultiplayerPeer);
}
diff --git a/modules/webrtc/webrtc_data_channel_extension.cpp b/modules/webrtc/webrtc_data_channel_extension.cpp
new file mode 100644
index 0000000000..ae346f6d8e
--- /dev/null
+++ b/modules/webrtc/webrtc_data_channel_extension.cpp
@@ -0,0 +1,215 @@
+/*************************************************************************/
+/* webrtc_data_channel_extension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "webrtc_data_channel_extension.h"
+
+void WebRTCDataChannelExtension::_bind_methods() {
+ ADD_PROPERTY_DEFAULT("write_mode", WRITE_MODE_BINARY);
+
+ GDVIRTUAL_BIND(_get_packet, "r_buffer", "r_buffer_size");
+ GDVIRTUAL_BIND(_put_packet, "p_buffer", "p_buffer_size");
+ GDVIRTUAL_BIND(_get_available_packet_count);
+ GDVIRTUAL_BIND(_get_max_packet_size);
+
+ GDVIRTUAL_BIND(_poll);
+ GDVIRTUAL_BIND(_close);
+
+ GDVIRTUAL_BIND(_set_write_mode, "p_write_mode");
+ GDVIRTUAL_BIND(_get_write_mode);
+
+ GDVIRTUAL_BIND(_was_string_packet);
+ GDVIRTUAL_BIND(_get_ready_state);
+ GDVIRTUAL_BIND(_get_label);
+ GDVIRTUAL_BIND(_is_ordered);
+ GDVIRTUAL_BIND(_get_id);
+ GDVIRTUAL_BIND(_get_max_packet_life_time);
+ GDVIRTUAL_BIND(_get_max_retransmits);
+ GDVIRTUAL_BIND(_get_protocol);
+ GDVIRTUAL_BIND(_is_negotiated);
+ GDVIRTUAL_BIND(_get_buffered_amount);
+}
+
+int WebRTCDataChannelExtension::get_available_packet_count() const {
+ int count;
+ if (GDVIRTUAL_CALL(_get_available_packet_count, count)) {
+ return count;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_available_packet_count is unimplemented!");
+ return -1;
+}
+
+Error WebRTCDataChannelExtension::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
+ int err;
+ if (GDVIRTUAL_CALL(_get_packet, r_buffer, &r_buffer_size, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_packet_native is unimplemented!");
+ return FAILED;
+}
+
+Error WebRTCDataChannelExtension::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
+ int err;
+ if (GDVIRTUAL_CALL(_put_packet, p_buffer, p_buffer_size, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_put_packet_native is unimplemented!");
+ return FAILED;
+}
+
+int WebRTCDataChannelExtension::get_max_packet_size() const {
+ int size;
+ if (GDVIRTUAL_CALL(_get_max_packet_size, size)) {
+ return size;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_packet_size is unimplemented!");
+ return 0;
+}
+
+Error WebRTCDataChannelExtension::poll() {
+ int err;
+ if (GDVIRTUAL_CALL(_poll, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_poll is unimplemented!");
+ return ERR_UNCONFIGURED;
+}
+
+void WebRTCDataChannelExtension::close() {
+ if (GDVIRTUAL_CALL(_close)) {
+ return;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_close is unimplemented!");
+}
+
+void WebRTCDataChannelExtension::set_write_mode(WriteMode p_mode) {
+ if (GDVIRTUAL_CALL(_set_write_mode, p_mode)) {
+ return;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_set_write_mode is unimplemented!");
+}
+
+WebRTCDataChannel::WriteMode WebRTCDataChannelExtension::get_write_mode() const {
+ int mode;
+ if (GDVIRTUAL_CALL(_get_write_mode, mode)) {
+ return (WriteMode)mode;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_write_mode is unimplemented!");
+ return WRITE_MODE_BINARY;
+}
+
+bool WebRTCDataChannelExtension::was_string_packet() const {
+ bool was_string;
+ if (GDVIRTUAL_CALL(_was_string_packet, was_string)) {
+ return was_string;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_was_string_packet is unimplemented!");
+ return false;
+}
+
+WebRTCDataChannel::ChannelState WebRTCDataChannelExtension::get_ready_state() const {
+ int state;
+ if (GDVIRTUAL_CALL(_get_ready_state, state)) {
+ return (ChannelState)state;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_ready_state is unimplemented!");
+ return STATE_CLOSED;
+}
+
+String WebRTCDataChannelExtension::get_label() const {
+ String label;
+ if (GDVIRTUAL_CALL(_get_label, label)) {
+ return label;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_label is unimplemented!");
+ return label;
+}
+
+bool WebRTCDataChannelExtension::is_ordered() const {
+ bool ordered;
+ if (GDVIRTUAL_CALL(_is_ordered, ordered)) {
+ return ordered;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_is_ordered is unimplemented!");
+ return false;
+}
+
+int WebRTCDataChannelExtension::get_id() const {
+ int id;
+ if (GDVIRTUAL_CALL(_get_id, id)) {
+ return id;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_id is unimplemented!");
+ return -1;
+}
+
+int WebRTCDataChannelExtension::get_max_packet_life_time() const {
+ int lifetime;
+ if (GDVIRTUAL_CALL(_get_max_packet_life_time, lifetime)) {
+ return lifetime;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_packet_life_time is unimplemented!");
+ return -1;
+}
+
+int WebRTCDataChannelExtension::get_max_retransmits() const {
+ int retransmits;
+ if (GDVIRTUAL_CALL(_get_max_retransmits, retransmits)) {
+ return retransmits;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_max_retransmits is unimplemented!");
+ return -1;
+}
+
+String WebRTCDataChannelExtension::get_protocol() const {
+ String protocol;
+ if (GDVIRTUAL_CALL(_get_protocol, protocol)) {
+ return protocol;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_protocol is unimplemented!");
+ return protocol;
+}
+
+bool WebRTCDataChannelExtension::is_negotiated() const {
+ bool negotiated;
+ if (GDVIRTUAL_CALL(_is_negotiated, negotiated)) {
+ return negotiated;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_is_negotiated is unimplemented!");
+ return false;
+}
+
+int WebRTCDataChannelExtension::get_buffered_amount() const {
+ int amount;
+ if (GDVIRTUAL_CALL(_get_buffered_amount, amount)) {
+ return amount;
+ }
+ WARN_PRINT_ONCE("WebRTCDataChannelExtension::_get_buffered_amount is unimplemented!");
+ return -1;
+}
diff --git a/modules/webrtc/webrtc_data_channel_gdnative.h b/modules/webrtc/webrtc_data_channel_extension.h
index 5c80edd48c..eec96b4c62 100644
--- a/modules/webrtc/webrtc_data_channel_gdnative.h
+++ b/modules/webrtc/webrtc_data_channel_extension.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* webrtc_data_channel_gdnative.h */
+/* webrtc_data_channel_extension.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,26 +28,22 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef WEBRTC_DATA_CHANNEL_GDNATIVE_H
-#define WEBRTC_DATA_CHANNEL_GDNATIVE_H
+#ifndef WEBRTC_DATA_CHANNEL_EXTENSION_H
+#define WEBRTC_DATA_CHANNEL_EXTENSION_H
-#ifdef WEBRTC_GDNATIVE_ENABLED
-
-#include "modules/gdnative/include/net/godot_net.h"
#include "webrtc_data_channel.h"
-class WebRTCDataChannelGDNative : public WebRTCDataChannel {
- GDCLASS(WebRTCDataChannelGDNative, WebRTCDataChannel);
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
+#include "core/variant/native_ptr.h"
+
+class WebRTCDataChannelExtension : public WebRTCDataChannel {
+ GDCLASS(WebRTCDataChannelExtension, WebRTCDataChannel);
protected:
static void _bind_methods();
-private:
- const godot_net_webrtc_data_channel *interface;
-
public:
- void set_native_webrtc_data_channel(const godot_net_webrtc_data_channel *p_impl);
-
virtual void set_write_mode(WriteMode mode) override;
virtual WriteMode get_write_mode() const override;
virtual bool was_string_packet() const override;
@@ -72,10 +68,31 @@ public:
virtual int get_max_packet_size() const override;
- WebRTCDataChannelGDNative();
- ~WebRTCDataChannelGDNative();
-};
+ /** GDExtension **/
+ GDVIRTUAL0RC(int, _get_available_packet_count);
+ GDVIRTUAL2R(int, _get_packet, GDNativeConstPtr<const uint8_t *>, GDNativePtr<int>);
+ GDVIRTUAL2R(int, _put_packet, GDNativeConstPtr<const uint8_t>, int);
+ GDVIRTUAL0RC(int, _get_max_packet_size);
-#endif // WEBRTC_GDNATIVE_ENABLED
+ GDVIRTUAL0R(int, _poll);
+ GDVIRTUAL0(_close);
+
+ GDVIRTUAL1(_set_write_mode, int);
+ GDVIRTUAL0RC(int, _get_write_mode);
+
+ GDVIRTUAL0RC(bool, _was_string_packet);
+
+ GDVIRTUAL0RC(int, _get_ready_state);
+ GDVIRTUAL0RC(String, _get_label);
+ GDVIRTUAL0RC(bool, _is_ordered);
+ GDVIRTUAL0RC(int, _get_id);
+ GDVIRTUAL0RC(int, _get_max_packet_life_time);
+ GDVIRTUAL0RC(int, _get_max_retransmits);
+ GDVIRTUAL0RC(String, _get_protocol);
+ GDVIRTUAL0RC(bool, _is_negotiated);
+ GDVIRTUAL0RC(int, _get_buffered_amount);
+
+ WebRTCDataChannelExtension() {}
+};
-#endif // WEBRTC_DATA_CHANNEL_GDNATIVE_H
+#endif // WEBRTC_DATA_CHANNEL_EXTENSION_H
diff --git a/modules/webrtc/webrtc_data_channel_gdnative.cpp b/modules/webrtc/webrtc_data_channel_gdnative.cpp
deleted file mode 100644
index 10a3367557..0000000000
--- a/modules/webrtc/webrtc_data_channel_gdnative.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*************************************************************************/
-/* webrtc_data_channel_gdnative.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#ifdef WEBRTC_GDNATIVE_ENABLED
-
-#include "webrtc_data_channel_gdnative.h"
-
-#include "core/io/resource_loader.h"
-#include "modules/gdnative/nativescript/nativescript.h"
-
-void WebRTCDataChannelGDNative::_bind_methods() {
- ADD_PROPERTY_DEFAULT("write_mode", WRITE_MODE_BINARY);
-}
-
-WebRTCDataChannelGDNative::WebRTCDataChannelGDNative() {
- interface = nullptr;
-}
-
-WebRTCDataChannelGDNative::~WebRTCDataChannelGDNative() {
-}
-
-Error WebRTCDataChannelGDNative::poll() {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->poll(interface->data);
-}
-
-void WebRTCDataChannelGDNative::close() {
- ERR_FAIL_COND(interface == nullptr);
- interface->close(interface->data);
-}
-
-void WebRTCDataChannelGDNative::set_write_mode(WriteMode p_mode) {
- ERR_FAIL_COND(interface == nullptr);
- interface->set_write_mode(interface->data, p_mode);
-}
-
-WebRTCDataChannel::WriteMode WebRTCDataChannelGDNative::get_write_mode() const {
- ERR_FAIL_COND_V(interface == nullptr, WRITE_MODE_BINARY);
- return (WriteMode)interface->get_write_mode(interface->data);
-}
-
-bool WebRTCDataChannelGDNative::was_string_packet() const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->was_string_packet(interface->data);
-}
-
-WebRTCDataChannel::ChannelState WebRTCDataChannelGDNative::get_ready_state() const {
- ERR_FAIL_COND_V(interface == nullptr, STATE_CLOSED);
- return (ChannelState)interface->get_ready_state(interface->data);
-}
-
-String WebRTCDataChannelGDNative::get_label() const {
- ERR_FAIL_COND_V(interface == nullptr, "");
- return String(interface->get_label(interface->data));
-}
-
-bool WebRTCDataChannelGDNative::is_ordered() const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->is_ordered(interface->data);
-}
-
-int WebRTCDataChannelGDNative::get_id() const {
- ERR_FAIL_COND_V(interface == nullptr, -1);
- return interface->get_id(interface->data);
-}
-
-int WebRTCDataChannelGDNative::get_max_packet_life_time() const {
- ERR_FAIL_COND_V(interface == nullptr, -1);
- return interface->get_max_packet_life_time(interface->data);
-}
-
-int WebRTCDataChannelGDNative::get_max_retransmits() const {
- ERR_FAIL_COND_V(interface == nullptr, -1);
- return interface->get_max_retransmits(interface->data);
-}
-
-String WebRTCDataChannelGDNative::get_protocol() const {
- ERR_FAIL_COND_V(interface == nullptr, "");
- return String(interface->get_protocol(interface->data));
-}
-
-bool WebRTCDataChannelGDNative::is_negotiated() const {
- ERR_FAIL_COND_V(interface == nullptr, false);
- return interface->is_negotiated(interface->data);
-}
-
-int WebRTCDataChannelGDNative::get_buffered_amount() const {
- ERR_FAIL_COND_V(interface == NULL, 0);
- return interface->get_buffered_amount(interface->data);
-}
-
-Error WebRTCDataChannelGDNative::get_packet(const uint8_t **r_buffer, int &r_buffer_size) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->get_packet(interface->data, r_buffer, &r_buffer_size);
-}
-
-Error WebRTCDataChannelGDNative::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->put_packet(interface->data, p_buffer, p_buffer_size);
-}
-
-int WebRTCDataChannelGDNative::get_max_packet_size() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_max_packet_size(interface->data);
-}
-
-int WebRTCDataChannelGDNative::get_available_packet_count() const {
- ERR_FAIL_COND_V(interface == nullptr, 0);
- return interface->get_available_packet_count(interface->data);
-}
-
-void WebRTCDataChannelGDNative::set_native_webrtc_data_channel(const godot_net_webrtc_data_channel *p_impl) {
- interface = p_impl;
-}
-
-#endif // WEBRTC_GDNATIVE_ENABLED
diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp
index d60d694df1..133bd71ddb 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.cpp
+++ b/modules/webrtc/webrtc_multiplayer_peer.cpp
@@ -43,22 +43,6 @@ void WebRTCMultiplayerPeer::_bind_methods() {
ClassDB::bind_method(D_METHOD("close"), &WebRTCMultiplayerPeer::close);
}
-void WebRTCMultiplayerPeer::set_transfer_channel(int p_channel) {
- transfer_channel = p_channel;
-}
-
-int WebRTCMultiplayerPeer::get_transfer_channel() const {
- return transfer_channel;
-}
-
-void WebRTCMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) {
- transfer_mode = p_mode;
-}
-
-Multiplayer::TransferMode WebRTCMultiplayerPeer::get_transfer_mode() const {
- return transfer_mode;
-}
-
void WebRTCMultiplayerPeer::set_target_peer(int p_peer_id) {
target_peer = p_peer_id;
}
@@ -79,8 +63,8 @@ void WebRTCMultiplayerPeer::poll() {
List<int> remove;
List<int> add;
- for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) {
- Ref<ConnectedPeer> peer = E->get();
+ for (KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) {
+ Ref<ConnectedPeer> peer = E.value;
peer->connection->poll();
// Check peer state
switch (peer->connection->get_connection_state()) {
@@ -93,7 +77,7 @@ void WebRTCMultiplayerPeer::poll() {
break;
default:
// Peer is closed or in error state. Got to next peer.
- remove.push_back(E->key());
+ remove.push_back(E.key);
continue;
}
// Check channels state
@@ -108,7 +92,7 @@ void WebRTCMultiplayerPeer::poll() {
continue;
default:
// Channel was closed or in error state, remove peer id.
- remove.push_back(E->key());
+ remove.push_back(E.key);
}
// We got a closed channel break out, the peer will be removed.
break;
@@ -116,7 +100,7 @@ void WebRTCMultiplayerPeer::poll() {
// This peer has newly connected, and all channels are now open.
if (ready == peer->channels.size() && !peer->connected) {
peer->connected = true;
- add.push_back(E->key());
+ add.push_back(E.key);
}
}
// Remove disconnected peers
@@ -141,9 +125,9 @@ void WebRTCMultiplayerPeer::poll() {
emit_signal(SNAME("peer_connected"), TARGET_PEER_SERVER);
emit_signal(SNAME("connection_succeeded"));
// Notify of all previously connected peers
- for (Map<int, Ref<ConnectedPeer>>::Element *F = peer_map.front(); F; F = F->next()) {
- if (F->key() != 1 && F->get()->connected) {
- emit_signal(SNAME("peer_connected"), F->key());
+ for (const KeyValue<int, Ref<ConnectedPeer>> &F : peer_map) {
+ if (F.key != 1 && F.value->connected) {
+ emit_signal(SNAME("peer_connected"), F.key);
}
}
break; // Because we already notified of all newly added peers.
@@ -188,14 +172,6 @@ void WebRTCMultiplayerPeer::_find_next_peer() {
next_packet_peer = 0;
}
-void WebRTCMultiplayerPeer::set_refuse_new_connections(bool p_enable) {
- refuse_connections = p_enable;
-}
-
-bool WebRTCMultiplayerPeer::is_refusing_new_connections() const {
- return refuse_connections;
-}
-
MultiplayerPeer::ConnectionStatus WebRTCMultiplayerPeer::get_connection_status() const {
return connection_status;
}
@@ -213,7 +189,7 @@ Error WebRTCMultiplayerPeer::initialize(int p_self_id, bool p_server_compat, Arr
cfg["ordered"] = true;
switch (mode) {
- case Multiplayer::TRANSFER_MODE_ORDERED:
+ case Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED:
cfg["maxPacketLifetime"] = 1;
break;
case Multiplayer::TRANSFER_MODE_UNRELIABLE:
@@ -268,10 +244,10 @@ Dictionary WebRTCMultiplayerPeer::get_peer(int p_peer_id) {
Dictionary WebRTCMultiplayerPeer::get_peers() {
Dictionary out;
- for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) {
+ for (const KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) {
Dictionary d;
- _peer_to_dict(E->get(), d);
- out[E->key()] = d;
+ _peer_to_dict(E.value, d);
+ out[E.key] = d;
}
return out;
}
@@ -279,7 +255,7 @@ Dictionary WebRTCMultiplayerPeer::get_peers() {
Error WebRTCMultiplayerPeer::add_peer(Ref<WebRTCPeerConnection> p_peer, int p_peer_id, int p_unreliable_lifetime) {
ERR_FAIL_COND_V(p_peer_id < 0 || p_peer_id > ~(1 << 31), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_unreliable_lifetime < 0, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(refuse_connections, ERR_UNAUTHORIZED);
+ ERR_FAIL_COND_V(is_refusing_new_connections(), ERR_UNAUTHORIZED);
// Peer must be valid, and in new state (to create data channels)
ERR_FAIL_COND_V(!p_peer.is_valid(), ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(p_peer->get_connection_state() != WebRTCPeerConnection::STATE_NEW, ERR_INVALID_PARAMETER);
@@ -352,13 +328,13 @@ Error WebRTCMultiplayerPeer::get_packet(const uint8_t **r_buffer, int &r_buffer_
Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_size) {
ERR_FAIL_COND_V(connection_status == CONNECTION_DISCONNECTED, ERR_UNCONFIGURED);
- int ch = transfer_channel;
+ int ch = get_transfer_channel();
if (ch == 0) {
- switch (transfer_mode) {
+ switch (get_transfer_mode()) {
case Multiplayer::TRANSFER_MODE_RELIABLE:
ch = CH_RELIABLE;
break;
- case Multiplayer::TRANSFER_MODE_ORDERED:
+ case Multiplayer::TRANSFER_MODE_UNRELIABLE_ORDERED:
ch = CH_ORDERED;
break;
case Multiplayer::TRANSFER_MODE_UNRELIABLE:
@@ -382,15 +358,15 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si
} else {
int exclude = -target_peer;
- for (Map<int, Ref<ConnectedPeer>>::Element *F = peer_map.front(); F; F = F->next()) {
+ for (KeyValue<int, Ref<ConnectedPeer>> &F : peer_map) {
// Exclude packet. If target_peer == 0 then don't exclude any packets
- if (target_peer != 0 && F->key() == exclude) {
+ if (target_peer != 0 && F.key == exclude) {
continue;
}
- ERR_CONTINUE_MSG(F->value()->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size()));
- ERR_CONTINUE(F->value()->channels[ch].is_null());
- F->value()->channels[ch]->put_packet(p_buffer, p_buffer_size);
+ ERR_CONTINUE_MSG(F.value->channels.size() <= ch, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size()));
+ ERR_CONTINUE(F.value->channels[ch].is_null());
+ F.value->channels[ch]->put_packet(p_buffer, p_buffer_size);
}
}
return OK;
@@ -401,8 +377,8 @@ int WebRTCMultiplayerPeer::get_available_packet_count() const {
return 0; // To be sure next call to get_packet works if size > 0 .
}
int size = 0;
- for (Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.front(); E; E = E->next()) {
- for (const Ref<WebRTCDataChannel> &F : E->get()->channels) {
+ for (const KeyValue<int, Ref<ConnectedPeer>> &E : peer_map) {
+ for (const Ref<WebRTCDataChannel> &F : E.value->channels) {
size += F->get_available_packet_count();
}
}
diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h
index 80a6491492..4a7e9ad7c8 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.h
+++ b/modules/webrtc/webrtc_multiplayer_peer.h
@@ -65,10 +65,7 @@ private:
uint32_t unique_id = 0;
int target_peer = 0;
int client_count = 0;
- bool refuse_connections = false;
ConnectionStatus connection_status = CONNECTION_DISCONNECTED;
- int transfer_channel = 0;
- Multiplayer::TransferMode transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE;
int next_packet_peer = 0;
bool server_compat = false;
@@ -97,10 +94,6 @@ public:
int get_max_packet_size() const override;
// MultiplayerPeer
- void set_transfer_channel(int p_channel) override;
- int get_transfer_channel() const override;
- void set_transfer_mode(Multiplayer::TransferMode p_mode) override;
- Multiplayer::TransferMode get_transfer_mode() const override;
void set_target_peer(int p_peer_id) override;
int get_unique_id() const override;
@@ -110,9 +103,6 @@ public:
void poll() override;
- void set_refuse_new_connections(bool p_enable) override;
- bool is_refusing_new_connections() const override;
-
ConnectionStatus get_connection_status() const override;
};
diff --git a/modules/webrtc/webrtc_peer_connection.cpp b/modules/webrtc/webrtc_peer_connection.cpp
index 3e2938bf7d..ad28aa76c7 100644
--- a/modules/webrtc/webrtc_peer_connection.cpp
+++ b/modules/webrtc/webrtc_peer_connection.cpp
@@ -30,17 +30,29 @@
#include "webrtc_peer_connection.h"
-WebRTCPeerConnection *(*WebRTCPeerConnection::_create)() = nullptr;
+#ifdef JAVASCRIPT_ENABLED
+#include "webrtc_peer_connection_js.h"
+#else
+#include "webrtc_peer_connection_extension.h"
+#endif
-Ref<WebRTCPeerConnection> WebRTCPeerConnection::create_ref() {
- return create();
+StringName WebRTCPeerConnection::default_extension;
+
+void WebRTCPeerConnection::set_default_extension(const StringName &p_extension) {
+ default_extension = p_extension;
}
WebRTCPeerConnection *WebRTCPeerConnection::create() {
- if (!_create) {
- return nullptr;
+#ifdef JAVASCRIPT_ENABLED
+ return memnew(WebRTCPeerConnectionJS);
+#else
+ if (default_extension == String()) {
+ WARN_PRINT_ONCE("No default WebRTC extension configured.");
+ return memnew(WebRTCPeerConnectionExtension);
}
- return _create();
+ Object *obj = ClassDB::instantiate(default_extension);
+ return Object::cast_to<WebRTCPeerConnectionExtension>(obj);
+#endif
}
void WebRTCPeerConnection::_bind_methods() {
diff --git a/modules/webrtc/webrtc_peer_connection.h b/modules/webrtc/webrtc_peer_connection.h
index fcfb9ae9ae..e2ef3e55ad 100644
--- a/modules/webrtc/webrtc_peer_connection.h
+++ b/modules/webrtc/webrtc_peer_connection.h
@@ -47,11 +47,15 @@ public:
STATE_CLOSED
};
+private:
+ static StringName default_extension;
+
protected:
static void _bind_methods();
- static WebRTCPeerConnection *(*_create)();
public:
+ static void set_default_extension(const StringName &p_name);
+
virtual ConnectionState get_connection_state() const = 0;
virtual Error initialize(Dictionary p_config = Dictionary()) = 0;
@@ -63,7 +67,6 @@ public:
virtual Error poll() = 0;
virtual void close() = 0;
- static Ref<WebRTCPeerConnection> create_ref();
static WebRTCPeerConnection *create();
WebRTCPeerConnection();
diff --git a/modules/webrtc/webrtc_peer_connection_extension.cpp b/modules/webrtc/webrtc_peer_connection_extension.cpp
new file mode 100644
index 0000000000..33288e66d6
--- /dev/null
+++ b/modules/webrtc/webrtc_peer_connection_extension.cpp
@@ -0,0 +1,131 @@
+/*************************************************************************/
+/* webrtc_peer_connection_extension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* 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 "webrtc_peer_connection_extension.h"
+
+void WebRTCPeerConnectionExtension::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("make_default"), &WebRTCPeerConnectionExtension::make_default);
+
+ GDVIRTUAL_BIND(_get_connection_state);
+ GDVIRTUAL_BIND(_initialize, "p_config");
+ GDVIRTUAL_BIND(_create_data_channel, "p_label", "p_config");
+ GDVIRTUAL_BIND(_create_offer);
+ GDVIRTUAL_BIND(_set_remote_description, "p_type", "p_sdp");
+ GDVIRTUAL_BIND(_set_local_description, "p_type", "p_sdp");
+ GDVIRTUAL_BIND(_add_ice_candidate, "p_sdp_mid_name", "p_sdp_mline_index", "p_sdp_name");
+ GDVIRTUAL_BIND(_poll);
+ GDVIRTUAL_BIND(_close);
+}
+
+void WebRTCPeerConnectionExtension::make_default() {
+ ERR_FAIL_COND_MSG(!_get_extension(), vformat("Can't make %s the default without extending it.", get_class()));
+ WebRTCPeerConnection::set_default_extension(get_class());
+}
+
+WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionExtension::get_connection_state() const {
+ int state;
+ if (GDVIRTUAL_CALL(_get_connection_state, state)) {
+ return (ConnectionState)state;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_get_connection_state is unimplemented!");
+ return STATE_DISCONNECTED;
+}
+
+Error WebRTCPeerConnectionExtension::initialize(Dictionary p_config) {
+ int err;
+ if (GDVIRTUAL_CALL(_initialize, p_config, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_initialize is unimplemented!");
+ return ERR_UNCONFIGURED;
+}
+
+Ref<WebRTCDataChannel> WebRTCPeerConnectionExtension::create_data_channel(String p_label, Dictionary p_options) {
+ Object *ret = nullptr;
+ if (GDVIRTUAL_CALL(_create_data_channel, p_label, p_options, ret)) {
+ WebRTCDataChannel *ch = Object::cast_to<WebRTCDataChannel>(ret);
+ ERR_FAIL_COND_V_MSG(ret && !ch, nullptr, "Returned object must be an instance of WebRTCDataChannel.");
+ return ch;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_data_channel is unimplemented!");
+ return nullptr;
+}
+
+Error WebRTCPeerConnectionExtension::create_offer() {
+ int err;
+ if (GDVIRTUAL_CALL(_create_offer, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_create_offer is unimplemented!");
+ return ERR_UNCONFIGURED;
+}
+
+Error WebRTCPeerConnectionExtension::set_local_description(String p_type, String p_sdp) {
+ int err;
+ if (GDVIRTUAL_CALL(_set_local_description, p_type, p_sdp, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_set_local_description is unimplemented!");
+ return ERR_UNCONFIGURED;
+}
+
+Error WebRTCPeerConnectionExtension::set_remote_description(String p_type, String p_sdp) {
+ int err;
+ if (GDVIRTUAL_CALL(_set_remote_description, p_type, p_sdp, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_set_remote_description is unimplemented!");
+ return ERR_UNCONFIGURED;
+}
+
+Error WebRTCPeerConnectionExtension::add_ice_candidate(String p_sdp_mid_name, int p_sdp_mline_index, String p_sdp_name) {
+ int err;
+ if (GDVIRTUAL_CALL(_add_ice_candidate, p_sdp_mid_name, p_sdp_mline_index, p_sdp_name, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_add_ice_candidate is unimplemented!");
+ return ERR_UNCONFIGURED;
+}
+
+Error WebRTCPeerConnectionExtension::poll() {
+ int err;
+ if (GDVIRTUAL_CALL(_poll, err)) {
+ return (Error)err;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_poll is unimplemented!");
+ return ERR_UNCONFIGURED;
+}
+
+void WebRTCPeerConnectionExtension::close() {
+ if (GDVIRTUAL_CALL(_close)) {
+ return;
+ }
+ WARN_PRINT_ONCE("WebRTCPeerConnectionExtension::_close is unimplemented!");
+}
diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.h b/modules/webrtc/webrtc_peer_connection_extension.h
index 578af0202f..b3c2039fc1 100644
--- a/modules/webrtc/webrtc_peer_connection_gdnative.h
+++ b/modules/webrtc/webrtc_peer_connection_extension.h
@@ -1,5 +1,5 @@
/*************************************************************************/
-/* webrtc_peer_connection_gdnative.h */
+/* webrtc_peer_connection_extension.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,30 +28,23 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-#ifndef WEBRTC_PEER_CONNECTION_GDNATIVE_H
-#define WEBRTC_PEER_CONNECTION_GDNATIVE_H
+#ifndef WEBRTC_PEER_CONNECTION_EXTENSION_H
+#define WEBRTC_PEER_CONNECTION_EXTENSION_H
-#ifdef WEBRTC_GDNATIVE_ENABLED
-
-#include "modules/gdnative/include/net/godot_net.h"
#include "webrtc_peer_connection.h"
-class WebRTCPeerConnectionGDNative : public WebRTCPeerConnection {
- GDCLASS(WebRTCPeerConnectionGDNative, WebRTCPeerConnection);
+#include "core/object/gdvirtual.gen.inc"
+#include "core/object/script_language.h"
+#include "core/variant/native_ptr.h"
+
+class WebRTCPeerConnectionExtension : public WebRTCPeerConnection {
+ GDCLASS(WebRTCPeerConnectionExtension, WebRTCPeerConnection);
protected:
static void _bind_methods();
- static WebRTCPeerConnection *_create();
-
-private:
- static const godot_net_webrtc_library *default_library;
- const godot_net_webrtc_peer_connection *interface;
public:
- static Error set_default_library(const godot_net_webrtc_library *p_library);
- static void make_default() { WebRTCPeerConnection::_create = WebRTCPeerConnectionGDNative::_create; }
-
- void set_native_webrtc_peer_connection(const godot_net_webrtc_peer_connection *p_impl);
+ void make_default();
virtual ConnectionState get_connection_state() const override;
@@ -60,14 +53,22 @@ public:
virtual Error create_offer() override;
virtual Error set_remote_description(String type, String sdp) override;
virtual Error set_local_description(String type, String sdp) override;
- virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) override;
+ virtual Error add_ice_candidate(String p_sdp_mid_name, int p_sdp_mline_index, String p_sdp_name) override;
virtual Error poll() override;
virtual void close() override;
- WebRTCPeerConnectionGDNative();
- ~WebRTCPeerConnectionGDNative();
-};
+ /** GDExtension **/
+ GDVIRTUAL0RC(int, _get_connection_state);
+ GDVIRTUAL1R(int, _initialize, Dictionary);
+ GDVIRTUAL2R(Object *, _create_data_channel, String, Dictionary);
+ GDVIRTUAL0R(int, _create_offer);
+ GDVIRTUAL2R(int, _set_remote_description, String, String);
+ GDVIRTUAL2R(int, _set_local_description, String, String);
+ GDVIRTUAL3R(int, _add_ice_candidate, String, int, String);
+ GDVIRTUAL0R(int, _poll);
+ GDVIRTUAL0(_close);
-#endif // WEBRTC_GDNATIVE_ENABLED
+ WebRTCPeerConnectionExtension() {}
+};
-#endif // WEBRTC_PEER_CONNECTION_GDNATIVE_H
+#endif // WEBRTC_PEER_CONNECTION_EXTENSION_H
diff --git a/modules/webrtc/webrtc_peer_connection_gdnative.cpp b/modules/webrtc/webrtc_peer_connection_gdnative.cpp
deleted file mode 100644
index dcf78dfb73..0000000000
--- a/modules/webrtc/webrtc_peer_connection_gdnative.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*************************************************************************/
-/* webrtc_peer_connection_gdnative.cpp */
-/*************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
-/* */
-/* 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. */
-/*************************************************************************/
-
-#ifdef WEBRTC_GDNATIVE_ENABLED
-
-#include "webrtc_peer_connection_gdnative.h"
-
-#include "core/io/resource_loader.h"
-#include "modules/gdnative/nativescript/nativescript.h"
-#include "webrtc_data_channel_gdnative.h"
-
-const godot_net_webrtc_library *WebRTCPeerConnectionGDNative::default_library = nullptr;
-
-Error WebRTCPeerConnectionGDNative::set_default_library(const godot_net_webrtc_library *p_lib) {
- if (default_library) {
- const godot_net_webrtc_library *old = default_library;
- default_library = nullptr;
- old->unregistered();
- }
- default_library = p_lib;
- return OK; // Maybe add version check and fail accordingly
-}
-
-WebRTCPeerConnection *WebRTCPeerConnectionGDNative::_create() {
- WebRTCPeerConnectionGDNative *obj = memnew(WebRTCPeerConnectionGDNative);
- ERR_FAIL_COND_V_MSG(!default_library, obj, "Default GDNative WebRTC implementation not defined.");
-
- // Call GDNative constructor
- Error err = (Error)default_library->create_peer_connection(obj);
- ERR_FAIL_COND_V_MSG(err != OK, obj, "GDNative default library constructor returned an error.");
-
- return obj;
-}
-
-void WebRTCPeerConnectionGDNative::_bind_methods() {
-}
-
-WebRTCPeerConnectionGDNative::WebRTCPeerConnectionGDNative() {
- interface = nullptr;
-}
-
-WebRTCPeerConnectionGDNative::~WebRTCPeerConnectionGDNative() {
-}
-
-Error WebRTCPeerConnectionGDNative::initialize(Dictionary p_config) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->initialize(interface->data, (const godot_dictionary *)&p_config);
-}
-
-Ref<WebRTCDataChannel> WebRTCPeerConnectionGDNative::create_data_channel(String p_label, Dictionary p_options) {
- ERR_FAIL_COND_V(interface == nullptr, nullptr);
- return (WebRTCDataChannel *)interface->create_data_channel(interface->data, p_label.utf8().get_data(), (const godot_dictionary *)&p_options);
-}
-
-Error WebRTCPeerConnectionGDNative::create_offer() {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->create_offer(interface->data);
-}
-
-Error WebRTCPeerConnectionGDNative::set_local_description(String p_type, String p_sdp) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->set_local_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data());
-}
-
-Error WebRTCPeerConnectionGDNative::set_remote_description(String p_type, String p_sdp) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->set_remote_description(interface->data, p_type.utf8().get_data(), p_sdp.utf8().get_data());
-}
-
-Error WebRTCPeerConnectionGDNative::add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName) {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->add_ice_candidate(interface->data, sdpMidName.utf8().get_data(), sdpMlineIndexName, sdpName.utf8().get_data());
-}
-
-Error WebRTCPeerConnectionGDNative::poll() {
- ERR_FAIL_COND_V(interface == nullptr, ERR_UNCONFIGURED);
- return (Error)interface->poll(interface->data);
-}
-
-void WebRTCPeerConnectionGDNative::close() {
- ERR_FAIL_COND(interface == nullptr);
- interface->close(interface->data);
-}
-
-WebRTCPeerConnection::ConnectionState WebRTCPeerConnectionGDNative::get_connection_state() const {
- ERR_FAIL_COND_V(interface == nullptr, STATE_DISCONNECTED);
- return (ConnectionState)interface->get_connection_state(interface->data);
-}
-
-void WebRTCPeerConnectionGDNative::set_native_webrtc_peer_connection(const godot_net_webrtc_peer_connection *p_impl) {
- interface = p_impl;
-}
-
-#endif // WEBRTC_GDNATIVE_ENABLED
diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h
index 0272e67f6f..d2beccaf03 100644
--- a/modules/webrtc/webrtc_peer_connection_js.h
+++ b/modules/webrtc/webrtc_peer_connection_js.h
@@ -63,9 +63,6 @@ private:
static void _on_error(void *p_obj);
public:
- static WebRTCPeerConnection *_create() { return memnew(WebRTCPeerConnectionJS); }
- static void make_default() { WebRTCPeerConnection::_create = WebRTCPeerConnectionJS::_create; }
-
virtual ConnectionState get_connection_state() const;
virtual Error initialize(Dictionary configuration = Dictionary());
diff --git a/modules/websocket/doc_classes/WebSocketClient.xml b/modules/websocket/doc_classes/WebSocketClient.xml
index b5202469f1..4b515c12a1 100644
--- a/modules/websocket/doc_classes/WebSocketClient.xml
+++ b/modules/websocket/doc_classes/WebSocketClient.xml
@@ -8,6 +8,7 @@
This client can be optionally used as a multiplayer peer for the [MultiplayerAPI].
After starting the client ([method connect_to_url]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]).
You will receive appropriate signals when connecting, disconnecting, or when new data is available.
+ [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
</tutorials>
@@ -90,6 +91,4 @@
</description>
</signal>
</signals>
- <constants>
- </constants>
</class>
diff --git a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
index c7a0ca100f..8d8ab220e2 100644
--- a/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketMultiplayerPeer.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
Base class for WebSocket server and client, allowing them to be used as multiplayer peer for the [MultiplayerAPI].
+ [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
</tutorials>
@@ -30,10 +31,6 @@
</description>
</method>
</methods>
- <members>
- <member name="refuse_new_connections" type="bool" setter="set_refuse_new_connections" getter="is_refusing_new_connections" override="true" default="false" />
- <member name="transfer_mode" type="int" setter="set_transfer_mode" getter="get_transfer_mode" override="true" enum="TransferMode" default="2" />
- </members>
<signals>
<signal name="peer_packet">
<argument index="0" name="peer_source" type="int" />
@@ -43,6 +40,4 @@
</description>
</signal>
</signals>
- <constants>
- </constants>
</class>
diff --git a/modules/websocket/doc_classes/WebSocketPeer.xml b/modules/websocket/doc_classes/WebSocketPeer.xml
index ab7ef6c4d0..2f455c32fd 100644
--- a/modules/websocket/doc_classes/WebSocketPeer.xml
+++ b/modules/websocket/doc_classes/WebSocketPeer.xml
@@ -4,7 +4,7 @@
A class representing a specific WebSocket connection.
</brief_description>
<description>
- This class represent a specific WebSocket connection, you can do lower level operations with it.
+ This class represents a specific WebSocket connection, allowing you to do lower level operations with it.
You can choose to write to the socket in binary or text mode, and you can recognize the mode used for writing by the other peer.
</description>
<tutorials>
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
index b66a1054ab..f901b089ea 100644
--- a/modules/websocket/doc_classes/WebSocketServer.xml
+++ b/modules/websocket/doc_classes/WebSocketServer.xml
@@ -7,6 +7,7 @@
This class implements a WebSocket server that can also support the high-level multiplayer API.
After starting the server ([method listen]), you will need to [method MultiplayerPeer.poll] it at regular intervals (e.g. inside [method Node._process]). When clients connect, disconnect, or send data, you will receive the appropriate signal.
[b]Note:[/b] Not available in HTML5 exports.
+ [b]Note:[/b] When exporting to Android, make sure to enable the [code]INTERNET[/code] permission in the Android export preset before exporting the project or using one-click deploy. Otherwise, network communication of any kind will be blocked by Android.
</description>
<tutorials>
</tutorials>
@@ -116,6 +117,4 @@
</description>
</signal>
</signals>
- <constants>
- </constants>
</class>
diff --git a/modules/websocket/editor_debugger_server_websocket.cpp b/modules/websocket/editor_debugger_server_websocket.cpp
index 2e61cbfc08..d248433d82 100644
--- a/modules/websocket/editor_debugger_server_websocket.cpp
+++ b/modules/websocket/editor_debugger_server_websocket.cpp
@@ -48,11 +48,19 @@ void EditorDebuggerServerWebSocket::poll() {
server->poll();
}
-Error EditorDebuggerServerWebSocket::start() {
- int remote_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+Error EditorDebuggerServerWebSocket::start(const String &p_uri) {
+ int bind_port = (int)EditorSettings::get_singleton()->get("network/debug/remote_port");
+ String bind_host = EditorSettings::get_singleton()->get("network/debug/remote_host");
+ if (!p_uri.is_empty() && p_uri != "ws://") {
+ String scheme, path;
+ Error err = p_uri.parse_url(scheme, bind_host, bind_port, path);
+ ERR_FAIL_COND_V(err != OK, ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!bind_host.is_valid_ip_address() && bind_host != "*", ERR_INVALID_PARAMETER);
+ }
+ server->set_bind_ip(bind_host);
Vector<String> compatible_protocols;
compatible_protocols.push_back("binary"); // compatibility with EMSCRIPTEN TCP-to-WebSocket layer.
- return server->listen(remote_port, compatible_protocols);
+ return server->listen(bind_port, compatible_protocols);
}
void EditorDebuggerServerWebSocket::stop() {
diff --git a/modules/websocket/editor_debugger_server_websocket.h b/modules/websocket/editor_debugger_server_websocket.h
index d9543bb647..14ab0109b2 100644
--- a/modules/websocket/editor_debugger_server_websocket.h
+++ b/modules/websocket/editor_debugger_server_websocket.h
@@ -48,7 +48,7 @@ public:
void _peer_disconnected(int p_peer, bool p_was_clean);
void poll() override;
- Error start() override;
+ Error start(const String &p_uri) override;
void stop() override;
bool is_active() const override;
bool is_connection_available() const override;
diff --git a/modules/websocket/websocket_client.cpp b/modules/websocket/websocket_client.cpp
index f7a8944745..bf35c91c7f 100644
--- a/modules/websocket/websocket_client.cpp
+++ b/modules/websocket/websocket_client.cpp
@@ -129,7 +129,7 @@ void WebSocketClient::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "verify_ssl", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE), "set_verify_ssl_enabled", "is_verify_ssl_enabled");
ClassDB::bind_method(D_METHOD("get_trusted_ssl_certificate"), &WebSocketClient::get_trusted_ssl_certificate);
- ClassDB::bind_method(D_METHOD("set_trusted_ssl_certificate"), &WebSocketClient::set_trusted_ssl_certificate);
+ ClassDB::bind_method(D_METHOD("set_trusted_ssl_certificate", "cert"), &WebSocketClient::set_trusted_ssl_certificate);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "trusted_ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_trusted_ssl_certificate", "get_trusted_ssl_certificate");
diff --git a/modules/websocket/websocket_multiplayer_peer.cpp b/modules/websocket/websocket_multiplayer_peer.cpp
index 7464cf2bf5..e54bfbca12 100644
--- a/modules/websocket/websocket_multiplayer_peer.cpp
+++ b/modules/websocket/websocket_multiplayer_peer.cpp
@@ -105,23 +105,6 @@ Error WebSocketMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer
//
// MultiplayerPeer
//
-void WebSocketMultiplayerPeer::set_transfer_channel(int p_channel) {
- // Websocket does not have channels.
-}
-
-int WebSocketMultiplayerPeer::get_transfer_channel() const {
- return 0;
-}
-
-void WebSocketMultiplayerPeer::set_transfer_mode(Multiplayer::TransferMode p_mode) {
- // Websocket uses TCP, reliable
-}
-
-Multiplayer::TransferMode WebSocketMultiplayerPeer::get_transfer_mode() const {
- // Websocket uses TCP, reliable
- return Multiplayer::TRANSFER_MODE_RELIABLE;
-}
-
void WebSocketMultiplayerPeer::set_target_peer(int p_target_peer) {
_target_peer = p_target_peer;
}
@@ -137,14 +120,6 @@ int WebSocketMultiplayerPeer::get_unique_id() const {
return _peer_id;
}
-void WebSocketMultiplayerPeer::set_refuse_new_connections(bool p_enable) {
- _refusing = p_enable;
-}
-
-bool WebSocketMultiplayerPeer::is_refusing_new_connections() const {
- return _refusing;
-}
-
void WebSocketMultiplayerPeer::_send_sys(Ref<WebSocketPeer> p_peer, uint8_t p_type, int32_t p_peer_id) {
ERR_FAIL_COND(!p_peer.is_valid());
ERR_FAIL_COND(!p_peer->is_connected_to_host());
@@ -173,8 +148,8 @@ void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
// Then send the server peer (which will trigger connection_succeded in client)
_send_sys(get_peer(p_peer_id), SYS_ADD, 1);
- for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
- int32_t id = E->key();
+ for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
+ int32_t id = E.key;
if (p_peer_id == id) {
continue; // Skip the newly added peer (already confirmed)
}
@@ -187,8 +162,8 @@ void WebSocketMultiplayerPeer::_send_add(int32_t p_peer_id) {
}
void WebSocketMultiplayerPeer::_send_del(int32_t p_peer_id) {
- for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
- int32_t id = E->key();
+ for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
+ int32_t id = E.key;
if (p_peer_id != id) {
_send_sys(get_peer(id), SYS_DEL, p_peer_id);
}
@@ -211,17 +186,17 @@ Error WebSocketMultiplayerPeer::_server_relay(int32_t p_from, int32_t p_to, cons
return OK; // Will not send to self
} else if (p_to == 0) {
- for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
- if (E->key() != p_from) {
- E->get()->put_packet(p_buffer, p_buffer_size);
+ for (KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
+ if (E.key != p_from) {
+ E.value->put_packet(p_buffer, p_buffer_size);
}
}
return OK; // Sent to all but sender
} else if (p_to < 0) {
- for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
- if (E->key() != p_from && E->key() != -p_to) {
- E->get()->put_packet(p_buffer, p_buffer_size);
+ for (KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
+ if (E.key != p_from && E.key != -p_to) {
+ E.value->put_packet(p_buffer, p_buffer_size);
}
}
return OK; // Sent to all but sender and excluded
diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h
index d97a599fe9..380edf67ed 100644
--- a/modules/websocket/websocket_multiplayer_peer.h
+++ b/modules/websocket/websocket_multiplayer_peer.h
@@ -68,7 +68,6 @@ protected:
bool _is_multiplayer = false;
int _target_peer = 0;
int _peer_id = 0;
- int _refusing = false;
static void _bind_methods();
@@ -78,15 +77,9 @@ protected:
public:
/* MultiplayerPeer */
- void set_transfer_channel(int p_channel) override;
- int get_transfer_channel() const override;
- void set_transfer_mode(Multiplayer::TransferMode p_mode) override;
- Multiplayer::TransferMode get_transfer_mode() const override;
void set_target_peer(int p_target_peer) override;
int get_packet_peer() const override;
int get_unique_id() const override;
- void set_refuse_new_connections(bool p_enable) override;
- bool is_refusing_new_connections() const override;
/* PacketPeer */
virtual int get_available_packet_count() const override;
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
index fb838109f3..e7f90fdeba 100644
--- a/modules/websocket/websocket_server.cpp
+++ b/modules/websocket/websocket_server.cpp
@@ -50,19 +50,19 @@ void WebSocketServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("disconnect_peer", "id", "code", "reason"), &WebSocketServer::disconnect_peer, DEFVAL(1000), DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_bind_ip"), &WebSocketServer::get_bind_ip);
- ClassDB::bind_method(D_METHOD("set_bind_ip"), &WebSocketServer::set_bind_ip);
+ ClassDB::bind_method(D_METHOD("set_bind_ip", "ip"), &WebSocketServer::set_bind_ip);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "bind_ip"), "set_bind_ip", "get_bind_ip");
ClassDB::bind_method(D_METHOD("get_private_key"), &WebSocketServer::get_private_key);
- ClassDB::bind_method(D_METHOD("set_private_key"), &WebSocketServer::set_private_key);
+ ClassDB::bind_method(D_METHOD("set_private_key", "key"), &WebSocketServer::set_private_key);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "private_key", PROPERTY_HINT_RESOURCE_TYPE, "CryptoKey", PROPERTY_USAGE_NONE), "set_private_key", "get_private_key");
ClassDB::bind_method(D_METHOD("get_ssl_certificate"), &WebSocketServer::get_ssl_certificate);
- ClassDB::bind_method(D_METHOD("set_ssl_certificate"), &WebSocketServer::set_ssl_certificate);
+ ClassDB::bind_method(D_METHOD("set_ssl_certificate", "cert"), &WebSocketServer::set_ssl_certificate);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ssl_certificate", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_ssl_certificate", "get_ssl_certificate");
ClassDB::bind_method(D_METHOD("get_ca_chain"), &WebSocketServer::get_ca_chain);
- ClassDB::bind_method(D_METHOD("set_ca_chain"), &WebSocketServer::set_ca_chain);
+ ClassDB::bind_method(D_METHOD("set_ca_chain", "ca_chain"), &WebSocketServer::set_ca_chain);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "ca_chain", PROPERTY_HINT_RESOURCE_TYPE, "X509Certificate", PROPERTY_USAGE_NONE), "set_ca_chain", "get_ca_chain");
ClassDB::bind_method(D_METHOD("get_handshake_timeout"), &WebSocketServer::get_handshake_timeout);
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index 7402bbb46e..514b2d055f 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -182,12 +182,12 @@ Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp
void WSLServer::poll() {
List<int> remove_ids;
- for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
- Ref<WSLPeer> peer = (WSLPeer *)E->get().ptr();
+ for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
+ Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr();
peer->poll();
if (!peer->is_connected_to_host()) {
- _on_disconnect(E->key(), peer->close_code != -1);
- remove_ids.push_back(E->key());
+ _on_disconnect(E.key, peer->close_code != -1);
+ remove_ids.push_back(E.key);
}
}
for (int &E : remove_ids) {
@@ -265,8 +265,8 @@ int WSLServer::get_max_packet_size() const {
void WSLServer::stop() {
_server->stop();
- for (Map<int, Ref<WebSocketPeer>>::Element *E = _peer_map.front(); E; E = E->next()) {
- Ref<WSLPeer> peer = (WSLPeer *)E->get().ptr();
+ for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
+ Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr();
peer->close_now();
}
_pending.clear();
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index ff7c46bbae..16d671c9e9 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -239,6 +239,4 @@
</description>
</signal>
</signals>
- <constants>
- </constants>
</class>
diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp
index 078a6547cf..16b483c39e 100644
--- a/modules/webxr/register_types.cpp
+++ b/modules/webxr/register_types.cpp
@@ -33,15 +33,34 @@
#include "webxr_interface.h"
#include "webxr_interface_js.h"
+#ifdef JAVASCRIPT_ENABLED
+Ref<WebXRInterfaceJS> webxr;
+#endif
+
void register_webxr_types() {
GDREGISTER_VIRTUAL_CLASS(WebXRInterface);
#ifdef JAVASCRIPT_ENABLED
- Ref<WebXRInterfaceJS> webxr;
webxr.instantiate();
XRServer::get_singleton()->add_interface(webxr);
#endif
}
void unregister_webxr_types() {
+#ifdef JAVASCRIPT_ENABLED
+ if (webxr.is_valid()) {
+ // uninitialise our interface if it is initialised
+ if (webxr->is_initialized()) {
+ webxr->uninitialize();
+ }
+
+ // unregister our interface from the XR server
+ if (XRServer::get_singleton()) {
+ XRServer::get_singleton()->remove_interface(webxr);
+ }
+
+ // and release
+ webxr.unref();
+ }
+#endif
}
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 2d699961ae..10c17aa672 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -341,7 +341,7 @@ Transform3D WebXRInterfaceJS::get_transform_for_view(uint32_t p_view, const Tran
return p_cam_transform * xr_server->get_reference_frame() * transform_for_eye;
};
-CameraMatrix WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
+CameraMatrix WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) {
CameraMatrix eye;
float *js_matrix = godot_webxr_get_projection_for_eye(p_view + 1);
diff --git a/modules/webxr/webxr_interface_js.h b/modules/webxr/webxr_interface_js.h
index 82307190db..eb77f35f39 100644
--- a/modules/webxr/webxr_interface_js.h
+++ b/modules/webxr/webxr_interface_js.h
@@ -86,7 +86,7 @@ public:
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
- virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
+ virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override;
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
virtual void process() override;
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index 8913ef1b65..58a6216b1e 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -114,7 +114,7 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
input_mesh.vertexPositionStride = sizeof(float) * 3;
input_mesh.vertexNormalData = p_normals;
input_mesh.vertexNormalStride = sizeof(uint32_t) * 3;
- input_mesh.vertexUvData = NULL;
+ input_mesh.vertexUvData = nullptr;
input_mesh.vertexUvStride = 0;
xatlas::ChartOptions chart_options;