summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/basis_universal/register_types.cpp14
-rw-r--r--modules/basis_universal/register_types.h6
-rw-r--r--modules/bmp/image_loader_bmp.cpp13
-rw-r--r--modules/bmp/image_loader_bmp.h3
-rw-r--r--modules/bmp/register_types.cpp12
-rw-r--r--modules/bmp/register_types.h6
-rw-r--r--modules/camera/register_types.cpp11
-rw-r--r--modules/camera/register_types.h6
-rw-r--r--modules/csg/csg.cpp25
-rw-r--r--modules/csg/csg.h10
-rw-r--r--modules/csg/csg_shape.cpp38
-rw-r--r--modules/csg/csg_shape.h8
-rw-r--r--modules/csg/doc_classes/CSGPrimitive3D.xml4
-rw-r--r--modules/csg/doc_classes/CSGSphere3D.xml2
-rw-r--r--modules/csg/editor/csg_gizmos.cpp14
-rw-r--r--modules/csg/register_types.cpp32
-rw-r--r--modules/csg/register_types.h6
-rw-r--r--modules/cvtt/image_compress_cvtt.cpp4
-rw-r--r--modules/cvtt/register_types.cpp12
-rw-r--r--modules/cvtt/register_types.h6
-rw-r--r--modules/dds/register_types.cpp12
-rw-r--r--modules/dds/register_types.h6
-rw-r--r--modules/dds/texture_loader_dds.cpp28
-rw-r--r--modules/dds/texture_loader_dds.h2
-rw-r--r--modules/denoise/register_types.cpp11
-rw-r--r--modules/denoise/register_types.h6
-rw-r--r--modules/enet/enet_multiplayer_peer.h4
-rw-r--r--modules/enet/register_types.cpp12
-rw-r--r--modules/enet/register_types.h6
-rw-r--r--modules/etcpak/register_types.cpp11
-rw-r--r--modules/etcpak/register_types.h8
-rw-r--r--modules/freetype/register_types.cpp12
-rw-r--r--modules/freetype/register_types.h6
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml29
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp5
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h2
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp2
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.h8
-rw-r--r--modules/gdscript/gdscript.cpp178
-rw-r--r--modules/gdscript/gdscript.h96
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp110
-rw-r--r--modules/gdscript/gdscript_analyzer.h5
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp30
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h45
-rw-r--r--modules/gdscript/gdscript_cache.cpp7
-rw-r--r--modules/gdscript/gdscript_cache.h4
-rw-r--r--modules/gdscript/gdscript_codegen.h3
-rw-r--r--modules/gdscript/gdscript_compiler.cpp29
-rw-r--r--modules/gdscript/gdscript_compiler.h14
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp43
-rw-r--r--modules/gdscript/gdscript_editor.cpp284
-rw-r--r--modules/gdscript/gdscript_function.cpp7
-rw-r--r--modules/gdscript/gdscript_function.h6
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp78
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h25
-rw-r--r--modules/gdscript/gdscript_parser.cpp53
-rw-r--r--modules/gdscript/gdscript_parser.h21
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp12
-rw-r--r--modules/gdscript/gdscript_tokenizer.h10
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp12
-rw-r--r--modules/gdscript/gdscript_vm.cpp151
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp40
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp32
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp30
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h3
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp78
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h6
-rw-r--r--modules/gdscript/language_server/lsp.hpp10
-rw-r--r--modules/gdscript/register_types.cpp72
-rw-r--r--modules/gdscript/register_types.h6
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp27
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.h4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd14
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd58
-rw-r--r--modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out5
-rw-r--r--modules/gdscript/tests/scripts/parser/features/dictionary.out6
-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.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/features/nested_dictionary.out4
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd23
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out5
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.out6
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp4
-rw-r--r--modules/glslang/register_types.cpp13
-rw-r--r--modules/glslang/register_types.h7
-rw-r--r--modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp9
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.cpp21
-rw-r--r--modules/gltf/editor/editor_scene_importer_blend.h18
-rw-r--r--modules/gltf/editor/editor_scene_importer_fbx.cpp24
-rw-r--r--modules/gltf/editor/editor_scene_importer_fbx.h8
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.cpp7
-rw-r--r--modules/gltf/editor/editor_scene_importer_gltf.h4
-rw-r--r--modules/gltf/gltf_animation.cpp2
-rw-r--r--modules/gltf/gltf_animation.h4
-rw-r--r--modules/gltf/gltf_document.cpp216
-rw-r--r--modules/gltf/gltf_document.h18
-rw-r--r--modules/gltf/gltf_skeleton.cpp2
-rw-r--r--modules/gltf/gltf_skeleton.h8
-rw-r--r--modules/gltf/gltf_skin.cpp12
-rw-r--r--modules/gltf/gltf_skin.h4
-rw-r--r--modules/gltf/gltf_state.cpp10
-rw-r--r--modules/gltf/gltf_state.h26
-rw-r--r--modules/gltf/register_types.cpp81
-rw-r--r--modules/gltf/register_types.h6
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp2
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.h36
-rw-r--r--modules/gridmap/grid_map.cpp23
-rw-r--r--modules/gridmap/grid_map.h23
-rw-r--r--modules/gridmap/register_types.cpp15
-rw-r--r--modules/gridmap/register_types.h6
-rw-r--r--modules/hdr/image_loader_hdr.cpp4
-rw-r--r--modules/hdr/image_loader_hdr.h2
-rw-r--r--modules/hdr/register_types.cpp12
-rw-r--r--modules/hdr/register_types.h6
-rw-r--r--modules/jpg/image_loader_jpegd.cpp4
-rw-r--r--modules/jpg/image_loader_jpegd.h2
-rw-r--r--modules/jpg/register_types.cpp12
-rw-r--r--modules/jpg/register_types.h6
-rw-r--r--modules/jsonrpc/jsonrpc.h2
-rw-r--r--modules/jsonrpc/register_types.cpp11
-rw-r--r--modules/jsonrpc/register_types.h6
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp18
-rw-r--r--modules/lightmapper_rd/register_types.cpp11
-rw-r--r--modules/lightmapper_rd/register_types.h6
-rw-r--r--modules/mbedtls/crypto_mbedtls.cpp22
-rw-r--r--modules/mbedtls/packet_peer_mbed_dtls.cpp10
-rw-r--r--modules/mbedtls/register_types.cpp12
-rw-r--r--modules/mbedtls/register_types.h6
-rw-r--r--modules/mbedtls/stream_peer_mbedtls.cpp8
-rw-r--r--modules/meshoptimizer/register_types.cpp12
-rw-r--r--modules/meshoptimizer/register_types.h6
-rw-r--r--modules/minimp3/register_types.cpp11
-rw-r--r--modules/minimp3/register_types.h6
-rw-r--r--modules/minimp3/resource_importer_mp3.cpp11
-rw-r--r--modules/minimp3/resource_importer_mp3.h4
-rw-r--r--modules/mobile_vr/mobile_vr_interface.cpp12
-rw-r--r--modules/mobile_vr/register_types.cpp12
-rw-r--r--modules/mobile_vr/register_types.h6
-rw-r--r--modules/mono/class_db_api_json.cpp46
-rw-r--r--modules/mono/csharp_script.cpp80
-rw-r--r--modules/mono/csharp_script.h38
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs9
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs1
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs3
-rw-r--r--modules/mono/editor/bindings_generator.cpp102
-rw-r--r--modules/mono/editor/bindings_generator.h12
-rw-r--r--modules/mono/editor/code_completion.cpp8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs8
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs4
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs4
-rw-r--r--modules/mono/glue/arguments_vector.h2
-rw-r--r--modules/mono/glue/base_object_glue.cpp6
-rw-r--r--modules/mono/godotsharp_dirs.cpp2
-rw-r--r--modules/mono/managed_callable.cpp2
-rw-r--r--modules/mono/managed_callable.h4
-rw-r--r--modules/mono/mono_gd/gd_mono.cpp29
-rw-r--r--modules/mono/mono_gd/gd_mono.h18
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.cpp4
-rw-r--r--modules/mono/mono_gd/gd_mono_assembly.h8
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h144
-rw-r--r--modules/mono/mono_gd/gd_mono_class.cpp39
-rw-r--r--modules/mono/mono_gd/gd_mono_class.h14
-rw-r--r--modules/mono/mono_gd/gd_mono_field.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_log.cpp28
-rw-r--r--modules/mono/mono_gd/gd_mono_log.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_marshal.h22
-rw-r--r--modules/mono/mono_gd/gd_mono_method.h2
-rw-r--r--modules/mono/mono_gd/gd_mono_property.h6
-rw-r--r--modules/mono/mono_gd/gd_mono_utils.cpp2
-rw-r--r--modules/mono/mono_gd/gd_mono_wasm_m2n.h4
-rw-r--r--modules/mono/register_types.cpp12
-rw-r--r--modules/mono/register_types.h6
-rw-r--r--modules/mono/signal_awaiter_utils.h2
-rw-r--r--modules/mono/utils/osx_utils.cpp4
-rw-r--r--modules/mono/utils/string_utils.cpp4
-rw-r--r--modules/msdfgen/register_types.cpp12
-rw-r--r--modules/msdfgen/register_types.h6
-rw-r--r--modules/navigation/editor/navigation_mesh_editor_plugin.h14
-rw-r--r--modules/navigation/godot_navigation_server.cpp108
-rw-r--r--modules/navigation/godot_navigation_server.h57
-rw-r--r--modules/navigation/nav_map.cpp36
-rw-r--r--modules/navigation/nav_map.h9
-rw-r--r--modules/navigation/nav_utils.h14
-rw-r--r--modules/navigation/navigation_mesh_generator.cpp132
-rw-r--r--modules/navigation/navigation_mesh_generator.h1
-rw-r--r--modules/navigation/register_types.cpp22
-rw-r--r--modules/navigation/register_types.h6
-rw-r--r--modules/noise/SCsub1
-rw-r--r--modules/noise/doc_classes/FastNoiseLite.xml8
-rw-r--r--modules/noise/doc_classes/Noise.xml18
-rw-r--r--modules/noise/doc_classes/NoiseTexture.xml11
-rw-r--r--modules/noise/editor/noise_editor_plugin.cpp149
-rw-r--r--modules/noise/editor/noise_editor_plugin.h49
-rw-r--r--modules/noise/fastnoise_lite.cpp237
-rw-r--r--modules/noise/fastnoise_lite.h63
-rw-r--r--modules/noise/noise.cpp56
-rw-r--r--modules/noise/noise.h19
-rw-r--r--modules/noise/noise_texture.cpp99
-rw-r--r--modules/noise/noise_texture.h20
-rw-r--r--modules/noise/register_types.cpp26
-rw-r--r--modules/noise/register_types.h6
-rw-r--r--modules/ogg/register_types.cpp12
-rw-r--r--modules/ogg/register_types.h6
-rw-r--r--modules/openxr/SCsub3
-rw-r--r--modules/openxr/action_map/openxr_action.cpp23
-rw-r--r--modules/openxr/action_map/openxr_action.h29
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp260
-rw-r--r--modules/openxr/action_map/openxr_action_map.h34
-rw-r--r--modules/openxr/action_map/openxr_action_set.cpp44
-rw-r--r--modules/openxr/action_map/openxr_action_set.h25
-rw-r--r--modules/openxr/action_map/openxr_defs.cpp493
-rw-r--r--modules/openxr/action_map/openxr_defs.h103
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile.cpp61
-rw-r--r--modules/openxr/action_map/openxr_interaction_profile.h40
-rw-r--r--modules/openxr/doc_classes/OpenXRActionMap.xml42
-rw-r--r--modules/openxr/doc_classes/OpenXRActionSet.xml9
-rw-r--r--modules/openxr/doc_classes/OpenXRIPBinding.xml33
-rw-r--r--modules/openxr/doc_classes/OpenXRInteractionProfile.xml15
-rw-r--r--modules/openxr/editor/SCsub5
-rw-r--r--modules/openxr/editor/openxr_action_editor.cpp112
-rw-r--r--modules/openxr/editor/openxr_action_editor.h67
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp370
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.h100
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp218
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.h88
-rw-r--r--modules/openxr/editor/openxr_editor_plugin.cpp58
-rw-r--r--modules/openxr/editor/openxr_editor_plugin.h53
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.cpp274
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.h83
-rw-r--r--modules/openxr/editor/openxr_select_action_dialog.cpp135
-rw-r--r--modules/openxr/editor/openxr_select_action_dialog.h67
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp125
-rw-r--r--modules/openxr/editor/openxr_select_interaction_profile_dialog.h66
-rw-r--r--modules/openxr/extensions/openxr_extension_wrapper.h9
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.cpp18
-rw-r--r--modules/openxr/extensions/openxr_vulkan_extension.h10
-rw-r--r--modules/openxr/openxr_api.cpp59
-rw-r--r--modules/openxr/openxr_api.h22
-rw-r--r--modules/openxr/openxr_interface.cpp2
-rw-r--r--modules/openxr/register_types.cpp78
-rw-r--r--modules/openxr/register_types.h7
-rw-r--r--modules/raycast/lightmap_raycaster.cpp6
-rw-r--r--modules/raycast/lightmap_raycaster.h6
-rw-r--r--modules/raycast/raycast_occlusion_cull.cpp23
-rw-r--r--modules/raycast/raycast_occlusion_cull.h8
-rw-r--r--modules/raycast/register_types.cpp12
-rw-r--r--modules/raycast/register_types.h6
-rw-r--r--modules/raycast/static_raycaster.cpp6
-rw-r--r--modules/raycast/static_raycaster.h4
-rw-r--r--modules/regex/regex.cpp8
-rw-r--r--modules/regex/regex.h6
-rw-r--r--modules/regex/register_types.cpp11
-rw-r--r--modules/regex/register_types.h6
-rw-r--r--modules/register_module_types.h14
-rw-r--r--modules/squish/register_types.cpp12
-rw-r--r--modules/squish/register_types.h6
-rw-r--r--modules/svg/image_loader_svg.cpp4
-rw-r--r--modules/svg/image_loader_svg.h2
-rw-r--r--modules/svg/register_types.cpp12
-rw-r--r--modules/svg/register_types.h6
-rw-r--r--modules/text_server_adv/register_types.cpp19
-rw-r--r--modules/text_server_adv/register_types.h12
-rw-r--r--modules/text_server_adv/script_iterator.cpp4
-rw-r--r--modules/text_server_adv/text_server_adv.cpp390
-rw-r--r--modules/text_server_adv/text_server_adv.h33
-rw-r--r--modules/text_server_fb/register_types.cpp19
-rw-r--r--modules/text_server_fb/register_types.h12
-rw-r--r--modules/text_server_fb/text_server_fb.cpp321
-rw-r--r--modules/text_server_fb/text_server_fb.h33
-rw-r--r--modules/tga/image_loader_tga.cpp11
-rw-r--r--modules/tga/image_loader_tga.h2
-rw-r--r--modules/tga/register_types.cpp12
-rw-r--r--modules/tga/register_types.h6
-rw-r--r--modules/theora/register_types.cpp12
-rw-r--r--modules/theora/register_types.h6
-rw-r--r--modules/theora/video_stream_theora.cpp34
-rw-r--r--modules/theora/video_stream_theora.h8
-rw-r--r--modules/tinyexr/image_loader_tinyexr.cpp8
-rw-r--r--modules/tinyexr/image_loader_tinyexr.h2
-rw-r--r--modules/tinyexr/image_saver_tinyexr.cpp4
-rw-r--r--modules/tinyexr/register_types.cpp12
-rw-r--r--modules/tinyexr/register_types.h6
-rw-r--r--modules/upnp/register_types.cpp11
-rw-r--r--modules/upnp/register_types.h6
-rw-r--r--modules/vhacd/register_types.cpp12
-rw-r--r--modules/vhacd/register_types.h6
-rw-r--r--modules/visual_script/doc_classes/VisualScript.xml2
-rw-r--r--modules/visual_script/editor/visual_script_editor.cpp130
-rw-r--r--modules/visual_script/editor/visual_script_editor.h21
-rw-r--r--modules/visual_script/editor/visual_script_property_selector.cpp97
-rw-r--r--modules/visual_script/editor/visual_script_property_selector.h62
-rw-r--r--modules/visual_script/register_types.cpp171
-rw-r--r--modules/visual_script/register_types.h6
-rw-r--r--modules/visual_script/visual_script.cpp238
-rw-r--r--modules/visual_script/visual_script.h34
-rw-r--r--modules/visual_script/visual_script_builtin_funcs.cpp10
-rw-r--r--modules/visual_script/visual_script_expression.cpp8
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp58
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp40
-rw-r--r--modules/visual_script/visual_script_nodes.cpp172
-rw-r--r--modules/visual_script/visual_script_yield_nodes.cpp16
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp3
-rw-r--r--modules/vorbis/register_types.cpp12
-rw-r--r--modules/vorbis/register_types.h6
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.cpp11
-rw-r--r--modules/vorbis/resource_importer_ogg_vorbis.h4
-rw-r--r--modules/webp/image_loader_webp.cpp4
-rw-r--r--modules/webp/image_loader_webp.h2
-rw-r--r--modules/webp/register_types.cpp12
-rw-r--r--modules/webp/register_types.h6
-rw-r--r--modules/webrtc/register_types.cpp12
-rw-r--r--modules/webrtc/register_types.h6
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.cpp36
-rw-r--r--modules/webrtc/webrtc_multiplayer_peer.h2
-rw-r--r--modules/webrtc/webrtc_peer_connection_js.h18
-rw-r--r--modules/websocket/doc_classes/WebSocketServer.xml7
-rw-r--r--modules/websocket/emws_client.h18
-rw-r--r--modules/websocket/emws_peer.h26
-rw-r--r--modules/websocket/emws_server.cpp3
-rw-r--r--modules/websocket/emws_server.h23
-rw-r--r--modules/websocket/register_types.cpp34
-rw-r--r--modules/websocket/register_types.h6
-rw-r--r--modules/websocket/remote_debugger_peer_websocket.h16
-rw-r--r--modules/websocket/websocket_multiplayer_peer.h2
-rw-r--r--modules/websocket/websocket_server.cpp1
-rw-r--r--modules/websocket/websocket_server.h1
-rw-r--r--modules/websocket/wsl_client.cpp29
-rw-r--r--modules/websocket/wsl_client.h23
-rw-r--r--modules/websocket/wsl_peer.cpp10
-rw-r--r--modules/websocket/wsl_peer.h28
-rw-r--r--modules/websocket/wsl_server.cpp17
-rw-r--r--modules/websocket/wsl_server.h26
-rw-r--r--modules/webxr/register_types.cpp12
-rw-r--r--modules/webxr/register_types.h6
-rw-r--r--modules/webxr/webxr_interface_js.cpp22
-rw-r--r--modules/xatlas_unwrap/register_types.cpp11
-rw-r--r--modules/xatlas_unwrap/register_types.h6
346 files changed, 7692 insertions, 3054 deletions
diff --git a/modules/basis_universal/register_types.cpp b/modules/basis_universal/register_types.cpp
index 4c2ebe603f..e80d453df7 100644
--- a/modules/basis_universal/register_types.cpp
+++ b/modules/basis_universal/register_types.cpp
@@ -244,7 +244,7 @@ static Ref<Image> basis_universal_unpacker_ptr(const uint8_t *p_data, int p_size
bool ret = tr.transcode_image_level(ptr, size, 0, i, dst + ofs, level.m_total_blocks - i, format);
if (!ret) {
- printf("failed! on level %i\n", i);
+ printf("failed! on level %u\n", i);
break;
};
@@ -266,7 +266,11 @@ static Ref<Image> basis_universal_unpacker(const Vector<uint8_t> &p_buffer) {
return basis_universal_unpacker_ptr(r, size);
}
-void register_basis_universal_types() {
+void initialize_basis_universal_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
using namespace basisu;
using namespace basist;
@@ -277,7 +281,11 @@ void register_basis_universal_types() {
Image::basis_universal_unpacker_ptr = basis_universal_unpacker_ptr;
}
-void unregister_basis_universal_types() {
+void uninitialize_basis_universal_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
Image::basis_universal_packer = nullptr;
#endif
diff --git a/modules/basis_universal/register_types.h b/modules/basis_universal/register_types.h
index 7275c2ebb7..68d5dd64f3 100644
--- a/modules/basis_universal/register_types.h
+++ b/modules/basis_universal/register_types.h
@@ -31,7 +31,9 @@
#ifndef BASIS_UNIVERSAL_REGISTER_TYPES_H
#define BASIS_UNIVERSAL_REGISTER_TYPES_H
-void register_basis_universal_types();
-void unregister_basis_universal_types();
+#include "modules/register_module_types.h"
+
+void initialize_basis_universal_module(ModuleInitializationLevel p_level);
+void uninitialize_basis_universal_module(ModuleInitializationLevel p_level);
#endif // BASIS_UNIVERSAL_REGISTER_TYPES_H
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index ad2c7d6a3e..8813c3827a 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -200,8 +200,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
return err;
}
-Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
- bool p_force_linear, float p_scale) {
+Error ImageLoaderBMP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
bmp_header_s bmp_header;
Error err = ERR_INVALID_DATA;
@@ -241,7 +240,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
case BI_CMYKRLE8:
case BI_CMYKRLE4: {
// Stop parsing.
- f->close();
ERR_FAIL_V_MSG(ERR_UNAVAILABLE,
vformat("Compressed BMP files are not supported: %s", f->get_path()));
} break;
@@ -283,7 +281,6 @@ Error ImageLoaderBMP::load_image(Ref<Image> p_image, FileAccess *f,
err = convert_to_image(p_image, bmp_buffer_r,
bmp_color_table_r, color_table_size, bmp_header);
}
- f->close();
}
}
return err;
@@ -294,12 +291,14 @@ void ImageLoaderBMP::get_recognized_extensions(List<String> *p_extensions) const
}
static Ref<Image> _bmp_mem_loader_func(const uint8_t *p_bmp, int p_size) {
- FileAccessMemory memfile;
- Error open_memfile_error = memfile.open_custom(p_bmp, p_size);
+ Ref<FileAccessMemory> memfile;
+ memfile.instantiate();
+ Error open_memfile_error = memfile->open_custom(p_bmp, p_size);
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for BMP image buffer.");
+
Ref<Image> img;
img.instantiate();
- Error load_error = ImageLoaderBMP().load_image(img, &memfile, false, 1.0f);
+ Error load_error = ImageLoaderBMP().load_image(img, memfile, false, 1.0f);
ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load BMP image.");
return img;
}
diff --git a/modules/bmp/image_loader_bmp.h b/modules/bmp/image_loader_bmp.h
index 9c9a16a9f5..63dee0a969 100644
--- a/modules/bmp/image_loader_bmp.h
+++ b/modules/bmp/image_loader_bmp.h
@@ -83,8 +83,7 @@ protected:
const bmp_header_s &p_header);
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f,
- bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderBMP();
};
diff --git a/modules/bmp/register_types.cpp b/modules/bmp/register_types.cpp
index 13e44099e5..7c4a2085b2 100644
--- a/modules/bmp/register_types.cpp
+++ b/modules/bmp/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderBMP *image_loader_bmp = nullptr;
-void register_bmp_types() {
+void initialize_bmp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_bmp = memnew(ImageLoaderBMP);
ImageLoader::add_image_format_loader(image_loader_bmp);
}
-void unregister_bmp_types() {
+void uninitialize_bmp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_bmp);
}
diff --git a/modules/bmp/register_types.h b/modules/bmp/register_types.h
index 1e53f4c2f7..45c8499c58 100644
--- a/modules/bmp/register_types.h
+++ b/modules/bmp/register_types.h
@@ -31,7 +31,9 @@
#ifndef BMP_REGISTER_TYPES_H
#define BMP_REGISTER_TYPES_H
-void register_bmp_types();
-void unregister_bmp_types();
+#include "modules/register_module_types.h"
+
+void initialize_bmp_module(ModuleInitializationLevel p_level);
+void uninitialize_bmp_module(ModuleInitializationLevel p_level);
#endif // BMP_REGISTER_TYPES_H
diff --git a/modules/camera/register_types.cpp b/modules/camera/register_types.cpp
index b0b1276436..98a4b5ca1a 100644
--- a/modules/camera/register_types.cpp
+++ b/modules/camera/register_types.cpp
@@ -37,7 +37,11 @@
#include "camera_osx.h"
#endif
-void register_camera_types() {
+void initialize_camera_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#if defined(WINDOWS_ENABLED)
CameraServer::make_default<CameraWindows>();
#endif
@@ -46,5 +50,8 @@ void register_camera_types() {
#endif
}
-void unregister_camera_types() {
+void uninitialize_camera_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/camera/register_types.h b/modules/camera/register_types.h
index 5ee7aec886..4ac4426588 100644
--- a/modules/camera/register_types.h
+++ b/modules/camera/register_types.h
@@ -31,7 +31,9 @@
#ifndef CAMERA_REGISTER_TYPES_H
#define CAMERA_REGISTER_TYPES_H
-void register_camera_types();
-void unregister_camera_types();
+#include "modules/register_module_types.h"
+
+void initialize_camera_module(ModuleInitializationLevel p_level);
+void uninitialize_camera_module(ModuleInitializationLevel p_level);
#endif // CAMERA_REGISTER_TYPES_H
diff --git a/modules/csg/csg.cpp b/modules/csg/csg.cpp
index 82dc4a4175..93533e1690 100644
--- a/modules/csg/csg.cpp
+++ b/modules/csg/csg.cpp
@@ -194,7 +194,7 @@ void CSGBrush::_regen_face_aabbs() {
}
}
-void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_invert_faces) {
+void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uvs, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials, const Vector<bool> &p_flip_faces) {
faces.clear();
int vc = p_vertices.size();
@@ -208,10 +208,10 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<
const bool *rs = p_smooth.ptr();
int mc = p_materials.size();
const Ref<Material> *rm = p_materials.ptr();
- int ic = p_invert_faces.size();
- const bool *ri = p_invert_faces.ptr();
+ int ic = p_flip_faces.size();
+ const bool *ri = p_flip_faces.ptr();
- Map<Ref<Material>, int> material_map;
+ HashMap<Ref<Material>, int> material_map;
faces.resize(p_vertices.size() / 3);
@@ -242,10 +242,10 @@ void CSGBrush::build_from_faces(const Vector<Vector3> &p_vertices, const Vector<
if (mc == vc / 3) {
Ref<Material> mat = rm[i];
if (mat.is_valid()) {
- const Map<Ref<Material>, int>::Element *E = material_map.find(mat);
+ HashMap<Ref<Material>, int>::ConstIterator E = material_map.find(mat);
if (E) {
- f.material = E->get();
+ f.material = E->value;
} else {
f.material = material_map.size();
material_map[mat] = f.material;
@@ -1336,9 +1336,9 @@ CSGBrushOperation::Build2DFaces::Build2DFaces(const CSGBrush &p_brush, int p_fac
plane = Plane(points_3D[0], points_3D[1], points_3D[2]);
to_3D.origin = points_3D[0];
- to_3D.basis.set_axis(2, plane.normal);
- to_3D.basis.set_axis(0, (points_3D[1] - points_3D[2]).normalized());
- to_3D.basis.set_axis(1, to_3D.basis.get_axis(0).cross(to_3D.basis.get_axis(2)).normalized());
+ to_3D.basis.set_column(2, plane.normal);
+ to_3D.basis.set_column(0, (points_3D[1] - points_3D[2]).normalized());
+ to_3D.basis.set_column(1, to_3D.basis.get_column(0).cross(to_3D.basis.get_column(2)).normalized());
to_2D = to_3D.affine_inverse();
Face2D face;
@@ -1387,13 +1387,13 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
}
// Ensure B has points either side of or in the plane of A.
- int in_plane_count = 0, over_count = 0, under_count = 0;
+ int over_count = 0, under_count = 0;
Plane plane_a(vertices_a[0], vertices_a[1], vertices_a[2]);
ERR_FAIL_COND_MSG(plane_a.normal == Vector3(), "Couldn't form plane from Brush A face.");
for (int i = 0; i < 3; i++) {
if (plane_a.has_point(vertices_b[i])) {
- in_plane_count++;
+ // In plane.
} else if (plane_a.is_point_over(vertices_b[i])) {
over_count++;
} else {
@@ -1406,7 +1406,6 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
}
// Ensure A has points either side of or in the plane of B.
- in_plane_count = 0;
over_count = 0;
under_count = 0;
Plane plane_b(vertices_b[0], vertices_b[1], vertices_b[2]);
@@ -1414,7 +1413,7 @@ void CSGBrushOperation::update_faces(const CSGBrush &p_brush_a, const int p_face
for (int i = 0; i < 3; i++) {
if (plane_b.has_point(vertices_a[i])) {
- in_plane_count++;
+ // In plane.
} else if (plane_b.is_point_over(vertices_a[i])) {
over_count++;
} else {
diff --git a/modules/csg/csg.h b/modules/csg/csg.h
index 9ff7b13a44..53a9e5d722 100644
--- a/modules/csg/csg.h
+++ b/modules/csg/csg.h
@@ -38,8 +38,8 @@
#include "core/math/vector3.h"
#include "core/object/ref_counted.h"
#include "core/templates/list.h"
-#include "core/templates/map.h"
#include "core/templates/oa_hash_map.h"
+#include "core/templates/rb_map.h"
#include "core/templates/vector.h"
#include "scene/resources/material.h"
@@ -139,8 +139,8 @@ struct CSGBrushOperation {
Vector<Vector3> points;
Vector<Face> faces;
- Map<Ref<Material>, int> materials;
- Map<Vector3, int> vertex_map;
+ HashMap<Ref<Material>, int> materials;
+ HashMap<Vector3, int> vertex_map;
OAHashMap<VertexKey, int, VertexKeyHash> snap_cache;
float vertex_snap = 0.0;
@@ -184,8 +184,8 @@ struct CSGBrushOperation {
};
struct Build2DFaceCollection {
- Map<int, Build2DFaces> build2DFacesA;
- Map<int, Build2DFaces> build2DFacesB;
+ HashMap<int, Build2DFaces> build2DFacesA;
+ HashMap<int, Build2DFaces> build2DFacesB;
};
void update_faces(const CSGBrush &p_brush_a, const int p_face_idx_a, const CSGBrush &p_brush_b, const int p_face_idx_b, Build2DFaceCollection &p_collection, float p_vertex_snap);
diff --git a/modules/csg/csg_shape.cpp b/modules/csg/csg_shape.cpp
index be9bf9538f..a5b3db89d9 100644
--- a/modules/csg/csg_shape.cpp
+++ b/modules/csg/csg_shape.cpp
@@ -682,7 +682,7 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver
int ic = invert.size();
bool *w = invert.ptrw();
for (int i = 0; i < ic; i++) {
- w[i] = invert_faces;
+ w[i] = flip_faces;
}
}
brush->build_from_faces(p_vertices, p_uv, p_smooth, p_materials, invert);
@@ -691,28 +691,28 @@ CSGBrush *CSGPrimitive3D::_create_brush_from_arrays(const Vector<Vector3> &p_ver
}
void CSGPrimitive3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_invert_faces", "invert_faces"), &CSGPrimitive3D::set_invert_faces);
- ClassDB::bind_method(D_METHOD("is_inverting_faces"), &CSGPrimitive3D::is_inverting_faces);
+ ClassDB::bind_method(D_METHOD("set_flip_faces", "flip_faces"), &CSGPrimitive3D::set_flip_faces);
+ ClassDB::bind_method(D_METHOD("get_flip_faces"), &CSGPrimitive3D::get_flip_faces);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert_faces"), "set_invert_faces", "is_inverting_faces");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flip_faces"), "set_flip_faces", "get_flip_faces");
}
-void CSGPrimitive3D::set_invert_faces(bool p_invert) {
- if (invert_faces == p_invert) {
+void CSGPrimitive3D::set_flip_faces(bool p_invert) {
+ if (flip_faces == p_invert) {
return;
}
- invert_faces = p_invert;
+ flip_faces = p_invert;
_make_dirty();
}
-bool CSGPrimitive3D::is_inverting_faces() {
- return invert_faces;
+bool CSGPrimitive3D::get_flip_faces() {
+ return flip_faces;
}
CSGPrimitive3D::CSGPrimitive3D() {
- invert_faces = false;
+ flip_faces = false;
}
/////////////////////
@@ -921,7 +921,7 @@ CSGBrush *CSGSphere3D::_build_brush() {
int face_count = rings * radial_segments * 2 - radial_segments * 2;
- bool invert_val = is_inverting_faces();
+ bool invert_val = get_flip_faces();
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1110,7 +1110,7 @@ Ref<Material> CSGSphere3D::get_material() const {
CSGSphere3D::CSGSphere3D() {
// defaults
- radius = 1.0;
+ radius = 0.5;
radial_segments = 12;
rings = 6;
smooth_faces = true;
@@ -1125,7 +1125,7 @@ CSGBrush *CSGBox3D::_build_brush() {
int face_count = 12; //it's a cube..
- bool invert_val = is_inverting_faces();
+ bool invert_val = get_flip_faces();
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1258,7 +1258,7 @@ CSGBrush *CSGCylinder3D::_build_brush() {
int face_count = sides * (cone ? 1 : 2) + sides + (cone ? 0 : sides);
- bool invert_val = is_inverting_faces();
+ bool invert_val = get_flip_faces();
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1503,7 +1503,7 @@ CSGBrush *CSGTorus3D::_build_brush() {
int face_count = ring_sides * sides * 2;
- bool invert_val = is_inverting_faces();
+ bool invert_val = get_flip_faces();
Ref<Material> material = get_material();
Vector<Vector3> faces;
@@ -1881,7 +1881,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
smoothw[face] = false;
materialsw[face] = material;
- invertw[face] = invert_faces;
+ invertw[face] = flip_faces;
face++;
}
}
@@ -1986,7 +1986,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
uvsw[face * 3 + 2] = u[2];
smoothw[face] = smooth_faces;
- invertw[face] = invert_faces;
+ invertw[face] = flip_faces;
materialsw[face] = material;
face++;
@@ -2001,7 +2001,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
uvsw[face * 3 + 2] = u[0];
smoothw[face] = smooth_faces;
- invertw[face] = invert_faces;
+ invertw[face] = flip_faces;
materialsw[face] = material;
face++;
@@ -2026,7 +2026,7 @@ CSGBrush *CSGPolygon3D::_build_brush() {
smoothw[face] = false;
materialsw[face] = material;
- invertw[face] = invert_faces;
+ invertw[face] = flip_faces;
face++;
}
}
diff --git a/modules/csg/csg_shape.h b/modules/csg/csg_shape.h
index 4721d0c11c..0eaf5c3727 100644
--- a/modules/csg/csg_shape.h
+++ b/modules/csg/csg_shape.h
@@ -171,13 +171,13 @@ class CSGPrimitive3D : public CSGShape3D {
GDCLASS(CSGPrimitive3D, CSGShape3D);
protected:
- bool invert_faces;
+ bool flip_faces;
CSGBrush *_create_brush_from_arrays(const Vector<Vector3> &p_vertices, const Vector<Vector2> &p_uv, const Vector<bool> &p_smooth, const Vector<Ref<Material>> &p_materials);
static void _bind_methods();
public:
- void set_invert_faces(bool p_invert);
- bool is_inverting_faces();
+ void set_flip_faces(bool p_invert);
+ bool get_flip_faces();
CSGPrimitive3D();
};
@@ -368,7 +368,7 @@ private:
PathRotation path_rotation;
bool path_local;
- Path3D *path;
+ Path3D *path = nullptr;
bool smooth_faces;
bool path_continuous_u;
diff --git a/modules/csg/doc_classes/CSGPrimitive3D.xml b/modules/csg/doc_classes/CSGPrimitive3D.xml
index 39f4fa320d..6ea413c991 100644
--- a/modules/csg/doc_classes/CSGPrimitive3D.xml
+++ b/modules/csg/doc_classes/CSGPrimitive3D.xml
@@ -11,8 +11,8 @@
<link title="Prototyping levels with CSG">$DOCS_URL/tutorials/3d/csg_tools.html</link>
</tutorials>
<members>
- <member name="invert_faces" type="bool" setter="set_invert_faces" getter="is_inverting_faces" default="false">
- Invert the faces of the mesh.
+ <member name="flip_faces" type="bool" setter="set_flip_faces" getter="get_flip_faces" default="false">
+ If set, the order of the vertices in each triangle are reversed resulting in the backside of the mesh being drawn.
</member>
</members>
</class>
diff --git a/modules/csg/doc_classes/CSGSphere3D.xml b/modules/csg/doc_classes/CSGSphere3D.xml
index 227f620a4e..d2f985b3a2 100644
--- a/modules/csg/doc_classes/CSGSphere3D.xml
+++ b/modules/csg/doc_classes/CSGSphere3D.xml
@@ -17,7 +17,7 @@
<member name="radial_segments" type="int" setter="set_radial_segments" getter="get_radial_segments" default="12">
Number of vertical slices for the sphere.
</member>
- <member name="radius" type="float" setter="set_radius" getter="get_radius" default="1.0">
+ <member name="radius" type="float" setter="set_radius" getter="get_radius" default="0.5">
Radius of the sphere.
</member>
<member name="rings" type="int" setter="set_rings" getter="get_rings" default="6">
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index be29810252..4d972e46c6 100644
--- a/modules/csg/editor/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -347,14 +347,12 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
- Array csg_meshes = cs->get_meshes();
- if (csg_meshes.size() != 2) {
- return;
- }
-
- Ref<Mesh> csg_mesh = csg_meshes[1];
- if (csg_mesh.is_valid()) {
- p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
+ if (cs->is_root_shape()) {
+ Array csg_meshes = cs->get_meshes();
+ Ref<Mesh> csg_mesh = csg_meshes[1];
+ if (csg_mesh.is_valid()) {
+ p_gizmo->add_collision_triangles(csg_mesh->generate_triangle_mesh());
+ }
}
if (p_gizmo->is_selected()) {
diff --git a/modules/csg/register_types.cpp b/modules/csg/register_types.cpp
index 72ed027dc9..9b5888dafe 100644
--- a/modules/csg/register_types.cpp
+++ b/modules/csg/register_types.cpp
@@ -38,23 +38,29 @@
#include "editor/csg_gizmos.h"
#endif
-void register_csg_types() {
- GDREGISTER_ABSTRACT_CLASS(CSGShape3D);
- GDREGISTER_ABSTRACT_CLASS(CSGPrimitive3D);
- GDREGISTER_CLASS(CSGMesh3D);
- GDREGISTER_CLASS(CSGSphere3D);
- GDREGISTER_CLASS(CSGBox3D);
- GDREGISTER_CLASS(CSGCylinder3D);
- GDREGISTER_CLASS(CSGTorus3D);
- GDREGISTER_CLASS(CSGPolygon3D);
- GDREGISTER_CLASS(CSGCombiner3D);
-
+void initialize_csg_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_ABSTRACT_CLASS(CSGShape3D);
+ GDREGISTER_ABSTRACT_CLASS(CSGPrimitive3D);
+ GDREGISTER_CLASS(CSGMesh3D);
+ GDREGISTER_CLASS(CSGSphere3D);
+ GDREGISTER_CLASS(CSGBox3D);
+ GDREGISTER_CLASS(CSGCylinder3D);
+ GDREGISTER_CLASS(CSGTorus3D);
+ GDREGISTER_CLASS(CSGPolygon3D);
+ GDREGISTER_CLASS(CSGCombiner3D);
+ }
#ifdef TOOLS_ENABLED
- EditorPlugins::add_by_type<EditorPluginCSG>();
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<EditorPluginCSG>();
+ }
#endif
}
-void unregister_csg_types() {
+void uninitialize_csg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
#endif // _3D_DISABLED
diff --git a/modules/csg/register_types.h b/modules/csg/register_types.h
index 59d84dd52a..ec65adde9c 100644
--- a/modules/csg/register_types.h
+++ b/modules/csg/register_types.h
@@ -31,7 +31,9 @@
#ifndef CSG_REGISTER_TYPES_H
#define CSG_REGISTER_TYPES_H
-void register_csg_types();
-void unregister_csg_types();
+#include "modules/register_module_types.h"
+
+void initialize_csg_module(ModuleInitializationLevel p_level);
+void uninitialize_csg_module(ModuleInitializationLevel p_level);
#endif // CSG_REGISTER_TYPES_H
diff --git a/modules/cvtt/image_compress_cvtt.cpp b/modules/cvtt/image_compress_cvtt.cpp
index d18340a2c8..a7cfcaa262 100644
--- a/modules/cvtt/image_compress_cvtt.cpp
+++ b/modules/cvtt/image_compress_cvtt.cpp
@@ -46,7 +46,7 @@ struct CVTTCompressionJobParams {
};
struct CVTTCompressionRowTask {
- const uint8_t *in_mm_bytes;
+ const uint8_t *in_mm_bytes = nullptr;
uint8_t *out_mm_bytes = nullptr;
int y_start = 0;
int width = 0;
@@ -55,7 +55,7 @@ struct CVTTCompressionRowTask {
struct CVTTCompressionJobQueue {
CVTTCompressionJobParams job_params;
- const CVTTCompressionRowTask *job_tasks;
+ const CVTTCompressionRowTask *job_tasks = nullptr;
uint32_t num_tasks = 0;
SafeNumeric<uint32_t> current_task;
};
diff --git a/modules/cvtt/register_types.cpp b/modules/cvtt/register_types.cpp
index 13903f700b..ff22c0f53e 100644
--- a/modules/cvtt/register_types.cpp
+++ b/modules/cvtt/register_types.cpp
@@ -34,11 +34,19 @@
#include "image_compress_cvtt.h"
-void register_cvtt_types() {
+void initialize_cvtt_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Image::set_compress_bptc_func(image_compress_cvtt);
Image::_image_decompress_bptc = image_decompress_cvtt;
}
-void unregister_cvtt_types() {}
+void uninitialize_cvtt_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
#endif
diff --git a/modules/cvtt/register_types.h b/modules/cvtt/register_types.h
index 9cbca75c7b..38a375eb44 100644
--- a/modules/cvtt/register_types.h
+++ b/modules/cvtt/register_types.h
@@ -33,8 +33,10 @@
#ifdef TOOLS_ENABLED
-void register_cvtt_types();
-void unregister_cvtt_types();
+#include "modules/register_module_types.h"
+
+void initialize_cvtt_module(ModuleInitializationLevel p_level);
+void uninitialize_cvtt_module(ModuleInitializationLevel p_level);
#endif // TOOLS_ENABLED
diff --git a/modules/dds/register_types.cpp b/modules/dds/register_types.cpp
index 15a93050ee..e819c92dd3 100644
--- a/modules/dds/register_types.cpp
+++ b/modules/dds/register_types.cpp
@@ -34,12 +34,20 @@
static Ref<ResourceFormatDDS> resource_loader_dds;
-void register_dds_types() {
+void initialize_dds_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
resource_loader_dds.instantiate();
ResourceLoader::add_resource_format_loader(resource_loader_dds);
}
-void unregister_dds_types() {
+void uninitialize_dds_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
ResourceLoader::remove_resource_format_loader(resource_loader_dds);
resource_loader_dds.unref();
}
diff --git a/modules/dds/register_types.h b/modules/dds/register_types.h
index d676346e02..3cd154d576 100644
--- a/modules/dds/register_types.h
+++ b/modules/dds/register_types.h
@@ -31,7 +31,9 @@
#ifndef DDS_REGISTER_TYPES_H
#define DDS_REGISTER_TYPES_H
-void register_dds_types();
-void unregister_dds_types();
+#include "modules/register_module_types.h"
+
+void initialize_dds_module(ModuleInitializationLevel p_level);
+void uninitialize_dds_module(ModuleInitializationLevel p_level);
#endif // DDS_REGISTER_TYPES_H
diff --git a/modules/dds/texture_loader_dds.cpp b/modules/dds/texture_loader_dds.cpp
index 7bfe849106..2c0e604e66 100644
--- a/modules/dds/texture_loader_dds.cpp
+++ b/modules/dds/texture_loader_dds.cpp
@@ -68,7 +68,7 @@ enum DDSFormat {
};
struct DDSFormatInfo {
- const char *name;
+ const char *name = nullptr;
bool compressed = false;
bool palette = false;
uint32_t divisor = 0;
@@ -94,23 +94,23 @@ static const DDSFormatInfo dds_format_info[DDS_MAX] = {
{ "GRAYSCALE_ALPHA", false, false, 1, 2, Image::FORMAT_LA8 }
};
-RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatDDS::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
- return RES();
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (f.is_null()) {
+ return Ref<Resource>();
}
- FileAccessRef fref(f);
+ Ref<FileAccess> fref(f);
if (r_error) {
*r_error = ERR_FILE_CORRUPT;
}
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Unable to open DDS texture file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Unable to open DDS texture file '" + p_path + "'.");
uint32_t magic = f->get_32();
uint32_t hsize = f->get_32();
@@ -131,7 +131,7 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
// We don't check DDSD_CAPS or DDSD_PIXELFORMAT, as they're mandatory when writing,
// but non-mandatory when reading (as some writers don't set them)...
if (magic != DDS_MAGIC || hsize != 124) {
- ERR_FAIL_V_MSG(RES(), "Invalid or unsupported DDS texture file '" + p_path + "'.");
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Invalid or unsupported DDS texture file '" + p_path + "'.");
}
/* uint32_t format_size = */ f->get_32();
@@ -204,7 +204,7 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
dds_format = DDS_BGR565;
} else {
printf("unrecognized fourcc %x format_flags: %x - rgbbits %i - red_mask %x green mask %x blue mask %x alpha mask %x\n", format_fourcc, format_flags, format_rgb_bits, format_red_mask, format_green_mask, format_blue_mask, format_alpha_mask);
- ERR_FAIL_V_MSG(RES(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'.");
+ ERR_FAIL_V_MSG(Ref<Resource>(), "Unrecognized or unsupported color layout in DDS '" + p_path + "'.");
}
if (!(flags & DDSD_MIPMAPCOUNT)) {
@@ -221,8 +221,8 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
//compressed bc
uint32_t size = MAX(info.divisor, w) / info.divisor * MAX(info.divisor, h) / info.divisor * info.block_size;
- ERR_FAIL_COND_V(size != pitch, RES());
- ERR_FAIL_COND_V(!(flags & DDSD_LINEARSIZE), RES());
+ ERR_FAIL_COND_V(size != pitch, Ref<Resource>());
+ ERR_FAIL_COND_V(!(flags & DDSD_LINEARSIZE), Ref<Resource>());
for (uint32_t i = 1; i < mipmaps; i++) {
w = MAX(1u, w >> 1);
@@ -238,11 +238,11 @@ RES ResourceFormatDDS::load(const String &p_path, const String &p_original_path,
} else if (info.palette) {
//indexed
- ERR_FAIL_COND_V(!(flags & DDSD_PITCH), RES());
- ERR_FAIL_COND_V(format_rgb_bits != 8, RES());
+ ERR_FAIL_COND_V(!(flags & DDSD_PITCH), Ref<Resource>());
+ ERR_FAIL_COND_V(format_rgb_bits != 8, Ref<Resource>());
uint32_t size = pitch * height;
- ERR_FAIL_COND_V(size != width * height * info.block_size, RES());
+ ERR_FAIL_COND_V(size != width * height * info.block_size, Ref<Resource>());
uint8_t palette[256 * 4];
f->get_buffer(palette, 256 * 4);
diff --git a/modules/dds/texture_loader_dds.h b/modules/dds/texture_loader_dds.h
index 25ded4e168..701f8f4a13 100644
--- a/modules/dds/texture_loader_dds.h
+++ b/modules/dds/texture_loader_dds.h
@@ -36,7 +36,7 @@
class ResourceFormatDDS : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/denoise/register_types.cpp b/modules/denoise/register_types.cpp
index 07393d0f5c..891a03c657 100644
--- a/modules/denoise/register_types.cpp
+++ b/modules/denoise/register_types.cpp
@@ -32,9 +32,16 @@
#include "core/config/engine.h"
#include "lightmap_denoiser.h"
-void register_denoise_types() {
+void initialize_denoise_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
LightmapDenoiserOIDN::make_default_denoiser();
}
-void unregister_denoise_types() {
+void uninitialize_denoise_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/denoise/register_types.h b/modules/denoise/register_types.h
index 6ce386dc5d..13eba88d17 100644
--- a/modules/denoise/register_types.h
+++ b/modules/denoise/register_types.h
@@ -31,7 +31,9 @@
#ifndef DENOISE_REGISTER_TYPES_H
#define DENOISE_REGISTER_TYPES_H
-void register_denoise_types();
-void unregister_denoise_types();
+#include "modules/register_module_types.h"
+
+void initialize_denoise_module(ModuleInitializationLevel p_level);
+void uninitialize_denoise_module(ModuleInitializationLevel p_level);
#endif // DENOISE_REGISTER_TYPES_H
diff --git a/modules/enet/enet_multiplayer_peer.h b/modules/enet/enet_multiplayer_peer.h
index e7b61169fb..18eca18e51 100644
--- a/modules/enet/enet_multiplayer_peer.h
+++ b/modules/enet/enet_multiplayer_peer.h
@@ -70,8 +70,8 @@ private:
ConnectionStatus connection_status = CONNECTION_DISCONNECTED;
- Map<int, Ref<ENetConnection>> hosts;
- Map<int, Ref<ENetPacketPeer>> peers;
+ HashMap<int, Ref<ENetConnection>> hosts;
+ HashMap<int, Ref<ENetPacketPeer>> peers;
struct Packet {
ENetPacket *packet = nullptr;
diff --git a/modules/enet/register_types.cpp b/modules/enet/register_types.cpp
index ebc5d95348..14f3374e24 100644
--- a/modules/enet/register_types.cpp
+++ b/modules/enet/register_types.cpp
@@ -36,7 +36,11 @@
static bool enet_ok = false;
-void register_enet_types() {
+void initialize_enet_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (enet_initialize() != 0) {
ERR_PRINT("ENet initialization failure");
} else {
@@ -48,7 +52,11 @@ void register_enet_types() {
GDREGISTER_CLASS(ENetConnection);
}
-void unregister_enet_types() {
+void uninitialize_enet_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (enet_ok) {
enet_deinitialize();
}
diff --git a/modules/enet/register_types.h b/modules/enet/register_types.h
index a94ecccc61..b4f491287d 100644
--- a/modules/enet/register_types.h
+++ b/modules/enet/register_types.h
@@ -31,7 +31,9 @@
#ifndef ENET_REGISTER_TYPES_H
#define ENET_REGISTER_TYPES_H
-void register_enet_types();
-void unregister_enet_types();
+#include "modules/register_module_types.h"
+
+void initialize_enet_module(ModuleInitializationLevel p_level);
+void uninitialize_enet_module(ModuleInitializationLevel p_level);
#endif // ENET_REGISTER_TYPES_H
diff --git a/modules/etcpak/register_types.cpp b/modules/etcpak/register_types.cpp
index e835004406..eaad1e7b01 100644
--- a/modules/etcpak/register_types.cpp
+++ b/modules/etcpak/register_types.cpp
@@ -32,11 +32,18 @@
#include "image_compress_etcpak.h"
-void register_etcpak_types() {
+void initialize_etcpak_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Image::_image_compress_etc1_func = _compress_etc1;
Image::_image_compress_etc2_func = _compress_etc2;
Image::_image_compress_bc_func = _compress_bc;
}
-void unregister_etcpak_types() {
+void uninitialize_etcpak_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/etcpak/register_types.h b/modules/etcpak/register_types.h
index 30ce974d08..2048a62737 100644
--- a/modules/etcpak/register_types.h
+++ b/modules/etcpak/register_types.h
@@ -31,7 +31,11 @@
#ifndef ETCPAK_REGISTER_TYPES_H
#define ETCPAK_REGISTER_TYPES_H
-void register_etcpak_types();
-void unregister_etcpak_types();
+#include "modules/register_module_types.h"
+
+#include "modules/register_module_types.h"
+
+void initialize_etcpak_module(ModuleInitializationLevel p_level);
+void uninitialize_etcpak_module(ModuleInitializationLevel p_level);
#endif // ETCPAK_REGISTER_TYPES_H
diff --git a/modules/freetype/register_types.cpp b/modules/freetype/register_types.cpp
index 28fd1a57c9..a5a60c0368 100644
--- a/modules/freetype/register_types.cpp
+++ b/modules/freetype/register_types.cpp
@@ -30,6 +30,14 @@
#include "register_types.h"
-void register_freetype_types() {}
+void initialize_freetype_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
-void unregister_freetype_types() {}
+void uninitialize_freetype_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/freetype/register_types.h b/modules/freetype/register_types.h
index c4eb241636..3399c0b3bc 100644
--- a/modules/freetype/register_types.h
+++ b/modules/freetype/register_types.h
@@ -31,7 +31,9 @@
#ifndef FREETYPE_REGISTER_TYPES_H
#define FREETYPE_REGISTER_TYPES_H
-void register_freetype_types();
-void unregister_freetype_types();
+#include "modules/register_module_types.h"
+
+void initialize_freetype_module(ModuleInitializationLevel p_level);
+void uninitialize_freetype_module(ModuleInitializationLevel p_level);
#endif // FREETYPE_REGISTER_TYPES_H
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index d9fab01dce..70151c4d21 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -184,27 +184,24 @@
<method name="range" qualifiers="vararg">
<return type="Array" />
<description>
- 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.
- [code]range()(/code] converts all arguments to [int] before processing.
+ Returns an array with the given range. [method range] can be called in three ways:
+ [code]range(n: int)[/code]: Starts from 0, increases by steps of 1, and stops [i]before[/i] [code]n[/code]. The argument [code]n[/code] is [b]exclusive[/b].
+ [code]range(b: int, n: int)[/code]: Starts from [code]b[/code], increases by steps of 1, and stops [i]before[/i] [code]n[/code]. The arguments [code]b[/code] and [code]n[/code] are [b]inclusive[/b] and [b]exclusive[/b], respectively.
+ [code]range(b: int, n: int, s: int)[/code]: Starts from [code]b[/code], increases/decreases by steps of [code]s[/code], and stops [i]before[/i] [code]n[/code]. The arguments [code]b[/code] and [code]n[/code] are [b]inclusive[/b] and [b]exclusive[/b], respectively. The argument [code]s[/code] [b]can[/b] be negative, but not [code]0[/code]. If [code]s[/code] is [code]0[/code], an error message is printed.
+ [method range] converts all arguments to [int] before processing.
+ [b]Note:[/b] Returns an empty array if no value meets the value constraint (e.g. [code]range(2, 5, -1)[/code] or [code]range(5, 5, 1)[/code]).
+ Examples:
[codeblock]
- print(range(4))
- print(range(2, 5))
- print(range(0, 6, 2))
- [/codeblock]
- Output:
- [codeblock]
- [0, 1, 2, 3]
- [2, 3, 4]
- [0, 2, 4]
+ print(range(4)) # Prints [0, 1, 2, 3]
+ print(range(2, 5)) # Prints [2, 3, 4]
+ print(range(0, 6, 2)) # Prints [0, 2, 4]
+ print(range(4, 1, -1)) # Prints [4, 3, 2]
[/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
+ for i in range(array.size(), 0, -1):
+ print(array[i - 1])
[/codeblock]
Output:
[codeblock]
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index e3f0ddfc35..191568661d 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -510,9 +510,8 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
/* Autoloads. */
- OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
- for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
- const ProjectSettings::AutoloadInfo &info = E.value();
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
+ const ProjectSettings::AutoloadInfo &info = E.value;
if (info.is_singleton) {
keywords[info.name] = usertype_color;
}
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index 1ae0d72896..92764e3891 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -45,7 +45,7 @@ private:
bool line_only = false;
};
Vector<ColorRegion> color_regions;
- Map<int, int> color_region_cache;
+ HashMap<int, int> color_region_cache;
HashMap<StringName, Color> keywords;
HashMap<StringName, Color> member_keywords;
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index a8f4483cf4..9b540b16f2 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -44,7 +44,7 @@ Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Ve
// Search strings in AssignmentNode -> text = "__", hint_tooltip = "__" etc.
Error err;
- RES loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
+ Ref<Resource> loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err);
if (err) {
ERR_PRINT("Failed to load " + p_path);
return err;
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
index e7b40aa367..4633a431d8 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
@@ -31,7 +31,7 @@
#ifndef GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
#define GDSCRIPT_TRANSLATION_PARSER_PLUGIN_H
-#include "core/templates/set.h"
+#include "core/templates/rb_set.h"
#include "editor/editor_translation_parser.h"
#include "modules/gdscript/gdscript_parser.h"
@@ -44,9 +44,9 @@ class GDScriptEditorTranslationParserPlugin : public EditorTranslationParserPlug
// List of patterns used for extracting translation strings.
StringName tr_func = "tr";
StringName trn_func = "tr_n";
- Set<StringName> assignment_patterns;
- Set<StringName> first_arg_patterns;
- Set<StringName> second_arg_patterns;
+ RBSet<StringName> assignment_patterns;
+ RBSet<StringName> first_arg_patterns;
+ RBSet<StringName> second_arg_patterns;
// FileDialog patterns.
StringName fd_add_filter = "add_filter";
StringName fd_set_filter = "set_filters";
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 3a0e320e9b..e3c9101733 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -82,7 +82,7 @@ Variant GDScriptNativeClass::_new() {
RefCounted *rc = Object::cast_to<RefCounted>(o);
if (rc) {
- return REF(rc);
+ return Ref<RefCounted>(rc);
} else {
return o;
}
@@ -92,6 +92,21 @@ Object *GDScriptNativeClass::instantiate() {
return ClassDB::instantiate(name);
}
+Variant GDScriptNativeClass::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ if (p_method == SNAME("new")) {
+ // Constructor.
+ return Object::callp(p_method, p_args, p_argcount, r_error);
+ }
+ MethodBind *method = ClassDB::get_method(name, p_method);
+ if (method) {
+ // Native static method.
+ return method->call(nullptr, p_args, p_argcount, r_error);
+ }
+
+ r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
+ return Variant();
+}
+
GDScriptFunction *GDScript::_super_constructor(GDScript *p_script) {
if (p_script->initializer) {
return p_script->initializer;
@@ -180,7 +195,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
}
r_error.error = Callable::CallError::CALL_OK;
- REF ref;
+ Ref<RefCounted> ref;
Object *owner = nullptr;
GDScript *_baseptr = this;
@@ -198,7 +213,7 @@ Variant GDScript::_new(const Variant **p_args, int p_argcount, Callable::CallErr
RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
- ref = REF(r);
+ ref = Ref<RefCounted>(r);
}
GDScriptInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
@@ -325,14 +340,14 @@ bool GDScript::has_method(const StringName &p_method) const {
}
MethodInfo GDScript::get_method_info(const StringName &p_method) const {
- const Map<StringName, GDScriptFunction *>::Element *E = member_functions.find(p_method);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = member_functions.find(p_method);
if (!E) {
return MethodInfo();
}
- GDScriptFunction *func = E->get();
+ GDScriptFunction *func = E->value;
MethodInfo mi;
- mi.name = E->key();
+ mi.name = E->key;
for (int i = 0; i < func->get_argument_count(); i++) {
mi.arguments.push_back(func->get_argument_type(i));
}
@@ -344,9 +359,9 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const {
bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
#ifdef TOOLS_ENABLED
- const Map<StringName, Variant>::Element *E = member_default_values_cache.find(p_property);
+ HashMap<StringName, Variant>::ConstIterator E = member_default_values_cache.find(p_property);
if (E) {
- r_value = E->get();
+ r_value = E->value;
return true;
}
@@ -412,7 +427,7 @@ void GDScript::set_source_code(const String &p_code) {
}
#ifdef TOOLS_ENABLED
-void GDScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) {
+void GDScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) {
if (base_cache.is_valid()) {
base_cache->_update_exports_values(values, propnames);
}
@@ -744,12 +759,12 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
if ((changed || p_instance_to_update) && placeholders.size()) { //hm :(
// update placeholders if any
- Map<StringName, Variant> values;
+ HashMap<StringName, Variant> values;
List<PropertyInfo> propnames;
_update_exports_values(values, propnames);
if (changed) {
- for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ for (RBSet<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
E->get()->update(propnames, values);
}
} else {
@@ -773,9 +788,9 @@ void GDScript::update_exports() {
return;
}
- Set<ObjectID> copy = inheriters_cache; //might get modified
+ RBSet<ObjectID> copy = inheriters_cache; //might get modified
- for (Set<ObjectID>::Element *E = copy.front(); E; E = E->next()) {
+ for (RBSet<ObjectID>::Element *E = copy.front(); E; E = E->next()) {
Object *id = ObjectDB::get_instance(E->get());
GDScript *s = Object::cast_to<GDScript>(id);
if (!s) {
@@ -914,7 +929,7 @@ ScriptLanguage *GDScript::get_language() const {
return GDScriptLanguage::get_singleton();
}
-void GDScript::get_constants(Map<StringName, Variant> *p_constants) {
+void GDScript::get_constants(HashMap<StringName, Variant> *p_constants) {
if (p_constants) {
for (const KeyValue<StringName, Variant> &E : constants) {
(*p_constants)[E.key] = E.value;
@@ -922,9 +937,9 @@ void GDScript::get_constants(Map<StringName, Variant> *p_constants) {
}
}
-void GDScript::get_members(Set<StringName> *p_members) {
+void GDScript::get_members(RBSet<StringName> *p_members) {
if (p_members) {
- for (Set<StringName>::Element *E = members.front(); E; E = E->next()) {
+ for (RBSet<StringName>::Element *E = members.front(); E; E = E->next()) {
p_members->insert(E->get());
}
}
@@ -937,11 +952,11 @@ const Vector<Multiplayer::RPCConfig> GDScript::get_rpc_methods() const {
Variant GDScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
GDScript *top = this;
while (top) {
- Map<StringName, GDScriptFunction *>::Element *E = top->member_functions.find(p_method);
+ HashMap<StringName, GDScriptFunction *>::Iterator E = top->member_functions.find(p_method);
if (E) {
- ERR_FAIL_COND_V_MSG(!E->get()->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
+ ERR_FAIL_COND_V_MSG(!E->value->is_static(), Variant(), "Can't call non-static function '" + String(p_method) + "' in script.");
- return E->get()->call(nullptr, p_args, p_argcount, r_error);
+ return E->value->call(nullptr, p_args, p_argcount, r_error);
}
top = top->_base;
}
@@ -956,17 +971,17 @@ bool GDScript::_get(const StringName &p_name, Variant &r_ret) const {
const GDScript *top = this;
while (top) {
{
- const Map<StringName, Variant>::Element *E = top->constants.find(p_name);
+ HashMap<StringName, Variant>::ConstIterator E = top->constants.find(p_name);
if (E) {
- r_ret = E->get();
+ r_ret = E->value;
return true;
}
}
{
- const Map<StringName, Ref<GDScript>>::Element *E = subclasses.find(p_name);
+ HashMap<StringName, Ref<GDScript>>::ConstIterator E = subclasses.find(p_name);
if (E) {
- r_ret = E->get();
+ r_ret = E->value;
return true;
}
}
@@ -1015,17 +1030,21 @@ Error GDScript::load_byte_code(const String &p_path) {
Error GDScript::load_source_code(const String &p_path) {
Vector<uint8_t> sourcef;
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
- ERR_FAIL_COND_V(err, err);
+ const char *err_name;
+ if (err < 0 || err >= ERR_MAX) {
+ err_name = "(invalid error code)";
+ } else {
+ err_name = error_names[err];
+ }
+ ERR_FAIL_COND_V_MSG(err, err, "Attempt to open script '" + p_path + "' resulted in error '" + err_name + "'.");
}
uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
uint64_t r = f->get_buffer(w, len);
- f->close();
- memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
w[len] = 0;
@@ -1042,7 +1061,7 @@ Error GDScript::load_source_code(const String &p_path) {
return OK;
}
-const Map<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const {
+const HashMap<StringName, GDScriptFunction *> &GDScript::debug_get_member_functions() const {
return member_functions;
}
@@ -1190,7 +1209,7 @@ void GDScript::_init_rpc_methods_properties() {
}
GDScript *cscript = this;
- Map<StringName, Ref<GDScript>>::Element *sub_E = subclasses.front();
+ HashMap<StringName, Ref<GDScript>>::Iterator sub_E = subclasses.begin();
while (cscript) {
// RPC Methods
for (KeyValue<StringName, GDScriptFunction *> &E : cscript->member_functions) {
@@ -1204,11 +1223,11 @@ void GDScript::_init_rpc_methods_properties() {
}
if (cscript != this) {
- sub_E = sub_E->next();
+ ++sub_E;
}
if (sub_E) {
- cscript = sub_E->get().ptr();
+ cscript = sub_E->value.ptr();
} else {
cscript = nullptr;
}
@@ -1263,9 +1282,9 @@ GDScript::~GDScript() {
bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
//member
{
- const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
+ HashMap<StringName, GDScript::MemberInfo>::Iterator E = script->member_indices.find(p_name);
if (E) {
- const GDScript::MemberInfo *member = &E->get();
+ const GDScript::MemberInfo *member = &E->value;
if (member->setter) {
const Variant *val = &p_value;
Callable::CallError err;
@@ -1306,13 +1325,13 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
GDScript *sptr = script.ptr();
while (sptr) {
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._set);
if (E) {
Variant name = p_name;
const Variant *args[2] = { &name, &p_value };
Callable::CallError err;
- Variant ret = E->get()->call(this, (const Variant **)args, 2, err);
+ Variant ret = E->value->call(this, (const Variant **)args, 2, err);
if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) {
return true;
}
@@ -1327,16 +1346,16 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
const GDScript *sptr = script.ptr();
while (sptr) {
{
- const Map<StringName, GDScript::MemberInfo>::Element *E = script->member_indices.find(p_name);
+ HashMap<StringName, GDScript::MemberInfo>::ConstIterator E = script->member_indices.find(p_name);
if (E) {
- if (E->get().getter) {
+ if (E->value.getter) {
Callable::CallError err;
- r_ret = const_cast<GDScriptInstance *>(this)->callp(E->get().getter, nullptr, 0, err);
+ r_ret = const_cast<GDScriptInstance *>(this)->callp(E->value.getter, nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
return true;
}
}
- r_ret = members[E->get().index];
+ r_ret = members[E->value.index];
return true; //index found
}
}
@@ -1344,9 +1363,9 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
{
const GDScript *sl = sptr;
while (sl) {
- const Map<StringName, Variant>::Element *E = sl->constants.find(p_name);
+ HashMap<StringName, Variant>::ConstIterator E = sl->constants.find(p_name);
if (E) {
- r_ret = E->get();
+ r_ret = E->value;
return true; //index found
}
sl = sl->_base;
@@ -1357,9 +1376,9 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
// Signals.
const GDScript *sl = sptr;
while (sl) {
- const Map<StringName, Vector<StringName>>::Element *E = sl->_signals.find(p_name);
+ HashMap<StringName, Vector<StringName>>::ConstIterator E = sl->_signals.find(p_name);
if (E) {
- r_ret = Signal(this->owner, E->key());
+ r_ret = Signal(this->owner, E->key);
return true; //index found
}
sl = sl->_base;
@@ -1370,14 +1389,14 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
// Methods.
const GDScript *sl = sptr;
while (sl) {
- const Map<StringName, GDScriptFunction *>::Element *E = sl->member_functions.find(p_name);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sl->member_functions.find(p_name);
if (E) {
Multiplayer::RPCConfig config;
config.name = p_name;
if (sptr->rpc_functions.find(config) != -1) {
- r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key())));
+ r_ret = Callable(memnew(GDScriptRPCCallable(this->owner, E->key)));
} else {
- r_ret = Callable(this->owner, E->key());
+ r_ret = Callable(this->owner, E->key);
}
return true; //index found
}
@@ -1386,13 +1405,13 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
{
- const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get);
if (E) {
Variant name = p_name;
const Variant *args[1] = { &name };
Callable::CallError err;
- Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err);
+ Variant ret = const_cast<GDScriptFunction *>(E->value)->call(const_cast<GDScriptInstance *>(this), (const Variant **)args, 1, err);
if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) {
r_ret = ret;
return true;
@@ -1430,10 +1449,10 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
List<PropertyInfo> props;
while (sptr) {
- const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._get_property_list);
if (E) {
Callable::CallError err;
- Variant ret = const_cast<GDScriptFunction *>(E->get())->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
+ Variant ret = const_cast<GDScriptFunction *>(E->value)->call(const_cast<GDScriptInstance *>(this), nullptr, 0, err);
if (err.error == Callable::CallError::CALL_OK) {
ERR_FAIL_COND_MSG(ret.get_type() != Variant::ARRAY, "Wrong type for _get_property_list, must be an array of dictionaries.");
@@ -1506,7 +1525,7 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
bool GDScriptInstance::has_method(const StringName &p_method) const {
const GDScript *sptr = script.ptr();
while (sptr) {
- const Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(p_method);
if (E) {
return true;
}
@@ -1519,9 +1538,9 @@ bool GDScriptInstance::has_method(const StringName &p_method) const {
Variant GDScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
GDScript *sptr = script.ptr();
while (sptr) {
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(p_method);
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(p_method);
if (E) {
- return E->get()->call(this, p_args, p_argcount, r_error);
+ return E->value->call(this, p_args, p_argcount, r_error);
}
sptr = sptr->_base;
}
@@ -1536,10 +1555,10 @@ void GDScriptInstance::notification(int p_notification) {
GDScript *sptr = script.ptr();
while (sptr) {
- Map<StringName, GDScriptFunction *>::Element *E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
+ HashMap<StringName, GDScriptFunction *>::Iterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._notification);
if (E) {
Callable::CallError err;
- E->get()->call(this, args, 1, err);
+ E->value->call(this, args, 1, err);
if (err.error != Callable::CallError::CALL_OK) {
//print error about notification call
}
@@ -1863,7 +1882,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
//when someone asks you why dynamically typed languages are easier to write....
- Map<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> to_reload;
+ HashMap<Ref<GDScript>, HashMap<ObjectID, List<Pair<StringName, Variant>>>> to_reload;
//as scripts are going to be reloaded, must proceed without locking here
@@ -1876,11 +1895,11 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
continue;
}
- to_reload.insert(script, Map<ObjectID, List<Pair<StringName, Variant>>>());
+ to_reload.insert(script, HashMap<ObjectID, List<Pair<StringName, Variant>>>());
if (!p_soft_reload) {
//save state and remove script from instances
- Map<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[script];
+ HashMap<ObjectID, List<Pair<StringName, Variant>>> &map = to_reload[script];
while (script->instances.front()) {
Object *obj = script->instances.front()->get();
@@ -1919,7 +1938,7 @@ void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_so
}
}
- for (KeyValue<Ref<GDScript>, Map<ObjectID, List<Pair<StringName, Variant>>>> &E : to_reload) {
+ for (KeyValue<Ref<GDScript>, HashMap<ObjectID, List<Pair<StringName, Variant>>>> &E : to_reload) {
Ref<GDScript> scr = E.key;
scr->reload(p_soft_reload);
@@ -2084,7 +2103,7 @@ bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_base_type, String *r_icon_path) const {
Vector<uint8_t> sourcef;
Error err;
- FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
return String();
}
@@ -2118,8 +2137,8 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
} else {
Vector<StringName> extend_classes = subclass->extends;
- FileAccessRef subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
- if (!subfile) {
+ Ref<FileAccess> subfile = FileAccess::open(subclass->extends_path, FileAccess::READ);
+ if (subfile.is_null()) {
break;
}
String subsource = subfile->get_as_utf8_string();
@@ -2258,13 +2277,13 @@ void GDScriptLanguage::add_orphan_subclass(const String &p_qualified_name, const
}
Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_name) {
- Map<String, ObjectID>::Element *orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
+ HashMap<String, ObjectID>::Iterator orphan_subclass_element = orphan_subclasses.find(p_qualified_name);
if (!orphan_subclass_element) {
return Ref<GDScript>();
}
- ObjectID orphan_subclass = orphan_subclass_element->get();
+ ObjectID orphan_subclass = orphan_subclass_element->value;
Object *obj = ObjectDB::get_instance(orphan_subclass);
- orphan_subclasses.erase(orphan_subclass_element);
+ orphan_subclasses.remove(orphan_subclass_element);
if (!obj) {
return Ref<GDScript>();
}
@@ -2273,7 +2292,7 @@ Ref<GDScript> GDScriptLanguage::get_orphan_subclass(const String &p_qualified_na
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -2316,8 +2335,8 @@ String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) con
}
void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<String> *p_dependencies, bool p_add_types) {
- FileAccessRef file = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_path + "'.");
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_path + "'.");
String source = file->get_as_utf8_string();
if (source.is_empty()) {
@@ -2334,24 +2353,23 @@ void ResourceFormatLoaderGDScript::get_dependencies(const String &p_path, List<S
}
}
-Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverGDScript::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
Ref<GDScript> sqscr = p_resource;
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
String source = sqscr->get_source_code();
- Error err;
- FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err, err, "Cannot save GDScript file '" + p_path + "'.");
- file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- memdelete(file);
- return ERR_CANT_CREATE;
+ file->store_string(source);
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
- file->close();
- memdelete(file);
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
GDScriptLanguage::get_singleton()->reload_tool_script(p_resource, false);
@@ -2360,12 +2378,12 @@ Error ResourceFormatSaverGDScript::save(const String &p_path, const RES &p_resou
return OK;
}
-void ResourceFormatSaverGDScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverGDScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (Object::cast_to<GDScript>(*p_resource)) {
p_extensions->push_back("gd");
}
}
-bool ResourceFormatSaverGDScript::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverGDScript::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<GDScript>(*p_resource) != nullptr;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index f7fa967883..5199d3215d 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -52,6 +52,7 @@ public:
_FORCE_INLINE_ const StringName &get_name() const { return name; }
Variant _new();
Object *instantiate();
+ virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
GDScriptNativeClass(const StringName &p_name);
};
@@ -79,48 +80,48 @@ class GDScript : public Script {
GDScript *_base = nullptr; //fast pointer access
GDScript *_owner = nullptr; //for subclasses
- Set<StringName> members; //members are just indices to the instantiated script.
- Map<StringName, Variant> constants;
- Map<StringName, GDScriptFunction *> member_functions;
- Map<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script.
- Map<StringName, Ref<GDScript>> subclasses;
- Map<StringName, Vector<StringName>> _signals;
+ RBSet<StringName> members; //members are just indices to the instantiated script.
+ HashMap<StringName, Variant> constants;
+ HashMap<StringName, GDScriptFunction *> member_functions;
+ HashMap<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script.
+ HashMap<StringName, Ref<GDScript>> subclasses;
+ HashMap<StringName, Vector<StringName>> _signals;
Vector<Multiplayer::RPCConfig> rpc_functions;
#ifdef TOOLS_ENABLED
- Map<StringName, int> member_lines;
- Map<StringName, Variant> member_default_values;
+ HashMap<StringName, int> member_lines;
+ HashMap<StringName, Variant> member_default_values;
List<PropertyInfo> members_cache;
- Map<StringName, Variant> member_default_values_cache;
+ HashMap<StringName, Variant> member_default_values_cache;
Ref<GDScript> base_cache;
- Set<ObjectID> inheriters_cache;
+ RBSet<ObjectID> inheriters_cache;
bool source_changed_cache = false;
bool placeholder_fallback_enabled = false;
- void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
+ void _update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames);
DocData::ClassDoc doc;
Vector<DocData::ClassDoc> docs;
String doc_brief_description;
String doc_description;
Vector<DocData::TutorialDoc> doc_tutorials;
- Map<String, String> doc_functions;
- Map<String, String> doc_variables;
- Map<String, String> doc_constants;
- Map<String, String> doc_signals;
- Map<String, DocData::EnumDoc> doc_enums;
+ HashMap<String, String> doc_functions;
+ HashMap<String, String> doc_variables;
+ HashMap<String, String> doc_constants;
+ HashMap<String, String> doc_signals;
+ HashMap<String, DocData::EnumDoc> doc_enums;
void _clear_doc();
void _update_doc();
void _add_doc(const DocData::ClassDoc &p_inner_class);
#endif
- Map<StringName, PropertyInfo> member_info;
+ HashMap<StringName, PropertyInfo> member_info;
GDScriptFunction *implicit_initializer = nullptr;
GDScriptFunction *initializer = nullptr; //direct pointer to new , faster to locate
int subclass_count = 0;
- Set<Object *> instances;
+ RBSet<Object *> instances;
//exported members
String source;
String path;
@@ -138,14 +139,14 @@ class GDScript : public Script {
String _get_debug_path() const;
#ifdef TOOLS_ENABLED
- Set<PlaceHolderScriptInstance *> placeholders;
+ RBSet<PlaceHolderScriptInstance *> placeholders;
//void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
#endif
#ifdef DEBUG_ENABLED
- Map<ObjectID, List<Pair<StringName, Variant>>> pending_reload_state;
+ HashMap<ObjectID, List<Pair<StringName, Variant>>> pending_reload_state;
#endif
@@ -175,14 +176,14 @@ public:
bool inherits_script(const Ref<Script> &p_script) const override;
- const Map<StringName, Ref<GDScript>> &get_subclasses() const { return subclasses; }
- const Map<StringName, Variant> &get_constants() const { return constants; }
- const Set<StringName> &get_members() const { return members; }
+ const HashMap<StringName, Ref<GDScript>> &get_subclasses() const { return subclasses; }
+ const HashMap<StringName, Variant> &get_constants() const { return constants; }
+ const RBSet<StringName> &get_members() const { return members; }
const GDScriptDataType &get_member_type(const StringName &p_member) const {
CRASH_COND(!member_indices.has(p_member));
return member_indices[p_member].data_type;
}
- const Map<StringName, GDScriptFunction *> &get_member_functions() const { return member_functions; }
+ const HashMap<StringName, GDScriptFunction *> &get_member_functions() const { return member_functions; }
const Ref<GDScriptNativeClass> &get_native() const { return native; }
const String &get_script_class_name() const { return name; }
@@ -192,8 +193,8 @@ public:
bool is_tool() const override { return tool; }
Ref<GDScript> get_base() const;
- const Map<StringName, MemberInfo> &debug_get_member_indices() const { return member_indices; }
- const Map<StringName, GDScriptFunction *> &debug_get_member_functions() const; //this is debug only
+ const HashMap<StringName, MemberInfo> &debug_get_member_indices() const { return member_indices; }
+ const HashMap<StringName, GDScriptFunction *> &debug_get_member_functions() const; //this is debug only
StringName debug_get_member_by_index(int p_idx) const;
Variant _new(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
@@ -244,8 +245,8 @@ public:
return -1;
}
- virtual void get_constants(Map<StringName, Variant> *p_constants) override;
- virtual void get_members(Set<StringName> *p_members) override;
+ virtual void get_constants(HashMap<StringName, Variant> *p_constants) override;
+ virtual void get_members(RBSet<StringName> *p_members) override;
virtual const Vector<Multiplayer::RPCConfig> get_rpc_methods() const override;
@@ -261,14 +262,15 @@ class GDScriptInstance : public ScriptInstance {
friend class GDScript;
friend class GDScriptFunction;
friend class GDScriptLambdaCallable;
+ friend class GDScriptLambdaSelfCallable;
friend class GDScriptCompiler;
friend struct GDScriptUtilityFunctionsDefinitions;
ObjectID owner_id;
- Object *owner;
+ Object *owner = nullptr;
Ref<GDScript> script;
#ifdef DEBUG_ENABLED
- Map<StringName, int> member_indices_cache; //used only for hot script reloading
+ HashMap<StringName, int> member_indices_cache; //used only for hot script reloading
#endif
Vector<Variant> members;
bool base_ref_counted;
@@ -311,17 +313,17 @@ class GDScriptLanguage : public ScriptLanguage {
static GDScriptLanguage *singleton;
- Variant *_global_array;
+ Variant *_global_array = nullptr;
Vector<Variant> global_array;
- Map<StringName, int> globals;
- Map<StringName, Variant> named_globals;
+ HashMap<StringName, int> globals;
+ HashMap<StringName, Variant> named_globals;
struct CallLevel {
- Variant *stack;
- GDScriptFunction *function;
- GDScriptInstance *instance;
- int *ip;
- int *line;
+ Variant *stack = nullptr;
+ GDScriptFunction *function = nullptr;
+ GDScriptInstance *instance = nullptr;
+ int *ip = nullptr;
+ int *line = nullptr;
};
int _debug_parse_err_line;
@@ -329,7 +331,7 @@ class GDScriptLanguage : public ScriptLanguage {
String _debug_error;
int _debug_call_stack_pos;
int _debug_max_call_stack;
- CallLevel *_call_stack;
+ CallLevel *_call_stack = nullptr;
void _add_global(const StringName &p_name, const Variant &p_value);
@@ -346,7 +348,7 @@ class GDScriptLanguage : public ScriptLanguage {
bool profiling;
uint64_t script_frame_time;
- Map<String, ObjectID> orphan_subclasses;
+ HashMap<String, ObjectID> orphan_subclasses;
public:
int calls;
@@ -425,8 +427,8 @@ public:
_FORCE_INLINE_ int get_global_array_size() const { return global_array.size(); }
_FORCE_INLINE_ Variant *get_global_array() { return _global_array; }
- _FORCE_INLINE_ const Map<StringName, int> &get_global_map() const { return globals; }
- _FORCE_INLINE_ const Map<StringName, Variant> &get_named_globals_map() const { return named_globals; }
+ _FORCE_INLINE_ const HashMap<StringName, int> &get_global_map() const { return globals; }
+ _FORCE_INLINE_ const HashMap<StringName, Variant> &get_named_globals_map() const { return named_globals; }
_FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; }
@@ -447,7 +449,7 @@ public:
virtual bool is_using_templates() override;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
- virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override;
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, RBSet<int> *r_safe_lines = nullptr) const override;
virtual Script *create_script() const override;
virtual bool has_named_classes() const override;
virtual bool supports_builtin_mode() const override;
@@ -510,7 +512,7 @@ public:
class ResourceFormatLoaderGDScript : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
@@ -519,9 +521,9 @@ public:
class ResourceFormatSaverGDScript : public ResourceFormatSaver {
public:
- virtual Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0);
- virtual void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const;
- virtual bool recognize(const RES &p_resource) const;
+ virtual Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0);
+ virtual void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const;
+ virtual bool recognize(const Ref<Resource> &p_resource) const;
};
#endif // GDSCRIPT_H
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 00931961b7..32fa3b8c87 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -898,7 +898,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
}
#ifdef DEBUG_ENABLED
- Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ RBSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
for (uint32_t ignored_warning : member.function->ignored_warnings) {
parser->ignored_warning_codes.insert(ignored_warning);
}
@@ -947,7 +947,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
#ifdef DEBUG_ENABLED
- Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ RBSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
for (uint32_t ignored_warning : member.function->ignored_warnings) {
parser->ignored_warning_codes.insert(ignored_warning);
}
@@ -1279,7 +1279,7 @@ void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) {
}
#ifdef DEBUG_ENABLED
- Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ RBSet<uint32_t> previously_ignored = parser->ignored_warning_codes;
for (uint32_t ignored_warning : stmt->ignored_warnings) {
parser->ignored_warning_codes.insert(ignored_warning);
}
@@ -2174,7 +2174,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_await, bool p_is_root) {
bool all_is_constant = true;
- Map<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing.
+ HashMap<int, GDScriptParser::ArrayNode *> arrays; // For array literal to potentially type when passing.
for (int i = 0; i < p_call->arguments.size(); i++) {
reduce_expression(p_call->arguments[i]);
if (p_call->arguments[i]->type == GDScriptParser::Node::ARRAY) {
@@ -2498,18 +2498,24 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
}
if (is_self && parser->current_function != nullptr && parser->current_function->is_static && !is_static) {
- push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parser->current_function->identifier->name), p_call);
+ // Get the parent function above any lambda.
+ GDScriptParser::FunctionNode *parent_function = parser->current_function;
+ while (parent_function->source_lambda) {
+ parent_function = parent_function->source_lambda->parent_function;
+ }
+ push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call);
} else if (!is_self && base_type.is_meta_type && !is_static) {
base_type.is_meta_type = false; // For `to_string()`.
push_error(vformat(R"*(Cannot call non-static function "%s()" on the class "%s" directly. Make an instance instead.)*", p_call->function_name, base_type.to_string()), p_call);
- } else if (is_self && !is_static && !lambda_stack.is_empty()) {
- push_error(vformat(R"*(Cannot call non-static function "%s()" from a lambda function.)*", p_call->function_name), p_call);
+ } else if (is_self && !is_static) {
+ mark_lambda_use_self();
}
call_type = return_type;
} else {
- // Check if the name exists as something else.
bool found = false;
+
+ // Check if the name exists as something else.
if (!p_call->is_super && callee_type != GDScriptParser::Node::NONE) {
GDScriptParser::IdentifierNode *callee_id;
if (callee_type == GDScriptParser::Node::IDENTIFIER) {
@@ -2539,6 +2545,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
if (!found && (is_self || (base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::BUILTIN))) {
String base_name = is_self && !p_call->is_super ? "self" : base_type.to_string();
push_error(vformat(R"*(Function "%s()" not found in base %s.)*", p_call->function_name, base_name), p_call->is_super ? p_call : p_call->callee);
+ } else if (!found && (!p_call->is_super && base_type.is_hard_type() && base_type.kind == GDScriptParser::DataType::NATIVE && base_type.is_meta_type)) {
+ push_error(vformat(R"*(Static function "%s()" not found in base "%s".)*", p_call->function_name, base_type.native_type.operator String()), p_call);
}
}
@@ -2633,10 +2641,10 @@ void GDScriptAnalyzer::reduce_get_node(GDScriptParser::GetNodeNode *p_get_node)
if (!ClassDB::is_parent_class(parser->current_class->base_type.native_type, result.native_type)) {
push_error(R"*(Cannot use shorthand "get_node()" notation ("$") on a class that isn't a node.)*", p_get_node);
- } else if (!lambda_stack.is_empty()) {
- push_error(R"*(Cannot use shorthand "get_node()" notation ("$") inside a lambda. Use a captured variable instead.)*", p_get_node);
}
+ mark_lambda_use_self();
+
p_get_node->set_datatype(result);
}
@@ -2851,21 +2859,25 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
MethodBind *getter = ClassDB::get_method(native, getter_name);
if (getter != nullptr) {
p_identifier->set_datatype(type_from_property(getter->get_return_info()));
+ p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
}
return;
}
if (ClassDB::get_method_info(native, name, &method_info)) {
// Method is callable.
p_identifier->set_datatype(make_callable_type(method_info));
+ p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
return;
}
if (ClassDB::get_signal(native, name, &method_info)) {
// Signal is a type too.
p_identifier->set_datatype(make_signal_type(method_info));
+ p_identifier->source = GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
return;
}
if (ClassDB::has_enum(native, name)) {
p_identifier->set_datatype(make_native_enum_type(native, name));
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
return;
}
bool valid = false;
@@ -2874,6 +2886,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
p_identifier->is_constant = true;
p_identifier->reduced_value = int_constant;
p_identifier->set_datatype(type_from_variant(int_constant, p_identifier));
+ p_identifier->source = GDScriptParser::IdentifierNode::MEMBER_CONSTANT;
return;
}
}
@@ -2924,7 +2937,11 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
p_identifier->reduced_value = p_identifier->constant_source->initializer->reduced_value;
found_source = true;
break;
+ case GDScriptParser::IdentifierNode::INHERITED_VARIABLE:
+ mark_lambda_use_self();
+ break;
case GDScriptParser::IdentifierNode::MEMBER_VARIABLE:
+ mark_lambda_use_self();
p_identifier->variable_source->usages++;
[[fallthrough]];
case GDScriptParser::IdentifierNode::LOCAL_VARIABLE:
@@ -2955,18 +2972,37 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
}
if (found_source) {
- // If the identifier is local, check if it's any kind of capture by comparing their source function.
- // Only capture locals and members and enum values. Constants are still accessible from the lambda using the script reference.
- if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT || lambda_stack.is_empty()) {
- return;
+ if ((p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE) && parser->current_function && parser->current_function->is_static) {
+ // Get the parent function above any lambda.
+ GDScriptParser::FunctionNode *parent_function = parser->current_function;
+ while (parent_function->source_lambda) {
+ parent_function = parent_function->source_lambda->parent_function;
+ }
+ push_error(vformat(R"*(Cannot access instance variable "%s" from the static function "%s()".)*", p_identifier->name, parent_function->identifier->name), p_identifier);
}
- GDScriptParser::FunctionNode *function_test = lambda_stack.back()->get()->function;
- while (function_test != nullptr && function_test != p_identifier->source_function && function_test->source_lambda != nullptr && !function_test->source_lambda->captures_indices.has(p_identifier->name)) {
- function_test->source_lambda->captures_indices[p_identifier->name] = function_test->source_lambda->captures.size();
- function_test->source_lambda->captures.push_back(p_identifier);
- function_test = function_test->source_lambda->parent_function;
+ if (!lambda_stack.is_empty()) {
+ // If the identifier is a member variable (including the native class properties), we consider the lambda to be using `self`, so we keep a reference to the current instance.
+ if (p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE) {
+ mark_lambda_use_self();
+ return; // No need to capture.
+ }
+ // If the identifier is local, check if it's any kind of capture by comparing their source function.
+ // Only capture locals and enum values. Constants are still accessible from the lambda using the script reference. If not, this method is done.
+ if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT) {
+ return;
+ }
+
+ GDScriptParser::FunctionNode *function_test = lambda_stack.back()->get()->function;
+ // Make sure we aren't capturing variable in the same lambda.
+ // This also add captures for nested lambdas.
+ while (function_test != nullptr && function_test != p_identifier->source_function && function_test->source_lambda != nullptr && !function_test->source_lambda->captures_indices.has(p_identifier->name)) {
+ function_test->source_lambda->captures_indices[p_identifier->name] = function_test->source_lambda->captures.size();
+ function_test->source_lambda->captures.push_back(p_identifier);
+ function_test = function_test->source_lambda->parent_function;
+ }
}
+
return;
}
@@ -3146,6 +3182,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
void GDScriptAnalyzer::reduce_self(GDScriptParser::SelfNode *p_self) {
p_self->is_constant = false;
p_self->set_datatype(type_from_metatype(parser->current_class->get_datatype()));
+ mark_lambda_use_self();
}
void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscript) {
@@ -3156,6 +3193,12 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
reduce_identifier(static_cast<GDScriptParser::IdentifierNode *>(p_subscript->base), true);
} else {
reduce_expression(p_subscript->base);
+
+ if (p_subscript->base->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(p_subscript->base));
+ } else if (p_subscript->base->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(p_subscript->base));
+ }
}
GDScriptParser::DataType result_type;
@@ -3473,6 +3516,13 @@ void GDScriptAnalyzer::const_fold_array(GDScriptParser::ArrayNode *p_array) {
for (int i = 0; i < p_array->elements.size(); i++) {
GDScriptParser::ExpressionNode *element = p_array->elements[i];
+
+ if (element->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(element));
+ } else if (element->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element));
+ }
+
all_is_constant = all_is_constant && element->is_constant;
if (!all_is_constant) {
return;
@@ -3493,6 +3543,13 @@ void GDScriptAnalyzer::const_fold_dictionary(GDScriptParser::DictionaryNode *p_d
for (int i = 0; i < p_dictionary->elements.size(); i++) {
const GDScriptParser::DictionaryNode::Pair &element = p_dictionary->elements[i];
+
+ if (element.value->type == GDScriptParser::Node::ARRAY) {
+ const_fold_array(static_cast<GDScriptParser::ArrayNode *>(element.value));
+ } else if (element.value->type == GDScriptParser::Node::DICTIONARY) {
+ const_fold_dictionary(static_cast<GDScriptParser::DictionaryNode *>(element.value));
+ }
+
all_is_constant = all_is_constant && element.key->is_constant && element.value->is_constant;
if (!all_is_constant) {
return;
@@ -3773,6 +3830,7 @@ bool GDScriptAnalyzer::function_signature_from_info(const MethodInfo &p_info, GD
r_return_type = type_from_property(p_info.return_val);
r_default_arg_count = p_info.default_arguments.size();
r_vararg = (p_info.flags & METHOD_FLAG_VARARG) != 0;
+ r_static = (p_info.flags & METHOD_FLAG_STATIC) != 0;
for (const PropertyInfo &E : p_info.arguments) {
r_par_types.push_back(type_from_property(E));
@@ -4117,6 +4175,12 @@ void GDScriptAnalyzer::mark_node_unsafe(const GDScriptParser::Node *p_node) {
#endif
}
+void GDScriptAnalyzer::mark_lambda_use_self() {
+ for (GDScriptParser::LambdaNode *lambda : lambda_stack) {
+ lambda->use_self = true;
+ }
+}
+
bool GDScriptAnalyzer::class_exists(const StringName &p_class) const {
return ClassDB::class_exists(p_class) && ClassDB::is_class_exposed(p_class);
}
@@ -4154,13 +4218,11 @@ Error GDScriptAnalyzer::resolve_program() {
resolve_class_interface(parser->head);
resolve_class_body(parser->head);
- List<String> parser_keys;
- depended_parsers.get_key_list(&parser_keys);
- for (const String &E : parser_keys) {
- if (depended_parsers[E].is_null()) {
+ for (KeyValue<String, Ref<GDScriptParserRef>> &K : depended_parsers) {
+ if (K.value.is_null()) {
return ERR_PARSE_ERROR;
}
- depended_parsers[E]->raise_status(GDScriptParserRef::FULLY_SOLVED);
+ K.value->raise_status(GDScriptParserRef::FULLY_SOLVED);
}
return parser->errors.is_empty() ? OK : ERR_PARSE_ERROR;
}
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index 7b8883e1d3..5b03f6dbb4 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -33,7 +33,7 @@
#include "core/object/object.h"
#include "core/object/ref_counted.h"
-#include "core/templates/set.h"
+#include "core/templates/rb_set.h"
#include "gdscript_cache.h"
#include "gdscript_parser.h"
@@ -42,7 +42,7 @@ class GDScriptAnalyzer {
HashMap<String, Ref<GDScriptParserRef>> depended_parsers;
const GDScriptParser::EnumNode *current_enum = nullptr;
- List<const GDScriptParser::LambdaNode *> lambda_stack;
+ List<GDScriptParser::LambdaNode *> lambda_stack;
// Tests for detecting invalid overloading of script members
static _FORCE_INLINE_ bool has_member_name_conflict_in_script_class(const StringName &p_name, const GDScriptParser::ClassNode *p_current_class_node);
@@ -115,6 +115,7 @@ class GDScriptAnalyzer {
bool is_type_compatible(const GDScriptParser::DataType &p_target, const GDScriptParser::DataType &p_source, bool p_allow_implicit_conversion = false, const GDScriptParser::Node *p_source_node = nullptr);
void push_error(const String &p_message, const GDScriptParser::Node *p_origin);
void mark_node_unsafe(const GDScriptParser::Node *p_node);
+ void mark_lambda_use_self();
bool class_exists(const StringName &p_class) const;
Ref<GDScriptParserRef> get_parser_for(const String &p_path);
#ifdef DEBUG_ENABLED
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 82aa14795e..3d5a39bf38 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -196,10 +196,8 @@ GDScriptFunction *GDScriptByteCodeGenerator::write_end() {
function->_constant_count = constant_map.size();
function->constants.resize(constant_map.size());
function->_constants_ptr = function->constants.ptrw();
- const Variant *K = nullptr;
- while ((K = constant_map.next(K))) {
- int idx = constant_map[*K];
- function->constants.write[idx] = *K;
+ for (const KeyValue<Variant, int> &K : constant_map) {
+ function->constants.write[K.value] = K.key;
}
} else {
function->_constants_ptr = nullptr;
@@ -468,7 +466,7 @@ void GDScriptByteCodeGenerator::write_type_adjust(const Address &p_target, Varia
append(GDScriptFunction::OPCODE_TYPE_ADJUST_BASIS, 1);
break;
case Variant::TRANSFORM3D:
- append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM, 1);
+ append(GDScriptFunction::OPCODE_TYPE_ADJUST_TRANSFORM3D, 1);
break;
case Variant::COLOR:
append(GDScriptFunction::OPCODE_TYPE_ADJUST_COLOR, 1);
@@ -1080,6 +1078,24 @@ void GDScriptByteCodeGenerator::write_call_builtin_type_static(const Address &p_
append(Variant::get_validated_builtin_method(p_type, p_method));
}
+void GDScriptByteCodeGenerator::write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) {
+ bool is_validated = false;
+
+ MethodBind *method = ClassDB::get_method(p_class, p_method);
+
+ if (!is_validated) {
+ // Perform regular call.
+ append(GDScriptFunction::OPCODE_CALL_NATIVE_STATIC, p_arguments.size() + 1);
+ for (int i = 0; i < p_arguments.size(); i++) {
+ append(p_arguments[i]);
+ }
+ append(p_target);
+ append(method);
+ append(p_arguments.size());
+ return;
+ }
+}
+
void GDScriptByteCodeGenerator::write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) {
append(p_target.mode == Address::NIL ? GDScriptFunction::OPCODE_CALL_METHOD_BIND : GDScriptFunction::OPCODE_CALL_METHOD_BIND_RET, 2 + p_arguments.size());
for (int i = 0; i < p_arguments.size(); i++) {
@@ -1193,8 +1209,8 @@ void GDScriptByteCodeGenerator::write_call_script_function(const Address &p_targ
append(p_function_name);
}
-void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) {
- append(GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());
+void GDScriptByteCodeGenerator::write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) {
+ append(p_use_self ? GDScriptFunction::OPCODE_CREATE_SELF_LAMBDA : GDScriptFunction::OPCODE_CREATE_LAMBDA, 1 + p_captures.size());
for (int i = 0; i < p_captures.size(); i++) {
append(p_captures[i]);
}
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index db15dc55ef..6ee8fda533 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -53,19 +53,19 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
bool debug_stack = false;
Vector<int> opcodes;
- List<Map<StringName, int>> stack_id_stack;
- Map<StringName, int> stack_identifiers;
+ List<RBMap<StringName, int>> stack_id_stack;
+ RBMap<StringName, int> stack_identifiers;
List<int> stack_identifiers_counts;
- Map<StringName, int> local_constants;
+ RBMap<StringName, int> local_constants;
Vector<StackSlot> locals;
Vector<StackSlot> temporaries;
List<int> used_temporaries;
- Map<Variant::Type, List<int>> temporaries_pool;
+ RBMap<Variant::Type, List<int>> temporaries_pool;
List<GDScriptFunction::StackDebug> stack_debug;
- List<Map<StringName, int>> block_identifier_stack;
- Map<StringName, int> block_identifiers;
+ List<RBMap<StringName, int>> block_identifier_stack;
+ RBMap<StringName, int> block_identifiers;
int max_locals = 0;
int current_line = 0;
@@ -77,23 +77,23 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
#endif
HashMap<Variant, int, VariantHasher, VariantComparator> constant_map;
- Map<StringName, int> name_map;
+ RBMap<StringName, int> name_map;
#ifdef TOOLS_ENABLED
Vector<StringName> named_globals;
#endif
- Map<Variant::ValidatedOperatorEvaluator, int> operator_func_map;
- Map<Variant::ValidatedSetter, int> setters_map;
- Map<Variant::ValidatedGetter, int> getters_map;
- Map<Variant::ValidatedKeyedSetter, int> keyed_setters_map;
- Map<Variant::ValidatedKeyedGetter, int> keyed_getters_map;
- Map<Variant::ValidatedIndexedSetter, int> indexed_setters_map;
- Map<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
- Map<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
- Map<Variant::ValidatedConstructor, int> constructors_map;
- Map<Variant::ValidatedUtilityFunction, int> utilities_map;
- Map<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map;
- Map<MethodBind *, int> method_bind_map;
- Map<GDScriptFunction *, int> lambdas_map;
+ RBMap<Variant::ValidatedOperatorEvaluator, int> operator_func_map;
+ RBMap<Variant::ValidatedSetter, int> setters_map;
+ RBMap<Variant::ValidatedGetter, int> getters_map;
+ RBMap<Variant::ValidatedKeyedSetter, int> keyed_setters_map;
+ RBMap<Variant::ValidatedKeyedGetter, int> keyed_getters_map;
+ RBMap<Variant::ValidatedIndexedSetter, int> indexed_setters_map;
+ RBMap<Variant::ValidatedIndexedGetter, int> indexed_getters_map;
+ RBMap<Variant::ValidatedBuiltInMethod, int> builtin_method_map;
+ RBMap<Variant::ValidatedConstructor, int> constructors_map;
+ RBMap<Variant::ValidatedUtilityFunction, int> utilities_map;
+ RBMap<GDScriptUtilityFunctions::FunctionPtr, int> gds_utilities_map;
+ RBMap<MethodBind *, int> method_bind_map;
+ RBMap<GDScriptFunction *, int> lambdas_map;
// Lists since these can be nested.
List<int> if_jmp_addrs;
@@ -135,7 +135,7 @@ class GDScriptByteCodeGenerator : public GDScriptCodeGenerator {
stack_identifiers_counts.push_back(locals.size());
stack_id_stack.push_back(stack_identifiers);
if (debug_stack) {
- Map<StringName, int> block_ids(block_identifiers);
+ RBMap<StringName, int> block_ids(block_identifiers);
block_identifier_stack.push_back(block_ids);
block_identifiers.clear();
}
@@ -464,12 +464,13 @@ public:
virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) override;
+ virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) override;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) override;
- virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) override;
+ virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) override;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) override;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) override;
virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) override;
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index 6ada7d36f5..bd98d66fcc 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -145,7 +145,7 @@ Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptP
String GDScriptCache::get_source_code(const String &p_path) {
Vector<uint8_t> source_file;
Error err;
- FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
if (err) {
ERR_FAIL_COND_V(err, "");
}
@@ -153,7 +153,6 @@ String GDScriptCache::get_source_code(const String &p_path) {
uint64_t len = f->get_length();
source_file.resize(len + 1);
uint64_t r = f->get_buffer(source_file.ptrw(), len);
- f->close();
ERR_FAIL_COND_V(r != len, "");
source_file.write[len] = 0;
@@ -224,10 +223,10 @@ Error GDScriptCache::finish_compiling(const String &p_owner) {
singleton->full_gdscript_cache[p_owner] = script.ptr();
singleton->shallow_gdscript_cache.erase(p_owner);
- Set<String> depends = singleton->dependencies[p_owner];
+ RBSet<String> depends = singleton->dependencies[p_owner];
Error err = OK;
- for (const Set<String>::Element *E = depends.front(); E != nullptr; E = E->next()) {
+ for (const RBSet<String>::Element *E = depends.front(); E != nullptr; E = E->next()) {
Error this_err = OK;
// No need to save the script. We assume it's already referenced in the owner.
get_full_script(E->get(), this_err);
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 3ce976ee14..8abae7d4ad 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -34,7 +34,7 @@
#include "core/object/ref_counted.h"
#include "core/os/mutex.h"
#include "core/templates/hash_map.h"
-#include "core/templates/set.h"
+#include "core/templates/rb_set.h"
#include "gdscript.h"
class GDScriptAnalyzer;
@@ -74,7 +74,7 @@ class GDScriptCache {
HashMap<String, GDScriptParserRef *> parser_map;
HashMap<String, GDScript *> shallow_gdscript_cache;
HashMap<String, GDScript *> full_gdscript_cache;
- HashMap<String, Set<String>> dependencies;
+ HashMap<String, RBSet<String>> dependencies;
friend class GDScript;
friend class GDScriptParserRef;
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index 4542dd94ae..326b66a295 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -125,12 +125,13 @@ public:
virtual void write_call_gdscript_utility(const Address &p_target, GDScriptUtilityFunctions::FunctionPtr p_function, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin_type(const Address &p_target, const Address &p_base, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_builtin_type_static(const Address &p_target, Variant::Type p_type, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
+ virtual void write_call_native_static(const Address &p_target, const StringName &p_class, const StringName &p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_method_bind(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_ptrcall(const Address &p_target, const Address &p_base, MethodBind *p_method, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_self_async(const Address &p_target, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
virtual void write_call_script_function(const Address &p_target, const Address &p_base, const StringName &p_function_name, const Vector<Address> &p_arguments) = 0;
- virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures) = 0;
+ virtual void write_lambda(const Address &p_target, GDScriptFunction *p_function, const Vector<Address> &p_captures, bool p_use_self) = 0;
virtual void write_construct(const Address &p_target, Variant::Type p_type, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_array(const Address &p_target, const Vector<Address> &p_arguments) = 0;
virtual void write_construct_typed_array(const Address &p_target, const GDScriptDataType &p_element_type, const Vector<Address> &p_arguments) = 0;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 8190eecbc7..cb389fd86a 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -35,6 +35,7 @@
#include "gdscript_cache.h"
#include "gdscript_utility_functions.h"
+#include "core/config/engine.h"
#include "core/config/project_settings.h"
bool GDScriptCompiler::_is_class_member_property(CodeGen &codegen, const StringName &p_name) {
@@ -335,7 +336,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
if (GDScriptLanguage::get_singleton()->get_global_map().has(identifier)) {
// 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();
+ HashMap<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];
@@ -355,7 +356,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
class_node = class_node->outer;
}
- RES res;
+ Ref<Resource> res;
if (class_node->identifier && class_node->identifier->name == identifier) {
res = Ref<GDScript>(main_script);
@@ -575,6 +576,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// May be static built-in method call.
if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) < Variant::VARIANT_MAX) {
gen->write_call_builtin_type_static(result, GDScriptParser::get_builtin_type(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name), subscript->attribute->name, arguments);
+ } else if (!call->is_super && subscript->base->type == GDScriptParser::Node::IDENTIFIER && call->function_name != SNAME("new") &&
+ ClassDB::class_exists(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name) && !Engine::get_singleton()->has_singleton(static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name)) {
+ // It's a static native method call.
+ gen->write_call_native_static(result, static_cast<GDScriptParser::IdentifierNode *>(subscript->base)->name, subscript->attribute->name, arguments);
} else {
GDScriptCodeGenerator::Address base = _parse_expression(codegen, r_error, subscript->base);
if (r_error) {
@@ -698,10 +703,10 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} else if (subscript->is_attribute) {
if (subscript->base->type == GDScriptParser::Node::SELF && codegen.script) {
GDScriptParser::IdentifierNode *identifier = subscript->attribute;
- const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(identifier->name);
+ HashMap<StringName, GDScript::MemberInfo>::Iterator MI = codegen.script->member_indices.find(identifier->name);
#ifdef DEBUG_ENABLED
- if (MI && MI->get().getter == codegen.function_name) {
+ if (MI && MI->value.getter == codegen.function_name) {
String n = identifier->name;
_set_error("Must use '" + n + "' instead of 'self." + n + "' in getter.", identifier);
r_error = ERR_COMPILATION_FAILED;
@@ -709,11 +714,11 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
#endif
- if (MI && MI->get().getter == "") {
+ if (MI && MI->value.getter == "") {
// Remove result temp as we don't need it.
gen->pop_temporary();
// Faster than indexing self (as if no self. had been used).
- return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, MI->get().index, _gdtype_from_datatype(subscript->get_datatype()));
+ return GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::MEMBER, MI->value.index, _gdtype_from_datatype(subscript->get_datatype()));
}
}
@@ -889,8 +894,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
const GDScriptParser::SubscriptNode *subscript = static_cast<GDScriptParser::SubscriptNode *>(assignment->assignee);
#ifdef DEBUG_ENABLED
if (subscript->is_attribute && subscript->base->type == GDScriptParser::Node::SELF && codegen.script) {
- const Map<StringName, GDScript::MemberInfo>::Element *MI = codegen.script->member_indices.find(subscript->attribute->name);
- if (MI && MI->get().setter == codegen.function_name) {
+ HashMap<StringName, GDScript::MemberInfo>::Iterator MI = codegen.script->member_indices.find(subscript->attribute->name);
+ if (MI && MI->value.setter == codegen.function_name) {
String n = subscript->attribute->name;
_set_error("Must use '" + n + "' instead of 'self." + n + "' in setter.", subscript);
r_error = ERR_COMPILATION_FAILED;
@@ -1192,7 +1197,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
return GDScriptCodeGenerator::Address();
}
- gen->write_lambda(result, function, captures);
+ gen->write_lambda(result, function, captures, lambda->use_self);
for (int i = 0; i < captures.size(); i++) {
if (captures[i].mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -2495,8 +2500,8 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
//validate instances if keeping state
if (p_keep_state) {
- for (Set<Object *>::Element *E = p_script->instances.front(); E;) {
- Set<Object *>::Element *N = E->next();
+ for (RBSet<Object *>::Element *E = p_script->instances.front(); E;) {
+ RBSet<Object *>::Element *N = E->next();
ScriptInstance *si = E->get()->get_script_instance();
if (si->is_placeholder()) {
@@ -2558,7 +2563,7 @@ Error GDScriptCompiler::_parse_class_blocks(GDScript *p_script, const GDScriptPa
}
void GDScriptCompiler::_make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
- Map<StringName, Ref<GDScript>> old_subclasses;
+ HashMap<StringName, Ref<GDScript>> old_subclasses;
if (p_keep_state) {
old_subclasses = p_script->subclasses;
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 8d71437344..c9ffb04fb8 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -31,7 +31,7 @@
#ifndef GDSCRIPT_COMPILER_H
#define GDSCRIPT_COMPILER_H
-#include "core/templates/set.h"
+#include "core/templates/rb_set.h"
#include "gdscript.h"
#include "gdscript_codegen.h"
#include "gdscript_function.h"
@@ -39,8 +39,8 @@
class GDScriptCompiler {
const GDScriptParser *parser = nullptr;
- Set<GDScript *> parsed_classes;
- Set<GDScript *> parsing_classes;
+ RBSet<GDScript *> parsed_classes;
+ RBSet<GDScript *> parsing_classes;
GDScript *main_script = nullptr;
struct CodeGen {
@@ -49,9 +49,9 @@ class GDScriptCompiler {
const GDScriptParser::FunctionNode *function_node = nullptr;
StringName function_name;
GDScriptCodeGenerator *generator = nullptr;
- Map<StringName, GDScriptCodeGenerator::Address> parameters;
- Map<StringName, GDScriptCodeGenerator::Address> locals;
- List<Map<StringName, GDScriptCodeGenerator::Address>> locals_stack;
+ HashMap<StringName, GDScriptCodeGenerator::Address> parameters;
+ HashMap<StringName, GDScriptCodeGenerator::Address> locals;
+ List<HashMap<StringName, GDScriptCodeGenerator::Address>> locals_stack;
GDScriptCodeGenerator::Address add_local(const StringName &p_name, const GDScriptDataType &p_type) {
uint32_t addr = generator->add_local(p_name, p_type);
@@ -101,7 +101,7 @@ class GDScriptCompiler {
}
void start_block() {
- Map<StringName, GDScriptCodeGenerator::Address> old_locals = locals;
+ HashMap<StringName, GDScriptCodeGenerator::Address> old_locals = locals;
locals_stack.push_back(old_locals);
generator->start_block();
}
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index cc0be94a9e..dc114f2eff 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -564,6 +564,28 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr += 5 + argc;
} break;
+ case OPCODE_CALL_NATIVE_STATIC: {
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 1 + instr_var_args]];
+ int argc = _code_ptr[ip + 2 + instr_var_args];
+
+ text += "call native method static ";
+ text += DADDR(1 + argc);
+ text += " = ";
+ text += method->get_instance_class();
+ text += ".";
+ text += method->get_name();
+ text += "(";
+
+ for (int i = 0; i < argc; i++) {
+ if (i > 0) {
+ text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr += 4 + argc;
+ } break;
case OPCODE_CALL_PTRCALL_NO_RETURN: {
text += "call-ptrcall (no return) ";
@@ -770,6 +792,25 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
incr = 3 + captures_count;
} break;
+ case OPCODE_CREATE_SELF_LAMBDA: {
+ int captures_count = _code_ptr[ip + 1 + instr_var_args];
+ GDScriptFunction *lambda = _lambdas_ptr[_code_ptr[ip + 2 + instr_var_args]];
+
+ text += DADDR(1 + captures_count);
+ text += "create self lambda from ";
+ text += lambda->name.operator String();
+ text += "function, captures (";
+
+ for (int i = 0; i < captures_count; i++) {
+ if (i > 0) {
+ text += ", ";
+ }
+ text += DADDR(1 + i);
+ }
+ text += ")";
+
+ incr = 3 + captures_count;
+ } break;
case OPCODE_JUMP: {
text += "jump ";
text += itos(_code_ptr[ip + 1]);
@@ -968,7 +1009,7 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const {
DISASSEMBLE_TYPE_ADJUST(QUATERNION);
DISASSEMBLE_TYPE_ADJUST(AABB);
DISASSEMBLE_TYPE_ADJUST(BASIS);
- DISASSEMBLE_TYPE_ADJUST(TRANSFORM);
+ DISASSEMBLE_TYPE_ADJUST(TRANSFORM3D);
DISASSEMBLE_TYPE_ADJUST(COLOR);
DISASSEMBLE_TYPE_ADJUST(STRING_NAME);
DISASSEMBLE_TYPE_ADJUST(NODE_PATH);
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 5ed4054c57..72f54626e3 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -98,7 +98,7 @@ Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(
return templates;
}
-static void get_function_names_recursively(const GDScriptParser::ClassNode *p_class, const String &p_prefix, Map<int, String> &r_funcs) {
+static void get_function_names_recursively(const GDScriptParser::ClassNode *p_class, const String &p_prefix, HashMap<int, String> &r_funcs) {
for (int i = 0; i < p_class->members.size(); i++) {
if (p_class->members[i].type == GDScriptParser::ClassNode::Member::FUNCTION) {
const GDScriptParser::FunctionNode *function = p_class->members[i].function;
@@ -110,7 +110,7 @@ static void get_function_names_recursively(const GDScriptParser::ClassNode *p_cl
}
}
-bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
+bool GDScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, RBSet<int> *r_safe_lines) const {
GDScriptParser parser;
GDScriptAnalyzer analyzer(&parser);
@@ -148,7 +148,7 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li
return false;
} else {
const GDScriptParser::ClassNode *cl = parser.get_tree();
- Map<int, String> funcs;
+ HashMap<int, String> funcs;
get_function_names_recursively(cl, "", funcs);
@@ -159,7 +159,7 @@ bool GDScriptLanguage::validate(const String &p_script, const String &p_path, Li
#ifdef DEBUG_ENABLED
if (r_safe_lines) {
- const Set<int> &unsafe_lines = parser.get_unsafe_lines();
+ const RBSet<int> &unsafe_lines = parser.get_unsafe_lines();
for (int i = 1; i <= parser.get_last_line_number(); i++) {
if (!unsafe_lines.has(i)) {
r_safe_lines->insert(i);
@@ -321,7 +321,7 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> *
Ref<GDScript> script = instance->get_script();
ERR_FAIL_COND(script.is_null());
- const Map<StringName, GDScript::MemberInfo> &mi = script->debug_get_member_indices();
+ const HashMap<StringName, GDScript::MemberInfo> &mi = script->debug_get_member_indices();
for (const KeyValue<StringName, GDScript::MemberInfo> &E : mi) {
p_members->push_back(E.key);
@@ -343,7 +343,7 @@ ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) {
}
void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) {
- const Map<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map();
+ const HashMap<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map();
const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array();
List<Pair<String, Variant>> cinfo;
@@ -485,6 +485,89 @@ struct GDScriptCompletionIdentifier {
const GDScriptParser::ExpressionNode *assigned_expression = nullptr;
};
+// LOCATION METHODS
+// These methods are used to populate the `CodeCompletionOption::location` integer.
+// For these methods, the location is based on the depth in the inheritance chain that the property
+// appears. For example, if you are completing code in a class that inherits Node2D, a property found on Node2D
+// will have a "better" (lower) location "score" than a property that is found on CanvasItem.
+
+static int _get_property_location(StringName p_class, StringName p_property) {
+ if (!ClassDB::has_property(p_class, p_property)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_property(class_test, p_property, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_constant_location(StringName p_class, StringName p_constant) {
+ if (!ClassDB::has_integer_constant(p_class, p_constant)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_integer_constant(class_test, p_constant, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_signal_location(StringName p_class, StringName p_signal) {
+ if (!ClassDB::has_signal(p_class, p_signal)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_signal(class_test, p_signal, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_method_location(StringName p_class, StringName p_method) {
+ if (!ClassDB::has_method(p_class, p_method)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::has_method(class_test, p_method, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+static int _get_enum_constant_location(StringName p_class, StringName p_enum_constant) {
+ if (!ClassDB::get_integer_constant_enum(p_class, p_enum_constant)) {
+ return ScriptLanguage::LOCATION_OTHER;
+ }
+
+ int depth = 0;
+ StringName class_test = p_class;
+ while (class_test && !ClassDB::get_integer_constant_enum(class_test, p_enum_constant, true)) {
+ class_test = ClassDB::get_parent_class(class_test);
+ depth++;
+ }
+
+ return depth | ScriptLanguage::LOCATION_PARENT_MASK;
+}
+
+// END LOCATION METHODS
+
static String _get_visual_datatype(const PropertyInfo &p_info, bool p_is_arg = true) {
if (p_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
String enum_name = p_info.class_name;
@@ -639,7 +722,7 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
return arghint;
}
-static void _get_directory_contents(EditorFileSystemDirectory *p_dir, Map<String, ScriptLanguage::CodeCompletionOption> &r_list) {
+static void _get_directory_contents(EditorFileSystemDirectory *p_dir, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_list) {
const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
for (int i = 0; i < p_dir->get_file_count(); i++) {
@@ -653,7 +736,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, ScriptLanguage::CodeCompletionOption> &r_result) {
+static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_annotation, int p_argument, const String p_quote_style, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) {
if (p_annotation->name == SNAME("@export_range")) {
if (p_argument == 3 || p_argument == 4) {
// Slider hint.
@@ -694,7 +777,22 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
}
}
-static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) {
+static void _find_built_in_variants(HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, bool exclude_nil = false) {
+ for (int i = 0; i < Variant::VARIANT_MAX; i++) {
+ if (!exclude_nil && Variant::Type(i) == Variant::Type::NIL) {
+ ScriptLanguage::CodeCompletionOption option("null", ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ r_result.insert(option.display, option);
+ } else {
+ ScriptLanguage::CodeCompletionOption option(Variant::get_type_name(Variant::Type(i)), ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ r_result.insert(option.display, option);
+ }
+ }
+}
+
+static void _list_available_types(bool p_inherit_only, GDScriptParser::CompletionContext &p_context, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) {
+ // Built-in Variant Types
+ _find_built_in_variants(r_result, true);
+
List<StringName> native_types;
ClassDB::get_class_list(&native_types);
for (const StringName &E : native_types) {
@@ -721,18 +819,18 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
const GDScriptParser::ClassNode::Member &member = current->members[i];
switch (member.type) {
case GDScriptParser::ClassNode::Member::CLASS: {
- ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
if (!p_inherit_only) {
- ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
+ ScriptLanguage::CodeCompletionOption option(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
}
} break;
case GDScriptParser::ClassNode::Member::CONSTANT: {
if (member.constant->get_datatype().is_meta_type && p_context.current_class->outer != nullptr) {
- ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_LOCAL);
r_result.insert(option.display, option);
}
} break;
@@ -748,30 +846,31 @@ static void _list_available_types(bool p_inherit_only, GDScriptParser::Completio
List<StringName> global_classes;
ScriptServer::get_global_class_list(&global_classes);
for (const StringName &E : global_classes) {
- ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
r_result.insert(option.display, option);
}
// Autoload singletons
- OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
- for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
- const ProjectSettings::AutoloadInfo &info = E.get();
+ HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
+ const ProjectSettings::AutoloadInfo &info = E.value;
if (!info.is_singleton || info.path.get_extension().to_lower() != "gd") {
continue;
}
- ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ ScriptLanguage::CodeCompletionOption option(info.name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
r_result.insert(option.display, option);
}
}
-static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) {
+static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) {
for (int i = 0; i < p_suite->locals.size(); i++) {
ScriptLanguage::CodeCompletionOption option;
if (p_suite->locals[i].type == GDScriptParser::SuiteNode::Local::CONSTANT) {
- option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, ScriptLanguage::LOCATION_LOCAL);
option.default_value = p_suite->locals[i].constant->initializer->reduced_value;
} else {
- option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE);
+ option = ScriptLanguage::CodeCompletionOption(p_suite->locals[i].name, ScriptLanguage::CODE_COMPLETION_KIND_VARIABLE, ScriptLanguage::LOCATION_LOCAL);
}
r_result.insert(option.display, option);
}
@@ -780,16 +879,18 @@ static void _find_identifiers_in_suite(const GDScriptParser::SuiteNode *p_suite,
}
}
-static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth);
+static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth);
-static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
+static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class, bool p_only_functions, bool p_static, bool p_parent_only, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
if (!p_parent_only) {
bool outer = false;
const GDScriptParser::ClassNode *clss = p_class;
+ int classes_processed = 0;
while (clss) {
for (int i = 0; i < clss->members.size(); i++) {
+ const int location = (classes_processed + p_recursion_depth) | ScriptLanguage::LOCATION_PARENT_MASK;
const GDScriptParser::ClassNode::Member &member = clss->members[i];
ScriptLanguage::CodeCompletionOption option;
switch (member.type) {
@@ -797,7 +898,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions || outer || (p_static)) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
+ option = ScriptLanguage::CodeCompletionOption(member.variable->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
break;
case GDScriptParser::ClassNode::Member::CONSTANT:
if (p_only_functions) {
@@ -806,7 +907,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (r_result.has(member.constant->identifier->name)) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(member.constant->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
if (member.constant->initializer) {
option.default_value = member.constant->initializer->reduced_value;
}
@@ -815,25 +916,25 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
+ option = ScriptLanguage::CodeCompletionOption(member.m_class->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, location);
break;
case GDScriptParser::ClassNode::Member::ENUM_VALUE:
if (p_only_functions) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ option = ScriptLanguage::CodeCompletionOption(member.enum_value.identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
break;
case GDScriptParser::ClassNode::Member::ENUM:
if (p_only_functions) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
+ option = ScriptLanguage::CodeCompletionOption(member.m_enum->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location);
break;
case GDScriptParser::ClassNode::Member::FUNCTION:
if (outer || (p_static && !member.function->is_static) || member.function->identifier->name.operator String().begins_with("@")) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ option = ScriptLanguage::CodeCompletionOption(member.function->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
if (member.function->parameters.size() > 0) {
option.insert_text += "(";
} else {
@@ -844,7 +945,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
if (p_only_functions || outer) {
continue;
}
- option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL);
+ option = ScriptLanguage::CodeCompletionOption(member.signal->identifier->name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
break;
case GDScriptParser::ClassNode::Member::UNDEFINED:
break;
@@ -853,6 +954,7 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
}
outer = true;
clss = clss->outer;
+ classes_processed++;
}
}
@@ -864,14 +966,14 @@ static void _find_identifiers_in_class(const GDScriptParser::ClassNode *p_class,
_find_identifiers_in_base(base_type, p_only_functions, r_result, p_recursion_depth + 1);
}
-static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
+static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
ERR_FAIL_COND(p_recursion_depth > COMPLETION_RECURSION_LIMIT);
GDScriptParser::DataType base_type = p_base.type;
bool _static = base_type.is_meta_type;
if (_static && base_type.kind != GDScriptParser::DataType::BUILTIN) {
- ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ ScriptLanguage::CodeCompletionOption option("new", ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, ScriptLanguage::LOCATION_LOCAL);
option.insert_text += "(";
r_result.insert(option.display, option);
}
@@ -891,21 +993,24 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<PropertyInfo> members;
scr->get_script_property_list(&members);
for (const PropertyInfo &E : members) {
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
+ int location = p_recursion_depth + _get_property_location(scr->get_class_name(), E.class_name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
r_result.insert(option.display, option);
}
}
- Map<StringName, Variant> constants;
+ HashMap<StringName, Variant> constants;
scr->get_constants(&constants);
for (const KeyValue<StringName, Variant> &E : constants) {
- ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ int location = p_recursion_depth + _get_constant_location(scr->get_class_name(), E.key);
+ ScriptLanguage::CodeCompletionOption option(E.key.operator String(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
r_result.insert(option.display, option);
}
List<MethodInfo> signals;
scr->get_script_signal_list(&signals);
for (const MethodInfo &E : signals) {
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL);
+ int location = p_recursion_depth + _get_signal_location(scr->get_class_name(), E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
r_result.insert(option.display, option);
}
}
@@ -916,7 +1021,8 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.begins_with("@")) {
continue;
}
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
+ int location = p_recursion_depth + _get_method_location(scr->get_class_name(), E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
if (E.arguments.size()) {
option.insert_text += "(";
} else {
@@ -946,7 +1052,16 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
List<String> constants;
ClassDB::get_integer_constant_list(type, &constants);
for (const String &E : constants) {
- ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ int location = p_recursion_depth + _get_constant_location(type, StringName(E));
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT, location);
+ r_result.insert(option.display, option);
+ }
+
+ List<MethodInfo> signals;
+ ClassDB::get_signal_list(type, &signals);
+ for (const MethodInfo &E : signals) {
+ int location = p_recursion_depth + _get_signal_location(type, StringName(E.name));
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_SIGNAL, location);
r_result.insert(option.display, option);
}
@@ -960,29 +1075,33 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (E.name.contains("/")) {
continue;
}
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER);
+ int location = p_recursion_depth + _get_property_location(type, E.class_name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_MEMBER, location);
r_result.insert(option.display, option);
}
}
}
- if (!_static || Engine::get_singleton()->has_singleton(type)) {
- List<MethodInfo> methods;
- ClassDB::get_method_list(type, &methods, false, true);
- for (const MethodInfo &E : methods) {
- if (E.name.begins_with("_")) {
- continue;
- }
- ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION);
- if (E.arguments.size()) {
- option.insert_text += "(";
- } else {
- option.insert_text += "()";
- }
- r_result.insert(option.display, option);
+ bool only_static = _static && !Engine::get_singleton()->has_singleton(type);
+
+ List<MethodInfo> methods;
+ ClassDB::get_method_list(type, &methods, false, true);
+ for (const MethodInfo &E : methods) {
+ if (only_static && (E.flags & METHOD_FLAG_STATIC) == 0) {
+ continue;
+ }
+ if (E.name.begins_with("_")) {
+ continue;
+ }
+ int location = p_recursion_depth + _get_method_location(type, E.name);
+ ScriptLanguage::CodeCompletionOption option(E.name, ScriptLanguage::CODE_COMPLETION_KIND_FUNCTION, location);
+ if (E.arguments.size()) {
+ option.insert_text += "(";
+ } else {
+ option.insert_text += "()";
}
+ r_result.insert(option.display, option);
}
-
return;
} break;
case GDScriptParser::DataType::BUILTIN: {
@@ -1030,7 +1149,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
}
}
-static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool p_only_functions, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
+static void _find_identifiers(const GDScriptParser::CompletionContext &p_context, bool p_only_functions, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, int p_recursion_depth) {
if (!p_only_functions && p_context.current_suite) {
// This includes function parameters, since they are also locals.
_find_identifiers_in_suite(p_context.current_suite, r_result);
@@ -1058,17 +1177,7 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
return;
}
- static const char *_type_names[Variant::VARIANT_MAX] = {
- "null", "bool", "int", "float", "String", "StringName", "Vector2", "Vector2i", "Rect2", "Rect2i", "Vector3", "Vector3i", "Transform2D", "Plane", "Quaternion", "AABB", "Basis", "Transform3D",
- "Color", "NodePath", "RID", "Signal", "Callable", "Object", "Dictionary", "Array", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "PackedFloat32Array", "PackedFloat64Array", "PackedStringArray",
- "PackedVector2Array", "PackedVector3Array", "PackedColorArray"
- };
- static_assert((sizeof(_type_names) / sizeof(*_type_names)) == Variant::VARIANT_MAX, "Completion for builtin types is incomplete");
-
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- ScriptLanguage::CodeCompletionOption option(_type_names[i], ScriptLanguage::CODE_COMPLETION_KIND_CLASS);
- r_result.insert(option.display, option);
- }
+ _find_built_in_variants(r_result);
static const char *_keywords[] = {
"false", "PI", "TAU", "INF", "NAN", "self", "true", "breakpoint", "tool", "super",
@@ -1119,12 +1228,11 @@ static void _find_identifiers(GDScriptParser::CompletionContext &p_context, bool
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) {
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
+ if (!E.value.is_singleton) {
continue;
}
- ScriptLanguage::CodeCompletionOption option(E.key(), ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
+ ScriptLanguage::CodeCompletionOption option(E.key, ScriptLanguage::CODE_COMPLETION_KIND_CONSTANT);
r_result.insert(option.display, option);
}
@@ -1417,12 +1525,10 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[which]);
found = true;
} else {
- OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-
- for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
- String name = E.key();
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
+ String name = E.key;
if (name == which) {
- String script = E.value().path;
+ String script = E.value.path;
if (!script.begins_with("res://")) {
script = "res://" + script;
@@ -1983,7 +2089,7 @@ static bool _guess_identifier_type_from_base(GDScriptParser::CompletionContext &
case GDScriptParser::DataType::SCRIPT: {
Ref<Script> scr = base_type.script_type;
if (scr.is_valid()) {
- Map<StringName, Variant> constants;
+ HashMap<StringName, Variant> constants;
scr->get_constants(&constants);
if (constants.has(p_identifier)) {
r_type = _type_from_variant(constants[p_identifier]);
@@ -2212,7 +2318,7 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
return false;
}
-static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, Map<String, ScriptLanguage::CodeCompletionOption> &r_result) {
+static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_context, const String &p_enum_hint, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result) {
if (!p_enum_hint.contains(".")) {
// Global constant or in the current class.
StringName current_enum = p_enum_hint;
@@ -2242,13 +2348,14 @@ static void _find_enumeration_candidates(GDScriptParser::CompletionContext &p_co
ClassDB::get_enum_constants(class_name, enum_name, &enum_constants);
for (const StringName &E : enum_constants) {
String candidate = class_name + "." + E;
- ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM);
+ int location = _get_enum_constant_location(class_name, E);
+ ScriptLanguage::CodeCompletionOption option(candidate, ScriptLanguage::CODE_COMPLETION_KIND_ENUM, location);
r_result.insert(option.display, option);
}
}
}
-static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) {
+static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptCompletionIdentifier &p_base, const StringName &p_method, int p_argidx, bool p_static, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, String &r_arghint) {
Variant base = p_base.value;
GDScriptParser::DataType base_type = p_base.type;
@@ -2367,7 +2474,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
}
-static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, Map<String, ScriptLanguage::CodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
+static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, const GDScriptParser::Node *p_call, int p_argidx, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_result, bool &r_forced, String &r_arghint) {
if (p_call->type == GDScriptParser::Node::PRELOAD) {
if (p_argidx == 0 && bool(EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))) {
_get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), r_result);
@@ -2482,7 +2589,7 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
analyzer.analyze();
r_forced = false;
- Map<String, ScriptLanguage::CodeCompletionOption> options;
+ HashMap<String, ScriptLanguage::CodeCompletionOption> options;
GDScriptParser::CompletionContext completion_context = parser.get_completion_context();
completion_context.base = p_owner;
@@ -2781,10 +2888,8 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
}
// Get autoloads.
- OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
-
- for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
- String path = "/root/" + E.key();
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
+ String path = "/root/" + E.key;
ScriptLanguage::CodeCompletionOption option(path.quote(quote_style), ScriptLanguage::CODE_COMPLETION_KIND_NODE_PATH);
options.insert(option.display, option);
}
@@ -2961,6 +3066,13 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
}
+ if (ClassDB::has_signal(class_name, p_symbol, true)) {
+ r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_SIGNAL;
+ r_result.class_name = base_type.native_type;
+ r_result.class_member = p_symbol;
+ return OK;
+ }
+
StringName enum_name = ClassDB::get_integer_constant_enum(class_name, p_symbol, true);
if (enum_name != StringName()) {
r_result.type = ScriptLanguage::LOOKUP_RESULT_CLASS_ENUM;
@@ -3005,7 +3117,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
Variant v;
- REF v_ref;
+ Ref<RefCounted> v_ref;
if (base_type.builtin_type == Variant::OBJECT) {
v_ref.instantiate();
v = v_ref;
@@ -3167,7 +3279,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
}
// Global.
- Map<StringName, int> classes = GDScriptLanguage::get_singleton()->get_global_map();
+ HashMap<StringName, int> classes = GDScriptLanguage::get_singleton()->get_global_map();
if (classes.has(p_symbol)) {
Variant value = GDScriptLanguage::get_singleton()->get_global_array()[classes[p_symbol]];
if (value.get_type() == Variant::OBJECT) {
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index 3d708955ed..deef593f34 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -93,7 +93,7 @@ struct _GDFKCS {
void GDScriptFunction::debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const {
int oc = 0;
- Map<StringName, _GDFKC> sdmap;
+ HashMap<StringName, _GDFKC> sdmap;
for (const StackDebug &sd : stack_debug) {
if (sd.line >= p_line) {
break;
@@ -279,7 +279,8 @@ Variant GDScriptFunctionState::resume(const Variant &p_arg) {
void GDScriptFunctionState::_clear_stack() {
if (state.stack_size) {
Variant *stack = (Variant *)state.stack.ptr();
- for (int i = 0; i < state.stack_size; i++) {
+ // The first 3 are special addresses and not copied to the state, so we skip them here.
+ for (int i = 3; i < state.stack_size; i++) {
stack[i].~Variant();
}
state.stack_size = 0;
@@ -300,8 +301,6 @@ GDScriptFunctionState::GDScriptFunctionState() :
}
GDScriptFunctionState::~GDScriptFunctionState() {
- _clear_stack();
-
{
MutexLock lock(GDScriptLanguage::singleton->lock);
scripts_list.remove_from_list();
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 3ee664c76d..d2ca795977 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -259,6 +259,7 @@ public:
OPCODE_CALL_METHOD_BIND,
OPCODE_CALL_METHOD_BIND_RET,
OPCODE_CALL_BUILTIN_STATIC,
+ OPCODE_CALL_NATIVE_STATIC,
// ptrcall have one instruction per return type.
OPCODE_CALL_PTRCALL_NO_RETURN,
OPCODE_CALL_PTRCALL_BOOL,
@@ -298,6 +299,7 @@ public:
OPCODE_AWAIT,
OPCODE_AWAIT_RESUME,
OPCODE_CREATE_LAMBDA,
+ OPCODE_CREATE_SELF_LAMBDA,
OPCODE_JUMP,
OPCODE_JUMP_IF,
OPCODE_JUMP_IF_NOT,
@@ -364,7 +366,7 @@ public:
OPCODE_TYPE_ADJUST_QUATERNION,
OPCODE_TYPE_ADJUST_AABB,
OPCODE_TYPE_ADJUST_BASIS,
- OPCODE_TYPE_ADJUST_TRANSFORM,
+ OPCODE_TYPE_ADJUST_TRANSFORM3D,
OPCODE_TYPE_ADJUST_COLOR,
OPCODE_TYPE_ADJUST_STRING_NAME,
OPCODE_TYPE_ADJUST_NODE_PATH,
@@ -493,7 +495,7 @@ private:
Vector<GDScriptDataType> argument_types;
GDScriptDataType return_type;
- Map<int, Variant::Type> temporary_slots;
+ HashMap<int, Variant::Type> temporary_slots;
#ifdef TOOLS_ENABLED
Vector<StringName> arg_names;
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index baf93e1098..c43fa12c8c 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -93,3 +93,81 @@ GDScriptLambdaCallable::GDScriptLambdaCallable(Ref<GDScript> p_script, GDScriptF
h = (uint32_t)hash_djb2_one_64((uint64_t)this);
}
+
+bool GDScriptLambdaSelfCallable::compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Lambda callables are only compared by reference.
+ return p_a == p_b;
+}
+
+bool GDScriptLambdaSelfCallable::compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ // Lambda callables are only compared by reference.
+ return p_a < p_b;
+}
+
+uint32_t GDScriptLambdaSelfCallable::hash() const {
+ return h;
+}
+
+String GDScriptLambdaSelfCallable::get_as_text() const {
+ if (function->get_name() != StringName()) {
+ return function->get_name().operator String() + "(lambda)";
+ }
+ return "(anonymous lambda)";
+}
+
+CallableCustom::CompareEqualFunc GDScriptLambdaSelfCallable::get_compare_equal_func() const {
+ return compare_equal;
+}
+
+CallableCustom::CompareLessFunc GDScriptLambdaSelfCallable::get_compare_less_func() const {
+ return compare_less;
+}
+
+ObjectID GDScriptLambdaSelfCallable::get_object() const {
+ return object->get_instance_id();
+}
+
+void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
+#ifdef DEBUG_ENABLED
+ if (object->get_script_instance() == nullptr || object->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) {
+ ERR_PRINT("Trying to call a lambda with an invalid instance.");
+ r_call_error.error = Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL;
+ return;
+ }
+#endif
+
+ int captures_amount = captures.size();
+
+ if (captures_amount > 0) {
+ Vector<const Variant *> args;
+ args.resize(p_argcount + captures_amount);
+ for (int i = 0; i < captures_amount; i++) {
+ args.write[i] = &captures[i];
+ }
+ for (int i = 0; i < p_argcount; i++) {
+ args.write[i + captures_amount] = p_arguments[i];
+ }
+
+ r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), args.ptrw(), args.size(), r_call_error);
+ r_call_error.argument -= captures_amount;
+ } else {
+ r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), p_arguments, p_argcount, r_call_error);
+ }
+}
+
+GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
+ reference = p_self;
+ object = p_self.ptr();
+ function = p_function;
+ captures = p_captures;
+
+ h = (uint32_t)hash_djb2_one_64((uint64_t)this);
+}
+
+GDScriptLambdaSelfCallable::GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures) {
+ object = p_self;
+ function = p_function;
+ captures = p_captures;
+
+ h = (uint32_t)hash_djb2_one_64((uint64_t)this);
+}
diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h
index f6a54a1a2f..248176e32c 100644
--- a/modules/gdscript/gdscript_lambda_callable.h
+++ b/modules/gdscript/gdscript_lambda_callable.h
@@ -62,4 +62,29 @@ public:
virtual ~GDScriptLambdaCallable() = default;
};
+// Lambda callable that references a particular object, so it can use `self` in the body.
+class GDScriptLambdaSelfCallable : public CallableCustom {
+ GDScriptFunction *function = nullptr;
+ Ref<RefCounted> reference; // For objects that are RefCounted, keep a reference.
+ Object *object = nullptr; // For non RefCounted objects, use a direct pointer.
+ uint32_t h;
+
+ Vector<Variant> captures;
+
+ static bool compare_equal(const CallableCustom *p_a, const CallableCustom *p_b);
+ static bool compare_less(const CallableCustom *p_a, const CallableCustom *p_b);
+
+public:
+ uint32_t hash() const override;
+ String get_as_text() const override;
+ CompareEqualFunc get_compare_equal_func() const override;
+ CompareLessFunc get_compare_less_func() const override;
+ ObjectID get_object() const override;
+ void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
+
+ GDScriptLambdaSelfCallable(Ref<RefCounted> p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
+ GDScriptLambdaSelfCallable(Object *p_self, GDScriptFunction *p_function, const Vector<Variant> &p_captures);
+ virtual ~GDScriptLambdaSelfCallable() = default;
+};
+
#endif // GDSCRIPT_LAMBDA_CALLABLE
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 67d778f932..8563f2b432 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -100,10 +100,8 @@ void GDScriptParser::cleanup() {
}
void GDScriptParser::get_annotation_list(List<MethodInfo> *r_annotations) const {
- List<StringName> keys;
- valid_annotations.get_key_list(&keys);
- for (const StringName &E : keys) {
- r_annotations->push_back(valid_annotations[E].info);
+ for (const KeyValue<StringName, AnnotationInfo> &E : valid_annotations) {
+ r_annotations->push_back(E.value.info);
}
}
@@ -1863,7 +1861,7 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
if (pattern == nullptr) {
continue;
}
- if (pattern->pattern_type == PatternNode::PT_BIND) {
+ if (pattern->binds.size() > 0) {
has_bind = true;
}
if (branch->patterns.size() > 0 && has_bind) {
@@ -1894,11 +1892,9 @@ GDScriptParser::MatchBranchNode *GDScriptParser::parse_match_branch() {
SuiteNode *suite = alloc_node<SuiteNode>();
if (branch->patterns.size() > 0) {
- List<StringName> binds;
- branch->patterns[0]->binds.get_key_list(&binds);
-
- for (const StringName &E : binds) {
- SuiteNode::Local local(branch->patterns[0]->binds[E], current_function);
+ for (const KeyValue<StringName, IdentifierNode *> &E : branch->patterns[0]->binds) {
+ SuiteNode::Local local(E.value, current_function);
+ local.type = SuiteNode::Local::PATTERN_BIND;
suite->add_local(local);
}
}
@@ -2200,9 +2196,6 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_self(ExpressionNode *p_pre
if (current_function && current_function->is_static) {
push_error(R"(Cannot use "self" inside a static function.)");
}
- if (in_lambda) {
- push_error(R"(Cannot use "self" inside a lambda.)");
- }
SelfNode *self = alloc_node<SelfNode>();
self->current_class = current_class;
return self;
@@ -2322,6 +2315,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_binary_operator(Expression
operation->operation = BinaryOpNode::OP_MODULO;
operation->variant_op = Variant::OP_MODULE;
break;
+ case GDScriptTokenizer::Token::STAR_STAR:
+ operation->operation = BinaryOpNode::OP_POWER;
+ operation->variant_op = Variant::OP_POWER;
+ break;
case GDScriptTokenizer::Token::LESS_LESS:
operation->operation = BinaryOpNode::OP_BIT_LEFT_SHIFT;
operation->variant_op = Variant::OP_SHIFT_LEFT;
@@ -2485,6 +2482,10 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_assignment(ExpressionNode
assignment->operation = AssignmentNode::OP_MULTIPLICATION;
assignment->variant_op = Variant::OP_MULTIPLY;
break;
+ case GDScriptTokenizer::Token::STAR_STAR_EQUAL:
+ assignment->operation = AssignmentNode::OP_POWER;
+ assignment->variant_op = Variant::OP_POWER;
+ break;
case GDScriptTokenizer::Token::SLASH_EQUAL:
assignment->operation = AssignmentNode::OP_DIVISION;
assignment->variant_op = Variant::OP_DIVIDE;
@@ -3052,7 +3053,7 @@ bool GDScriptParser::has_comment(int p_line) {
}
String GDScriptParser::get_doc_comment(int p_line, bool p_single_line) {
- const Map<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
+ const HashMap<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
ERR_FAIL_COND_V(!comments.has(p_line), String());
if (p_single_line) {
@@ -3104,7 +3105,7 @@ String GDScriptParser::get_doc_comment(int p_line, bool p_single_line) {
}
void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &p_desc, Vector<Pair<String, String>> &p_tutorials, bool p_inner_class) {
- const Map<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
+ const HashMap<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
if (!comments.has(p_line)) {
return;
}
@@ -3267,6 +3268,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // PLUS,
{ &GDScriptParser::parse_unary_operator, &GDScriptParser::parse_binary_operator, PREC_ADDITION_SUBTRACTION }, // MINUS,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // STAR,
+ { nullptr, &GDScriptParser::parse_binary_operator, PREC_POWER }, // STAR_STAR,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // SLASH,
{ nullptr, &GDScriptParser::parse_binary_operator, PREC_FACTOR }, // PERCENT,
// Assignment
@@ -3274,6 +3276,7 @@ GDScriptParser::ParseRule *GDScriptParser::get_rule(GDScriptTokenizer::Token::Ty
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // PLUS_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // MINUS_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // STAR_EQUAL,
+ { nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // STAR_STAR_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // SLASH_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // PERCENT_EQUAL,
{ nullptr, &GDScriptParser::parse_assignment, PREC_ASSIGNMENT }, // LESS_LESS_EQUAL,
@@ -3558,14 +3561,16 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint = PROPERTY_HINT_ENUM;
String enum_hint_string;
- for (OrderedHashMap<StringName, int>::Element E = export_type.enum_values.front(); E; E = E.next()) {
- enum_hint_string += E.key().operator String().capitalize().xml_escape();
- enum_hint_string += ":";
- enum_hint_string += String::num_int64(E.value()).xml_escape();
-
- if (E.next()) {
+ bool first = true;
+ for (const KeyValue<StringName, int> &E : export_type.enum_values) {
+ if (!first) {
enum_hint_string += ",";
+ } else {
+ first = false;
}
+ enum_hint_string += E.key.operator String().capitalize().xml_escape();
+ enum_hint_string += ":";
+ enum_hint_string += String::num_int64(E.value).xml_escape();
}
variable->export_info.hint_string = enum_hint_string;
@@ -3898,6 +3903,9 @@ void GDScriptParser::TreePrinter::print_assignment(AssignmentNode *p_assignment)
case AssignmentNode::OP_MODULO:
push_text("%");
break;
+ case AssignmentNode::OP_POWER:
+ push_text("**");
+ break;
case AssignmentNode::OP_BIT_SHIFT_LEFT:
push_text("<<");
break;
@@ -3946,6 +3954,9 @@ void GDScriptParser::TreePrinter::print_binary_op(BinaryOpNode *p_binary_op) {
case BinaryOpNode::OP_MODULO:
push_text(" % ");
break;
+ case BinaryOpNode::OP_POWER:
+ push_text(" ** ");
+ break;
case BinaryOpNode::OP_BIT_LEFT_SHIFT:
push_text(" << ");
break;
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 0da1896936..17f87edeeb 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -39,7 +39,7 @@
#include "core/string/ustring.h"
#include "core/templates/hash_map.h"
#include "core/templates/list.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "core/templates/vector.h"
#include "core/variant/variant.h"
#include "gdscript_cache.h"
@@ -132,7 +132,7 @@ public:
ClassNode *class_type = nullptr;
MethodInfo method_info; // For callable/signals.
- OrderedHashMap<StringName, int> enum_values; // For enums.
+ HashMap<StringName, int> enum_values; // For enums.
_FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
@@ -312,7 +312,7 @@ public:
bool is_constant = false;
Variant reduced_value;
- virtual bool is_expression() const { return true; }
+ virtual bool is_expression() const override { return true; }
virtual ~ExpressionNode() {}
protected:
@@ -360,6 +360,7 @@ public:
OP_MULTIPLICATION,
OP_DIVISION,
OP_MODULO,
+ OP_POWER,
OP_BIT_SHIFT_LEFT,
OP_BIT_SHIFT_RIGHT,
OP_BIT_AND,
@@ -393,6 +394,7 @@ public:
OP_MULTIPLICATION,
OP_DIVISION,
OP_MODULO,
+ OP_POWER,
OP_BIT_LEFT_SHIFT,
OP_BIT_RIGHT_SHIFT,
OP_BIT_AND,
@@ -767,6 +769,7 @@ public:
LOCAL_BIND, // Pattern bind.
MEMBER_VARIABLE,
MEMBER_CONSTANT,
+ INHERITED_VARIABLE,
};
Source source = UNDEFINED_SOURCE;
@@ -799,7 +802,8 @@ public:
FunctionNode *function = nullptr;
FunctionNode *parent_function = nullptr;
Vector<IdentifierNode *> captures;
- Map<StringName, int> captures_indices;
+ HashMap<StringName, int> captures_indices;
+ bool use_self = false;
bool has_name() const {
return function && function->identifier;
@@ -1201,9 +1205,9 @@ private:
List<ParserError> errors;
#ifdef DEBUG_ENABLED
List<GDScriptWarning> warnings;
- Set<String> ignored_warnings;
- Set<uint32_t> ignored_warning_codes;
- Set<int> unsafe_lines;
+ RBSet<String> ignored_warnings;
+ RBSet<uint32_t> ignored_warning_codes;
+ RBSet<int> unsafe_lines;
#endif
GDScriptTokenizer tokenizer;
@@ -1261,6 +1265,7 @@ private:
PREC_FACTOR,
PREC_SIGN,
PREC_BIT_NOT,
+ PREC_POWER,
PREC_TYPE_TEST,
PREC_AWAIT,
PREC_CALL,
@@ -1414,7 +1419,7 @@ public:
}
#ifdef DEBUG_ENABLED
const List<GDScriptWarning> &get_warnings() const { return warnings; }
- const Set<int> &get_unsafe_lines() const { return unsafe_lines; }
+ const RBSet<int> &get_unsafe_lines() const { return unsafe_lines; }
int get_last_line_number() const { return current.end_line; }
#endif
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index d3287ab345..6c17afe939 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -67,6 +67,7 @@ static const char *token_names[] = {
"+", // PLUS,
"-", // MINUS,
"*", // STAR,
+ "**", // STAR_STAR,
"/", // SLASH,
"%", // PERCENT,
// Assignment
@@ -74,6 +75,7 @@ static const char *token_names[] = {
"+=", // PLUS_EQUAL,
"-=", // MINUS_EQUAL,
"*=", // STAR_EQUAL,
+ "**=", // STAR_STAR_EQUAL,
"/=", // SLASH_EQUAL,
"%=", // PERCENT_EQUAL,
"<<=", // LESS_LESS_EQUAL,
@@ -1403,6 +1405,14 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
if (_peek() == '=') {
_advance();
return make_token(Token::STAR_EQUAL);
+ } else if (_peek() == '*') {
+ if (_peek(1) == '=') {
+ _advance();
+ _advance(); // Advance both '*' and '='
+ return make_token(Token::STAR_STAR_EQUAL);
+ }
+ _advance();
+ return make_token(Token::STAR_STAR);
} else {
return make_token(Token::STAR);
}
@@ -1493,7 +1503,7 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
}
default:
- return make_error(vformat(R"(Unknown character "%s".")", String(&c, 1)));
+ return make_error(vformat(R"(Unknown character "%s".)", String(&c, 1)));
}
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index abd090e381..ad818cf812 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -31,9 +31,9 @@
#ifndef GDSCRIPT_TOKENIZER_H
#define GDSCRIPT_TOKENIZER_H
+#include "core/templates/hash_map.h"
#include "core/templates/list.h"
-#include "core/templates/map.h"
-#include "core/templates/set.h"
+#include "core/templates/rb_set.h"
#include "core/templates/vector.h"
#include "core/variant/variant.h"
@@ -78,6 +78,7 @@ public:
PLUS,
MINUS,
STAR,
+ STAR_STAR,
SLASH,
PERCENT,
// Assignment
@@ -85,6 +86,7 @@ public:
PLUS_EQUAL,
MINUS_EQUAL,
STAR_EQUAL,
+ STAR_STAR_EQUAL,
SLASH_EQUAL,
PERCENT_EQUAL,
LESS_LESS_EQUAL,
@@ -191,7 +193,7 @@ public:
new_line = p_new_line;
}
};
- const Map<int, CommentData> &get_comments() const {
+ const HashMap<int, CommentData> &get_comments() const {
return comments;
}
#endif // TOOLS_ENABLED
@@ -224,7 +226,7 @@ private:
int length = 0;
#ifdef TOOLS_ENABLED
- Map<int, CommentData> comments;
+ HashMap<int, CommentData> comments;
#endif // TOOLS_ENABLED
_FORCE_INLINE_ bool _is_at_end() { return position >= length; }
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 16b2dac343..a914374985 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -432,21 +432,21 @@ struct GDScriptUtilityFunctionsDefinitions {
}
static inline void print_debug(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
- String str;
+ String s;
for (int i = 0; i < p_arg_count; i++) {
- str += p_args[i]->operator String();
+ s += p_args[i]->operator String();
}
if (Thread::get_caller_id() == Thread::get_main_id()) {
ScriptLanguage *script = GDScriptLanguage::get_singleton();
if (script->debug_get_stack_level_count() > 0) {
- str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
+ s += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
}
} else {
- str += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id());
+ s += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id());
}
- print_line(str);
+ print_line(s);
*r_ret = Variant();
}
@@ -545,7 +545,7 @@ struct GDScriptUtilityFunctionsDefinitions {
};
struct GDScriptUtilityFunctionInfo {
- GDScriptUtilityFunctions::FunctionPtr function;
+ GDScriptUtilityFunctions::FunctionPtr function = nullptr;
MethodInfo info;
bool is_constant = false;
};
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 41c59c7703..8f85d8159b 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -93,9 +93,13 @@ static String _get_var_type(const Variant *p_var) {
basestr = "null instance";
}
} else {
- basestr = bobj->get_class();
- if (bobj->get_script_instance()) {
- basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")";
+ if (bobj->is_class_ptr(GDScriptNativeClass::get_class_ptr_static())) {
+ basestr = Object::cast_to<GDScriptNativeClass>(bobj)->get_name();
+ } else {
+ basestr = bobj->get_class();
+ if (bobj->get_script_instance()) {
+ basestr += " (" + _get_script_name(bobj->get_script_instance()->get_script()) + ")";
+ }
}
}
@@ -263,6 +267,7 @@ void (*type_init_function_table[])(Variant *) = {
&&OPCODE_CALL_METHOD_BIND, \
&&OPCODE_CALL_METHOD_BIND_RET, \
&&OPCODE_CALL_BUILTIN_STATIC, \
+ &&OPCODE_CALL_NATIVE_STATIC, \
&&OPCODE_CALL_PTRCALL_NO_RETURN, \
&&OPCODE_CALL_PTRCALL_BOOL, \
&&OPCODE_CALL_PTRCALL_INT, \
@@ -301,6 +306,7 @@ void (*type_init_function_table[])(Variant *) = {
&&OPCODE_AWAIT, \
&&OPCODE_AWAIT_RESUME, \
&&OPCODE_CREATE_LAMBDA, \
+ &&OPCODE_CREATE_SELF_LAMBDA, \
&&OPCODE_JUMP, \
&&OPCODE_JUMP_IF, \
&&OPCODE_JUMP_IF_NOT, \
@@ -367,7 +373,7 @@ void (*type_init_function_table[])(Variant *) = {
&&OPCODE_TYPE_ADJUST_QUATERNION, \
&&OPCODE_TYPE_ADJUST_AABB, \
&&OPCODE_TYPE_ADJUST_BASIS, \
- &&OPCODE_TYPE_ADJUST_TRANSFORM, \
+ &&OPCODE_TYPE_ADJUST_TRANSFORM3D, \
&&OPCODE_TYPE_ADJUST_COLOR, \
&&OPCODE_TYPE_ADJUST_STRING_NAME, \
&&OPCODE_TYPE_ADJUST_NODE_PATH, \
@@ -540,33 +546,32 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
memnew_placement(&stack[i], Variant);
}
- memnew_placement(&stack[ADDR_STACK_NIL], Variant);
-
if (_instruction_args_size) {
instruction_args = (Variant **)&aptr[sizeof(Variant) * _stack_size];
} else {
instruction_args = nullptr;
}
- if (p_instance) {
- memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
- script = p_instance->script.ptr();
- } else {
- memnew_placement(&stack[ADDR_STACK_SELF], Variant);
- script = _script;
+ for (const KeyValue<int, Variant::Type> &E : temporary_slots) {
+ type_init_function_table[E.value](&stack[E.key]);
}
}
+
if (_ptrcall_args_size) {
call_args_ptr = (const void **)alloca(_ptrcall_args_size * sizeof(void *));
} else {
call_args_ptr = nullptr;
}
- memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
-
- for (const KeyValue<int, Variant::Type> &E : temporary_slots) {
- type_init_function_table[E.value](&stack[E.key]);
+ if (p_instance) {
+ memnew_placement(&stack[ADDR_STACK_SELF], Variant(p_instance->owner));
+ script = p_instance->script.ptr();
+ } else {
+ memnew_placement(&stack[ADDR_STACK_SELF], Variant);
+ script = _script;
}
+ memnew_placement(&stack[ADDR_STACK_CLASS], Variant(script));
+ memnew_placement(&stack[ADDR_STACK_NIL], Variant);
String err_text;
@@ -1710,6 +1715,47 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CALL_NATIVE_STATIC) {
+ CHECK_SPACE(3 + instr_arg_count);
+
+ ip += instr_arg_count;
+
+ GD_ERR_BREAK(_code_ptr[ip + 1] < 0 || _code_ptr[ip + 1] >= _methods_count);
+ MethodBind *method = _methods_ptr[_code_ptr[ip + 1]];
+
+ int argc = _code_ptr[ip + 2];
+ GD_ERR_BREAK(argc < 0);
+
+ GET_INSTRUCTION_ARG(ret, argc);
+
+ const Variant **argptrs = const_cast<const Variant **>(instruction_args);
+
+#ifdef DEBUG_ENABLED
+ uint64_t call_time = 0;
+
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ call_time = OS::get_singleton()->get_ticks_usec();
+ }
+#endif
+
+ Callable::CallError err;
+ *ret = method->call(nullptr, argptrs, argc, err);
+
+#ifdef DEBUG_ENABLED
+ if (GDScriptLanguage::get_singleton()->profiling) {
+ function_call_time += OS::get_singleton()->get_ticks_usec() - call_time;
+ }
+
+ if (err.error != Callable::CallError::CALL_OK) {
+ err_text = _get_call_error(err, "static function '" + method->get_name().operator String() + "' in type '" + method->get_instance_class().operator String() + "'", argptrs);
+ OPCODE_BREAK;
+ }
+#endif
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
#ifdef DEBUG_ENABLED
#define OPCODE_CALL_PTR(m_type) \
OPCODE(OPCODE_CALL_PTRCALL_##m_type) { \
@@ -2057,7 +2103,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
const GDScript *gds = _script;
- const Map<StringName, GDScriptFunction *>::Element *E = nullptr;
+ HashMap<StringName, GDScriptFunction *>::ConstIterator E;
while (gds->base.ptr()) {
gds = gds->base.ptr();
E = gds->member_functions.find(*methodname);
@@ -2069,7 +2115,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
Callable::CallError err;
if (E) {
- *dst = E->get()->call(p_instance, (const Variant **)argptrs, argc, err);
+ *dst = E->value->call(p_instance, (const Variant **)argptrs, argc, err);
} else if (gds->native.ptr()) {
if (*methodname != GDScriptLanguage::get_singleton()->strings._init) {
MethodBind *mb = ClassDB::get_method(gds->native->get_name(), *methodname);
@@ -2124,8 +2170,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
// Is this even possible to be null at this point?
if (obj) {
if (obj->is_class_ptr(GDScriptFunctionState::get_class_ptr_static())) {
- static StringName completed = _scs_create("completed");
- result = Signal(obj, completed);
+ result = Signal(obj, "completed");
}
}
}
@@ -2146,8 +2191,9 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
gdfs->function = this;
gdfs->state.stack.resize(alloca_size);
- //copy variant stack
- for (int i = 0; i < _stack_size; i++) {
+
+ // First 3 stack addresses are special, so we just skip them here.
+ for (int i = 3; i < _stack_size; i++) {
memnew_placement(&gdfs->state.stack.write[sizeof(Variant) * i], Variant(stack[i]));
}
gdfs->state.stack_size = _stack_size;
@@ -2231,6 +2277,41 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
}
DISPATCH_OPCODE;
+ OPCODE(OPCODE_CREATE_SELF_LAMBDA) {
+ CHECK_SPACE(2 + instr_arg_count);
+
+ GD_ERR_BREAK(p_instance == nullptr);
+
+ ip += instr_arg_count;
+
+ int captures_count = _code_ptr[ip + 1];
+ GD_ERR_BREAK(captures_count < 0);
+
+ int lambda_index = _code_ptr[ip + 2];
+ GD_ERR_BREAK(lambda_index < 0 || lambda_index >= _lambdas_count);
+ GDScriptFunction *lambda = _lambdas_ptr[lambda_index];
+
+ Vector<Variant> captures;
+ captures.resize(captures_count);
+ for (int i = 0; i < captures_count; i++) {
+ GET_INSTRUCTION_ARG(arg, i);
+ captures.write[i] = *arg;
+ }
+
+ GDScriptLambdaSelfCallable *callable;
+ if (Object::cast_to<RefCounted>(p_instance->owner)) {
+ callable = memnew(GDScriptLambdaSelfCallable(Ref<RefCounted>(Object::cast_to<RefCounted>(p_instance->owner)), lambda, captures));
+ } else {
+ callable = memnew(GDScriptLambdaSelfCallable(p_instance->owner, lambda, captures));
+ }
+
+ GET_INSTRUCTION_ARG(result, captures_count);
+ *result = Callable(callable);
+
+ ip += 3;
+ }
+ DISPATCH_OPCODE;
+
OPCODE(OPCODE_JUMP) {
CHECK_SPACE(2);
int to = _code_ptr[ip + 1];
@@ -3217,7 +3298,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
OPCODE_TYPE_ADJUST(QUATERNION, Quaternion);
OPCODE_TYPE_ADJUST(AABB, AABB);
OPCODE_TYPE_ADJUST(BASIS, Basis);
- OPCODE_TYPE_ADJUST(TRANSFORM, Transform3D);
+ OPCODE_TYPE_ADJUST(TRANSFORM3D, Transform3D);
OPCODE_TYPE_ADJUST(COLOR, Color);
OPCODE_TYPE_ADJUST(STRING_NAME, StringName);
OPCODE_TYPE_ADJUST(NODE_PATH, NodePath);
@@ -3369,26 +3450,24 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GDScriptLanguage::get_singleton()->script_frame_time += time_taken - function_call_time;
}
- // Check if this is the last time the function is resuming from await
- // Will be true if never awaited as well
- // When it's the last resume it will postpone the exit from stack,
- // so the debugger knows which function triggered the resume of the next function (if any)
- if (!p_state || awaited) {
+ // Check if this function has been interrupted by `await`.
+ // If that is the case we want to keep it in the debugger until it actually exits.
+ // This ensures the call stack can be properly shown when using `await`, showing what resumed the function.
+ if (!awaited) {
if (EngineDebugger::is_active()) {
GDScriptLanguage::get_singleton()->exit_function();
}
+ }
#endif
- if (_stack_size) {
- //free stack
- for (int i = 0; i < _stack_size; i++) {
- stack[i].~Variant();
- }
+ // Clear the stack even if there was an `await`.
+ // The stack saved in the state is a copy, so this needs to be destructed to avoid leaks.
+ if (_stack_size) {
+ // Free stack.
+ for (int i = 0; i < _stack_size; i++) {
+ stack[i].~Variant();
}
-
-#ifdef DEBUG_ENABLED
}
-#endif
return retvalue;
}
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 17886181d5..d3c5fed95a 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -89,16 +89,16 @@ void ExtendGDScriptParser::update_symbols() {
for (int i = 0; i < class_symbol.children.size(); i++) {
const lsp::DocumentSymbol &symbol = class_symbol.children[i];
- members.set(symbol.name, &symbol);
+ members.insert(symbol.name, &symbol);
// cache level one inner classes
if (symbol.kind == lsp::SymbolKind::Class) {
ClassMembers inner_class;
for (int j = 0; j < symbol.children.size(); j++) {
const lsp::DocumentSymbol &s = symbol.children[j];
- inner_class.set(s.name, &s);
+ inner_class.insert(s.name, &s);
}
- inner_classes.set(symbol.name, inner_class);
+ inner_classes.insert(symbol.name, inner_class);
}
}
}
@@ -108,7 +108,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) {
document_links.clear();
GDScriptTokenizer tokenizer;
- FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
+ Ref<FileAccess> fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
tokenizer.set_source_code(p_code);
while (true) {
GDScriptTokenizer::Token token = tokenizer.scan();
@@ -212,12 +212,12 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
const Variant &default_value = m.constant->initializer->reduced_value;
String value_text;
if (default_value.get_type() == Variant::OBJECT) {
- RES res = default_value;
+ Ref<Resource> res = default_value;
if (res.is_valid() && !res->get_path().is_empty()) {
value_text = "preload(\"" + res->get_path() + "\")";
if (symbol.documentation.is_empty()) {
- if (Map<String, ExtendGDScriptParser *>::Element *S = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(res->get_path())) {
- symbol.documentation = S->get()->class_symbol.documentation;
+ if (HashMap<String, ExtendGDScriptParser *>::Iterator S = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(res->get_path())) {
+ symbol.documentation = S->value->class_symbol.documentation;
}
}
} else {
@@ -661,30 +661,22 @@ const List<lsp::DocumentLink> &ExtendGDScriptParser::get_document_links() const
const Array &ExtendGDScriptParser::get_member_completions() {
if (member_completions.is_empty()) {
- const String *name = members.next(nullptr);
- while (name) {
- const lsp::DocumentSymbol *symbol = members.get(*name);
+ for (const KeyValue<String, const lsp::DocumentSymbol *> &E : members) {
+ const lsp::DocumentSymbol *symbol = E.value;
lsp::CompletionItem item = symbol->make_completion_item();
- item.data = JOIN_SYMBOLS(path, *name);
+ item.data = JOIN_SYMBOLS(path, E.key);
member_completions.push_back(item.to_json());
-
- name = members.next(name);
}
- const String *_class = inner_classes.next(nullptr);
- while (_class) {
- const ClassMembers *inner_class = inner_classes.getptr(*_class);
- const String *member_name = inner_class->next(nullptr);
- while (member_name) {
- const lsp::DocumentSymbol *symbol = inner_class->get(*member_name);
+ for (const KeyValue<String, ClassMembers> &E : inner_classes) {
+ const ClassMembers *inner_class = &E.value;
+
+ for (const KeyValue<String, const lsp::DocumentSymbol *> &F : *inner_class) {
+ const lsp::DocumentSymbol *symbol = F.value;
lsp::CompletionItem item = symbol->make_completion_item();
- item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(*_class, *member_name));
+ item.data = JOIN_SYMBOLS(path, JOIN_SYMBOLS(E.key, F.key));
member_completions.push_back(item.to_json());
-
- member_name = inner_class->next(member_name);
}
-
- _class = inner_classes.next(_class);
}
}
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index cdddab319d..7460f8edff 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -126,7 +126,7 @@ Error GDScriptLanguageProtocol::on_client_connected() {
ERR_FAIL_COND_V_MSG(clients.size() >= LSP_MAX_CLIENTS, FAILED, "Max client limits reached");
Ref<LSPeer> peer = memnew(LSPeer);
peer->connection = tcp_peer;
- clients.set(next_client_id, peer);
+ clients.insert(next_client_id, peer);
next_client_id++;
EditorNode::get_log()->add_message("[LSP] Connection Taken", EditorLog::MSG_TYPE_EDITOR);
return OK;
@@ -229,28 +229,33 @@ void GDScriptLanguageProtocol::poll() {
if (server->is_connection_available()) {
on_client_connected();
}
- const int *id = nullptr;
- while ((id = clients.next(id))) {
- Ref<LSPeer> peer = clients.get(*id);
+
+ HashMap<int, Ref<LSPeer>>::Iterator E = clients.begin();
+ while (E != clients.end()) {
+ Ref<LSPeer> peer = E->value;
StreamPeerTCP::Status status = peer->connection->get_status();
if (status == StreamPeerTCP::STATUS_NONE || status == StreamPeerTCP::STATUS_ERROR) {
- on_client_disconnected(*id);
- id = nullptr;
+ on_client_disconnected(E->key);
+ E = clients.begin();
+ continue;
} else {
if (peer->connection->get_available_bytes() > 0) {
- latest_client_id = *id;
+ latest_client_id = E->key;
Error err = peer->handle_data();
if (err != OK && err != ERR_BUSY) {
- on_client_disconnected(*id);
- id = nullptr;
+ on_client_disconnected(E->key);
+ E = clients.begin();
+ continue;
}
}
Error err = peer->send_data();
if (err != OK && err != ERR_BUSY) {
- on_client_disconnected(*id);
- id = nullptr;
+ on_client_disconnected(E->key);
+ E = clients.begin();
+ continue;
}
}
+ ++E;
}
}
@@ -259,9 +264,8 @@ Error GDScriptLanguageProtocol::start(int p_port, const IPAddress &p_bind_ip) {
}
void GDScriptLanguageProtocol::stop() {
- const int *id = nullptr;
- while ((id = clients.next(id))) {
- Ref<LSPeer> peer = clients.get(*id);
+ for (const KeyValue<int, Ref<LSPeer>> &E : clients) {
+ Ref<LSPeer> peer = clients.get(E.key);
peer->connection->disconnect_from_host();
}
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index d5ef8fed74..d763701911 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -109,23 +109,15 @@ void GDScriptTextDocument::notify_client_show_symbol(const lsp::DocumentSymbol *
void GDScriptTextDocument::initialize() {
if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
- const HashMap<StringName, ClassMembers> &native_members = GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members;
+ for (const KeyValue<StringName, ClassMembers> &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->native_members) {
+ const ClassMembers &members = E.value;
- const StringName *class_ptr = native_members.next(nullptr);
- while (class_ptr) {
- const ClassMembers &members = native_members.get(*class_ptr);
-
- const String *name = members.next(nullptr);
- while (name) {
- const lsp::DocumentSymbol *symbol = members.get(*name);
+ for (const KeyValue<String, const lsp::DocumentSymbol *> &F : members) {
+ const lsp::DocumentSymbol *symbol = members.get(F.key);
lsp::CompletionItem item = symbol->make_completion_item();
- item.data = JOIN_SYMBOLS(String(*class_ptr), *name);
+ item.data = JOIN_SYMBOLS(String(E.key), F.key);
native_member_completions.push_back(item.to_json());
-
- name = members.next(name);
}
-
- class_ptr = native_members.next(class_ptr);
}
}
}
@@ -149,9 +141,9 @@ Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) {
String uri = params["uri"];
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(uri);
Array arr;
- if (const Map<String, ExtendGDScriptParser *>::Element *parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(path)) {
+ if (HashMap<String, ExtendGDScriptParser *>::ConstIterator parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(path)) {
Vector<lsp::DocumentedSymbolInformation> list;
- parser->get()->get_symbols().symbol_tree_as_list(uri, list);
+ parser->value->get_symbols().symbol_tree_as_list(uri, list);
for (int i = 0; i < list.size(); i++) {
arr.push_back(list[i].to_json());
}
@@ -275,8 +267,8 @@ Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
}
if (!symbol) {
- if (const Map<String, ExtendGDScriptParser *>::Element *E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(class_name)) {
- symbol = E->get()->get_member_symbol(member_name, inner_class_name);
+ if (HashMap<String, ExtendGDScriptParser *>::ConstIterator E = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(class_name)) {
+ symbol = E->value->get_member_symbol(member_name, inner_class_name);
}
}
}
@@ -424,10 +416,6 @@ GDScriptTextDocument::GDScriptTextDocument() {
file_checker = FileAccess::create(FileAccess::ACCESS_RESOURCES);
}
-GDScriptTextDocument::~GDScriptTextDocument() {
- memdelete(file_checker);
-}
-
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);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index eb7b2c0240..9732765f34 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -40,7 +40,7 @@ class GDScriptTextDocument : public RefCounted {
protected:
static void _bind_methods();
- FileAccess *file_checker;
+ Ref<FileAccess> file_checker;
void didOpen(const Variant &p_param);
void didClose(const Variant &p_param);
@@ -75,7 +75,6 @@ public:
void initialize();
GDScriptTextDocument();
- virtual ~GDScriptTextDocument();
};
#endif
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 1bf0b40842..d9de112bb0 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -116,22 +116,22 @@ void GDScriptWorkspace::did_delete_files(const Dictionary &p_params) {
}
void GDScriptWorkspace::remove_cache_parser(const String &p_path) {
- Map<String, ExtendGDScriptParser *>::Element *parser = parse_results.find(p_path);
- Map<String, ExtendGDScriptParser *>::Element *script = scripts.find(p_path);
+ HashMap<String, ExtendGDScriptParser *>::Iterator parser = parse_results.find(p_path);
+ HashMap<String, ExtendGDScriptParser *>::Iterator script = scripts.find(p_path);
if (parser && script) {
- if (script->get() && script->get() == parser->get()) {
- memdelete(script->get());
+ if (script->value && script->value == parser->value) {
+ memdelete(script->value);
} else {
- memdelete(script->get());
- memdelete(parser->get());
+ memdelete(script->value);
+ memdelete(parser->value);
}
parse_results.erase(p_path);
scripts.erase(p_path);
} else if (parser) {
- memdelete(parser->get());
+ memdelete(parser->value);
parse_results.erase(p_path);
} else if (script) {
- memdelete(script->get());
+ memdelete(script->value);
scripts.erase(p_path);
}
}
@@ -141,8 +141,8 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_
StringName empty;
while (class_name != empty) {
- if (const Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(class_name)) {
- const lsp::DocumentSymbol &class_symbol = E->value();
+ if (HashMap<StringName, lsp::DocumentSymbol>::ConstIterator E = native_symbols.find(class_name)) {
+ const lsp::DocumentSymbol &class_symbol = E->value;
if (p_member.is_empty()) {
return &class_symbol;
@@ -162,9 +162,9 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_native_symbol(const String &p_
}
const lsp::DocumentSymbol *GDScriptWorkspace::get_script_symbol(const String &p_path) const {
- const Map<String, ExtendGDScriptParser *>::Element *S = scripts.find(p_path);
+ HashMap<String, ExtendGDScriptParser *>::ConstIterator S = scripts.find(p_path);
if (S) {
- return &(S->get()->get_symbols());
+ return &(S->value->get_symbols());
}
return nullptr;
}
@@ -209,10 +209,10 @@ void GDScriptWorkspace::reload_all_workspace_scripts() {
err = parse_script(path, content);
if (err != OK) {
- Map<String, ExtendGDScriptParser *>::Element *S = parse_results.find(path);
+ HashMap<String, ExtendGDScriptParser *>::Iterator S = parse_results.find(path);
String err_msg = "Failed parse script " + path;
if (S) {
- err_msg += "\n" + S->get()->get_errors()[0].message;
+ err_msg += "\n" + S->value->get_errors()[0].message;
}
ERR_CONTINUE_MSG(err != OK, err_msg);
}
@@ -221,7 +221,7 @@ void GDScriptWorkspace::reload_all_workspace_scripts() {
void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> &r_files) {
Error err;
- DirAccessRef dir = DirAccess::open(p_root_dir, &err);
+ Ref<DirAccess> dir = DirAccess::open(p_root_dir, &err);
if (OK == err) {
dir->list_dir_begin();
String file_name = dir->get_next();
@@ -238,25 +238,25 @@ void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String>
}
ExtendGDScriptParser *GDScriptWorkspace::get_parse_successed_script(const String &p_path) {
- const Map<String, ExtendGDScriptParser *>::Element *S = scripts.find(p_path);
+ HashMap<String, ExtendGDScriptParser *>::Iterator S = scripts.find(p_path);
if (!S) {
parse_local_script(p_path);
S = scripts.find(p_path);
}
if (S) {
- return S->get();
+ return S->value;
}
return nullptr;
}
ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path) {
- const Map<String, ExtendGDScriptParser *>::Element *S = parse_results.find(p_path);
+ HashMap<String, ExtendGDScriptParser *>::Iterator S = parse_results.find(p_path);
if (!S) {
parse_local_script(p_path);
S = parse_results.find(p_path);
}
if (S) {
- return S->get();
+ return S->value;
}
return nullptr;
}
@@ -404,9 +404,9 @@ Error GDScriptWorkspace::initialize() {
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);
+ members.insert(symbol.name, &symbol);
}
- native_members.set(E.key, members);
+ native_members.insert(E.key, members);
}
// cache member completions
@@ -424,8 +424,8 @@ Error GDScriptWorkspace::initialize() {
Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_content) {
ExtendGDScriptParser *parser = memnew(ExtendGDScriptParser);
Error err = parser->parse(p_content, p_path);
- Map<String, ExtendGDScriptParser *>::Element *last_parser = parse_results.find(p_path);
- Map<String, ExtendGDScriptParser *>::Element *last_script = scripts.find(p_path);
+ HashMap<String, ExtendGDScriptParser *>::Iterator last_parser = parse_results.find(p_path);
+ HashMap<String, ExtendGDScriptParser *>::Iterator last_script = scripts.find(p_path);
if (err == OK) {
remove_cache_parser(p_path);
@@ -433,8 +433,8 @@ Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_cont
scripts[p_path] = parser;
} else {
- if (last_parser && last_script && last_parser->get() != last_script->get()) {
- memdelete(last_parser->get());
+ if (last_parser && last_script && last_parser->value != last_script->value) {
+ memdelete(last_parser->value);
}
parse_results[p_path] = parser;
}
@@ -513,9 +513,9 @@ String GDScriptWorkspace::get_file_uri(const String &p_path) const {
void GDScriptWorkspace::publish_diagnostics(const String &p_path) {
Dictionary params;
Array errors;
- const Map<String, ExtendGDScriptParser *>::Element *ele = parse_results.find(p_path);
+ HashMap<String, ExtendGDScriptParser *>::ConstIterator ele = parse_results.find(p_path);
if (ele) {
- const Vector<lsp::Diagnostic> &list = ele->get()->get_diagnostics();
+ const Vector<lsp::Diagnostic> &list = ele->value->get_diagnostics();
errors.resize(list.size());
for (int i = 0; i < list.size(); ++i) {
errors[i] = list[i].to_json();
@@ -560,7 +560,7 @@ Node *GDScriptWorkspace::_get_owner_scene_node(String p_path) {
for (int i = 0; i < owners.size(); i++) {
NodePath owner_path = owners[i];
- RES owner_res = ResourceLoader::load(owner_path);
+ Ref<Resource> owner_res = ResourceLoader::load(owner_path);
if (Object::cast_to<PackedScene>(owner_res.ptr())) {
Ref<PackedScene> owner_packed_scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*owner_res));
owner_scene_node = owner_packed_scene->instantiate();
@@ -682,13 +682,11 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
Vector2i offset;
symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, offset);
- const StringName *class_ptr = native_members.next(nullptr);
- while (class_ptr) {
- const ClassMembers &members = native_members.get(*class_ptr);
+ for (const KeyValue<StringName, ClassMembers> &E : native_members) {
+ const ClassMembers &members = native_members.get(E.key);
if (const lsp::DocumentSymbol *const *symbol = members.getptr(symbol_identifier)) {
r_list.push_back(*symbol);
}
- class_ptr = native_members.next(class_ptr);
}
for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) {
@@ -698,23 +696,19 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
r_list.push_back(*symbol);
}
- const HashMap<String, ClassMembers> &inner_classes = script->get_inner_classes();
- const String *_class = inner_classes.next(nullptr);
- while (_class) {
- const ClassMembers *inner_class = inner_classes.getptr(*_class);
+ for (const KeyValue<String, ClassMembers> &F : script->get_inner_classes()) {
+ const ClassMembers *inner_class = &F.value;
if (const lsp::DocumentSymbol *const *symbol = inner_class->getptr(symbol_identifier)) {
r_list.push_back(*symbol);
}
-
- _class = inner_classes.next(_class);
}
}
}
}
const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params) {
- if (Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(p_params.native_class)) {
- const lsp::DocumentSymbol &symbol = E->get();
+ if (HashMap<StringName, lsp::DocumentSymbol>::Iterator E = native_symbols.find(p_params.native_class)) {
+ const lsp::DocumentSymbol &symbol = E->value;
if (p_params.symbol_name.is_empty() || p_params.symbol_name == symbol.name) {
return &symbol;
}
@@ -790,7 +784,7 @@ GDScriptWorkspace::GDScriptWorkspace() {
}
GDScriptWorkspace::~GDScriptWorkspace() {
- Set<String> cached_parsers;
+ RBSet<String> cached_parsers;
for (const KeyValue<String, ExtendGDScriptParser *> &E : parse_results) {
cached_parsers.insert(E.key);
@@ -800,7 +794,7 @@ GDScriptWorkspace::~GDScriptWorkspace() {
cached_parsers.insert(E.key);
}
- for (Set<String>::Element *E = cached_parsers.front(); E; E = E->next()) {
+ for (RBSet<String>::Element *E = cached_parsers.front(); E; E = E->next()) {
remove_cache_parser(E->get());
}
}
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index 92e78f8992..7bff5db81f 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -48,7 +48,7 @@ protected:
static void _bind_methods();
void remove_cache_parser(const String &p_path);
bool initialized = false;
- Map<StringName, lsp::DocumentSymbol> native_symbols;
+ HashMap<StringName, lsp::DocumentSymbol> native_symbols;
const lsp::DocumentSymbol *get_native_symbol(const String &p_class, const String &p_member = "") const;
const lsp::DocumentSymbol *get_script_symbol(const String &p_path) const;
@@ -68,8 +68,8 @@ public:
String root;
String root_uri;
- Map<String, ExtendGDScriptParser *> scripts;
- Map<String, ExtendGDScriptParser *> parse_results;
+ HashMap<String, ExtendGDScriptParser *> scripts;
+ HashMap<String, ExtendGDScriptParser *> parse_results;
HashMap<StringName, ClassMembers> native_members;
public:
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index a63f9df918..d4aa207972 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -261,7 +261,7 @@ struct WorkspaceEdit {
/**
* Holds changes to existing resources.
*/
- Map<String, Vector<TextEdit>> changes;
+ HashMap<String, Vector<TextEdit>> changes;
_FORCE_INLINE_ void add_edit(const String &uri, const TextEdit &edit) {
if (changes.has(uri)) {
@@ -293,8 +293,8 @@ struct WorkspaceEdit {
}
_FORCE_INLINE_ void add_change(const String &uri, const int &line, const int &start_character, const int &end_character, const String &new_text) {
- if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) {
- Vector<TextEdit> edit_list = E->value();
+ if (HashMap<String, Vector<TextEdit>>::Iterator E = changes.find(uri)) {
+ Vector<TextEdit> edit_list = E->value;
for (int i = 0; i < edit_list.size(); ++i) {
TextEdit edit = edit_list[i];
if (edit.range.start.character == start_character) {
@@ -310,8 +310,8 @@ struct WorkspaceEdit {
new_edit.range.end.line = line;
new_edit.range.end.character = end_character;
- if (Map<String, Vector<TextEdit>>::Element *E = changes.find(uri)) {
- E->value().push_back(new_edit);
+ if (HashMap<String, Vector<TextEdit>>::Iterator E = changes.find(uri)) {
+ E->value.push_back(new_edit);
} else {
Vector<TextEdit> edit_list;
edit_list.push_back(new_edit);
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index fcf122f567..7cedbda804 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -70,7 +70,7 @@ class EditorExportGDScript : public EditorExportPlugin {
GDCLASS(EditorExportGDScript, EditorExportPlugin);
public:
- virtual void _export_file(const String &p_path, const String &p_type, const Set<String> &p_features) override {
+ virtual void _export_file(const String &p_path, const String &p_type, const RBSet<String> &p_features) override {
int script_mode = EditorExportPreset::MODE_SCRIPT_COMPILED;
String script_key;
@@ -111,54 +111,62 @@ static void _editor_init() {
#endif // TOOLS_ENABLED
-void register_gdscript_types() {
- GDREGISTER_CLASS(GDScript);
+void initialize_gdscript_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ GDREGISTER_CLASS(GDScript);
- script_language_gd = memnew(GDScriptLanguage);
- ScriptServer::register_language(script_language_gd);
+ script_language_gd = memnew(GDScriptLanguage);
+ ScriptServer::register_language(script_language_gd);
- resource_loader_gd.instantiate();
- ResourceLoader::add_resource_format_loader(resource_loader_gd);
+ resource_loader_gd.instantiate();
+ ResourceLoader::add_resource_format_loader(resource_loader_gd);
- resource_saver_gd.instantiate();
- ResourceSaver::add_resource_format_saver(resource_saver_gd);
+ resource_saver_gd.instantiate();
+ ResourceSaver::add_resource_format_saver(resource_saver_gd);
- gdscript_cache = memnew(GDScriptCache);
+ gdscript_cache = memnew(GDScriptCache);
+
+ GDScriptUtilityFunctions::register_functions();
+ }
#ifdef TOOLS_ENABLED
- EditorNode::add_init_callback(_editor_init);
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ EditorNode::add_init_callback(_editor_init);
- gdscript_translation_parser_plugin.instantiate();
- EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
+ gdscript_translation_parser_plugin.instantiate();
+ EditorTranslationParser::get_singleton()->add_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
+ }
#endif // TOOLS_ENABLED
-
- GDScriptUtilityFunctions::register_functions();
}
-void unregister_gdscript_types() {
- ScriptServer::unregister_language(script_language_gd);
+void uninitialize_gdscript_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ ScriptServer::unregister_language(script_language_gd);
- if (gdscript_cache) {
- memdelete(gdscript_cache);
- }
+ if (gdscript_cache) {
+ memdelete(gdscript_cache);
+ }
- if (script_language_gd) {
- memdelete(script_language_gd);
- }
+ if (script_language_gd) {
+ memdelete(script_language_gd);
+ }
+
+ ResourceLoader::remove_resource_format_loader(resource_loader_gd);
+ resource_loader_gd.unref();
- ResourceLoader::remove_resource_format_loader(resource_loader_gd);
- resource_loader_gd.unref();
+ ResourceSaver::remove_resource_format_saver(resource_saver_gd);
+ resource_saver_gd.unref();
- ResourceSaver::remove_resource_format_saver(resource_saver_gd);
- resource_saver_gd.unref();
+ GDScriptParser::cleanup();
+ GDScriptUtilityFunctions::unregister_functions();
+ }
#ifdef TOOLS_ENABLED
- EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
- gdscript_translation_parser_plugin.unref();
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorTranslationParser::get_singleton()->remove_parser(gdscript_translation_parser_plugin, EditorTranslationParser::STANDARD);
+ gdscript_translation_parser_plugin.unref();
+ }
#endif // TOOLS_ENABLED
-
- GDScriptParser::cleanup();
- GDScriptUtilityFunctions::unregister_functions();
}
#ifdef TESTS_ENABLED
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index baa7dcbbd1..a7e6b02dcf 100644
--- a/modules/gdscript/register_types.h
+++ b/modules/gdscript/register_types.h
@@ -31,7 +31,9 @@
#ifndef GDSCRIPT_REGISTER_TYPES_H
#define GDSCRIPT_REGISTER_TYPES_H
-void register_gdscript_types();
-void unregister_gdscript_types();
+#include "modules/register_module_types.h"
+
+void initialize_gdscript_module(ModuleInitializationLevel p_level);
+void uninitialize_gdscript_module(ModuleInitializationLevel p_level);
#endif // GDSCRIPT_REGISTER_TYPES_H
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index e8ddf90836..de5cd10e7c 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -48,11 +48,11 @@
namespace GDScriptTests {
void init_autoloads() {
- OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+ HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
// First pass, add the constants so they exist before any script is loaded.
- for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
- const ProjectSettings::AutoloadInfo &info = E.get();
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
+ const ProjectSettings::AutoloadInfo &info = E.value;
if (info.is_singleton) {
for (int i = 0; i < ScriptServer::get_language_count(); i++) {
@@ -62,15 +62,15 @@ void init_autoloads() {
}
// Second pass, load into global constants.
- for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
- const ProjectSettings::AutoloadInfo &info = E.get();
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : ProjectSettings::get_singleton()->get_autoload_list()) {
+ const ProjectSettings::AutoloadInfo &info = E.value;
if (!info.is_singleton) {
// Skip non-singletons since we don't have a scene tree here anyway.
continue;
}
- RES res = ResourceLoader::load(info.path);
+ Ref<Resource> res = ResourceLoader::load(info.path);
ERR_CONTINUE_MSG(res.is_null(), "Can't autoload: " + info.path);
Node *n = nullptr;
Ref<PackedScene> scn = res;
@@ -80,7 +80,7 @@ void init_autoloads() {
} else if (script.is_valid()) {
StringName ibt = script->get_instance_base_type();
bool valid_type = ClassDB::is_parent_class(ibt, "Node");
- ERR_CONTINUE_MSG(!valid_type, "Script does not inherit a Node: " + info.path);
+ ERR_CONTINUE_MSG(!valid_type, "Script does not inherit from Node: " + info.path);
Object *obj = ClassDB::instantiate(ibt);
@@ -229,7 +229,7 @@ bool GDScriptTestRunner::generate_outputs() {
bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
Error err = OK;
- DirAccessRef dir(DirAccess::open(p_dir, &err));
+ Ref<DirAccess> dir(DirAccess::open(p_dir, &err));
if (err != OK) {
return false;
@@ -254,7 +254,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
#ifndef DEBUG_ENABLED
// On release builds, skip tests marked as debug only.
Error open_err = OK;
- FileAccessRef script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err));
+ Ref<FileAccess> script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err));
if (open_err != OK) {
ERR_PRINT(vformat(R"(Couldn't open test file "%s".)", next));
next = dir->get_next();
@@ -286,7 +286,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) {
bool GDScriptTestRunner::make_tests() {
Error err = OK;
- DirAccessRef dir(DirAccess::open(source_dir, &err));
+ Ref<DirAccess> dir(DirAccess::open(source_dir, &err));
ERR_FAIL_COND_V_MSG(err != OK, false, "Could not open specified test directory.");
@@ -543,8 +543,8 @@ GDScriptTest::TestResult GDScriptTest::execute_test_code(bool p_is_generating) {
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) {
+ const HashMap<StringName, GDScriptFunction *>::ConstIterator test_function_element = script->get_member_functions().find(GDScriptTestRunner::test_function_name);
+ if (!test_function_element) {
enable_stdout();
result.status = GDTEST_LOAD_ERROR;
result.output = "";
@@ -611,7 +611,7 @@ bool GDScriptTest::generate_output() {
}
Error err = OK;
- FileAccessRef out_file = FileAccess::open(output_file, FileAccess::WRITE, &err);
+ Ref<FileAccess> out_file = FileAccess::open(output_file, FileAccess::WRITE, &err);
if (err != OK) {
return false;
}
@@ -620,7 +620,6 @@ bool GDScriptTest::generate_output() {
output += "\n"; // Make sure to insert newline for CI static checks.
out_file->store_string(output);
- out_file->close();
return true;
}
diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h
index 1a950c6898..d6c6419e21 100644
--- a/modules/gdscript/tests/gdscript_test_runner.h
+++ b/modules/gdscript/tests/gdscript_test_runner.h
@@ -63,8 +63,8 @@ public:
private:
struct ErrorHandlerData {
- TestResult *result;
- GDScriptTest *self;
+ TestResult *result = nullptr;
+ GDScriptTest *self = nullptr;
ErrorHandlerData(TestResult *p_result, GDScriptTest *p_this) {
result = p_result;
self = p_this;
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out
index 015ad756f8..6f7f0783f0 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out
+++ b/modules/gdscript/tests/scripts/analyzer/errors/invalid_array_index.out
@@ -1,2 +1,2 @@
GDTEST_ANALYZER_ERROR
-Invalid index type "bool" for a base of type "Array".
+Cannot get index "true" from "[0, 1]".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd
new file mode 100644
index 0000000000..631e7be5ce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.gd
@@ -0,0 +1,14 @@
+func test():
+ var instance := Parent.new()
+ instance.my_function({"a": 1})
+ instance = Child.new()
+ instance.my_function({"a": 1})
+ print("No failure")
+
+class Parent:
+ func my_function(_par1: Dictionary = {}) -> void:
+ pass
+
+class Child extends Parent:
+ func my_function(_par1: Dictionary = {}) -> void:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out
new file mode 100644
index 0000000000..67f0045867
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/function_match_parent_signature_with_default_dict_void.out
@@ -0,0 +1,2 @@
+GDTEST_OK
+No failure
diff --git a/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd
new file mode 100644
index 0000000000..4608c778aa
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.gd
@@ -0,0 +1,4 @@
+func test():
+ match 1:
+ [[[var a]]], 2:
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out
new file mode 100644
index 0000000000..1cdc24683b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/match_multiple_variable_binds_in_branch.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Cannot use a variable bind with multiple patterns.
diff --git a/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out
index 67c7e28046..3cdafb04a9 100644
--- a/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out
+++ b/modules/gdscript/tests/scripts/parser/features/advanced_expression_matching.out
@@ -10,5 +10,5 @@ wildcard
[1,2,[1,{1:2,2:var z,..}]]
3
[1,2,[1,{1:2,2:var z,..}]]
-[1, 3, 5, 123]
+[1, 3, 5, "123"]
wildcard
diff --git a/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd
new file mode 100644
index 0000000000..cc78309ae4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.gd
@@ -0,0 +1,58 @@
+# https://github.com/godotengine/godot/issues/50285
+
+@warning_ignore(unused_local_constant)
+func test():
+ const CONST_INNER_DICTIONARY = { "key": true }
+ const CONST_NESTED_DICTIONARY_OLD_WORKAROUND = {
+ "key1": "value1",
+ "key2": CONST_INNER_DICTIONARY
+ }
+ # All of these should be valid
+ const CONST_NESTED_DICTIONARY = {
+ "key1": "value1",
+ "key2": { "key": true }
+ }
+
+
+ const CONST_DICTIONARY_WITH_ARRAY = {
+ "key1": [1,2,3,4]
+ }
+
+ const CONST_NESTED_ARRAY = [[],[2],[1,2,3]]
+ const CONST_ARRAY_WITH_DICT = [{"key1": 3}, {"key2": 5}]
+
+ const THREE_DIMENSIONAL_ARRAY = [[[],[],[]],[[],[],[]],[[],[],[]]]
+ const MANY_NESTED_DICT = {
+ "key1": {
+ "key11": {
+ "key111": {},
+ "key112": {},
+ },
+ "key12": {
+ "key121": {},
+ "key122": {},
+ },
+ },
+ "key2": {
+ "key21": {
+ "key211": {},
+ "key212": {},
+ },
+ "key22": {
+ "key221": {},
+ "key222": {},
+ },
+ }
+ }
+
+
+ const CONST_ARRAY_ACCESS = [1,2,3][0]
+ const CONST_DICT_ACCESS = {"key1": 5}["key1"]
+
+ const CONST_ARRAY_NESTED_ACCESS = [[1,2,3],[4,5,6],[8,9,10]][0][1]
+ const CONST_DICT_NESTED_ACCESS = {"key1": {"key2": 1}}["key1"]["key2"]
+
+ print(CONST_ARRAY_ACCESS)
+ print(CONST_DICT_ACCESS)
+ print(CONST_ARRAY_NESTED_ACCESS)
+ print(CONST_DICT_NESTED_ACCESS)
diff --git a/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out
new file mode 100644
index 0000000000..5883fc5c18
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/arrays_dictionaries_nested_const.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+1
+5
+2
+1
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary.out b/modules/gdscript/tests/scripts/parser/features/dictionary.out
index 54083c1afc..5f999f573a 100644
--- a/modules/gdscript/tests/scripts/parser/features/dictionary.out
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary.out
@@ -7,8 +7,8 @@ null
false
empty array
zero Vector2i
-{22:{4:[nesting, arrays]}}
-{4:[nesting, arrays]}
-[nesting, arrays]
+{22:{4:["nesting", "arrays"]}}
+{4:["nesting", "arrays"]}
+["nesting", "arrays"]
nesting
arrays
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out
index 5b0ea9df43..5143d040a9 100644
--- a/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary_lua_style.out
@@ -1,2 +1,2 @@
GDTEST_OK
-{a:1, b:2, with spaces:3, 2:4}
+{"a":1, "b":2, "with spaces":3, "2":4}
diff --git a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out
index 62be807a1f..dd28609850 100644
--- a/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out
+++ b/modules/gdscript/tests/scripts/parser/features/dictionary_mixed_syntax.out
@@ -1,2 +1,2 @@
GDTEST_OK
-{hello:{world:{is:beautiful}}}
+{"hello":{"world":{"is":"beautiful"}}}
diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd
new file mode 100644
index 0000000000..a0ae7fb17c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.gd
@@ -0,0 +1,6 @@
+func test():
+ match [1, 2, 3]:
+ [var a, var b, var c]:
+ print(a == 1)
+ print(b == 2)
+ print(c == 3)
diff --git a/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out
new file mode 100644
index 0000000000..316db6d748
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/match_multiple_variable_binds_in_pattern.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out
index 4009160439..8b8c33202f 100644
--- a/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out
+++ b/modules/gdscript/tests/scripts/parser/features/nested_dictionary.out
@@ -1,5 +1,5 @@
GDTEST_OK
-{8:{key:value}}
-{key:value}
+{8:{"key":"value"}}
+{"key":"value"}
value
value
diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd
new file mode 100644
index 0000000000..3d063869ab
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.gd
@@ -0,0 +1,23 @@
+var member = "foo"
+
+func bar():
+ print("bar")
+
+func test():
+ var lambda1 = func():
+ print(member)
+ lambda1.call()
+
+ var lambda2 = func():
+ var nested = func():
+ print(member)
+ nested.call()
+ lambda2.call()
+
+ var lambda3 = func():
+ bar()
+ lambda3.call()
+
+ var lambda4 = func():
+ return self
+ print(lambda4.call() == self)
diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out
new file mode 100644
index 0000000000..53d602b234
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/lambda_use_self.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+foo
+foo
+bar
+true
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out
index 7670fc0128..d4468737a5 100644
--- a/modules/gdscript/tests/scripts/runtime/features/stringify.out
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out
@@ -21,14 +21,14 @@ hello/world
RID(0)
Node::get_name
Node::[signal]property_list_changed
-{hello:123}
-[hello, 123]
+{"hello":123}
+["hello", 123]
[255, 0, 1]
[-1, 0, 1]
[-1, 0, 1]
[-1, 0, 1]
[-1, 0, 1]
-[hello, world]
+["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 4255030b4e..d8f60d5e9b 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -204,8 +204,8 @@ void test(TestType p_type) {
return;
}
- FileAccessRef fa = FileAccess::open(test, FileAccess::READ);
- ERR_FAIL_COND_MSG(!fa, "Could not open file: " + test);
+ Ref<FileAccess> fa = FileAccess::open(test, FileAccess::READ);
+ ERR_FAIL_COND_MSG(fa.is_null(), "Could not open file: " + test);
// Initialize the language for the test routine.
init_language(fa->get_path_absolute().get_base_dir());
diff --git a/modules/glslang/register_types.cpp b/modules/glslang/register_types.cpp
index 8e69ba78c7..64891d9ee8 100644
--- a/modules/glslang/register_types.cpp
+++ b/modules/glslang/register_types.cpp
@@ -190,7 +190,11 @@ static String _get_cache_key_function_glsl(const RenderingDevice::Capabilities *
return version;
}
-void preregister_glslang_types() {
+void initialize_glslang_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) {
+ return;
+ }
+
// Initialize in case it's not initialized. This is done once per thread
// and it's safe to call multiple times.
glslang::InitializeProcess();
@@ -198,9 +202,10 @@ void preregister_glslang_types() {
RenderingDevice::shader_set_get_cache_key_function(_get_cache_key_function_glsl);
}
-void register_glslang_types() {
-}
+void uninitialize_glslang_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_CORE) {
+ return;
+ }
-void unregister_glslang_types() {
glslang::FinalizeProcess();
}
diff --git a/modules/glslang/register_types.h b/modules/glslang/register_types.h
index 9d8dc9dc2a..d9611cc02f 100644
--- a/modules/glslang/register_types.h
+++ b/modules/glslang/register_types.h
@@ -33,8 +33,9 @@
#define MODULE_GLSLANG_HAS_PREREGISTER
-void preregister_glslang_types();
-void register_glslang_types();
-void unregister_glslang_types();
+#include "modules/register_module_types.h"
+
+void initialize_glslang_module(ModuleInitializationLevel p_level);
+void uninitialize_glslang_module(ModuleInitializationLevel p_level);
#endif // GLSLANG_REGISTER_TYPES_H
diff --git a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
index 23a7b7fed6..95db1c0965 100644
--- a/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
+++ b/modules/gltf/editor/editor_scene_exporter_gltf_plugin.cpp
@@ -64,9 +64,12 @@ SceneExporterGLTFPlugin::SceneExporterGLTFPlugin() {
file_export_lib->clear_filters();
file_export_lib->add_filter("*.glb");
file_export_lib->add_filter("*.gltf");
- file_export_lib->set_title(TTR("Export Mesh GLTF2"));
- String gltf_scene_name = TTR("Export GLTF...");
- add_tool_menu_item(gltf_scene_name, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2));
+ file_export_lib->set_title(TTR("Export Scene to glTF 2.0 File"));
+
+ PopupMenu *menu = get_export_as_menu();
+ int idx = menu->get_item_count();
+ menu->add_item(TTR("glTF 2.0 Scene..."));
+ menu->set_item_metadata(idx, callable_mp(this, &SceneExporterGLTFPlugin::convert_scene_to_gltf2));
}
void SceneExporterGLTFPlugin::_gltf2_dialog_action(String p_file) {
diff --git a/modules/gltf/editor/editor_scene_importer_blend.cpp b/modules/gltf/editor/editor_scene_importer_blend.cpp
index cdb22b7d19..63f446561a 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.cpp
+++ b/modules/gltf/editor/editor_scene_importer_blend.cpp
@@ -58,14 +58,15 @@ void EditorSceneFormatImporterBlend::get_extensions(List<String> *r_extensions)
}
Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_t p_flags,
- const Map<StringName, Variant> &p_options, int p_bake_fps,
+ const HashMap<StringName, Variant> &p_options, int p_bake_fps,
List<String> *r_missing_deps, Error *r_err) {
// Get global paths for source and sink.
- const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path);
+ // Escape paths to be valid Python strings to embed in the script.
+ const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape();
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file(
vformat("%s-%s.gltf", p_path.get_file().get_basename(), p_path.md5_text()));
- const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink);
+ const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape();
// Handle configuration options.
@@ -237,13 +238,12 @@ Node *EditorSceneFormatImporterBlend::import_scene(const String &p_path, uint32_
return gltf->generate_scene(state, p_bake_fps);
}
-Ref<Animation> EditorSceneFormatImporterBlend::import_animation(const String &p_path, uint32_t p_flags,
- const Map<StringName, Variant> &p_options, int p_bake_fps) {
- return Ref<Animation>();
-}
+Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
+ const HashMap<StringName, Variant> &p_options) {
+ if (p_path.get_extension().to_lower() != "blend") {
+ return true;
+ }
-Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_path, const String &p_option,
- const Map<StringName, Variant> &p_options) {
if (p_option.begins_with("animation/")) {
if (p_option != "animation/import" && !bool(p_options["animation/import"])) {
return false;
@@ -253,6 +253,9 @@ Variant EditorSceneFormatImporterBlend::get_option_visibility(const String &p_pa
}
void EditorSceneFormatImporterBlend::get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options) {
+ if (p_path.get_extension().to_lower() != "blend") {
+ return;
+ }
#define ADD_OPTION_BOOL(PATH, VALUE) \
r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, SNAME(PATH)), VALUE));
#define ADD_OPTION_ENUM(PATH, ENUM_HINT, VALUE) \
diff --git a/modules/gltf/editor/editor_scene_importer_blend.h b/modules/gltf/editor/editor_scene_importer_blend.h
index 05e8a565f7..dd1c1b9889 100644
--- a/modules/gltf/editor/editor_scene_importer_blend.h
+++ b/modules/gltf/editor/editor_scene_importer_blend.h
@@ -66,14 +66,12 @@ 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,
- const Map<StringName, Variant> &p_options, int p_bake_fps,
+ const HashMap<StringName, Variant> &p_options, 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,
- const Map<StringName, Variant> &p_options, int p_bake_fps) override;
virtual void get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) override;
- virtual Variant get_option_visibility(const String &p_path, const String &p_option,
- const Map<StringName, Variant> &p_options) override;
+ virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
+ const HashMap<StringName, Variant> &p_options) override;
};
class LineEdit;
@@ -84,11 +82,11 @@ class Label;
class EditorFileSystemImportFormatSupportQueryBlend : public EditorFileSystemImportFormatSupportQuery {
GDCLASS(EditorFileSystemImportFormatSupportQueryBlend, EditorFileSystemImportFormatSupportQuery);
- ConfirmationDialog *configure_blender_dialog;
- LineEdit *blender_path;
- Button *blender_path_browse;
- EditorFileDialog *browse_dialog;
- Label *path_status;
+ ConfirmationDialog *configure_blender_dialog = nullptr;
+ LineEdit *blender_path = nullptr;
+ Button *blender_path_browse = nullptr;
+ EditorFileDialog *browse_dialog = nullptr;
+ Label *path_status = nullptr;
bool confirmed = false;
String auto_detected_path;
diff --git a/modules/gltf/editor/editor_scene_importer_fbx.cpp b/modules/gltf/editor/editor_scene_importer_fbx.cpp
index 7cfd85c73a..faad2d315d 100644
--- a/modules/gltf/editor/editor_scene_importer_fbx.cpp
+++ b/modules/gltf/editor/editor_scene_importer_fbx.cpp
@@ -30,7 +30,7 @@
#include "editor_scene_importer_fbx.h"
-#if TOOLS_ENABLED
+#ifdef TOOLS_ENABLED
#include "../gltf_document.h"
#include "../gltf_state.h"
@@ -49,14 +49,17 @@ void EditorSceneFormatImporterFBX::get_extensions(List<String> *r_extensions) co
}
Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t p_flags,
- const Map<StringName, Variant> &p_options, int p_bake_fps,
+ const HashMap<StringName, Variant> &p_options, int p_bake_fps,
List<String> *r_missing_deps, Error *r_err) {
// Get global paths for source and sink.
- const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path);
+ // Don't use `c_escape()` as it can generate broken paths. These paths will be
+ // enclosed in double quotes by OS::execute(), so we only need to escape those.
+ // `c_escape_multiline()` seems to do this (escapes `\` and `"` only).
+ const String source_global = ProjectSettings::get_singleton()->globalize_path(p_path).c_escape_multiline();
const String sink = ProjectSettings::get_singleton()->get_imported_files_path().plus_file(
vformat("%s-%s.glb", p_path.get_file().get_basename(), p_path.md5_text()));
- const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink);
+ const String sink_global = ProjectSettings::get_singleton()->globalize_path(sink).c_escape_multiline();
// Run fbx2gltf.
@@ -65,9 +68,9 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t
List<String> args;
args.push_back("--pbr-metallic-roughness");
args.push_back("--input");
- args.push_back(vformat("\"%s\"", source_global));
+ args.push_back(source_global);
args.push_back("--output");
- args.push_back(vformat("\"%s\"", sink_global));
+ args.push_back(sink_global);
args.push_back("--binary");
String standard_out;
@@ -102,13 +105,8 @@ Node *EditorSceneFormatImporterFBX::import_scene(const String &p_path, uint32_t
return gltf->generate_scene(state, p_bake_fps);
}
-Ref<Animation> EditorSceneFormatImporterFBX::import_animation(const String &p_path,
- uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) {
- return Ref<Animation>();
-}
-
-Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path,
- const String &p_option, const Map<StringName, Variant> &p_options) {
+Variant EditorSceneFormatImporterFBX::get_option_visibility(const String &p_path, bool p_for_animation,
+ const String &p_option, const HashMap<StringName, Variant> &p_options) {
return true;
}
diff --git a/modules/gltf/editor/editor_scene_importer_fbx.h b/modules/gltf/editor/editor_scene_importer_fbx.h
index bb69cfaa30..b0039b1c8f 100644
--- a/modules/gltf/editor/editor_scene_importer_fbx.h
+++ b/modules/gltf/editor/editor_scene_importer_fbx.h
@@ -45,14 +45,12 @@ 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,
- const Map<StringName, Variant> &p_options, int p_bake_fps,
+ const HashMap<StringName, Variant> &p_options, 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,
- const Map<StringName, Variant> &p_options, int p_bake_fps) override;
virtual void get_import_options(const String &p_path,
List<ResourceImporter::ImportOption> *r_options) override;
- virtual Variant get_option_visibility(const String &p_path, const String &p_option,
- const Map<StringName, Variant> &p_options) override;
+ virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option,
+ const HashMap<StringName, Variant> &p_options) override;
};
#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.cpp b/modules/gltf/editor/editor_scene_importer_gltf.cpp
index 1d6a82e58a..d5b247fc6e 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.cpp
+++ b/modules/gltf/editor/editor_scene_importer_gltf.cpp
@@ -48,7 +48,7 @@ void EditorSceneFormatImporterGLTF::get_extensions(List<String> *r_extensions) c
}
Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t p_flags,
- const Map<StringName, Variant> &p_options, int p_bake_fps,
+ const HashMap<StringName, Variant> &p_options, int p_bake_fps,
List<String> *r_missing_deps, Error *r_err) {
Ref<GLTFDocument> doc;
doc.instantiate();
@@ -64,9 +64,4 @@ Node *EditorSceneFormatImporterGLTF::import_scene(const String &p_path, uint32_t
return doc->generate_scene(state, p_bake_fps);
}
-Ref<Animation> EditorSceneFormatImporterGLTF::import_animation(const String &p_path,
- uint32_t p_flags, const Map<StringName, Variant> &p_options, int p_bake_fps) {
- return Ref<Animation>();
-}
-
#endif // TOOLS_ENABLED
diff --git a/modules/gltf/editor/editor_scene_importer_gltf.h b/modules/gltf/editor/editor_scene_importer_gltf.h
index 1f62ca9537..edca038532 100644
--- a/modules/gltf/editor/editor_scene_importer_gltf.h
+++ b/modules/gltf/editor/editor_scene_importer_gltf.h
@@ -45,10 +45,8 @@ 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,
- const Map<StringName, Variant> &p_options, int p_bake_fps,
+ const HashMap<StringName, Variant> &p_options, 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,
- const Map<StringName, Variant> &p_options, int p_bake_fps) override;
};
#endif // TOOLS_ENABLED
diff --git a/modules/gltf/gltf_animation.cpp b/modules/gltf/gltf_animation.cpp
index c857be4b2c..e598c870ab 100644
--- a/modules/gltf/gltf_animation.cpp
+++ b/modules/gltf/gltf_animation.cpp
@@ -45,7 +45,7 @@ void GLTFAnimation::set_loop(bool p_val) {
loop = p_val;
}
-Map<int, GLTFAnimation::Track> &GLTFAnimation::get_tracks() {
+HashMap<int, GLTFAnimation::Track> &GLTFAnimation::get_tracks() {
return tracks;
}
diff --git a/modules/gltf/gltf_animation.h b/modules/gltf/gltf_animation.h
index ba8ae8a273..8688ddb937 100644
--- a/modules/gltf/gltf_animation.h
+++ b/modules/gltf/gltf_animation.h
@@ -64,11 +64,11 @@ public:
public:
bool get_loop() const;
void set_loop(bool p_val);
- Map<int, GLTFAnimation::Track> &get_tracks();
+ HashMap<int, GLTFAnimation::Track> &get_tracks();
GLTFAnimation();
private:
bool loop = false;
- Map<int, Track> tracks;
+ HashMap<int, Track> tracks;
};
#endif // GLTF_ANIMATION_H
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index ee756c6d2e..f440a29f28 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -65,6 +65,7 @@
#include "scene/3d/node_3d.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/importer_mesh.h"
+#include "scene/resources/material.h"
#include "scene/resources/mesh.h"
#include "scene/resources/multimesh.h"
#include "scene/resources/surface_tool.h"
@@ -80,6 +81,7 @@
// FIXME: Hardcoded to avoid editor dependency.
#define GLTF_IMPORT_USE_NAMED_SKIN_BINDS 16
+#define GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS 32
#include <stdio.h>
#include <stdlib.h>
@@ -256,8 +258,8 @@ Error GLTFDocument::_serialize_scenes(Ref<GLTFState> state) {
Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
Error err;
- FileAccessRef f = FileAccess::open(p_path, FileAccess::READ, &err);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
+ if (f.is_null()) {
return err;
}
@@ -278,7 +280,7 @@ Error GLTFDocument::_parse_json(const String &p_path, Ref<GLTFState> state) {
return OK;
}
-Error GLTFDocument::_parse_glb(FileAccess *f, Ref<GLTFState> state) {
+Error GLTFDocument::_parse_glb(Ref<FileAccess> f, Ref<GLTFState> state) {
ERR_FAIL_NULL_V(f, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(state, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(f->get_position() != 0, ERR_FILE_CANT_READ);
@@ -358,9 +360,9 @@ static Transform3D _arr_to_xform(const Array &p_array) {
ERR_FAIL_COND_V(p_array.size() != 16, Transform3D());
Transform3D xform;
- xform.basis.set_axis(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2]));
- xform.basis.set_axis(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6]));
- xform.basis.set_axis(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10]));
+ xform.basis.set_column(Vector3::AXIS_X, Vector3(p_array[0], p_array[1], p_array[2]));
+ xform.basis.set_column(Vector3::AXIS_Y, Vector3(p_array[4], p_array[5], p_array[6]));
+ xform.basis.set_column(Vector3::AXIS_Z, Vector3(p_array[8], p_array[9], p_array[10]));
xform.set_origin(Vector3(p_array[12], p_array[13], p_array[14]));
return xform;
@@ -369,17 +371,17 @@ static Transform3D _arr_to_xform(const Array &p_array) {
static Vector<real_t> _xform_to_array(const Transform3D p_transform) {
Vector<real_t> array;
array.resize(16);
- Vector3 axis_x = p_transform.get_basis().get_axis(Vector3::AXIS_X);
+ Vector3 axis_x = p_transform.get_basis().get_column(Vector3::AXIS_X);
array.write[0] = axis_x.x;
array.write[1] = axis_x.y;
array.write[2] = axis_x.z;
array.write[3] = 0.0f;
- Vector3 axis_y = p_transform.get_basis().get_axis(Vector3::AXIS_Y);
+ Vector3 axis_y = p_transform.get_basis().get_column(Vector3::AXIS_Y);
array.write[4] = axis_y.x;
array.write[5] = axis_y.y;
array.write[6] = axis_y.z;
array.write[7] = 0.0f;
- Vector3 axis_z = p_transform.get_basis().get_axis(Vector3::AXIS_Z);
+ Vector3 axis_z = p_transform.get_basis().get_column(Vector3::AXIS_Z);
array.write[8] = axis_z.x;
array.write[9] = axis_z.y;
array.write[10] = axis_z.z;
@@ -696,8 +698,8 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat
String filename = p_path.get_basename().get_file() + itos(i) + ".bin";
String path = p_path.get_base_dir() + "/" + filename;
Error err;
- FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err);
+ if (f.is_null()) {
return err;
}
if (buffer_data.size() == 0) {
@@ -705,7 +707,6 @@ Error GLTFDocument::_encode_buffer_glb(Ref<GLTFState> state, const String &p_pat
}
f->create(FileAccess::ACCESS_RESOURCES);
f->store_buffer(buffer_data.ptr(), buffer_data.size());
- f->close();
gltf_buffer["uri"] = filename;
gltf_buffer["byteLength"] = buffer_data.size();
buffers.push_back(gltf_buffer);
@@ -729,8 +730,8 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa
String filename = p_path.get_basename().get_file() + itos(i) + ".bin";
String path = p_path.get_base_dir() + "/" + filename;
Error err;
- FileAccessRef f = FileAccess::open(path, FileAccess::WRITE, &err);
- if (!f) {
+ Ref<FileAccess> f = FileAccess::open(path, FileAccess::WRITE, &err);
+ if (f.is_null()) {
return err;
}
if (buffer_data.size() == 0) {
@@ -738,7 +739,6 @@ Error GLTFDocument::_encode_buffer_bins(Ref<GLTFState> state, const String &p_pa
}
f->create(FileAccess::ACCESS_RESOURCES);
f->store_buffer(buffer_data.ptr(), buffer_data.size());
- f->close();
gltf_buffer["uri"] = filename;
gltf_buffer["byteLength"] = buffer_data.size();
buffers.push_back(gltf_buffer);
@@ -1960,20 +1960,20 @@ GLTFAccessorIndex GLTFDocument::_encode_accessor_as_xform(Ref<GLTFState> state,
for (int i = 0; i < p_attribs.size(); i++) {
Transform3D attrib = p_attribs[i];
Basis basis = attrib.get_basis();
- Vector3 axis_0 = basis.get_axis(Vector3::AXIS_X);
+ Vector3 axis_0 = basis.get_column(Vector3::AXIS_X);
attribs.write[i * element_count + 0] = Math::snapped(axis_0.x, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 1] = Math::snapped(axis_0.y, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 2] = Math::snapped(axis_0.z, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 3] = 0.0;
- Vector3 axis_1 = basis.get_axis(Vector3::AXIS_Y);
+ Vector3 axis_1 = basis.get_column(Vector3::AXIS_Y);
attribs.write[i * element_count + 4] = Math::snapped(axis_1.x, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 5] = Math::snapped(axis_1.y, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 6] = Math::snapped(axis_1.z, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 7] = 0.0;
- Vector3 axis_2 = basis.get_axis(Vector3::AXIS_Z);
+ Vector3 axis_2 = basis.get_column(Vector3::AXIS_Z);
attribs.write[i * element_count + 8] = Math::snapped(axis_2.x, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 9] = Math::snapped(axis_2.y, CMP_NORMALIZE_TOLERANCE);
attribs.write[i * element_count + 10] = Math::snapped(axis_2.z, CMP_NORMALIZE_TOLERANCE);
@@ -2105,9 +2105,9 @@ Vector<Basis> GLTFDocument::_decode_accessor_as_basis(Ref<GLTFState> state, cons
ERR_FAIL_COND_V(attribs.size() % 9 != 0, ret);
ret.resize(attribs.size() / 9);
for (int i = 0; i < ret.size(); i++) {
- ret.write[i].set_axis(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2]));
- ret.write[i].set_axis(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5]));
- ret.write[i].set_axis(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8]));
+ ret.write[i].set_column(0, Vector3(attribs[i * 9 + 0], attribs[i * 9 + 1], attribs[i * 9 + 2]));
+ ret.write[i].set_column(1, Vector3(attribs[i * 9 + 3], attribs[i * 9 + 4], attribs[i * 9 + 5]));
+ ret.write[i].set_column(2, Vector3(attribs[i * 9 + 6], attribs[i * 9 + 7], attribs[i * 9 + 8]));
}
return ret;
}
@@ -2123,9 +2123,9 @@ Vector<Transform3D> GLTFDocument::_decode_accessor_as_xform(Ref<GLTFState> state
ERR_FAIL_COND_V(attribs.size() % 16 != 0, ret);
ret.resize(attribs.size() / 16);
for (int i = 0; i < ret.size(); i++) {
- ret.write[i].basis.set_axis(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2]));
- ret.write[i].basis.set_axis(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6]));
- ret.write[i].basis.set_axis(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10]));
+ ret.write[i].basis.set_column(0, Vector3(attribs[i * 16 + 0], attribs[i * 16 + 1], attribs[i * 16 + 2]));
+ ret.write[i].basis.set_column(1, Vector3(attribs[i * 16 + 4], attribs[i * 16 + 5], attribs[i * 16 + 6]));
+ ret.write[i].basis.set_column(2, Vector3(attribs[i * 16 + 8], attribs[i * 16 + 9], attribs[i * 16 + 10]));
ret.write[i].set_origin(Vector3(attribs[i * 16 + 12], attribs[i * 16 + 13], attribs[i * 16 + 14]));
}
return ret;
@@ -2294,7 +2294,7 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
attributes["COLOR_0"] = _encode_accessor_as_color(state, a, true);
}
}
- Map<int, int> joint_i_to_bone_i;
+ HashMap<int, int> joint_i_to_bone_i;
for (GLTFNodeIndex node_i = 0; node_i < state->nodes.size(); node_i++) {
GLTFSkinIndex skin_i = -1;
if (state->nodes[node_i]->mesh == gltf_mesh_i) {
@@ -2468,9 +2468,9 @@ Error GLTFDocument::_serialize_meshes(Ref<GLTFState> state) {
mat = import_mesh->get_surface_material(surface_i);
}
if (mat.is_valid()) {
- Map<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Element *material_cache_i = state->material_cache.find(mat);
- if (material_cache_i && material_cache_i->get() != -1) {
- primitive["material"] = material_cache_i->get();
+ HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex>::Iterator material_cache_i = state->material_cache.find(mat);
+ if (material_cache_i && material_cache_i->value != -1) {
+ primitive["material"] = material_cache_i->value;
} else {
GLTFMaterialIndex mat_i = state->materials.size();
state->materials.push_back(mat);
@@ -2920,30 +2920,32 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> state) {
}
}
- //just add it
-
Ref<BaseMaterial3D> mat;
- if (p.has("material")) {
- 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;
+ String mat_name;
+ if (!state->discard_meshes_and_materials) {
+ if (p.has("material")) {
+ 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 {
- Ref<StandardMaterial3D> mat3d;
- mat3d.instantiate();
- if (has_vertex_color) {
- mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ } else {
+ Ref<StandardMaterial3D> mat3d;
+ mat3d.instantiate();
+ if (has_vertex_color) {
+ mat3d->set_flag(BaseMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
+ }
+ mat = mat3d;
}
- mat = mat3d;
+ ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT);
+ mat_name = mat->get_name();
}
- ERR_FAIL_NULL_V(mat, ERR_FILE_CORRUPT);
import_mesh->add_surface(primitive, array, morphs,
- Dictionary(), mat, mat->get_name(), flags);
+ Dictionary(), mat, mat_name, flags);
}
Vector<float> blend_weights;
@@ -3021,7 +3023,7 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> state, const String &p_path
String texture_dir = "textures";
String path = p_path.get_base_dir();
String new_texture_dir = path + "/" + texture_dir;
- DirAccessRef da = DirAccess::open(path);
+ Ref<DirAccess> da = DirAccess::open(path);
if (!da->dir_exists(new_texture_dir)) {
da->make_dir(new_texture_dir);
}
@@ -3274,7 +3276,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
Dictionary mr;
{
Array arr;
- const Color c = material->get_albedo().to_linear();
+ const Color c = material->get_albedo().srgb_to_linear();
arr.push_back(c.r);
arr.push_back(c.g);
arr.push_back(c.b);
@@ -3475,7 +3477,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> state) {
}
if (material->get_feature(BaseMaterial3D::FEATURE_EMISSION)) {
- const Color c = material->get_emission().to_srgb();
+ const Color c = material->get_emission().linear_to_srgb();
Array arr;
arr.push_back(c.r);
arr.push_back(c.g);
@@ -3557,7 +3559,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (sgm.has("diffuseFactor")) {
const Array &arr = sgm["diffuseFactor"];
ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb();
+ const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb();
spec_gloss->diffuse_factor = c;
material->set_albedo(spec_gloss->diffuse_factor);
}
@@ -3588,7 +3590,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (mr.has("baseColorFactor")) {
const Array &arr = mr["baseColorFactor"];
ERR_FAIL_COND_V(arr.size() != 4, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2], arr[3]).to_srgb();
+ const Color c = Color(arr[0], arr[1], arr[2], arr[3]).linear_to_srgb();
material->set_albedo(c);
}
@@ -3655,7 +3657,7 @@ Error GLTFDocument::_parse_materials(Ref<GLTFState> state) {
if (d.has("emissiveFactor")) {
const Array &arr = d["emissiveFactor"];
ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2]).to_srgb();
+ const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
material->set_feature(BaseMaterial3D::FEATURE_EMISSION, true);
material->set_emission(c);
@@ -3739,11 +3741,11 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re
}
for (int32_t y = 0; y < r_spec_gloss->spec_gloss_img->get_height(); y++) {
for (int32_t x = 0; x < r_spec_gloss->spec_gloss_img->get_width(); x++) {
- const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).to_linear();
+ const Color specular_pixel = r_spec_gloss->spec_gloss_img->get_pixel(x, y).srgb_to_linear();
Color specular = Color(specular_pixel.r, specular_pixel.g, specular_pixel.b);
specular *= r_spec_gloss->specular_factor;
Color diffuse = Color(1.0f, 1.0f, 1.0f);
- diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).to_linear();
+ diffuse *= r_spec_gloss->diffuse_img->get_pixel(x, y).srgb_to_linear();
float metallic = 0.0f;
Color base_color;
spec_gloss_to_metal_base_color(specular, diffuse, base_color, metallic);
@@ -3760,7 +3762,7 @@ void GLTFDocument::spec_gloss_to_rough_metal(Ref<GLTFSpecGloss> r_spec_gloss, Re
mr.g = 1.0f - mr.g;
rm_img->set_pixel(x, y, mr);
if (r_spec_gloss->diffuse_img.is_valid()) {
- r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.to_srgb());
+ r_spec_gloss->diffuse_img->set_pixel(x, y, base_color.linear_to_srgb());
}
}
}
@@ -4628,7 +4630,7 @@ Error GLTFDocument::_parse_lights(Ref<GLTFState> state) {
if (d.has("color")) {
const Array &arr = d["color"];
ERR_FAIL_COND_V(arr.size() != 3, ERR_PARSE_ERROR);
- const Color c = Color(arr[0], arr[1], arr[2]).to_srgb();
+ const Color c = Color(arr[0], arr[1], arr[2]).linear_to_srgb();
light->color = c;
}
if (d.has("intensity")) {
@@ -5902,9 +5904,9 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
Node *root = ap->get_parent();
ERR_FAIL_COND(root == nullptr);
- Map<GLTFNodeIndex, Node *>::Element *node_element = state->scene_nodes.find(node_index);
- ERR_CONTINUE_MSG(node_element == nullptr, vformat("Unable to find node %d for animation", node_index));
- node_path = root->get_path_to(node_element->get());
+ HashMap<GLTFNodeIndex, Node *>::Iterator node_element = state->scene_nodes.find(node_index);
+ ERR_CONTINUE_MSG(!node_element, vformat("Unable to find node %d for animation", node_index));
+ node_path = root->get_path_to(node_element->value);
if (gltf_node->skeleton >= 0) {
const Skeleton3D *sk = state->skeletons[gltf_node->skeleton]->godot_skeleton;
@@ -6097,7 +6099,14 @@ void GLTFDocument::_import_animation(Ref<GLTFState> state, AnimationPlayer *ap,
animation->set_length(length);
- ap->add_animation(name, animation);
+ Ref<AnimationLibrary> library;
+ if (!ap->has_animation_library("")) {
+ library.instantiate();
+ ap->add_animation_library("", library);
+ } else {
+ library = ap->get_animation_library("");
+ }
+ library->add_animation(name, animation);
}
void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
@@ -6107,11 +6116,11 @@ void GLTFDocument::_convert_mesh_instances(Ref<GLTFState> state) {
if (node->mesh < 0) {
continue;
}
- Map<GLTFNodeIndex, Node *>::Element *mi_element = state->scene_nodes.find(mi_node_i);
+ HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = state->scene_nodes.find(mi_node_i);
if (!mi_element) {
continue;
}
- MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->get());
+ MeshInstance3D *mi = Object::cast_to<MeshInstance3D>(mi_element->value);
if (!mi) {
continue;
}
@@ -6241,11 +6250,11 @@ void GLTFDocument::_process_mesh_instances(Ref<GLTFState> state, Node *scene_roo
if (node->skin >= 0 && node->mesh >= 0) {
const GLTFSkinIndex skin_i = node->skin;
- 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));
+ HashMap<GLTFNodeIndex, Node *>::Iterator mi_element = state->scene_nodes.find(node_i);
+ ERR_CONTINUE_MSG(!mi_element, vformat("Unable to find node %d", node_i));
- 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()));
+ ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(mi_element->value);
+ ERR_CONTINUE_MSG(mi == nullptr, vformat("Unable to cast node %d of type %s to ImporterMeshInstance3D", node_i, mi_element->value->get_class_name()));
const GLTFSkeletonIndex skel_i = state->skins.write[node->skin]->skeleton;
Ref<GLTFSkeleton> gltf_skeleton = state->skeletons.write[skel_i];
@@ -6427,10 +6436,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
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);
+ HashMap<int, GLTFAnimation::Track>::Iterator position_track_i = gltf_animation->get_tracks().find(node_index);
GLTFAnimation::Track track;
if (position_track_i) {
- track = position_track_i->get();
+ track = position_track_i->value;
}
track = _convert_animation_track(state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
@@ -6443,10 +6452,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
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);
+ HashMap<int, GLTFAnimation::Track>::Iterator rotation_degree_track_i = gltf_animation->get_tracks().find(node_index);
GLTFAnimation::Track track;
if (rotation_degree_track_i) {
- track = rotation_degree_track_i->get();
+ track = rotation_degree_track_i->value;
}
track = _convert_animation_track(state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
@@ -6459,10 +6468,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
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);
+ HashMap<int, GLTFAnimation::Track>::Iterator scale_track_i = gltf_animation->get_tracks().find(node_index);
GLTFAnimation::Track track;
if (scale_track_i) {
- track = scale_track_i->get();
+ track = scale_track_i->value;
}
track = _convert_animation_track(state, track, animation, track_i, node_index);
gltf_animation->get_tracks().insert(node_index, track);
@@ -6494,7 +6503,7 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
ERR_CONTINUE(mesh_index == -1);
- Map<int, GLTFAnimation::Track> &tracks = gltf_animation->get_tracks();
+ HashMap<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++) {
@@ -6556,10 +6565,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
continue;
}
GLTFNodeIndex node_i = skeleton_gltf->godot_bone_node[bone];
- Map<int, GLTFAnimation::Track>::Element *property_track_i = gltf_animation->get_tracks().find(node_i);
+ HashMap<int, GLTFAnimation::Track>::Iterator property_track_i = gltf_animation->get_tracks().find(node_i);
GLTFAnimation::Track track;
if (property_track_i) {
- track = property_track_i->get();
+ track = property_track_i->value;
}
track = _convert_animation_track(state, track, animation, track_i, node_i);
gltf_animation->get_tracks()[node_i] = track;
@@ -6571,10 +6580,10 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
for (const KeyValue<GLTFNodeIndex, Node *> &scene_node_i : state->scene_nodes) {
if (scene_node_i.value == godot_node) {
GLTFNodeIndex node_i = scene_node_i.key;
- Map<int, GLTFAnimation::Track>::Element *node_track_i = gltf_animation->get_tracks().find(node_i);
+ HashMap<int, GLTFAnimation::Track>::Iterator node_track_i = gltf_animation->get_tracks().find(node_i);
GLTFAnimation::Track track;
if (node_track_i) {
- track = node_track_i->get();
+ track = node_track_i->value;
}
track = _convert_animation_track(state, track, animation, track_i, node_i);
gltf_animation->get_tracks()[node_i] = track;
@@ -6588,9 +6597,9 @@ void GLTFDocument::_convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
}
}
-Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps) {
+Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps) {
Error err;
- if (!f) {
+ if (f.is_null()) {
return FAILED;
}
f->seek(0);
@@ -6614,7 +6623,6 @@ Error GLTFDocument::_parse(Ref<GLTFState> state, String p_path, FileAccess *f, i
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
state->json = json.get_data();
}
- f->close();
if (!state->json.has("asset")) {
return ERR_PARSE_ERROR;
@@ -6703,8 +6711,8 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
if (p_path.to_lower().ends_with("glb")) {
err = _encode_buffer_glb(state, p_path);
ERR_FAIL_COND_V(err != OK, err);
- FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V(!f, FAILED);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(f.is_null(), FAILED);
String json = Variant(state->json).to_json_string();
@@ -6741,18 +6749,15 @@ Error GLTFDocument::_serialize_file(Ref<GLTFState> state, const String p_path) {
for (uint32_t pad_i = binary_data_length; pad_i < binary_chunk_length; pad_i++) {
f->store_8(0);
}
-
- f->close();
} else {
err = _encode_buffer_bins(state, p_path);
ERR_FAIL_COND_V(err != OK, err);
- FileAccessRef f = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V(!f, FAILED);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V(f.is_null(), FAILED);
f->create(FileAccess::ACCESS_RESOURCES);
String json = Variant(state->json).to_json_string();
f->store_string(json);
- f->close();
}
return err;
}
@@ -6907,8 +6912,8 @@ Node *GLTFDocument::generate_scene(Ref<GLTFState> state, int32_t p_bake_fps) {
Error GLTFDocument::append_from_scene(Node *p_node, Ref<GLTFState> state, uint32_t p_flags, int32_t p_bake_fps) {
ERR_FAIL_COND_V(state.is_null(), FAILED);
- state->use_named_skin_binds =
- p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
_convert_scene_node(state, p_node, -1, -1);
if (!state->buffers.size()) {
@@ -6927,9 +6932,11 @@ Error GLTFDocument::append_from_buffer(PackedByteArray p_bytes, String p_base_pa
ERR_FAIL_COND_V(state.is_null(), FAILED);
// TODO Add missing texture and missing .bin file paths to r_missing_deps 2021-09-10 fire
Error err = FAILED;
- state->use_named_skin_binds =
- p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
- FileAccessMemory *file_access = memnew(FileAccessMemory);
+ state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
+
+ Ref<FileAccessMemory> file_access;
+ file_access.instantiate();
file_access->open_custom(p_bytes.ptr(), p_bytes.size());
err = _parse(state, p_base_path.get_base_dir(), file_access, p_bake_fps);
ERR_FAIL_COND_V(err != OK, FAILED);
@@ -6966,20 +6973,22 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> state, const String &p_sear
ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- /* PARSE IMAGES */
- err = _parse_images(state, p_search_path);
+ if (!state->discard_meshes_and_materials) {
+ /* PARSE IMAGES */
+ err = _parse_images(state, p_search_path);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- /* PARSE TEXTURES */
- err = _parse_textures(state);
+ /* PARSE TEXTURES */
+ err = _parse_textures(state);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
- /* PARSE TEXTURES */
- err = _parse_materials(state);
+ /* PARSE TEXTURES */
+ err = _parse_materials(state);
- ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ ERR_FAIL_COND_V(err != OK, ERR_PARSE_ERROR);
+ }
/* PARSE SKINS */
err = _parse_skins(state);
@@ -7031,8 +7040,9 @@ Error GLTFDocument::append_from_file(String p_path, Ref<GLTFState> r_state, uint
}
r_state->filename = p_path.get_file().get_basename();
r_state->use_named_skin_binds = p_flags & GLTF_IMPORT_USE_NAMED_SKIN_BINDS;
+ r_state->discard_meshes_and_materials = p_flags & GLTF_IMPORT_DISCARD_MESHES_AND_MATERIALS;
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V(err != OK, ERR_FILE_CANT_OPEN);
ERR_FAIL_NULL_V(f, ERR_FILE_CANT_OPEN);
String base_path = p_base_path;
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index 0b7664a616..9db824a0d4 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -135,9 +135,9 @@ private:
}
template <class T>
- static Array to_array(const Set<T> &p_inp) {
+ static Array to_array(const RBSet<T> &p_inp) {
Array ret;
- typename Set<T>::Element *elem = p_inp.front();
+ typename RBSet<T>::Element *elem = p_inp.front();
while (elem) {
ret.push_back(elem->get());
elem = elem->next();
@@ -154,23 +154,23 @@ private:
}
template <class T>
- static void set_from_array(Set<T> &r_out, const Array &p_inp) {
+ static void set_from_array(RBSet<T> &r_out, const Array &p_inp) {
r_out.clear();
for (int i = 0; i < p_inp.size(); i++) {
r_out.insert(p_inp[i]);
}
}
template <class K, class V>
- static Dictionary to_dict(const Map<K, V> &p_inp) {
+ static Dictionary to_dict(const HashMap<K, V> &p_inp) {
Dictionary ret;
- for (typename Map<K, V>::Element *E = p_inp.front(); E; E = E->next()) {
- ret[E->key()] = E->value();
+ for (const KeyValue<K, V> &E : p_inp) {
+ ret[E.key] = E.value;
}
return ret;
}
template <class K, class V>
- static void set_from_dict(Map<K, V> &r_out, const Dictionary &p_inp) {
+ static void set_from_dict(HashMap<K, V> &r_out, const Dictionary &p_inp) {
r_out.clear();
Array keys = p_inp.keys();
for (int i = 0; i < keys.size(); i++) {
@@ -196,7 +196,7 @@ private:
Ref<Texture2D> _get_texture(Ref<GLTFState> state,
const GLTFTextureIndex p_texture);
Error _parse_json(const String &p_path, Ref<GLTFState> state);
- Error _parse_glb(FileAccess *f, Ref<GLTFState> state);
+ Error _parse_glb(Ref<FileAccess> f, Ref<GLTFState> state);
void _compute_node_heights(Ref<GLTFState> state);
Error _parse_buffers(Ref<GLTFState> state, const String &p_base_path);
Error _parse_buffer_views(Ref<GLTFState> state);
@@ -457,7 +457,7 @@ public:
void _convert_animation(Ref<GLTFState> state, AnimationPlayer *ap,
String p_animation_track_name);
Error _serialize(Ref<GLTFState> state, const String &p_path);
- Error _parse(Ref<GLTFState> state, String p_path, FileAccess *f, int p_bake_fps);
+ Error _parse(Ref<GLTFState> state, String p_path, Ref<FileAccess> f, int p_bake_fps);
};
#endif // GLTF_DOCUMENT_H
diff --git a/modules/gltf/gltf_skeleton.cpp b/modules/gltf/gltf_skeleton.cpp
index e80376f130..b813f39a27 100644
--- a/modules/gltf/gltf_skeleton.cpp
+++ b/modules/gltf/gltf_skeleton.cpp
@@ -46,7 +46,7 @@ void GLTFSkeleton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "joints"), "set_joints", "get_joints"); // Vector<GLTFNodeIndex>
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_names", "get_unique_names"); // Set<String>
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "godot_bone_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_godot_bone_node", "get_godot_bone_node"); // Map<int32_t,
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "godot_bone_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_godot_bone_node", "get_godot_bone_node"); // RBMap<int32_t,
}
Vector<GLTFNodeIndex> GLTFSkeleton::get_joints() {
diff --git a/modules/gltf/gltf_skeleton.h b/modules/gltf/gltf_skeleton.h
index 7d07d528cb..4dcee41465 100644
--- a/modules/gltf/gltf_skeleton.h
+++ b/modules/gltf/gltf_skeleton.h
@@ -50,9 +50,9 @@ private:
Skeleton3D *godot_skeleton = nullptr;
// Set of unique bone names for the skeleton
- Set<String> unique_names;
+ RBSet<String> unique_names;
- Map<int32_t, GLTFNodeIndex> godot_bone_node;
+ HashMap<int32_t, GLTFNodeIndex> godot_bone_node;
Vector<BoneAttachment3D *> bone_attachments;
@@ -78,10 +78,10 @@ public:
Array get_unique_names();
void set_unique_names(Array p_unique_names);
- //Map<int32_t, GLTFNodeIndex> get_godot_bone_node() {
+ //RBMap<int32_t, GLTFNodeIndex> get_godot_bone_node() {
// return this->godot_bone_node;
//}
- //void set_godot_bone_node(Map<int32_t, GLTFNodeIndex> p_godot_bone_node) {
+ //void set_godot_bone_node(RBMap<int32_t, GLTFNodeIndex> p_godot_bone_node) {
// this->godot_bone_node = p_godot_bone_node;
//}
Dictionary get_godot_bone_node();
diff --git a/modules/gltf/gltf_skin.cpp b/modules/gltf/gltf_skin.cpp
index 283fc34ff5..e8005aa0c1 100644
--- a/modules/gltf/gltf_skin.cpp
+++ b/modules/gltf/gltf_skin.cpp
@@ -59,8 +59,8 @@ void GLTFSkin::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "non_joints"), "set_non_joints", "get_non_joints"); // Vector<GLTFNodeIndex>
ADD_PROPERTY(PropertyInfo(Variant::PACKED_INT32_ARRAY, "roots"), "set_roots", "get_roots"); // Vector<GLTFNodeIndex>
ADD_PROPERTY(PropertyInfo(Variant::INT, "skeleton"), "set_skeleton", "get_skeleton"); // int
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_bone_i", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_bone_i", "get_joint_i_to_bone_i"); // Map<int,
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_name", "get_joint_i_to_name"); // Map<int,
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_bone_i", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_bone_i", "get_joint_i_to_bone_i"); // RBMap<int,
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "joint_i_to_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL), "set_joint_i_to_name", "get_joint_i_to_name"); // RBMap<int,
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "godot_skin"), "set_godot_skin", "get_godot_skin"); // Ref<Skin>
}
@@ -130,16 +130,16 @@ void GLTFSkin::set_joint_i_to_bone_i(Dictionary p_joint_i_to_bone_i) {
Dictionary GLTFSkin::get_joint_i_to_name() {
Dictionary ret;
- Map<int, StringName>::Element *elem = joint_i_to_name.front();
+ HashMap<int, StringName>::Iterator elem = joint_i_to_name.begin();
while (elem) {
- ret[elem->key()] = String(elem->value());
- elem = elem->next();
+ ret[elem->key] = String(elem->value);
+ ++elem;
}
return ret;
}
void GLTFSkin::set_joint_i_to_name(Dictionary p_joint_i_to_name) {
- joint_i_to_name = Map<int, StringName>();
+ joint_i_to_name = HashMap<int, StringName>();
Array keys = p_joint_i_to_name.keys();
for (int i = 0; i < keys.size(); i++) {
joint_i_to_name[keys[i]] = p_joint_i_to_name[keys[i]];
diff --git a/modules/gltf/gltf_skin.h b/modules/gltf/gltf_skin.h
index 31cb892f19..d946324756 100644
--- a/modules/gltf/gltf_skin.h
+++ b/modules/gltf/gltf_skin.h
@@ -65,8 +65,8 @@ private:
// A mapping from the joint indices (in the order of joints_original) to the
// Godot Skeleton's bone_indices
- Map<int, int> joint_i_to_bone_i;
- Map<int, StringName> joint_i_to_name;
+ HashMap<int, int> joint_i_to_bone_i;
+ HashMap<int, StringName> joint_i_to_name;
// The Actual Skin that will be created as a mapping between the IBM's of
// this skin to the generated skeleton for the mesh instances.
diff --git a/modules/gltf/gltf_state.cpp b/modules/gltf/gltf_state.cpp
index 3f638bbca5..e959a640b4 100644
--- a/modules/gltf/gltf_state.cpp
+++ b/modules/gltf/gltf_state.cpp
@@ -102,7 +102,7 @@ void GLTFState::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_names", "get_unique_names"); // Set<String>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "unique_animation_names", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_unique_animation_names", "get_unique_animation_names"); // Set<String>
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "skeletons", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeletons", "get_skeletons"); // Vector<Ref<GLTFSkeleton>>
- ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "skeleton_to_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeleton_to_node", "get_skeleton_to_node"); // Map<GLTFSkeletonIndex,
+ ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "skeleton_to_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_skeleton_to_node", "get_skeleton_to_node"); // RBMap<GLTFSkeletonIndex,
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "animations", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_INTERNAL | PROPERTY_USAGE_EDITOR), "set_animations", "get_animations"); // Vector<Ref<GLTFAnimation>>
}
@@ -305,3 +305,11 @@ AnimationPlayer *GLTFState::get_animation_player(int idx) {
ERR_FAIL_INDEX_V(idx, animation_players.size(), nullptr);
return animation_players[idx];
}
+
+void GLTFState::set_discard_meshes_and_materials(bool p_discard_meshes_and_materials) {
+ discard_meshes_and_materials = p_discard_meshes_and_materials;
+}
+
+bool GLTFState::get_discard_meshes_and_materials() {
+ return discard_meshes_and_materials;
+}
diff --git a/modules/gltf/gltf_state.h b/modules/gltf/gltf_state.h
index d03434d2f1..f695b20b49 100644
--- a/modules/gltf/gltf_state.h
+++ b/modules/gltf/gltf_state.h
@@ -45,8 +45,8 @@
#include "gltf_texture.h"
#include "core/io/resource.h"
-#include "core/templates/map.h"
#include "core/templates/pair.h"
+#include "core/templates/rb_map.h"
#include "core/templates/vector.h"
#include "scene/animation/animation_player.h"
#include "scene/resources/texture.h"
@@ -62,6 +62,7 @@ class GLTFState : public Resource {
Vector<uint8_t> glb_data;
bool use_named_skin_binds = false;
+ bool discard_meshes_and_materials = false;
Vector<Ref<GLTFNode>> nodes;
Vector<Vector<uint8_t>> buffers;
@@ -71,7 +72,7 @@ class GLTFState : public Resource {
Vector<Ref<GLTFMesh>> meshes; // meshes are loaded directly, no reason not to.
Vector<AnimationPlayer *> animation_players;
- Map<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache;
+ HashMap<Ref<BaseMaterial3D>, GLTFMaterialIndex> material_cache;
Vector<Ref<BaseMaterial3D>> materials;
String scene_name;
@@ -82,16 +83,16 @@ class GLTFState : public Resource {
Vector<Ref<GLTFSkin>> skins;
Vector<Ref<GLTFCamera>> cameras;
Vector<Ref<GLTFLight>> lights;
- Set<String> unique_names;
- Set<String> unique_animation_names;
+ RBSet<String> unique_names;
+ RBSet<String> unique_animation_names;
Vector<Ref<GLTFSkeleton>> skeletons;
- Map<GLTFSkeletonIndex, GLTFNodeIndex> skeleton_to_node;
+ HashMap<GLTFSkeletonIndex, GLTFNodeIndex> skeleton_to_node;
Vector<Ref<GLTFAnimation>> animations;
- Map<GLTFNodeIndex, Node *> scene_nodes;
+ HashMap<GLTFNodeIndex, Node *> scene_nodes;
- Map<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton;
- Map<ObjectID, Map<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin;
+ HashMap<ObjectID, GLTFSkeletonIndex> skeleton3d_to_gltf_skeleton;
+ HashMap<ObjectID, HashMap<ObjectID, GLTFSkinIndex>> skin_and_skeleton3d_to_gltf_skin;
protected:
static void _bind_methods();
@@ -112,6 +113,9 @@ public:
bool get_use_named_skin_binds();
void set_use_named_skin_binds(bool p_use_named_skin_binds);
+ bool get_discard_meshes_and_materials();
+ void set_discard_meshes_and_materials(bool p_discard_meshes_and_materials);
+
Array get_nodes();
void set_nodes(Array p_nodes);
@@ -172,7 +176,7 @@ public:
AnimationPlayer *get_animation_player(int idx);
- //void set_scene_nodes(Map<GLTFNodeIndex, Node *> p_scene_nodes) {
+ //void set_scene_nodes(RBMap<GLTFNodeIndex, Node *> p_scene_nodes) {
// this->scene_nodes = p_scene_nodes;
//}
@@ -180,10 +184,10 @@ public:
// this->animation_players = p_animation_players;
//}
- //Map<Ref<Material>, GLTFMaterialIndex> get_material_cache() {
+ //RBMap<Ref<Material>, GLTFMaterialIndex> get_material_cache() {
// return this->material_cache;
//}
- //void set_material_cache(Map<Ref<Material>, GLTFMaterialIndex> p_material_cache) {
+ //void set_material_cache(RBMap<Ref<Material>, GLTFMaterialIndex> p_material_cache) {
// this->material_cache = p_material_cache;
//}
};
diff --git a/modules/gltf/register_types.cpp b/modules/gltf/register_types.cpp
index 4166f92502..b8bac79584 100644
--- a/modules/gltf/register_types.cpp
+++ b/modules/gltf/register_types.cpp
@@ -60,7 +60,7 @@
static void _editor_init() {
Ref<EditorSceneFormatImporterGLTF> import_gltf;
import_gltf.instantiate();
- ResourceImporterScene::get_singleton()->add_importer(import_gltf);
+ ResourceImporterScene::add_importer(import_gltf);
// Blend to glTF importer.
@@ -72,7 +72,7 @@ static void _editor_init() {
if (blend_enabled) {
Ref<EditorSceneFormatImporterBlend> importer;
importer.instantiate();
- ResourceImporterScene::get_singleton()->add_importer(importer);
+ ResourceImporterScene::add_importer(importer);
Ref<EditorFileSystemImportFormatSupportQueryBlend> blend_import_query;
blend_import_query.instantiate();
@@ -87,7 +87,7 @@ static void _editor_init() {
EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,
"filesystem/import/fbx/fbx2gltf_path", PROPERTY_HINT_GLOBAL_FILE));
if (fbx_enabled) {
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (fbx2gltf_path.is_empty()) {
WARN_PRINT("FBX file import is enabled, but no FBX2glTF path is configured. FBX files will not be imported.");
} else if (!da->file_exists(fbx2gltf_path)) {
@@ -95,51 +95,58 @@ static void _editor_init() {
} else {
Ref<EditorSceneFormatImporterFBX> importer;
importer.instantiate();
- ResourceImporterScene::get_singleton()->add_importer(importer);
+ ResourceImporterScene::add_importer(importer);
}
}
}
#endif // TOOLS_ENABLED
-void register_gltf_types() {
- // glTF API available at runtime.
- GDREGISTER_CLASS(GLTFAccessor);
- GDREGISTER_CLASS(GLTFAnimation);
- GDREGISTER_CLASS(GLTFBufferView);
- GDREGISTER_CLASS(GLTFCamera);
- GDREGISTER_CLASS(GLTFDocument);
- GDREGISTER_CLASS(GLTFDocumentExtension);
- GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
- GDREGISTER_CLASS(GLTFLight);
- GDREGISTER_CLASS(GLTFMesh);
- GDREGISTER_CLASS(GLTFNode);
- GDREGISTER_CLASS(GLTFSkeleton);
- GDREGISTER_CLASS(GLTFSkin);
- GDREGISTER_CLASS(GLTFSpecGloss);
- GDREGISTER_CLASS(GLTFState);
- GDREGISTER_CLASS(GLTFTexture);
+void initialize_gltf_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ // glTF API available at runtime.
+ GDREGISTER_CLASS(GLTFAccessor);
+ GDREGISTER_CLASS(GLTFAnimation);
+ GDREGISTER_CLASS(GLTFBufferView);
+ GDREGISTER_CLASS(GLTFCamera);
+ GDREGISTER_CLASS(GLTFDocument);
+ GDREGISTER_CLASS(GLTFDocumentExtension);
+ GDREGISTER_CLASS(GLTFDocumentExtensionConvertImporterMesh);
+ GDREGISTER_CLASS(GLTFLight);
+ GDREGISTER_CLASS(GLTFMesh);
+ GDREGISTER_CLASS(GLTFNode);
+ GDREGISTER_CLASS(GLTFSkeleton);
+ GDREGISTER_CLASS(GLTFSkin);
+ GDREGISTER_CLASS(GLTFSpecGloss);
+ GDREGISTER_CLASS(GLTFState);
+ GDREGISTER_CLASS(GLTFTexture);
+ }
#ifdef TOOLS_ENABLED
- // Editor-specific API.
- ClassDB::APIType prev_api = ClassDB::get_current_api();
- ClassDB::set_current_api(ClassDB::API_EDITOR);
-
- GDREGISTER_CLASS(EditorSceneFormatImporterGLTF);
- EditorPlugins::add_by_type<SceneExporterGLTFPlugin>();
-
- // Project settings defined here so doctool finds them.
- GLOBAL_DEF_RST("filesystem/import/blender/enabled", true);
- GLOBAL_DEF_RST("filesystem/import/fbx/enabled", true);
- GDREGISTER_CLASS(EditorSceneFormatImporterBlend);
- GDREGISTER_CLASS(EditorSceneFormatImporterFBX);
-
- ClassDB::set_current_api(prev_api);
- EditorNode::add_init_callback(_editor_init);
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ // Editor-specific API.
+ ClassDB::APIType prev_api = ClassDB::get_current_api();
+ ClassDB::set_current_api(ClassDB::API_EDITOR);
+
+ GDREGISTER_CLASS(EditorSceneFormatImporterGLTF);
+ EditorPlugins::add_by_type<SceneExporterGLTFPlugin>();
+
+ // Project settings defined here so doctool finds them.
+ GLOBAL_DEF_RST("filesystem/import/blender/enabled", true);
+ GLOBAL_DEF_RST("filesystem/import/fbx/enabled", true);
+ GDREGISTER_CLASS(EditorSceneFormatImporterBlend);
+ GDREGISTER_CLASS(EditorSceneFormatImporterFBX);
+
+ ClassDB::set_current_api(prev_api);
+ EditorNode::add_init_callback(_editor_init);
+ }
#endif // TOOLS_ENABLED
}
-void unregister_gltf_types() {
+void uninitialize_gltf_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
#endif // _3D_DISABLED
diff --git a/modules/gltf/register_types.h b/modules/gltf/register_types.h
index 4a9c31241c..90b9a83c88 100644
--- a/modules/gltf/register_types.h
+++ b/modules/gltf/register_types.h
@@ -28,5 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-void register_gltf_types();
-void unregister_gltf_types();
+#include "modules/register_module_types.h"
+
+void initialize_gltf_module(ModuleInitializationLevel p_level);
+void uninitialize_gltf_module(ModuleInitializationLevel p_level);
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 8914d32bd0..4902adb827 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -958,7 +958,7 @@ void GridMapEditor::update_grid() {
}
void GridMapEditor::_draw_grids(const Vector3 &cell_size) {
- Vector3 edited_floor = node->has_meta("_editor_floor_") ? node->get_meta("_editor_floor_") : Variant();
+ Vector3 edited_floor = node->get_meta("_editor_floor_", Vector3());
for (int i = 0; i < 3; i++) {
RS::get_singleton()->mesh_clear(grid[i]);
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.h b/modules/gridmap/editor/grid_map_editor_plugin.h
index adb0da6e2c..3b29397502 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.h
+++ b/modules/gridmap/editor/grid_map_editor_plugin.h
@@ -62,21 +62,21 @@ class GridMapEditor : public VBoxContainer {
DISPLAY_LIST
};
- UndoRedo *undo_redo;
+ UndoRedo *undo_redo = nullptr;
InputAction input_action = INPUT_NONE;
- Panel *panel;
- MenuButton *options;
- SpinBox *floor;
+ Panel *panel = nullptr;
+ MenuButton *options = nullptr;
+ SpinBox *floor = nullptr;
double accumulated_floor_delta = 0.0;
- Button *mode_thumbnail;
- Button *mode_list;
- LineEdit *search_box;
- HSlider *size_slider;
- HBoxContainer *spatial_editor_hb;
- ConfirmationDialog *settings_dialog;
- VBoxContainer *settings_vbc;
- SpinBox *settings_pick_distance;
- Label *spin_box_label;
+ Button *mode_thumbnail = nullptr;
+ Button *mode_list = nullptr;
+ LineEdit *search_box = nullptr;
+ HSlider *size_slider = nullptr;
+ HBoxContainer *spatial_editor_hb = nullptr;
+ ConfirmationDialog *settings_dialog = nullptr;
+ VBoxContainer *settings_vbc = nullptr;
+ SpinBox *settings_pick_distance = nullptr;
+ Label *spin_box_label = nullptr;
struct SetItem {
Vector3i position;
@@ -89,7 +89,7 @@ class GridMapEditor : public VBoxContainer {
List<SetItem> set_items;
GridMap *node = nullptr;
- MeshLibrary *last_mesh_library;
+ MeshLibrary *last_mesh_library = nullptr;
Transform3D grid_xform;
Transform3D edit_grid_xform;
@@ -173,15 +173,15 @@ class GridMapEditor : public VBoxContainer {
};
- Node3DEditorPlugin *spatial_editor;
+ Node3DEditorPlugin *spatial_editor = nullptr;
struct AreaDisplay {
RID mesh;
RID instance;
};
- ItemList *mesh_library_palette;
- Label *info_message;
+ ItemList *mesh_library_palette = nullptr;
+ Label *info_message = nullptr;
void update_grid(); // Change which and where the grid is displayed
void _draw_grids(const Vector3 &cell_size);
@@ -234,7 +234,7 @@ public:
class GridMapEditorPlugin : public EditorPlugin {
GDCLASS(GridMapEditorPlugin, EditorPlugin);
- GridMapEditor *grid_map_editor;
+ GridMapEditor *grid_map_editor = nullptr;
protected:
void _notification(int p_what);
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 02fe4d93de..9da137f9d5 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -103,9 +103,10 @@ bool GridMap::_get(const StringName &p_name, Variant &r_ret) const {
{
int *w = cells.ptrw();
int i = 0;
- for (Map<IndexKey, Cell>::Element *E = cell_map.front(); E; E = E->next(), i++) {
- encode_uint64(E->key().key, (uint8_t *)&w[i * 3]);
- encode_uint32(E->get().cell, (uint8_t *)&w[i * 3 + 2]);
+ for (const KeyValue<IndexKey, Cell> &E : cell_map) {
+ encode_uint64(E.key.key, (uint8_t *)&w[i * 3]);
+ encode_uint32(E.value.cell, (uint8_t *)&w[i * 3 + 2]);
+ i++;
}
}
@@ -480,9 +481,9 @@ bool GridMap::_octant_update(const OctantKey &p_key) {
* and set said multimesh bounding box to one containing all cells which have this item
*/
- Map<int, List<Pair<Transform3D, IndexKey>>> multimesh_items;
+ HashMap<int, List<Pair<Transform3D, IndexKey>>> multimesh_items;
- for (Set<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) {
+ for (RBSet<IndexKey>::Element *E = g.cells.front(); E; E = E->next()) {
ERR_CONTINUE(!cell_map.has(E->get()));
const Cell &c = cell_map[E->get()];
@@ -770,7 +771,7 @@ void GridMap::_queue_octants_dirty() {
void GridMap::_recreate_octant_data() {
recreating_octants = true;
- Map<IndexKey, Cell> cell_copy = cell_map;
+ HashMap<IndexKey, Cell, IndexKey> cell_copy = cell_map;
_clear_internal();
for (const KeyValue<IndexKey, Cell> &E : cell_copy) {
set_cell_item(Vector3i(E.key), E.value.item, E.value.rot);
@@ -797,7 +798,7 @@ void GridMap::clear() {
clear_baked_meshes();
}
-void GridMap::resource_changed(const RES &p_res) {
+void GridMap::resource_changed(const Ref<Resource> &p_res) {
_recreate_octant_data();
}
@@ -998,7 +999,7 @@ 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;
+ HashMap<OctantKey, HashMap<Ref<Material>, Ref<SurfaceTool>>, OctantKey> surface_map;
for (KeyValue<IndexKey, Cell> &E : cell_map) {
IndexKey key = E.key;
@@ -1028,10 +1029,10 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
ok.z = key.z / octant_size;
if (!surface_map.has(ok)) {
- surface_map[ok] = Map<Ref<Material>, Ref<SurfaceTool>>();
+ surface_map[ok] = HashMap<Ref<Material>, Ref<SurfaceTool>>();
}
- Map<Ref<Material>, Ref<SurfaceTool>> &mat_map = surface_map[ok];
+ HashMap<Ref<Material>, Ref<SurfaceTool>> &mat_map = surface_map[ok];
for (int i = 0; i < mesh->get_surface_count(); i++) {
if (mesh->surface_get_primitive_type(i) != Mesh::PRIMITIVE_TRIANGLES) {
@@ -1051,7 +1052,7 @@ void GridMap::make_baked_meshes(bool p_gen_lightmap_uv, float p_lightmap_uv_texe
}
}
- for (KeyValue<OctantKey, Map<Ref<Material>, Ref<SurfaceTool>>> &E : surface_map) {
+ for (KeyValue<OctantKey, HashMap<Ref<Material>, Ref<SurfaceTool>>> &E : surface_map) {
Ref<ArrayMesh> mesh;
mesh.instantiate();
for (KeyValue<Ref<Material>, Ref<SurfaceTool>> &F : E.value) {
diff --git a/modules/gridmap/grid_map.h b/modules/gridmap/grid_map.h
index b09cabfe25..88e16bce82 100644
--- a/modules/gridmap/grid_map.h
+++ b/modules/gridmap/grid_map.h
@@ -56,9 +56,15 @@ class GridMap : public Node3D {
};
uint64_t key = 0;
+ static uint32_t hash(const IndexKey &p_key) {
+ return hash_one_uint64(p_key.key);
+ }
_FORCE_INLINE_ bool operator<(const IndexKey &p_key) const {
return key < p_key.key;
}
+ _FORCE_INLINE_ bool operator==(const IndexKey &p_key) const {
+ return key == p_key.key;
+ }
_FORCE_INLINE_ operator Vector3i() const {
return Vector3i(x, y, z);
@@ -107,13 +113,13 @@ class GridMap : public Node3D {
};
Vector<MultimeshInstance> multimesh_instances;
- Set<IndexKey> cells;
+ RBSet<IndexKey> cells;
RID collision_debug;
RID collision_debug_instance;
bool dirty = false;
RID static_body;
- Map<IndexKey, NavMesh> navmesh_ids;
+ HashMap<IndexKey, NavMesh> navmesh_ids;
};
union OctantKey {
@@ -126,8 +132,11 @@ class GridMap : public Node3D {
uint64_t key = 0;
- _FORCE_INLINE_ bool operator<(const OctantKey &p_key) const {
- return key < p_key.key;
+ static uint32_t hash(const OctantKey &p_key) {
+ return hash_one_uint64(p_key.key);
+ }
+ _FORCE_INLINE_ bool operator==(const OctantKey &p_key) const {
+ return key == p_key.key;
}
//OctantKey(const IndexKey& p_k, int p_item) { indexkey=p_k.key; item=p_item; }
@@ -154,8 +163,8 @@ class GridMap : public Node3D {
Ref<MeshLibrary> mesh_library;
- Map<OctantKey, Octant *> octant_map;
- Map<IndexKey, Cell> cell_map;
+ HashMap<OctantKey, Octant *, OctantKey> octant_map;
+ HashMap<IndexKey, Cell, IndexKey> cell_map;
void _recreate_octant_data();
@@ -181,7 +190,7 @@ class GridMap : public Node3D {
void _queue_octants_dirty();
void _update_octants_callback();
- void resource_changed(const RES &p_res);
+ void resource_changed(const Ref<Resource> &p_res);
void _clear_internal();
diff --git a/modules/gridmap/register_types.cpp b/modules/gridmap/register_types.cpp
index d7c9f5c92e..9efd18a265 100644
--- a/modules/gridmap/register_types.cpp
+++ b/modules/gridmap/register_types.cpp
@@ -39,14 +39,21 @@
#include "editor/grid_map_editor_plugin.h"
#endif
-void register_gridmap_types() {
- GDREGISTER_CLASS(GridMap);
+void initialize_gridmap_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_CLASS(GridMap);
+ }
#ifdef TOOLS_ENABLED
- EditorPlugins::add_by_type<GridMapEditorPlugin>();
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<GridMapEditorPlugin>();
+ }
#endif
}
-void unregister_gridmap_types() {
+void uninitialize_gridmap_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
#endif // _3D_DISABLED
diff --git a/modules/gridmap/register_types.h b/modules/gridmap/register_types.h
index fa3511c5d1..28f14cd398 100644
--- a/modules/gridmap/register_types.h
+++ b/modules/gridmap/register_types.h
@@ -31,7 +31,9 @@
#ifndef GRIDMAP_REGISTER_TYPES_H
#define GRIDMAP_REGISTER_TYPES_H
-void register_gridmap_types();
-void unregister_gridmap_types();
+#include "modules/register_module_types.h"
+
+void initialize_gridmap_module(ModuleInitializationLevel p_level);
+void uninitialize_gridmap_module(ModuleInitializationLevel p_level);
#endif // GRIDMAP_REGISTER_TYPES_H
diff --git a/modules/hdr/image_loader_hdr.cpp b/modules/hdr/image_loader_hdr.cpp
index 996bbfadd1..eca689e87a 100644
--- a/modules/hdr/image_loader_hdr.cpp
+++ b/modules/hdr/image_loader_hdr.cpp
@@ -33,7 +33,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderHDR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
String header = f->get_token();
ERR_FAIL_COND_V_MSG(header != "#?RADIANCE" && header != "#?RGBE", ERR_FILE_UNRECOGNIZED, "Unsupported header information in HDR: " + header + ".");
@@ -132,7 +132,7 @@ Error ImageLoaderHDR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
ptr[2] * exp / 255.0);
if (p_force_linear) {
- c = c.to_linear();
+ c = c.srgb_to_linear();
}
*(uint32_t *)ptr = c.to_rgbe9995();
diff --git a/modules/hdr/image_loader_hdr.h b/modules/hdr/image_loader_hdr.h
index 0213fdbcb2..f2d53cc206 100644
--- a/modules/hdr/image_loader_hdr.h
+++ b/modules/hdr/image_loader_hdr.h
@@ -35,7 +35,7 @@
class ImageLoaderHDR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderHDR();
};
diff --git a/modules/hdr/register_types.cpp b/modules/hdr/register_types.cpp
index 6bfeecc927..b988bf4587 100644
--- a/modules/hdr/register_types.cpp
+++ b/modules/hdr/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderHDR *image_loader_hdr = nullptr;
-void register_hdr_types() {
+void initialize_hdr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_hdr = memnew(ImageLoaderHDR);
ImageLoader::add_image_format_loader(image_loader_hdr);
}
-void unregister_hdr_types() {
+void uninitialize_hdr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_hdr);
}
diff --git a/modules/hdr/register_types.h b/modules/hdr/register_types.h
index 4224aa2ce2..0254e43b6c 100644
--- a/modules/hdr/register_types.h
+++ b/modules/hdr/register_types.h
@@ -31,7 +31,9 @@
#ifndef HDR_REGISTER_TYPES_H
#define HDR_REGISTER_TYPES_H
-void register_hdr_types();
-void unregister_hdr_types();
+#include "modules/register_module_types.h"
+
+void initialize_hdr_module(ModuleInitializationLevel p_level);
+void uninitialize_hdr_module(ModuleInitializationLevel p_level);
#endif // HDR_REGISTER_TYPES_H
diff --git a/modules/jpg/image_loader_jpegd.cpp b/modules/jpg/image_loader_jpegd.cpp
index e8c66ab9da..51358876a4 100644
--- a/modules/jpg/image_loader_jpegd.cpp
+++ b/modules/jpg/image_loader_jpegd.cpp
@@ -103,7 +103,7 @@ Error jpeg_load_image_from_buffer(Image *p_image, const uint8_t *p_buffer, int p
return OK;
}
-Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderJPG::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -113,8 +113,6 @@ Error ImageLoaderJPG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
f->get_buffer(&w[0], src_image_len);
- f->close();
-
Error err = jpeg_load_image_from_buffer(p_image.ptr(), w, src_image_len);
return err;
diff --git a/modules/jpg/image_loader_jpegd.h b/modules/jpg/image_loader_jpegd.h
index 8e64f6fba7..de9700faec 100644
--- a/modules/jpg/image_loader_jpegd.h
+++ b/modules/jpg/image_loader_jpegd.h
@@ -35,7 +35,7 @@
class ImageLoaderJPG : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderJPG();
};
diff --git a/modules/jpg/register_types.cpp b/modules/jpg/register_types.cpp
index 63203274f4..b8b48a550f 100644
--- a/modules/jpg/register_types.cpp
+++ b/modules/jpg/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderJPG *image_loader_jpg = nullptr;
-void register_jpg_types() {
+void initialize_jpg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_jpg = memnew(ImageLoaderJPG);
ImageLoader::add_image_format_loader(image_loader_jpg);
}
-void unregister_jpg_types() {
+void uninitialize_jpg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_jpg);
}
diff --git a/modules/jpg/register_types.h b/modules/jpg/register_types.h
index 97223cefda..f0a205f6a8 100644
--- a/modules/jpg/register_types.h
+++ b/modules/jpg/register_types.h
@@ -31,7 +31,9 @@
#ifndef JPG_REGISTER_TYPES_H
#define JPG_REGISTER_TYPES_H
-void register_jpg_types();
-void unregister_jpg_types();
+#include "modules/register_module_types.h"
+
+void initialize_jpg_module(ModuleInitializationLevel p_level);
+void uninitialize_jpg_module(ModuleInitializationLevel p_level);
#endif // JPG_REGISTER_TYPES_H
diff --git a/modules/jsonrpc/jsonrpc.h b/modules/jsonrpc/jsonrpc.h
index 3144746f6d..f57d6aef42 100644
--- a/modules/jsonrpc/jsonrpc.h
+++ b/modules/jsonrpc/jsonrpc.h
@@ -37,7 +37,7 @@
class JSONRPC : public Object {
GDCLASS(JSONRPC, Object)
- Map<String, Object *> method_scopes;
+ HashMap<String, Object *> method_scopes;
protected:
static void _bind_methods();
diff --git a/modules/jsonrpc/register_types.cpp b/modules/jsonrpc/register_types.cpp
index d89b7e9353..6d35d6aeb8 100644
--- a/modules/jsonrpc/register_types.cpp
+++ b/modules/jsonrpc/register_types.cpp
@@ -32,9 +32,16 @@
#include "core/object/class_db.h"
#include "jsonrpc.h"
-void register_jsonrpc_types() {
+void initialize_jsonrpc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(JSONRPC);
}
-void unregister_jsonrpc_types() {
+void uninitialize_jsonrpc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/jsonrpc/register_types.h b/modules/jsonrpc/register_types.h
index 57744e6c07..83d315a9eb 100644
--- a/modules/jsonrpc/register_types.h
+++ b/modules/jsonrpc/register_types.h
@@ -31,7 +31,9 @@
#ifndef JSONRPC_REGISTER_TYPES_H
#define JSONRPC_REGISTER_TYPES_H
-void register_jsonrpc_types();
-void unregister_jsonrpc_types();
+#include "modules/register_module_types.h"
+
+void initialize_jsonrpc_module(ModuleInitializationLevel p_level);
+void uninitialize_jsonrpc_module(ModuleInitializationLevel p_level);
#endif // JSONRPC_REGISTER_TYPES_H
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index faa1d21490..214c60091c 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -1028,17 +1028,17 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
push_constant.atlas_slice = 0;
push_constant.region_ofs[0] = 0;
push_constant.region_ofs[1] = 0;
- push_constant.environment_xform[0] = p_environment_transform.elements[0][0];
- push_constant.environment_xform[1] = p_environment_transform.elements[1][0];
- push_constant.environment_xform[2] = p_environment_transform.elements[2][0];
+ push_constant.environment_xform[0] = p_environment_transform.rows[0][0];
+ push_constant.environment_xform[1] = p_environment_transform.rows[1][0];
+ push_constant.environment_xform[2] = p_environment_transform.rows[2][0];
push_constant.environment_xform[3] = 0;
- push_constant.environment_xform[4] = p_environment_transform.elements[0][1];
- push_constant.environment_xform[5] = p_environment_transform.elements[1][1];
- push_constant.environment_xform[6] = p_environment_transform.elements[2][1];
+ push_constant.environment_xform[4] = p_environment_transform.rows[0][1];
+ push_constant.environment_xform[5] = p_environment_transform.rows[1][1];
+ push_constant.environment_xform[6] = p_environment_transform.rows[2][1];
push_constant.environment_xform[7] = 0;
- push_constant.environment_xform[8] = p_environment_transform.elements[0][2];
- push_constant.environment_xform[9] = p_environment_transform.elements[1][2];
- push_constant.environment_xform[10] = p_environment_transform.elements[2][2];
+ push_constant.environment_xform[8] = p_environment_transform.rows[0][2];
+ push_constant.environment_xform[9] = p_environment_transform.rows[1][2];
+ push_constant.environment_xform[10] = p_environment_transform.rows[2][2];
push_constant.environment_xform[11] = 0;
}
diff --git a/modules/lightmapper_rd/register_types.cpp b/modules/lightmapper_rd/register_types.cpp
index 0a96a86076..0e0330c1a1 100644
--- a/modules/lightmapper_rd/register_types.cpp
+++ b/modules/lightmapper_rd/register_types.cpp
@@ -40,7 +40,11 @@ static Lightmapper *create_lightmapper_rd() {
}
#endif
-void register_lightmapper_rd_types() {
+void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GLOBAL_DEF("rendering/lightmapping/bake_quality/low_quality_ray_count", 16);
GLOBAL_DEF("rendering/lightmapping/bake_quality/medium_quality_ray_count", 64);
GLOBAL_DEF("rendering/lightmapping/bake_quality/high_quality_ray_count", 256);
@@ -59,5 +63,8 @@ void register_lightmapper_rd_types() {
#endif
}
-void unregister_lightmapper_rd_types() {
+void uninitialize_lightmapper_rd_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/lightmapper_rd/register_types.h b/modules/lightmapper_rd/register_types.h
index 35a701ce01..42e0ebbf77 100644
--- a/modules/lightmapper_rd/register_types.h
+++ b/modules/lightmapper_rd/register_types.h
@@ -31,7 +31,9 @@
#ifndef LIGHTMAPPER_RD_REGISTER_TYPES_H
#define LIGHTMAPPER_RD_REGISTER_TYPES_H
-void register_lightmapper_rd_types();
-void unregister_lightmapper_rd_types();
+#include "modules/register_module_types.h"
+
+void initialize_lightmapper_rd_module(ModuleInitializationLevel p_level);
+void uninitialize_lightmapper_rd_module(ModuleInitializationLevel p_level);
#endif // XATLAS_UNWRAP_REGISTER_TYPES_H
diff --git a/modules/mbedtls/crypto_mbedtls.cpp b/modules/mbedtls/crypto_mbedtls.cpp
index ea6b6d8233..e62581ab40 100644
--- a/modules/mbedtls/crypto_mbedtls.cpp
+++ b/modules/mbedtls/crypto_mbedtls.cpp
@@ -55,14 +55,13 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) {
ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Key is in use");
PackedByteArray out;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open CryptoKeyMbedTLS file '" + p_path + "'.");
uint64_t flen = f->get_length();
out.resize(flen + 1);
f->get_buffer(out.ptrw(), flen);
out.write[flen] = 0; // string terminator
- memdelete(f);
int ret = 0;
if (p_public_only) {
@@ -79,8 +78,8 @@ Error CryptoKeyMbedTLS::load(String p_path, bool p_public_only) {
}
Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save CryptoKeyMbedTLS file '" + p_path + "'.");
unsigned char w[16000];
memset(w, 0, sizeof(w));
@@ -92,14 +91,12 @@ Error CryptoKeyMbedTLS::save(String p_path, bool p_public_only) {
ret = mbedtls_pk_write_key_pem(&pkey, w, sizeof(w));
}
if (ret != 0) {
- memdelete(f);
mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize anything we might have written.
ERR_FAIL_V_MSG(FAILED, "Error writing key '" + itos(ret) + "'.");
}
size_t len = strlen((char *)w);
f->store_buffer(w, len);
- memdelete(f);
mbedtls_platform_zeroize(w, sizeof(w)); // Zeroize temporary buffer.
return OK;
}
@@ -143,14 +140,13 @@ Error X509CertificateMbedTLS::load(String p_path) {
ERR_FAIL_COND_V_MSG(locks, ERR_ALREADY_IN_USE, "Certificate is in use");
PackedByteArray out;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot open X509CertificateMbedTLS file '" + p_path + "'.");
uint64_t flen = f->get_length();
out.resize(flen + 1);
f->get_buffer(out.ptrw(), flen);
out.write[flen] = 0; // string terminator
- memdelete(f);
int ret = mbedtls_x509_crt_parse(&cert, out.ptr(), out.size());
ERR_FAIL_COND_V_MSG(ret, FAILED, "Error parsing some certificates: " + itos(ret));
@@ -167,8 +163,8 @@ Error X509CertificateMbedTLS::load_from_memory(const uint8_t *p_buffer, int p_le
}
Error X509CertificateMbedTLS::save(String p_path) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V_MSG(!f, ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_INVALID_PARAMETER, "Cannot save X509CertificateMbedTLS file '" + p_path + "'.");
mbedtls_x509_crt *crt = &cert;
while (crt) {
@@ -176,14 +172,12 @@ Error X509CertificateMbedTLS::save(String p_path) {
size_t wrote = 0;
int ret = mbedtls_pem_write_buffer(PEM_BEGIN_CRT, PEM_END_CRT, cert.raw.p, cert.raw.len, w, sizeof(w), &wrote);
if (ret != 0 || wrote == 0) {
- memdelete(f);
ERR_FAIL_V_MSG(FAILED, "Error writing certificate '" + itos(ret) + "'.");
}
f->store_buffer(w, wrote - 1); // don't write the string terminator
crt = crt->next;
}
- memdelete(f);
return OK;
}
diff --git a/modules/mbedtls/packet_peer_mbed_dtls.cpp b/modules/mbedtls/packet_peer_mbed_dtls.cpp
index 2a5eaa0109..1296a4587c 100644
--- a/modules/mbedtls/packet_peer_mbed_dtls.cpp
+++ b/modules/mbedtls/packet_peer_mbed_dtls.cpp
@@ -35,11 +35,11 @@
#include "core/io/stream_peer_ssl.h"
int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
- if (buf == nullptr || len <= 0) {
+ if (buf == nullptr || len == 0) {
return 0;
}
- PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx;
+ PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);
ERR_FAIL_COND_V(sp == nullptr, 0);
@@ -53,11 +53,11 @@ int PacketPeerMbedDTLS::bio_send(void *ctx, const unsigned char *buf, size_t len
}
int PacketPeerMbedDTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
- if (buf == nullptr || len <= 0) {
+ if (buf == nullptr || len == 0) {
return 0;
}
- PacketPeerMbedDTLS *sp = (PacketPeerMbedDTLS *)ctx;
+ PacketPeerMbedDTLS *sp = static_cast<PacketPeerMbedDTLS *>(ctx);
ERR_FAIL_COND_V(sp == nullptr, 0);
@@ -115,7 +115,7 @@ Error PacketPeerMbedDTLS::_do_handshake() {
}
Error PacketPeerMbedDTLS::connect_to_peer(Ref<PacketPeerUDP> p_base, bool p_validate_certs, const String &p_for_hostname, Ref<X509Certificate> p_ca_certs) {
- ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_connected_to_host(), ERR_INVALID_PARAMETER);
+ ERR_FAIL_COND_V(!p_base.is_valid() || !p_base->is_socket_connected(), ERR_INVALID_PARAMETER);
base = p_base;
int ret = 0;
diff --git a/modules/mbedtls/register_types.cpp b/modules/mbedtls/register_types.cpp
index 1af978e70a..2d4a18b3fc 100644
--- a/modules/mbedtls/register_types.cpp
+++ b/modules/mbedtls/register_types.cpp
@@ -39,14 +39,22 @@
#include "tests/test_crypto_mbedtls.h"
#endif
-void register_mbedtls_types() {
+void initialize_mbedtls_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
CryptoMbedTLS::initialize_crypto();
StreamPeerMbedTLS::initialize_ssl();
PacketPeerMbedDTLS::initialize_dtls();
DTLSServerMbedTLS::initialize();
}
-void unregister_mbedtls_types() {
+void uninitialize_mbedtls_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
DTLSServerMbedTLS::finalize();
PacketPeerMbedDTLS::finalize_dtls();
StreamPeerMbedTLS::finalize_ssl();
diff --git a/modules/mbedtls/register_types.h b/modules/mbedtls/register_types.h
index 4bc2cca118..ebe76f44f1 100644
--- a/modules/mbedtls/register_types.h
+++ b/modules/mbedtls/register_types.h
@@ -31,7 +31,9 @@
#ifndef MBEDTLS_REGISTER_TYPES_H
#define MBEDTLS_REGISTER_TYPES_H
-void register_mbedtls_types();
-void unregister_mbedtls_types();
+#include "modules/register_module_types.h"
+
+void initialize_mbedtls_module(ModuleInitializationLevel p_level);
+void uninitialize_mbedtls_module(ModuleInitializationLevel p_level);
#endif // MBEDTLS_REGISTER_TYPES_H
diff --git a/modules/mbedtls/stream_peer_mbedtls.cpp b/modules/mbedtls/stream_peer_mbedtls.cpp
index 05a57607cd..1818048877 100644
--- a/modules/mbedtls/stream_peer_mbedtls.cpp
+++ b/modules/mbedtls/stream_peer_mbedtls.cpp
@@ -34,11 +34,11 @@
#include "core/io/stream_peer_tcp.h"
int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len) {
- if (buf == nullptr || len <= 0) {
+ if (buf == nullptr || len == 0) {
return 0;
}
- StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx;
+ StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx);
ERR_FAIL_COND_V(sp == nullptr, 0);
@@ -54,11 +54,11 @@ int StreamPeerMbedTLS::bio_send(void *ctx, const unsigned char *buf, size_t len)
}
int StreamPeerMbedTLS::bio_recv(void *ctx, unsigned char *buf, size_t len) {
- if (buf == nullptr || len <= 0) {
+ if (buf == nullptr || len == 0) {
return 0;
}
- StreamPeerMbedTLS *sp = (StreamPeerMbedTLS *)ctx;
+ StreamPeerMbedTLS *sp = static_cast<StreamPeerMbedTLS *>(ctx);
ERR_FAIL_COND_V(sp == nullptr, 0);
diff --git a/modules/meshoptimizer/register_types.cpp b/modules/meshoptimizer/register_types.cpp
index 597c12ed23..3e212360c0 100644
--- a/modules/meshoptimizer/register_types.cpp
+++ b/modules/meshoptimizer/register_types.cpp
@@ -32,7 +32,11 @@
#include "scene/resources/surface_tool.h"
#include "thirdparty/meshoptimizer/meshoptimizer.h"
-void register_meshoptimizer_types() {
+void initialize_meshoptimizer_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
SurfaceTool::optimize_vertex_cache_func = meshopt_optimizeVertexCache;
SurfaceTool::simplify_func = meshopt_simplify;
SurfaceTool::simplify_with_attrib_func = meshopt_simplifyWithAttributes;
@@ -43,7 +47,11 @@ void register_meshoptimizer_types() {
SurfaceTool::remap_index_func = meshopt_remapIndexBuffer;
}
-void unregister_meshoptimizer_types() {
+void uninitialize_meshoptimizer_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
SurfaceTool::optimize_vertex_cache_func = nullptr;
SurfaceTool::simplify_func = nullptr;
SurfaceTool::simplify_scale_func = nullptr;
diff --git a/modules/meshoptimizer/register_types.h b/modules/meshoptimizer/register_types.h
index fdd8bed657..99c71efceb 100644
--- a/modules/meshoptimizer/register_types.h
+++ b/modules/meshoptimizer/register_types.h
@@ -31,7 +31,9 @@
#ifndef MESHOPTIMIZER_REGISTER_TYPES_H
#define MESHOPTIMIZER_REGISTER_TYPES_H
-void register_meshoptimizer_types();
-void unregister_meshoptimizer_types();
+#include "modules/register_module_types.h"
+
+void initialize_meshoptimizer_module(ModuleInitializationLevel p_level);
+void uninitialize_meshoptimizer_module(ModuleInitializationLevel p_level);
#endif // PVR_REGISTER_TYPES_H
diff --git a/modules/minimp3/register_types.cpp b/modules/minimp3/register_types.cpp
index 4d32ebf8ea..9d1b56abdf 100644
--- a/modules/minimp3/register_types.cpp
+++ b/modules/minimp3/register_types.cpp
@@ -37,7 +37,11 @@
#include "resource_importer_mp3.h"
#endif
-void register_minimp3_types() {
+void initialize_minimp3_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
Ref<ResourceImporterMP3> mp3_import;
@@ -48,5 +52,8 @@ void register_minimp3_types() {
GDREGISTER_CLASS(AudioStreamMP3);
}
-void unregister_minimp3_types() {
+void uninitialize_minimp3_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/minimp3/register_types.h b/modules/minimp3/register_types.h
index fa7f67eefc..9e5eb85abe 100644
--- a/modules/minimp3/register_types.h
+++ b/modules/minimp3/register_types.h
@@ -31,7 +31,9 @@
#ifndef MINIMP3_REGISTER_TYPES_H
#define MINIMP3_REGISTER_TYPES_H
-void register_minimp3_types();
-void unregister_minimp3_types();
+#include "modules/register_module_types.h"
+
+void initialize_minimp3_module(ModuleInitializationLevel p_level);
+void uninitialize_minimp3_module(ModuleInitializationLevel p_level);
#endif // MINIMP3_REGISTER_TYPES_H
diff --git a/modules/minimp3/resource_importer_mp3.cpp b/modules/minimp3/resource_importer_mp3.cpp
index 0e0da806bf..e03940f963 100644
--- a/modules/minimp3/resource_importer_mp3.cpp
+++ b/modules/minimp3/resource_importer_mp3.cpp
@@ -54,7 +54,7 @@ String ResourceImporterMP3::get_resource_type() const {
return "AudioStreamMP3";
}
-bool ResourceImporterMP3::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const {
+bool ResourceImporterMP3::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
return true;
}
@@ -71,13 +71,12 @@ void ResourceImporterMP3::get_import_options(const String &p_path, List<ImportOp
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0));
}
-Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
+Error ResourceImporterMP3::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
bool loop = p_options["loop"];
float loop_offset = p_options["loop_offset"];
- FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
-
- ERR_FAIL_COND_V(!f, ERR_CANT_OPEN);
+ Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ);
+ ERR_FAIL_COND_V(f.is_null(), ERR_CANT_OPEN);
uint64_t len = f->get_length();
@@ -87,8 +86,6 @@ Error ResourceImporterMP3::import(const String &p_source_file, const String &p_s
f->get_buffer(w, len);
- memdelete(f);
-
Ref<AudioStreamMP3> mp3_stream;
mp3_stream.instantiate();
diff --git a/modules/minimp3/resource_importer_mp3.h b/modules/minimp3/resource_importer_mp3.h
index 75890228b9..678a3773bb 100644
--- a/modules/minimp3/resource_importer_mp3.h
+++ b/modules/minimp3/resource_importer_mp3.h
@@ -48,9 +48,9 @@ public:
virtual String get_preset_name(int p_idx) const override;
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
- virtual bool get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const override;
+ virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
ResourceImporterMP3();
};
diff --git a/modules/mobile_vr/mobile_vr_interface.cpp b/modules/mobile_vr/mobile_vr_interface.cpp
index 8cd23ffb24..5876b6cbf3 100644
--- a/modules/mobile_vr/mobile_vr_interface.cpp
+++ b/modules/mobile_vr/mobile_vr_interface.cpp
@@ -112,9 +112,9 @@ Basis MobileVRInterface::combine_acc_mag(const Vector3 &p_grav, const Vector3 &p
// We use our gravity and magnetometer vectors to construct our matrix
Basis acc_mag_m3;
- acc_mag_m3.elements[0] = -magneto_east;
- acc_mag_m3.elements[1] = up;
- acc_mag_m3.elements[2] = magneto;
+ acc_mag_m3.rows[0] = -magneto_east;
+ acc_mag_m3.rows[1] = up;
+ acc_mag_m3.rows[2] = magneto;
return acc_mag_m3;
};
@@ -175,9 +175,9 @@ void MobileVRInterface::set_position_from_sensors() {
if (has_gyro) {
// start with applying our gyro (do NOT smooth our gyro!)
Basis rotate;
- rotate.rotate(orientation.get_axis(0), gyro.x * delta_time);
- rotate.rotate(orientation.get_axis(1), gyro.y * delta_time);
- rotate.rotate(orientation.get_axis(2), gyro.z * delta_time);
+ rotate.rotate(orientation.get_column(0), gyro.x * delta_time);
+ rotate.rotate(orientation.get_column(1), gyro.y * delta_time);
+ rotate.rotate(orientation.get_column(2), gyro.z * delta_time);
orientation = rotate * orientation;
tracking_state = XRInterface::XR_NORMAL_TRACKING;
diff --git a/modules/mobile_vr/register_types.cpp b/modules/mobile_vr/register_types.cpp
index 682d8bf59a..4df8af9009 100644
--- a/modules/mobile_vr/register_types.cpp
+++ b/modules/mobile_vr/register_types.cpp
@@ -34,7 +34,11 @@
Ref<MobileVRInterface> mobile_vr;
-void register_mobile_vr_types() {
+void initialize_mobile_vr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(MobileVRInterface);
if (XRServer::get_singleton()) {
@@ -43,7 +47,11 @@ void register_mobile_vr_types() {
}
}
-void unregister_mobile_vr_types() {
+void uninitialize_mobile_vr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (mobile_vr.is_valid()) {
// uninitialise our interface if it is initialised
if (mobile_vr->is_initialized()) {
diff --git a/modules/mobile_vr/register_types.h b/modules/mobile_vr/register_types.h
index 8db96ac2fa..26812af512 100644
--- a/modules/mobile_vr/register_types.h
+++ b/modules/mobile_vr/register_types.h
@@ -31,7 +31,9 @@
#ifndef MOBILE_VR_REGISTER_TYPES_H
#define MOBILE_VR_REGISTER_TYPES_H
-void register_mobile_vr_types();
-void unregister_mobile_vr_types();
+#include "modules/register_module_types.h"
+
+void initialize_mobile_vr_module(ModuleInitializationLevel p_level);
+void uninitialize_mobile_vr_module(ModuleInitializationLevel p_level);
#endif // MOBILE_VR_REGISTER_TYPES_H
diff --git a/modules/mono/class_db_api_json.cpp b/modules/mono/class_db_api_json.cpp
index 5884a24454..3afde1e8d3 100644
--- a/modules/mono/class_db_api_json.cpp
+++ b/modules/mono/class_db_api_json.cpp
@@ -40,17 +40,12 @@
void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
Dictionary classes_dict;
- List<StringName> names;
+ List<StringName> class_list;
+ ClassDB::get_class_list(&class_list);
+ // Must be alphabetically sorted for hash to compute.
+ class_list.sort_custom<StringName::AlphCompare>();
- const StringName *k = nullptr;
-
- while ((k = ClassDB::classes.next(k))) {
- names.push_back(*k);
- }
- //must be alphabetically sorted for hash to compute
- names.sort_custom<StringName::AlphCompare>();
-
- for (const StringName &E : names) {
+ for (const StringName &E : class_list) {
ClassDB::ClassInfo *t = ClassDB::classes.getptr(E);
ERR_FAIL_COND(!t);
if (t->api != p_api || !t->exposed) {
@@ -66,10 +61,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = nullptr;
-
- while ((k = t->method_map.next(k))) {
- String name = k->operator String();
+ for (const KeyValue<StringName, MethodBind *> &F : t->method_map) {
+ String name = F.key.operator String();
ERR_CONTINUE(name.is_empty());
@@ -77,7 +70,7 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
continue; // Ignore non-virtual methods that start with an underscore
}
- snames.push_back(*k);
+ snames.push_back(F.key);
}
snames.sort_custom<StringName::AlphCompare>();
@@ -131,10 +124,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = nullptr;
-
- while ((k = t->constant_map.next(k))) {
- snames.push_back(*k);
+ for (const KeyValue<StringName, int> &F : t->constant_map) {
+ snames.push_back(F.key);
}
snames.sort_custom<StringName::AlphCompare>();
@@ -158,10 +149,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = nullptr;
-
- while ((k = t->signal_map.next(k))) {
- snames.push_back(*k);
+ for (const KeyValue<StringName, MethodInfo> &F : t->signal_map) {
+ snames.push_back(F.key);
}
snames.sort_custom<StringName::AlphCompare>();
@@ -193,10 +182,8 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
List<StringName> snames;
- k = nullptr;
-
- while ((k = t->property_setget.next(k))) {
- snames.push_back(*k);
+ for (const KeyValue<StringName, ClassDB::PropertySetGet> &F : t->property_setget) {
+ snames.push_back(F.key);
}
snames.sort_custom<StringName::AlphCompare>();
@@ -238,11 +225,10 @@ void class_db_api_to_json(const String &p_output_file, ClassDB::APIType p_api) {
}
}
- FileAccessRef f = FileAccess::open(p_output_file, FileAccess::WRITE);
- ERR_FAIL_COND_MSG(!f, "Cannot open file '" + p_output_file + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_output_file, FileAccess::WRITE);
+ ERR_FAIL_COND_MSG(f.is_null(), "Cannot open file '" + p_output_file + "'.");
JSON json;
f->store_string(json.stringify(classes_dict, "\t"));
- f->close();
print_line(String() + "ClassDB API JSON written to: " + ProjectSettings::get_singleton()->globalize_path(p_output_file));
}
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 8acd119880..d0140f117c 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -686,10 +686,10 @@ void CSharpLanguage::pre_unsafe_unreference(Object *p_obj) {
#ifdef DEBUG_ENABLED
MutexLock lock(unsafe_object_references_lock);
ObjectID id = p_obj->get_instance_id();
- Map<ObjectID, int>::Element *elem = unsafe_object_references.find(id);
+ HashMap<ObjectID, int>::Iterator elem = unsafe_object_references.find(id);
ERR_FAIL_NULL(elem);
- if (--elem->value() == 0) {
- unsafe_object_references.erase(elem);
+ if (--elem->value == 0) {
+ unsafe_object_references.remove(elem);
}
#endif
}
@@ -897,7 +897,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
#endif
// Save state and remove script from instances
- Map<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state;
+ RBMap<ObjectID, CSharpScript::StateBackup> &owners_map = script->pending_reload_state;
for (Object *&obj : script->instances) {
ERR_CONTINUE(!obj->get_script_instance());
@@ -924,7 +924,7 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
for (Ref<CSharpScript> &script : scripts) {
while (script->instances.front()) {
Object *obj = script->instances.front()->get();
- obj->set_script(REF()); // Remove script and existing script instances (placeholder are not removed before domain reload)
+ obj->set_script(Ref<RefCounted>()); // Remove script and existing script instances (placeholder are not removed before domain reload)
}
script->_clear();
@@ -1099,14 +1099,14 @@ void CSharpLanguage::reload_assemblies(bool p_soft_reload) {
const StringName &name = G.first;
const Array &serialized_data = G.second;
- Map<StringName, CSharpScript::EventSignal>::Element *match = script->event_signals.find(name);
+ HashMap<StringName, CSharpScript::EventSignal>::Iterator match = script->event_signals.find(name);
if (!match) {
// The event or its signal attribute were removed
continue;
}
- const CSharpScript::EventSignal &event_signal = match->value();
+ const CSharpScript::EventSignal &event_signal = match->value;
MonoObject *managed_serialized_data = GDMonoMarshal::variant_to_mono_object(serialized_data);
MonoDelegate *delegate = nullptr;
@@ -1428,7 +1428,7 @@ bool CSharpLanguage::setup_csharp_script_binding(CSharpScriptBinding &r_script_b
return true;
}
-Map<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
+RBMap<Object *, CSharpScriptBinding>::Element *CSharpLanguage::insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding) {
return script_bindings.insert(p_object, p_script_binding);
}
@@ -1437,7 +1437,7 @@ void *CSharpLanguage::_instance_binding_create_callback(void *, void *p_instance
MutexLock lock(csharp_lang->language_bind_mutex);
- Map<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance);
+ RBMap<Object *, CSharpScriptBinding>::Element *match = csharp_lang->script_bindings.find((Object *)p_instance);
if (match) {
return (void *)match;
}
@@ -1467,7 +1467,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
{
MutexLock lock(csharp_lang->language_bind_mutex);
- Map<Object *, CSharpScriptBinding>::Element *data = (Map<Object *, CSharpScriptBinding>::Element *)p_binding;
+ RBMap<Object *, CSharpScriptBinding>::Element *data = (RBMap<Object *, CSharpScriptBinding>::Element *)p_binding;
CSharpScriptBinding &script_binding = data->value();
@@ -1488,7 +1488,7 @@ void CSharpLanguage::_instance_binding_free_callback(void *, void *, void *p_bin
GDNativeBool CSharpLanguage::_instance_binding_reference_callback(void *p_token, void *p_binding, GDNativeBool p_reference) {
CRASH_COND(!p_binding);
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)p_binding)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)p_binding)->get();
RefCounted *rc_owner = Object::cast_to<RefCounted>(script_binding.owner);
@@ -1558,7 +1558,7 @@ void *CSharpLanguage::get_instance_binding(Object *p_object) {
// `setup_csharp_script_binding` may call `reference()`. It was moved here outside to fix that.
if (binding) {
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)binding)->value();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)binding)->value();
if (!script_binding.inited) {
MutexLock lock(CSharpLanguage::get_singleton()->get_language_bind_mutex());
@@ -1798,8 +1798,8 @@ void CSharpInstance::get_event_signals_state_for_reloading(List<Pair<StringName,
void CSharpInstance::get_property_list(List<PropertyInfo> *p_properties) const {
List<PropertyInfo> props;
- for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = script->member_info.front(); E; E = E.next()) {
- props.push_front(E.value());
+ for (const KeyValue<StringName, PropertyInfo> &E : script->member_info) {
+ props.push_front(E.value);
}
// Call _get_property_list
@@ -2301,7 +2301,7 @@ CSharpInstance::~CSharpInstance() {
void *data = CSharpLanguage::get_instance_binding(owner);
CRASH_COND(data == nullptr);
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
CRASH_COND(!script_binding.inited);
#ifdef DEBUG_ENABLED
@@ -2315,7 +2315,7 @@ CSharpInstance::~CSharpInstance() {
#ifdef DEBUG_ENABLED
// CSharpInstance must not be created unless it's going to be added to the list for sure
- Set<Object *>::Element *match = script->instances.find(owner);
+ RBSet<Object *>::Element *match = script->instances.find(owner);
CRASH_COND(!match);
script->instances.erase(match);
#else
@@ -2331,7 +2331,7 @@ void CSharpScript::_placeholder_erased(PlaceHolderScriptInstance *p_placeholder)
#endif
#ifdef TOOLS_ENABLED
-void CSharpScript::_update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames) {
+void CSharpScript::_update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames) {
if (base_cache.is_valid()) {
base_cache->_update_exports_values(values, propnames);
}
@@ -2567,7 +2567,7 @@ bool CSharpScript::_update_exports(PlaceHolderScriptInstance *p_instance_to_upda
if ((changed || p_instance_to_update) && placeholders.size()) {
// Update placeholders if any
- Map<StringName, Variant> values;
+ HashMap<StringName, Variant> values;
List<PropertyInfo> propnames;
_update_exports_values(values, propnames);
@@ -3144,7 +3144,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
void *data = CSharpLanguage::get_existing_instance_binding(p_owner);
CRASH_COND(data == nullptr);
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited && !script_binding.gchandle.is_released()) {
MonoObject *mono_object = script_binding.gchandle.get_target();
if (mono_object) {
@@ -3221,10 +3221,10 @@ Variant CSharpScript::_new(const Variant **p_args, int p_argcount, Callable::Cal
Object *owner = ClassDB::instantiate(NATIVE_GDMONOCLASS_NAME(native));
- REF ref;
+ Ref<RefCounted> ref;
RefCounted *r = Object::cast_to<RefCounted>(owner);
if (r) {
- ref = REF(r);
+ ref = Ref<RefCounted>(r);
}
CSharpInstance *instance = _create_instance(p_args, p_argcount, owner, r != nullptr, r_error);
@@ -3401,9 +3401,9 @@ ScriptLanguage *CSharpScript::get_language() const {
bool CSharpScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
#ifdef TOOLS_ENABLED
- const Map<StringName, Variant>::Element *E = exported_members_defval_cache.find(p_property);
+ HashMap<StringName, Variant>::ConstIterator E = exported_members_defval_cache.find(p_property);
if (E) {
- r_value = E->get();
+ r_value = E->value;
return true;
}
@@ -3491,8 +3491,8 @@ Ref<Script> CSharpScript::get_base_script() const {
void CSharpScript::get_script_property_list(List<PropertyInfo> *r_list) const {
List<PropertyInfo> props;
- for (OrderedHashMap<StringName, PropertyInfo>::ConstElement E = member_info.front(); E; E = E.next()) {
- props.push_front(E.value());
+ for (const KeyValue<StringName, PropertyInfo> &E : member_info) {
+ props.push_front(E.value);
}
for (const PropertyInfo &prop : props) {
@@ -3574,7 +3574,7 @@ CSharpScript::~CSharpScript() {
#endif
}
-void CSharpScript::get_members(Set<StringName> *p_members) {
+void CSharpScript::get_members(RBSet<StringName> *p_members) {
#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED)
if (p_members) {
for (const StringName &member_name : exported_members_names) {
@@ -3586,7 +3586,7 @@ void CSharpScript::get_members(Set<StringName> *p_members) {
/*************** RESOURCE ***************/
-RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+Ref<Resource> ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
if (r_error) {
*r_error = ERR_FILE_CANT_OPEN;
}
@@ -3599,7 +3599,7 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p
#if defined(DEBUG_ENABLED) || defined(TOOLS_ENABLED)
Error err = script->load_source_code(p_path);
- ERR_FAIL_COND_V_MSG(err != OK, RES(), "Cannot load C# script file '" + p_path + "'.");
+ ERR_FAIL_COND_V_MSG(err != OK, Ref<Resource>(), "Cannot load C# script file '" + p_path + "'.");
#endif
script->set_path(p_original_path);
@@ -3625,7 +3625,7 @@ String ResourceFormatLoaderCSharpScript::get_resource_type(const String &p_path)
return p_path.get_extension().to_lower() == "cs" ? CSharpLanguage::get_singleton()->get_type() : "";
}
-Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_resource, uint32_t p_flags) {
+Error ResourceFormatSaverCSharpScript::save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags) {
Ref<CSharpScript> sqscr = p_resource;
ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER);
@@ -3641,20 +3641,18 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
}
#endif
- Error err;
- FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err);
- ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'.");
+ {
+ Error err;
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE, &err);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot save C# script file '" + p_path + "'.");
- file->store_string(source);
+ file->store_string(source);
- if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
- memdelete(file);
- return ERR_CANT_CREATE;
+ if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) {
+ return ERR_CANT_CREATE;
+ }
}
- file->close();
- memdelete(file);
-
#ifdef TOOLS_ENABLED
if (ScriptServer::is_reload_scripts_on_save_enabled()) {
CSharpLanguage::get_singleton()->reload_tool_script(p_resource, false);
@@ -3664,13 +3662,13 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
return OK;
}
-void ResourceFormatSaverCSharpScript::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const {
+void ResourceFormatSaverCSharpScript::get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const {
if (Object::cast_to<CSharpScript>(p_resource.ptr())) {
p_extensions->push_back("cs");
}
}
-bool ResourceFormatSaverCSharpScript::recognize(const RES &p_resource) const {
+bool ResourceFormatSaverCSharpScript::recognize(const Ref<Resource> &p_resource) const {
return Object::cast_to<CSharpScript>(p_resource.ptr()) != nullptr;
}
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 1e5f218c95..6e600bb47a 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -110,7 +110,7 @@ private:
Ref<CSharpScript> base_cache; // TODO what's this for?
- Set<Object *> instances;
+ RBSet<Object *> instances;
#ifdef GD_MONO_HOT_RELOAD
struct StateBackup {
@@ -121,8 +121,8 @@ private:
List<Pair<StringName, Array>> event_signals;
};
- Set<ObjectID> pending_reload_instances;
- Map<ObjectID, StateBackup> pending_reload_state;
+ RBSet<ObjectID> pending_reload_instances;
+ RBMap<ObjectID, StateBackup> pending_reload_state;
StringName tied_class_name_for_reload;
StringName tied_class_namespace_for_reload;
#endif
@@ -132,29 +132,29 @@ private:
SelfList<CSharpScript> script_list = this;
- Map<StringName, Vector<SignalParameter>> _signals;
- Map<StringName, EventSignal> event_signals;
+ HashMap<StringName, Vector<SignalParameter>> _signals;
+ HashMap<StringName, EventSignal> event_signals;
bool signals_invalidated = true;
Vector<Multiplayer::RPCConfig> rpc_functions;
#ifdef TOOLS_ENABLED
List<PropertyInfo> exported_members_cache; // members_cache
- Map<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
- Set<PlaceHolderScriptInstance *> placeholders;
+ HashMap<StringName, Variant> exported_members_defval_cache; // member_default_values_cache
+ RBSet<PlaceHolderScriptInstance *> placeholders;
bool source_changed_cache = false;
bool placeholder_fallback_enabled = false;
bool exports_invalidated = true;
- void _update_exports_values(Map<StringName, Variant> &values, List<PropertyInfo> &propnames);
+ void _update_exports_values(HashMap<StringName, Variant> &values, List<PropertyInfo> &propnames);
void _update_member_info_no_exports();
void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
#endif
#if defined(TOOLS_ENABLED) || defined(DEBUG_ENABLED)
- Set<StringName> exported_members_names;
+ RBSet<StringName> exported_members_names;
#endif
- OrderedHashMap<StringName, PropertyInfo> member_info;
+ HashMap<StringName, PropertyInfo> member_info;
void _clear();
@@ -218,7 +218,7 @@ public:
void get_script_property_list(List<PropertyInfo> *r_list) const override;
void update_exports() override;
- void get_members(Set<StringName> *p_members) override;
+ void get_members(RBSet<StringName> *p_members) override;
bool is_tool() const override { return tool; }
bool is_valid() const override { return valid; }
@@ -356,11 +356,11 @@ class CSharpLanguage : public ScriptLanguage {
Mutex script_gchandle_release_mutex;
Mutex language_bind_mutex;
- Map<Object *, CSharpScriptBinding> script_bindings;
+ RBMap<Object *, CSharpScriptBinding> script_bindings;
#ifdef DEBUG_ENABLED
// List of unsafe object references
- Map<ObjectID, int> unsafe_object_references;
+ HashMap<ObjectID, int> unsafe_object_references;
Mutex unsafe_object_references_lock;
#endif
@@ -467,7 +467,7 @@ public:
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
/* TODO */ bool validate(const String &p_script, const String &p_path, List<String> *r_functions,
- List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override {
+ List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, RBSet<int> *r_safe_lines = nullptr) const override {
return true;
}
String validate_path(const String &p_path) const override;
@@ -518,7 +518,7 @@ public:
void thread_enter() override;
void thread_exit() override;
- Map<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
+ RBMap<Object *, CSharpScriptBinding>::Element *insert_script_binding(Object *p_object, const CSharpScriptBinding &p_script_binding);
bool setup_csharp_script_binding(CSharpScriptBinding &r_script_binding, Object *p_object);
#ifdef DEBUG_ENABLED
@@ -534,7 +534,7 @@ public:
class ResourceFormatLoaderCSharpScript : public ResourceFormatLoader {
public:
- RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
+ Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE) override;
void get_recognized_extensions(List<String> *p_extensions) const override;
bool handles_type(const String &p_type) const override;
String get_resource_type(const String &p_path) const override;
@@ -542,9 +542,9 @@ public:
class ResourceFormatSaverCSharpScript : public ResourceFormatSaver {
public:
- Error save(const String &p_path, const RES &p_resource, uint32_t p_flags = 0) override;
- void get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const override;
- bool recognize(const RES &p_resource) const override;
+ Error save(const String &p_path, const Ref<Resource> &p_resource, uint32_t p_flags = 0) override;
+ void get_recognized_extensions(const Ref<Resource> &p_resource, List<String> *p_extensions) const override;
+ bool recognize(const Ref<Resource> &p_resource) const override;
};
#endif // CSHARP_SCRIPT_H
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
index bfc807c01a..ebdaca0ce8 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildOutputView.cs
@@ -334,8 +334,13 @@ namespace GodotTools.Build
}
}
- private void IssuesListRmbSelected(int index, Vector2 atPosition)
+ private void IssuesListClicked(int index, Vector2 atPosition, int mouseButtonIndex)
{
+ if (mouseButtonIndex != (int)MouseButton.Right)
+ {
+ return;
+ }
+
_ = index; // Unused
_issuesListContextMenu.Clear();
@@ -375,7 +380,7 @@ namespace GodotTools.Build
};
_issuesList.ItemActivated += IssueActivated;
_issuesList.AllowRmbSelect = true;
- _issuesList.ItemRmbSelected += IssuesListRmbSelected;
+ _issuesList.ItemClicked += IssuesListClicked;
hsc.AddChild(_issuesList);
_issuesListContextMenu = new PopupMenu();
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
index bac7a2e6db..02e9d98647 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/BuildSystem.cs
@@ -63,6 +63,7 @@ namespace GodotTools.Build
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
startInfo.UseShellExecute = false;
+ startInfo.CreateNoWindow = true;
if (UsingMonoMsBuildOnWindows)
{
diff --git a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
index 93a1360cb6..2db549c623 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Utils/OS.cs
@@ -184,7 +184,8 @@ namespace GodotTools.Utils
{
RedirectStandardOutput = true,
RedirectStandardError = true,
- UseShellExecute = false
+ UseShellExecute = false,
+ CreateNoWindow = true
};
using (Process process = Process.Start(startInfo))
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index d8f5b814e4..e602396ede 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -604,14 +604,14 @@ void BindingsGenerator::_append_xml_signal(StringBuilder &p_xml_output, const Ty
void BindingsGenerator::_append_xml_enum(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector<String> &p_link_target_parts) {
const StringName search_cname = !p_target_itype ? p_target_cname : StringName(p_target_itype->name + "." + (String)p_target_cname);
- const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(search_cname);
+ HashMap<StringName, TypeInterface>::ConstIterator enum_match = enum_types.find(search_cname);
if (!enum_match && search_cname != p_target_cname) {
enum_match = enum_types.find(p_target_cname);
}
if (enum_match) {
- const TypeInterface &target_enum_itype = enum_match->value();
+ const TypeInterface &target_enum_itype = enum_match->value;
p_xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
p_xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any
@@ -1035,8 +1035,8 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(p_proj_dir)) {
Error err = da->make_dir_recursive(p_proj_dir);
@@ -1078,8 +1078,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
compile_items.push_back(output_file);
}
- for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
- const TypeInterface &itype = E.get();
+ for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+ const TypeInterface &itype = E.value;
if (itype.api_type == ClassDB::API_EDITOR) {
continue;
@@ -1170,8 +1170,8 @@ Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
ERR_FAIL_COND_V(!initialized, ERR_UNCONFIGURED);
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(p_proj_dir)) {
Error err = da->make_dir_recursive(p_proj_dir);
@@ -1187,8 +1187,8 @@ Error BindingsGenerator::generate_cs_editor_project(const String &p_proj_dir) {
Vector<String> compile_items;
- for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
- const TypeInterface &itype = E.get();
+ for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+ const TypeInterface &itype = E.value;
if (itype.api_type != ClassDB::API_EDITOR) {
continue;
@@ -1280,8 +1280,8 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
String output_dir = path::abspath(path::realpath(p_output_dir));
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!da, ERR_CANT_CREATE);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(da.is_null(), ERR_CANT_CREATE);
if (!DirAccess::exists(output_dir)) {
Error err = da->make_dir_recursive(output_dir);
@@ -1573,9 +1573,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
// Search it in base types too
const TypeInterface *current_type = &p_itype;
while (!setter && current_type->base_name != StringName()) {
- OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name);
+ HashMap<StringName, TypeInterface>::Iterator base_match = obj_types.find(current_type->base_name);
ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'.");
- current_type = &base_match.get();
+ current_type = &base_match->value;
setter = current_type->find_method_by_name(p_iprop.setter);
}
@@ -1584,9 +1584,9 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
// Search it in base types too
current_type = &p_itype;
while (!getter && current_type->base_name != StringName()) {
- OrderedHashMap<StringName, TypeInterface>::Element base_match = obj_types.find(current_type->base_name);
+ HashMap<StringName, TypeInterface>::Iterator base_match = obj_types.find(current_type->base_name);
ERR_FAIL_COND_V_MSG(!base_match, ERR_BUG, "Type not found '" + current_type->base_name + "'. Inherited by '" + current_type->name + "'.");
- current_type = &base_match.get();
+ current_type = &base_match->value;
getter = current_type->find_method_by_name(p_iprop.getter);
}
@@ -1938,10 +1938,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
return OK; // Won't increment method bind count
}
- const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
+ HashMap<const MethodInterface *, const InternalCall *>::ConstIterator match = method_icalls_map.find(&p_imethod);
ERR_FAIL_NULL_V(match, ERR_BUG);
- const InternalCall *im_icall = match->value();
+ const InternalCall *im_icall = match->value;
String im_call = im_icall->editor_only ? BINDINGS_CLASS_NATIVECALLS_EDITOR : BINDINGS_CLASS_NATIVECALLS;
im_call += ".";
@@ -2096,8 +2096,8 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
generated_icall_funcs.clear();
- for (OrderedHashMap<StringName, TypeInterface>::Element type_elem = obj_types.front(); type_elem; type_elem = type_elem.next()) {
- const TypeInterface &itype = type_elem.get();
+ for (const KeyValue<StringName, TypeInterface> &type_elem : obj_types) {
+ const TypeInterface &itype = type_elem.value;
bool is_derived_type = itype.base_name != StringName();
@@ -2255,12 +2255,10 @@ uint32_t BindingsGenerator::get_version() {
}
Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p_content) {
- FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
-
- ERR_FAIL_COND_V_MSG(!file, ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
+ Ref<FileAccess> file = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V_MSG(file.is_null(), ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
file->store_string(p_content.as_string());
- file->close();
return OK;
}
@@ -2324,10 +2322,10 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
i++;
}
- const Map<const MethodInterface *, const InternalCall *>::Element *match = method_icalls_map.find(&p_imethod);
+ HashMap<const MethodInterface *, const InternalCall *>::ConstIterator match = method_icalls_map.find(&p_imethod);
ERR_FAIL_NULL_V(match, ERR_BUG);
- const InternalCall *im_icall = match->value();
+ const InternalCall *im_icall = match->value;
String icall_method = im_icall->name;
if (!generated_icall_funcs.find(im_icall)) {
@@ -2470,29 +2468,29 @@ Error BindingsGenerator::_generate_glue_method(const BindingsGenerator::TypeInte
}
const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_null(const TypeReference &p_typeref) {
- const Map<StringName, TypeInterface>::Element *builtin_type_match = builtin_types.find(p_typeref.cname);
+ HashMap<StringName, TypeInterface>::ConstIterator builtin_type_match = builtin_types.find(p_typeref.cname);
if (builtin_type_match) {
- return &builtin_type_match->get();
+ return &builtin_type_match->value;
}
- const OrderedHashMap<StringName, TypeInterface>::Element obj_type_match = obj_types.find(p_typeref.cname);
+ HashMap<StringName, TypeInterface>::ConstIterator obj_type_match = obj_types.find(p_typeref.cname);
if (obj_type_match) {
- return &obj_type_match.get();
+ return &obj_type_match->value;
}
if (p_typeref.is_enum) {
- const Map<StringName, TypeInterface>::Element *enum_match = enum_types.find(p_typeref.cname);
+ HashMap<StringName, TypeInterface>::ConstIterator enum_match = enum_types.find(p_typeref.cname);
if (enum_match) {
- return &enum_match->get();
+ return &enum_match->value;
}
// Enum not found. Most likely because none of its constants were bound, so it's empty. That's fine. Use int instead.
- const Map<StringName, TypeInterface>::Element *int_match = builtin_types.find(name_cache.type_int);
+ HashMap<StringName, TypeInterface>::ConstIterator int_match = builtin_types.find(name_cache.type_int);
ERR_FAIL_NULL_V(int_match, nullptr);
- return &int_match->get();
+ return &int_match->value;
}
return nullptr;
@@ -2507,16 +2505,16 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol
ERR_PRINT(String() + "Type not found. Creating placeholder: '" + p_typeref.cname.operator String() + "'.");
- const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_typeref.cname);
+ HashMap<StringName, TypeInterface>::ConstIterator match = placeholder_types.find(p_typeref.cname);
if (match) {
- return &match->get();
+ return &match->value;
}
TypeInterface placeholder;
TypeInterface::create_placeholder_type(placeholder, p_typeref.cname);
- return &placeholder_types.insert(placeholder.cname, placeholder)->get();
+ return &placeholder_types.insert(placeholder.cname, placeholder)->value;
}
StringName BindingsGenerator::_get_int_type_name_from_meta(GodotTypeInfo::Metadata p_meta) {
@@ -2710,7 +2708,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
List<PropertyInfo> property_list;
ClassDB::get_property_list(type_cname, &property_list, true);
- Map<StringName, StringName> accessor_methods;
+ HashMap<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 || (property.type == Variant::NIL && property.usage & PROPERTY_USAGE_ARRAY)) {
@@ -2905,9 +2903,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
imethod.proxy_name += "_";
}
- Map<StringName, StringName>::Element *accessor = accessor_methods.find(imethod.cname);
+ HashMap<StringName, StringName>::Iterator accessor = accessor_methods.find(imethod.cname);
if (accessor) {
- const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value());
+ const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value);
// We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also
// we don't know if an accessor method in a different class could have other purposes, so better leave those untouched.
@@ -2944,12 +2942,11 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
// Populate signals
const HashMap<StringName, MethodInfo> &signal_map = class_info->signal_map;
- const StringName *k = nullptr;
- while ((k = signal_map.next(k))) {
+ for (const KeyValue<StringName, MethodInfo> &E : signal_map) {
SignalInterface isignal;
- const MethodInfo &method_info = signal_map.get(*k);
+ const MethodInfo &method_info = E.value;
isignal.name = method_info.name;
isignal.cname = method_info.name;
@@ -3026,10 +3023,9 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
ClassDB::get_integer_constant_list(type_cname, &constants, true);
const HashMap<StringName, List<StringName>> &enum_map = class_info->enum_map;
- k = nullptr;
- while ((k = enum_map.next(k))) {
- StringName enum_proxy_cname = *k;
+ for (const KeyValue<StringName, List<StringName>> &E : enum_map) {
+ StringName enum_proxy_cname = E.key;
String enum_proxy_name = enum_proxy_cname.operator String();
if (itype.find_property_by_proxy_name(enum_proxy_cname)) {
// We have several conflicts between enums and PascalCase properties,
@@ -3038,7 +3034,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
enum_proxy_cname = StringName(enum_proxy_name);
}
EnumInterface ienum(enum_proxy_cname);
- const List<StringName> &enum_constants = enum_map.get(*k);
+ const List<StringName> &enum_constants = E.value;
for (const StringName &constant_cname : enum_constants) {
String constant_name = constant_cname.operator String();
int *value = class_info->constant_map.getptr(constant_cname);
@@ -3068,7 +3064,7 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
TypeInterface enum_itype;
enum_itype.is_enum = true;
- enum_itype.name = itype.name + "." + String(*k);
+ enum_itype.name = itype.name + "." + String(E.key);
enum_itype.cname = StringName(enum_itype.name);
enum_itype.proxy_name = itype.proxy_name + "." + enum_proxy_name;
TypeInterface::postsetup_enum_type(enum_itype);
@@ -3204,7 +3200,7 @@ bool BindingsGenerator::_arg_default_value_from_variant(const Variant &p_val, Ar
if (transform == Transform2D()) {
r_iarg.default_argument = "Transform2D.Identity";
} else {
- r_iarg.default_argument = "new Transform2D(new Vector2" + transform.elements[0].operator String() + ", new Vector2" + transform.elements[1].operator String() + ", new Vector2" + transform.elements[2].operator String() + ")";
+ r_iarg.default_argument = "new Transform2D(new Vector2" + transform.columns[0].operator String() + ", new Vector2" + transform.columns[1].operator String() + ", new Vector2" + transform.columns[2].operator String() + ")";
}
r_iarg.def_param_mode = ArgumentInterface::NULLABLE_VAL;
} break;
@@ -3598,11 +3594,11 @@ void BindingsGenerator::_populate_global_constants() {
int global_constants_count = CoreConstants::get_global_constant_count();
if (global_constants_count > 0) {
- Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope");
+ HashMap<String, DocData::ClassDoc>::Iterator match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope");
CRASH_COND_MSG(!match, "Could not find '@GlobalScope' in DocData.");
- const DocData::ClassDoc &global_scope_doc = match->value();
+ const DocData::ClassDoc &global_scope_doc = match->value;
for (int i = 0; i < global_constants_count; i++) {
String constant_name = CoreConstants::get_global_constant_name(i);
@@ -3717,8 +3713,8 @@ void BindingsGenerator::_initialize() {
core_custom_icalls.clear();
editor_custom_icalls.clear();
- for (OrderedHashMap<StringName, TypeInterface>::Element E = obj_types.front(); E; E = E.next()) {
- _generate_method_icalls(E.get());
+ for (const KeyValue<StringName, TypeInterface> &E : obj_types) {
+ _generate_method_icalls(E.value);
}
initialized = true;
diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h
index dec4fae8cd..fb7e0e5a81 100644
--- a/modules/mono/editor/bindings_generator.h
+++ b/modules/mono/editor/bindings_generator.h
@@ -533,24 +533,24 @@ class BindingsGenerator {
bool log_print_enabled = true;
bool initialized = false;
- OrderedHashMap<StringName, TypeInterface> obj_types;
+ HashMap<StringName, TypeInterface> obj_types;
- Map<StringName, TypeInterface> placeholder_types;
- Map<StringName, TypeInterface> builtin_types;
- Map<StringName, TypeInterface> enum_types;
+ HashMap<StringName, TypeInterface> placeholder_types;
+ HashMap<StringName, TypeInterface> builtin_types;
+ HashMap<StringName, TypeInterface> enum_types;
List<EnumInterface> global_enums;
List<ConstantInterface> global_constants;
List<InternalCall> method_icalls;
- Map<const MethodInterface *, const InternalCall *> method_icalls_map;
+ HashMap<const MethodInterface *, const InternalCall *> method_icalls_map;
List<const InternalCall *> generated_icall_funcs;
List<InternalCall> core_custom_icalls;
List<InternalCall> editor_custom_icalls;
- Map<StringName, List<StringName>> blacklisted_methods;
+ HashMap<StringName, List<StringName>> blacklisted_methods;
void _initialize_blacklisted_methods();
diff --git a/modules/mono/editor/code_completion.cpp b/modules/mono/editor/code_completion.cpp
index 3a41b3f6f5..a1789412f4 100644
--- a/modules/mono/editor/code_completion.cpp
+++ b/modules/mono/editor/code_completion.cpp
@@ -121,10 +121,10 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
case CompletionKind::NODE_PATHS: {
{
// Autoloads.
- OrderedHashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
+ HashMap<StringName, ProjectSettings::AutoloadInfo> autoloads = ProjectSettings::get_singleton()->get_autoload_list();
- for (OrderedHashMap<StringName, ProjectSettings::AutoloadInfo>::Element E = autoloads.front(); E; E = E.next()) {
- const ProjectSettings::AutoloadInfo &info = E.value();
+ for (const KeyValue<StringName, ProjectSettings::AutoloadInfo> &E : autoloads) {
+ const ProjectSettings::AutoloadInfo &info = E.value;
suggestions.push_back(quoted("/root/" + String(info.name)));
}
}
@@ -144,7 +144,7 @@ PackedStringArray get_code_completion(CompletionKind p_kind, const String &p_scr
}
} break;
case CompletionKind::SCENE_PATHS: {
- DirAccessRef dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
+ Ref<DirAccess> dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
List<String> directories;
directories.push_back(dir_access->get_current_dir());
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 656796c5c7..37bdc42c2d 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -526,10 +526,10 @@ namespace Godot
/// <summary>
/// Introduce an additional rotation around the given <paramref name="axis"/>
- /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector.
+ /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated basis matrix.</returns>
public Basis Rotated(Vector3 axis, real_t phi)
{
@@ -770,10 +770,10 @@ namespace Godot
/// <summary>
/// Constructs a pure rotation basis matrix, rotated around the given <paramref name="axis"/>
- /// by <paramref name="phi"/> (in radians). The axis must be a normalized vector.
+ /// by <paramref name="angle"/> (in radians). The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
public Basis(Vector3 axis, real_t phi)
{
Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index 8e253388bf..89947899cb 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -297,9 +297,9 @@ namespace Godot
}
/// <summary>
- /// Rotates the transform by <paramref name="phi"/> (in radians), using matrix multiplication.
+ /// Rotates the transform by <paramref name="angle"/> (in radians), using matrix multiplication.
/// </summary>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform2D Rotated(real_t phi)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 5d9aabdd2f..7b211b6577 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -186,11 +186,11 @@ namespace Godot
}
/// <summary>
- /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="phi"/> (in radians),
+ /// Rotates the transform around the given <paramref name="axis"/> by <paramref name="angle"/> (in radians),
/// using matrix multiplication. The axis must be a normalized vector.
/// </summary>
/// <param name="axis">The axis to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate, in radians.</param>
+ /// <param name="angle">The angle to rotate, in radians.</param>
/// <returns>The rotated transformation matrix.</returns>
public Transform3D Rotated(Vector3 axis, real_t phi)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index d4b623b2ea..9e990ce83e 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -470,9 +470,9 @@ namespace Godot
}
/// <summary>
- /// Rotates this vector by <paramref name="phi"/> radians.
+ /// Rotates this vector by <paramref name="angle"/> radians.
/// </summary>
- /// <param name="phi">The angle to rotate by, in radians.</param>
+ /// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
public Vector2 Rotated(real_t phi)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index eddfa76f10..56859da7f2 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -488,11 +488,11 @@ namespace Godot
}
/// <summary>
- /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="phi"/> radians.
+ /// Rotates this vector around a given <paramref name="axis"/> vector by <paramref name="angle"/> (in radians).
/// The <paramref name="axis"/> vector must be a normalized vector.
/// </summary>
/// <param name="axis">The vector to rotate around. Must be normalized.</param>
- /// <param name="phi">The angle to rotate by, in radians.</param>
+ /// <param name="angle">The angle to rotate by, in radians.</param>
/// <returns>The rotated vector.</returns>
public Vector3 Rotated(Vector3 axis, real_t phi)
{
diff --git a/modules/mono/glue/arguments_vector.h b/modules/mono/glue/arguments_vector.h
index 7c991d87a4..4405809887 100644
--- a/modules/mono/glue/arguments_vector.h
+++ b/modules/mono/glue/arguments_vector.h
@@ -37,7 +37,7 @@ template <typename T, int POOL_SIZE = 5>
struct ArgumentsVector {
private:
T pool[POOL_SIZE];
- T *_ptr;
+ T *_ptr = nullptr;
int size;
ArgumentsVector() = delete;
diff --git a/modules/mono/glue/base_object_glue.cpp b/modules/mono/glue/base_object_glue.cpp
index b5f2c98af5..7b9dbc87cf 100644
--- a/modules/mono/glue/base_object_glue.cpp
+++ b/modules/mono/glue/base_object_glue.cpp
@@ -68,7 +68,7 @@ void godot_icall_Object_Disposed(MonoObject *p_obj, Object *p_ptr) {
void *data = CSharpLanguage::get_existing_instance_binding(p_ptr);
if (data) {
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited) {
MonoGCHandleData &gchandle = script_binding.gchandle;
if (!gchandle.is_released()) {
@@ -115,7 +115,7 @@ void godot_icall_RefCounted_Disposed(MonoObject *p_obj, Object *p_ptr, MonoBoole
void *data = CSharpLanguage::get_existing_instance_binding(rc);
if (data) {
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->get();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->get();
if (script_binding.inited) {
MonoGCHandleData &gchandle = script_binding.gchandle;
if (!gchandle.is_released()) {
@@ -148,7 +148,7 @@ MonoObject *godot_icall_Object_weakref(Object *p_ptr) {
RefCounted *rc = Object::cast_to<RefCounted>(p_ptr);
if (rc) {
- REF r = rc;
+ Ref<RefCounted> r = rc;
if (!r.is_valid()) {
return nullptr;
}
diff --git a/modules/mono/godotsharp_dirs.cpp b/modules/mono/godotsharp_dirs.cpp
index 7c2cb2e260..cb2b60fcce 100644
--- a/modules/mono/godotsharp_dirs.cpp
+++ b/modules/mono/godotsharp_dirs.cpp
@@ -76,7 +76,7 @@ String _get_mono_user_dir() {
exe_dir = exe_dir.plus_file("../../..").simplify_path();
}
- DirAccessRef d = DirAccess::create_for_path(exe_dir);
+ Ref<DirAccess> d = DirAccess::create_for_path(exe_dir);
if (d->file_exists("._sc_") || d->file_exists("_sc_")) {
// contain yourself
diff --git a/modules/mono/managed_callable.cpp b/modules/mono/managed_callable.cpp
index 8ed21c323f..4f7783b765 100644
--- a/modules/mono/managed_callable.cpp
+++ b/modules/mono/managed_callable.cpp
@@ -36,7 +36,7 @@
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable>::List ManagedCallable::instances;
-Map<ManagedCallable *, Array> ManagedCallable::instances_pending_reload;
+RBMap<ManagedCallable *, Array> ManagedCallable::instances_pending_reload;
Mutex ManagedCallable::instances_mutex;
#endif
diff --git a/modules/mono/managed_callable.h b/modules/mono/managed_callable.h
index ea7231f43b..11bee6cf60 100644
--- a/modules/mono/managed_callable.h
+++ b/modules/mono/managed_callable.h
@@ -43,12 +43,12 @@
class ManagedCallable : public CallableCustom {
friend class CSharpLanguage;
MonoGCHandleData delegate_handle;
- GDMonoMethod *delegate_invoke;
+ GDMonoMethod *delegate_invoke = nullptr;
#ifdef GD_MONO_HOT_RELOAD
SelfList<ManagedCallable> self_instance = this;
static SelfList<ManagedCallable>::List instances;
- static Map<ManagedCallable *, Array> instances_pending_reload;
+ static RBMap<ManagedCallable *, Array> instances_pending_reload;
static Mutex instances_mutex;
#endif
diff --git a/modules/mono/mono_gd/gd_mono.cpp b/modules/mono/mono_gd/gd_mono.cpp
index 424b74906f..39a8ef22b7 100644
--- a/modules/mono/mono_gd/gd_mono.cpp
+++ b/modules/mono/mono_gd/gd_mono.cpp
@@ -643,7 +643,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const
// Create destination directory if needed
if (!DirAccess::exists(dst_dir)) {
- DirAccessRef da = DirAccess::create_for_path(dst_dir);
+ Ref<DirAccess> da = DirAccess::create_for_path(dst_dir);
Error err = da->make_dir_recursive(dst_dir);
if (err != OK) {
@@ -652,7 +652,7 @@ bool GDMono::copy_prebuilt_api_assembly(ApiAssemblyInfo::Type p_api_type, const
}
}
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
String xml_file = assembly_name + ".xml";
if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK) {
@@ -1167,9 +1167,8 @@ GDMonoClass *GDMono::get_class(MonoClass *p_raw_class) {
int32_t domain_id = mono_domain_get_id(mono_domain_get());
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
- const String *k = nullptr;
- while ((k = domain_assemblies.next(k))) {
- GDMonoAssembly *assembly = domain_assemblies.get(*k);
+ for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+ GDMonoAssembly *assembly = E.value;
if (assembly->get_image() == image) {
GDMonoClass *klass = assembly->get_class(p_raw_class);
if (klass) {
@@ -1190,9 +1189,8 @@ GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &
int32_t domain_id = mono_domain_get_id(mono_domain_get());
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[domain_id];
- const String *k = nullptr;
- while ((k = domain_assemblies.next(k))) {
- GDMonoAssembly *assembly = domain_assemblies.get(*k);
+ for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+ GDMonoAssembly *assembly = E.value;
klass = assembly->get_class(p_namespace, p_name);
if (klass) {
return klass;
@@ -1205,9 +1203,8 @@ GDMonoClass *GDMono::get_class(const StringName &p_namespace, const StringName &
void GDMono::_domain_assemblies_cleanup(int32_t p_domain_id) {
HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies[p_domain_id];
- const String *k = nullptr;
- while ((k = domain_assemblies.next(k))) {
- memdelete(domain_assemblies.get(*k));
+ for (const KeyValue<String, GDMonoAssembly *> &E : domain_assemblies) {
+ memdelete(E.value);
}
assemblies.erase(p_domain_id);
@@ -1298,13 +1295,11 @@ GDMono::~GDMono() {
// Leave the rest to 'mono_jit_cleanup'
#endif
- const int32_t *k = nullptr;
- while ((k = assemblies.next(k))) {
- HashMap<String, GDMonoAssembly *> &domain_assemblies = assemblies.get(*k);
+ for (const KeyValue<int32_t, HashMap<String, GDMonoAssembly *>> &E : assemblies) {
+ const HashMap<String, GDMonoAssembly *> &domain_assemblies = E.value;
- const String *kk = nullptr;
- while ((kk = domain_assemblies.next(kk))) {
- memdelete(domain_assemblies.get(*kk));
+ for (const KeyValue<String, GDMonoAssembly *> &F : domain_assemblies) {
+ memdelete(F.value);
}
}
assemblies.clear();
diff --git a/modules/mono/mono_gd/gd_mono.h b/modules/mono/mono_gd/gd_mono.h
index aab0b31c37..51fd0f8483 100644
--- a/modules/mono/mono_gd/gd_mono.h
+++ b/modules/mono/mono_gd/gd_mono.h
@@ -94,16 +94,16 @@ private:
UnhandledExceptionPolicy unhandled_exception_policy;
- MonoDomain *root_domain;
- MonoDomain *scripts_domain;
+ MonoDomain *root_domain = nullptr;
+ MonoDomain *scripts_domain = nullptr;
HashMap<int32_t, HashMap<String, GDMonoAssembly *>> assemblies;
- GDMonoAssembly *corlib_assembly;
- GDMonoAssembly *project_assembly;
+ GDMonoAssembly *corlib_assembly = nullptr;
+ GDMonoAssembly *project_assembly = nullptr;
#ifdef TOOLS_ENABLED
- GDMonoAssembly *tools_assembly;
- GDMonoAssembly *tools_project_editor_assembly;
+ GDMonoAssembly *tools_assembly = nullptr;
+ GDMonoAssembly *tools_project_editor_assembly = nullptr;
#endif
LoadedApiAssembly core_api_assembly;
@@ -150,7 +150,7 @@ private:
void _init_godot_api_hashes();
void _init_exception_policy();
- GDMonoLog *gdmono_log;
+ GDMonoLog *gdmono_log = nullptr;
#if defined(WINDOWS_ENABLED) && defined(TOOLS_ENABLED)
MonoRegInfo mono_reg_info;
@@ -250,7 +250,7 @@ public:
namespace gdmono {
class ScopeDomain {
- MonoDomain *prev_domain;
+ MonoDomain *prev_domain = nullptr;
public:
ScopeDomain(MonoDomain *p_domain) {
@@ -270,7 +270,7 @@ public:
};
class ScopeExitDomainUnload {
- MonoDomain *domain;
+ MonoDomain *domain = nullptr;
public:
ScopeExitDomainUnload(MonoDomain *p_domain) :
diff --git a/modules/mono/mono_gd/gd_mono_assembly.cpp b/modules/mono/mono_gd/gd_mono_assembly.cpp
index 3991b14612..42c6b6305f 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.cpp
+++ b/modules/mono/mono_gd/gd_mono_assembly.cpp
@@ -412,10 +412,10 @@ GDMonoClass *GDMonoAssembly::get_class(const StringName &p_namespace, const Stri
GDMonoClass *GDMonoAssembly::get_class(MonoClass *p_mono_class) {
ERR_FAIL_NULL_V(image, nullptr);
- Map<MonoClass *, GDMonoClass *>::Element *match = cached_raw.find(p_mono_class);
+ HashMap<MonoClass *, GDMonoClass *>::Iterator match = cached_raw.find(p_mono_class);
if (match) {
- return match->value();
+ return match->value;
}
StringName namespace_name = String::utf8(mono_class_get_namespace(p_mono_class));
diff --git a/modules/mono/mono_gd/gd_mono_assembly.h b/modules/mono/mono_gd/gd_mono_assembly.h
index b25d773be7..0a3ae6c4fe 100644
--- a/modules/mono/mono_gd/gd_mono_assembly.h
+++ b/modules/mono/mono_gd/gd_mono_assembly.h
@@ -36,7 +36,7 @@
#include "core/string/ustring.h"
#include "core/templates/hash_map.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "gd_mono_utils.h"
class GDMonoAssembly {
@@ -68,8 +68,8 @@ class GDMonoAssembly {
};
String name;
- MonoImage *image;
- MonoAssembly *assembly;
+ MonoImage *image = nullptr;
+ MonoAssembly *assembly = nullptr;
bool attrs_fetched = false;
MonoCustomAttrInfo *attributes = nullptr;
@@ -79,7 +79,7 @@ class GDMonoAssembly {
#endif
HashMap<ClassKey, GDMonoClass *, ClassKey::Hasher> cached_classes;
- Map<MonoClass *, GDMonoClass *> cached_raw;
+ HashMap<MonoClass *, GDMonoClass *> cached_raw;
static Vector<String> search_dirs;
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index 49f47b0a15..4000342c94 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -41,91 +41,91 @@ struct CachedData {
// corlib classes
// Let's use the no-namespace format for these too
- GDMonoClass *class_MonoObject; // object
- GDMonoClass *class_bool; // bool
- GDMonoClass *class_int8_t; // sbyte
- GDMonoClass *class_int16_t; // short
- GDMonoClass *class_int32_t; // int
- GDMonoClass *class_int64_t; // long
- GDMonoClass *class_uint8_t; // byte
- GDMonoClass *class_uint16_t; // ushort
- GDMonoClass *class_uint32_t; // uint
- GDMonoClass *class_uint64_t; // ulong
- GDMonoClass *class_float; // float
- GDMonoClass *class_double; // double
- GDMonoClass *class_String; // string
- GDMonoClass *class_IntPtr; // System.IntPtr
-
- GDMonoClass *class_System_Collections_IEnumerable;
- GDMonoClass *class_System_Collections_ICollection;
- GDMonoClass *class_System_Collections_IDictionary;
+ GDMonoClass *class_MonoObject = nullptr; // object
+ GDMonoClass *class_bool = nullptr; // bool
+ GDMonoClass *class_int8_t = nullptr; // sbyte
+ GDMonoClass *class_int16_t = nullptr; // short
+ GDMonoClass *class_int32_t = nullptr; // int
+ GDMonoClass *class_int64_t = nullptr; // long
+ GDMonoClass *class_uint8_t = nullptr; // byte
+ GDMonoClass *class_uint16_t = nullptr; // ushort
+ GDMonoClass *class_uint32_t = nullptr; // uint
+ GDMonoClass *class_uint64_t = nullptr; // ulong
+ GDMonoClass *class_float = nullptr; // float
+ GDMonoClass *class_double = nullptr; // double
+ GDMonoClass *class_String = nullptr; // string
+ GDMonoClass *class_IntPtr = nullptr; // System.IntPtr
+
+ GDMonoClass *class_System_Collections_IEnumerable = nullptr;
+ GDMonoClass *class_System_Collections_ICollection = nullptr;
+ GDMonoClass *class_System_Collections_IDictionary = nullptr;
#ifdef DEBUG_ENABLED
- GDMonoClass *class_System_Diagnostics_StackTrace;
+ GDMonoClass *class_System_Diagnostics_StackTrace = nullptr;
GDMonoMethodThunkR<MonoArray *, MonoObject *> methodthunk_System_Diagnostics_StackTrace_GetFrames;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool;
- GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool;
+ GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_bool = nullptr;
+ GDMonoMethod *method_System_Diagnostics_StackTrace_ctor_Exception_bool = nullptr;
#endif
- GDMonoClass *class_KeyNotFoundException;
+ GDMonoClass *class_KeyNotFoundException = nullptr;
- MonoClass *rawclass_Dictionary;
+ MonoClass *rawclass_Dictionary = nullptr;
// -----------------------------------------------
- GDMonoClass *class_Vector2;
- GDMonoClass *class_Vector2i;
- GDMonoClass *class_Rect2;
- GDMonoClass *class_Rect2i;
- GDMonoClass *class_Transform2D;
- GDMonoClass *class_Vector3;
- GDMonoClass *class_Vector3i;
- GDMonoClass *class_Basis;
- GDMonoClass *class_Quaternion;
- GDMonoClass *class_Transform3D;
- GDMonoClass *class_AABB;
- GDMonoClass *class_Color;
- GDMonoClass *class_Plane;
- GDMonoClass *class_StringName;
- GDMonoClass *class_NodePath;
- GDMonoClass *class_RID;
- GDMonoClass *class_GodotObject;
- GDMonoClass *class_GodotResource;
- GDMonoClass *class_Node;
- GDMonoClass *class_Control;
- GDMonoClass *class_Node3D;
- GDMonoClass *class_WeakRef;
- GDMonoClass *class_Callable;
- GDMonoClass *class_SignalInfo;
- GDMonoClass *class_Array;
- GDMonoClass *class_Dictionary;
- GDMonoClass *class_MarshalUtils;
- GDMonoClass *class_ISerializationListener;
+ GDMonoClass *class_Vector2 = nullptr;
+ GDMonoClass *class_Vector2i = nullptr;
+ GDMonoClass *class_Rect2 = nullptr;
+ GDMonoClass *class_Rect2i = nullptr;
+ GDMonoClass *class_Transform2D = nullptr;
+ GDMonoClass *class_Vector3 = nullptr;
+ GDMonoClass *class_Vector3i = nullptr;
+ GDMonoClass *class_Basis = nullptr;
+ GDMonoClass *class_Quaternion = nullptr;
+ GDMonoClass *class_Transform3D = nullptr;
+ GDMonoClass *class_AABB = nullptr;
+ GDMonoClass *class_Color = nullptr;
+ GDMonoClass *class_Plane = nullptr;
+ GDMonoClass *class_StringName = nullptr;
+ GDMonoClass *class_NodePath = nullptr;
+ GDMonoClass *class_RID = nullptr;
+ GDMonoClass *class_GodotObject = nullptr;
+ GDMonoClass *class_GodotResource = nullptr;
+ GDMonoClass *class_Node = nullptr;
+ GDMonoClass *class_Control = nullptr;
+ GDMonoClass *class_Node3D = nullptr;
+ GDMonoClass *class_WeakRef = nullptr;
+ GDMonoClass *class_Callable = nullptr;
+ GDMonoClass *class_SignalInfo = nullptr;
+ GDMonoClass *class_Array = nullptr;
+ GDMonoClass *class_Dictionary = nullptr;
+ GDMonoClass *class_MarshalUtils = nullptr;
+ GDMonoClass *class_ISerializationListener = nullptr;
#ifdef DEBUG_ENABLED
- GDMonoClass *class_DebuggingUtils;
+ GDMonoClass *class_DebuggingUtils = nullptr;
GDMonoMethodThunk<MonoObject *, MonoString **, int *, MonoString **> methodthunk_DebuggingUtils_GetStackFrameInfo;
#endif
- GDMonoClass *class_ExportAttribute;
- GDMonoField *field_ExportAttribute_hint;
- GDMonoField *field_ExportAttribute_hintString;
- GDMonoClass *class_SignalAttribute;
- GDMonoClass *class_ToolAttribute;
- GDMonoClass *class_AnyPeerAttribute;
- GDMonoClass *class_AuthorityAttribute;
- GDMonoClass *class_GodotMethodAttribute;
- GDMonoField *field_GodotMethodAttribute_methodName;
- GDMonoClass *class_ScriptPathAttribute;
- GDMonoField *field_ScriptPathAttribute_path;
- GDMonoClass *class_AssemblyHasScriptsAttribute;
- GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup;
- GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes;
-
- GDMonoField *field_GodotObject_ptr;
- GDMonoField *field_StringName_ptr;
- GDMonoField *field_NodePath_ptr;
- GDMonoField *field_Image_ptr;
- GDMonoField *field_RID_ptr;
+ GDMonoClass *class_ExportAttribute = nullptr;
+ GDMonoField *field_ExportAttribute_hint = nullptr;
+ GDMonoField *field_ExportAttribute_hintString = nullptr;
+ GDMonoClass *class_SignalAttribute = nullptr;
+ GDMonoClass *class_ToolAttribute = nullptr;
+ GDMonoClass *class_AnyPeerAttribute = nullptr;
+ GDMonoClass *class_AuthorityAttribute = nullptr;
+ GDMonoClass *class_GodotMethodAttribute = nullptr;
+ GDMonoField *field_GodotMethodAttribute_methodName = nullptr;
+ GDMonoClass *class_ScriptPathAttribute = nullptr;
+ GDMonoField *field_ScriptPathAttribute_path = nullptr;
+ GDMonoClass *class_AssemblyHasScriptsAttribute = nullptr;
+ GDMonoField *field_AssemblyHasScriptsAttribute_requiresLookup = nullptr;
+ GDMonoField *field_AssemblyHasScriptsAttribute_scriptTypes = nullptr;
+
+ GDMonoField *field_GodotObject_ptr = nullptr;
+ GDMonoField *field_StringName_ptr = nullptr;
+ GDMonoField *field_NodePath_ptr = nullptr;
+ GDMonoField *field_Image_ptr = nullptr;
+ GDMonoField *field_RID_ptr = nullptr;
GDMonoMethodThunk<MonoObject *> methodthunk_GodotObject_Dispose;
GDMonoMethodThunkR<Array *, MonoObject *> methodthunk_Array_GetPtr;
diff --git a/modules/mono/mono_gd/gd_mono_class.cpp b/modules/mono/mono_gd/gd_mono_class.cpp
index 3fc0f16e05..51c5aa3542 100644
--- a/modules/mono/mono_gd/gd_mono_class.cpp
+++ b/modules/mono/mono_gd/gd_mono_class.cpp
@@ -247,7 +247,7 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
if (existing_method) {
memdelete(*existing_method); // Must delete old one
}
- methods.set(key, method);
+ methods.insert(key, method);
break;
}
@@ -266,11 +266,9 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
GDMonoMethod *GDMonoClass::get_fetched_method_unknown_params(const StringName &p_name) {
ERR_FAIL_COND_V(!methods_fetched, nullptr);
- const MethodKey *k = nullptr;
-
- while ((k = methods.next(k))) {
- if (k->name == p_name) {
- return methods.get(*k);
+ for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
+ if (E.key.name == p_name) {
+ return E.value;
}
}
@@ -307,7 +305,7 @@ GDMonoMethod *GDMonoClass::get_method(const StringName &p_name, uint16_t p_param
if (raw_method) {
GDMonoMethod *method = memnew(GDMonoMethod(p_name, raw_method));
- methods.set(key, method);
+ methods.insert(key, method);
return method;
}
@@ -342,7 +340,7 @@ GDMonoMethod *GDMonoClass::get_method(MonoMethod *p_raw_method, const StringName
}
GDMonoMethod *method = memnew(GDMonoMethod(p_name, p_raw_method));
- methods.set(key, method);
+ methods.insert(key, method);
return method;
}
@@ -362,10 +360,10 @@ GDMonoMethod *GDMonoClass::get_method_with_desc(const String &p_description, boo
}
GDMonoField *GDMonoClass::get_field(const StringName &p_name) {
- Map<StringName, GDMonoField *>::Element *result = fields.find(p_name);
+ HashMap<StringName, GDMonoField *>::Iterator result = fields.find(p_name);
if (result) {
- return result->value();
+ return result->value;
}
if (fields_fetched) {
@@ -394,10 +392,10 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
while ((raw_field = mono_class_get_fields(mono_class, &iter)) != nullptr) {
StringName name = String::utf8(mono_field_get_name(raw_field));
- Map<StringName, GDMonoField *>::Element *match = fields.find(name);
+ HashMap<StringName, GDMonoField *>::Iterator match = fields.find(name);
if (match) {
- fields_list.push_back(match->get());
+ fields_list.push_back(match->value);
} else {
GDMonoField *field = memnew(GDMonoField(raw_field, this));
fields.insert(name, field);
@@ -411,10 +409,10 @@ const Vector<GDMonoField *> &GDMonoClass::get_all_fields() {
}
GDMonoProperty *GDMonoClass::get_property(const StringName &p_name) {
- Map<StringName, GDMonoProperty *>::Element *result = properties.find(p_name);
+ HashMap<StringName, GDMonoProperty *>::Iterator result = properties.find(p_name);
if (result) {
- return result->value();
+ return result->value;
}
if (properties_fetched) {
@@ -443,10 +441,10 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
while ((raw_property = mono_class_get_properties(mono_class, &iter)) != nullptr) {
StringName name = String::utf8(mono_property_get_name(raw_property));
- Map<StringName, GDMonoProperty *>::Element *match = properties.find(name);
+ HashMap<StringName, GDMonoProperty *>::Iterator match = properties.find(name);
if (match) {
- properties_list.push_back(match->get());
+ properties_list.push_back(match->value);
} else {
GDMonoProperty *property = memnew(GDMonoProperty(raw_property, this));
properties.insert(name, property);
@@ -479,10 +477,10 @@ const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
if (mono_class_is_delegate(raw_class)) {
StringName name = String::utf8(mono_class_get_name(raw_class));
- Map<StringName, GDMonoClass *>::Element *match = delegates.find(name);
+ HashMap<StringName, GDMonoClass *>::Iterator match = delegates.find(name);
if (match) {
- delegates_list.push_back(match->get());
+ delegates_list.push_back(match->value);
} else {
GDMonoClass *delegate = memnew(GDMonoClass(String::utf8(mono_class_get_namespace(raw_class)), String::utf8(mono_class_get_name(raw_class)), raw_class, assembly));
delegates.insert(name, delegate);
@@ -549,9 +547,8 @@ GDMonoClass::~GDMonoClass() {
Vector<GDMonoMethod *> deleted_methods;
deleted_methods.resize(methods.size());
- const MethodKey *k = nullptr;
- while ((k = methods.next(k))) {
- GDMonoMethod *method = methods.get(*k);
+ for (const KeyValue<MethodKey, GDMonoMethod *> &E : methods) {
+ GDMonoMethod *method = E.value;
if (method) {
for (int i = 0; i < offset; i++) {
diff --git a/modules/mono/mono_gd/gd_mono_class.h b/modules/mono/mono_gd/gd_mono_class.h
index bfb5797d4b..6b35da30f9 100644
--- a/modules/mono/mono_gd/gd_mono_class.h
+++ b/modules/mono/mono_gd/gd_mono_class.h
@@ -32,7 +32,7 @@
#define GD_MONO_CLASS_H
#include "core/string/ustring.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "gd_mono_field.h"
#include "gd_mono_header.h"
@@ -70,11 +70,11 @@ class GDMonoClass {
StringName namespace_name;
StringName class_name;
- MonoClass *mono_class;
- GDMonoAssembly *assembly;
+ MonoClass *mono_class = nullptr;
+ GDMonoAssembly *assembly = nullptr;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
// This contains both the original method names and remapped method names from the native Godot identifiers to the C# functions.
// Most method-related functions refer to this and it's possible this is unintuitive for outside users; this may be a prime location for refactoring or renaming.
@@ -85,15 +85,15 @@ class GDMonoClass {
Vector<GDMonoMethod *> method_list;
bool fields_fetched;
- Map<StringName, GDMonoField *> fields;
+ HashMap<StringName, GDMonoField *> fields;
Vector<GDMonoField *> fields_list;
bool properties_fetched;
- Map<StringName, GDMonoProperty *> properties;
+ HashMap<StringName, GDMonoProperty *> properties;
Vector<GDMonoProperty *> properties_list;
bool delegates_fetched;
- Map<StringName, GDMonoClass *> delegates;
+ HashMap<StringName, GDMonoClass *> delegates;
Vector<GDMonoClass *> delegates_list;
friend class GDMonoAssembly;
diff --git a/modules/mono/mono_gd/gd_mono_field.h b/modules/mono/mono_gd/gd_mono_field.h
index abcdef378c..87ef245f3f 100644
--- a/modules/mono/mono_gd/gd_mono_field.h
+++ b/modules/mono/mono_gd/gd_mono_field.h
@@ -36,14 +36,14 @@
#include "i_mono_class_member.h"
class GDMonoField : public IMonoClassMember {
- GDMonoClass *owner;
- MonoClassField *mono_field;
+ GDMonoClass *owner = nullptr;
+ MonoClassField *mono_field = nullptr;
StringName name;
ManagedType type;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
public:
virtual GDMonoClass *get_enclosing_class() const final { return owner; }
diff --git a/modules/mono/mono_gd/gd_mono_log.cpp b/modules/mono/mono_gd/gd_mono_log.cpp
index 01a6521876..6ea3c5539e 100644
--- a/modules/mono/mono_gd/gd_mono_log.cpp
+++ b/modules/mono/mono_gd/gd_mono_log.cpp
@@ -77,23 +77,20 @@ static String make_text(const char *log_domain, const char *log_level, const cha
}
void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *) {
- FileAccess *f = GDMonoLog::get_singleton()->log_file;
-
if (GDMonoLog::get_singleton()->log_level_id >= get_log_level_id(log_level)) {
String text = make_text(log_domain, log_level, message);
text += "\n";
- f->seek_end();
- f->store_string(text);
+ GDMonoLog::get_singleton()->log_file->seek_end();
+ GDMonoLog::get_singleton()->log_file->store_string(text);
}
if (fatal) {
String text = make_text(log_domain, log_level, message);
ERR_PRINT("Mono: FATAL ERROR '" + text + "', ABORTING! Logfile: '" + GDMonoLog::get_singleton()->log_file_path + "'.");
// Make sure to flush before aborting
- f->flush();
- f->close();
- memdelete(f);
+ GDMonoLog::get_singleton()->log_file->flush();
+ GDMonoLog::get_singleton()->log_file.unref();
abort();
}
@@ -101,8 +98,8 @@ void GDMonoLog::mono_log_callback(const char *log_domain, const char *log_level,
bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
if (!DirAccess::exists(p_logs_dir)) {
- DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V(!diraccess, false);
+ Ref<DirAccess> diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V(diraccess.is_null(), false);
Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir);
ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory.");
}
@@ -113,8 +110,8 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
void GDMonoLog::_delete_old_log_files(const String &p_logs_dir) {
static const uint64_t MAX_SECS = 5 * 86400; // 5 days
- DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND(!da);
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND(da.is_null());
Error err = da->change_dir(p_logs_dir);
ERR_FAIL_COND_MSG(err != OK, "Cannot change directory to '" + p_logs_dir + "'.");
@@ -170,7 +167,7 @@ void GDMonoLog::initialize() {
log_file_path = logs_dir.plus_file(log_file_name);
log_file = FileAccess::open(log_file_path, FileAccess::WRITE);
- if (!log_file) {
+ if (log_file.is_null()) {
ERR_PRINT("Mono: Cannot create log file at: " + log_file_path);
}
}
@@ -178,7 +175,7 @@ void GDMonoLog::initialize() {
mono_trace_set_level_string(log_level.get_data());
log_level_id = get_log_level_id(log_level.get_data());
- if (log_file) {
+ if (log_file.is_valid()) {
OS::get_singleton()->print("Mono: Log file is: '%s'\n", log_file_path.utf8().get_data());
mono_trace_set_log_handler(mono_log_callback, this);
} else {
@@ -192,11 +189,6 @@ GDMonoLog::GDMonoLog() {
GDMonoLog::~GDMonoLog() {
singleton = nullptr;
-
- if (log_file) {
- log_file->close();
- memdelete(log_file);
- }
}
#else
diff --git a/modules/mono/mono_gd/gd_mono_log.h b/modules/mono/mono_gd/gd_mono_log.h
index 9aa67a09e2..9fc35f8e31 100644
--- a/modules/mono/mono_gd/gd_mono_log.h
+++ b/modules/mono/mono_gd/gd_mono_log.h
@@ -48,7 +48,7 @@ class GDMonoLog {
#ifdef GD_MONO_LOG_ENABLED
int log_level_id = -1;
- FileAccess *log_file = nullptr;
+ Ref<FileAccess> log_file;
String log_file_path;
bool _try_create_logs_dir(const String &p_logs_dir);
diff --git a/modules/mono/mono_gd/gd_mono_marshal.h b/modules/mono/mono_gd/gd_mono_marshal.h
index 20d4743e5c..778e52b6cb 100644
--- a/modules/mono/mono_gd/gd_mono_marshal.h
+++ b/modules/mono/mono_gd/gd_mono_marshal.h
@@ -196,14 +196,14 @@ PackedVector3Array mono_array_to_PackedVector3Array(MonoArray *p_array);
#pragma pack(push, 1)
struct M_Callable {
- MonoObject *target;
- MonoObject *method_string_name;
- MonoDelegate *delegate;
+ MonoObject *target = nullptr;
+ MonoObject *method_string_name = nullptr;
+ MonoDelegate *delegate = nullptr;
};
struct M_SignalInfo {
- MonoObject *owner;
- MonoObject *name_string_name;
+ MonoObject *owner = nullptr;
+ MonoObject *name_string_name = nullptr;
};
#pragma pack(pop)
@@ -367,9 +367,9 @@ struct M_Transform2D {
static _FORCE_INLINE_ M_Transform2D convert_from(const Transform2D &p_from) {
M_Transform2D ret = {
- M_Vector2::convert_from(p_from.elements[0]),
- M_Vector2::convert_from(p_from.elements[1]),
- M_Vector2::convert_from(p_from.elements[2])
+ M_Vector2::convert_from(p_from.columns[0]),
+ M_Vector2::convert_from(p_from.columns[1]),
+ M_Vector2::convert_from(p_from.columns[2])
};
return ret;
}
@@ -412,9 +412,9 @@ struct M_Basis {
static _FORCE_INLINE_ M_Basis convert_from(const Basis &p_from) {
M_Basis ret = {
- M_Vector3::convert_from(p_from.elements[0]),
- M_Vector3::convert_from(p_from.elements[1]),
- M_Vector3::convert_from(p_from.elements[2])
+ M_Vector3::convert_from(p_from.rows[0]),
+ M_Vector3::convert_from(p_from.rows[1]),
+ M_Vector3::convert_from(p_from.rows[2])
};
return ret;
}
diff --git a/modules/mono/mono_gd/gd_mono_method.h b/modules/mono/mono_gd/gd_mono_method.h
index 6e87a60ee2..be11ef5bfe 100644
--- a/modules/mono/mono_gd/gd_mono_method.h
+++ b/modules/mono/mono_gd/gd_mono_method.h
@@ -54,7 +54,7 @@ class GDMonoMethod : public IMonoClassMember {
friend class GDMonoClass;
- MonoMethod *mono_method;
+ MonoMethod *mono_method = nullptr;
public:
virtual GDMonoClass *get_enclosing_class() const final;
diff --git a/modules/mono/mono_gd/gd_mono_property.h b/modules/mono/mono_gd/gd_mono_property.h
index 003bcf05e1..6fc681aeb5 100644
--- a/modules/mono/mono_gd/gd_mono_property.h
+++ b/modules/mono/mono_gd/gd_mono_property.h
@@ -36,14 +36,14 @@
#include "i_mono_class_member.h"
class GDMonoProperty : public IMonoClassMember {
- GDMonoClass *owner;
- MonoProperty *mono_property;
+ GDMonoClass *owner = nullptr;
+ MonoProperty *mono_property = nullptr;
StringName name;
ManagedType type;
bool attrs_fetched;
- MonoCustomAttrInfo *attributes;
+ MonoCustomAttrInfo *attributes = nullptr;
unsigned int param_buffer_size;
diff --git a/modules/mono/mono_gd/gd_mono_utils.cpp b/modules/mono/mono_gd/gd_mono_utils.cpp
index a884bf4da0..25678be624 100644
--- a/modules/mono/mono_gd/gd_mono_utils.cpp
+++ b/modules/mono/mono_gd/gd_mono_utils.cpp
@@ -70,7 +70,7 @@ MonoObject *unmanaged_get_managed(Object *unmanaged) {
void *data = CSharpLanguage::get_instance_binding(unmanaged);
ERR_FAIL_NULL_V(data, nullptr);
- CSharpScriptBinding &script_binding = ((Map<Object *, CSharpScriptBinding>::Element *)data)->value();
+ CSharpScriptBinding &script_binding = ((RBMap<Object *, CSharpScriptBinding>::Element *)data)->value();
ERR_FAIL_COND_V(!script_binding.inited, nullptr);
MonoGCHandleData &gchandle = script_binding.gchandle;
diff --git a/modules/mono/mono_gd/gd_mono_wasm_m2n.h b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
index 68299aa984..83e2750e5a 100644
--- a/modules/mono/mono_gd/gd_mono_wasm_m2n.h
+++ b/modules/mono/mono_gd/gd_mono_wasm_m2n.h
@@ -47,11 +47,11 @@ struct Mono_InterpMethodArguments {
size_t ilen;
void **iargs;
size_t flen;
- double *fargs;
+ double *fargs = nullptr;
void **retval;
size_t is_float_ret;
//#ifdef TARGET_WASM
- void *sig;
+ void *sig = nullptr;
//#endif
};
} // extern "C"
diff --git a/modules/mono/register_types.cpp b/modules/mono/register_types.cpp
index 531a4bb11f..755e1f7a30 100644
--- a/modules/mono/register_types.cpp
+++ b/modules/mono/register_types.cpp
@@ -40,7 +40,11 @@ Ref<ResourceFormatSaverCSharpScript> resource_saver_cs;
mono_bind::GodotSharp *_godotsharp = nullptr;
-void register_mono_types() {
+void initialize_mono_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(CSharpScript);
_godotsharp = memnew(mono_bind::GodotSharp);
@@ -59,7 +63,11 @@ void register_mono_types() {
ResourceSaver::add_resource_format_saver(resource_saver_cs);
}
-void unregister_mono_types() {
+void uninitialize_mono_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
ScriptServer::unregister_language(script_language_cs);
if (script_language_cs) {
diff --git a/modules/mono/register_types.h b/modules/mono/register_types.h
index 12f7e36f02..bc2690c277 100644
--- a/modules/mono/register_types.h
+++ b/modules/mono/register_types.h
@@ -31,7 +31,9 @@
#ifndef MONO_REGISTER_TYPES_H
#define MONO_REGISTER_TYPES_H
-void register_mono_types();
-void unregister_mono_types();
+#include "modules/register_module_types.h"
+
+void initialize_mono_module(ModuleInitializationLevel p_level);
+void uninitialize_mono_module(ModuleInitializationLevel p_level);
#endif // MONO_REGISTER_TYPES_H
diff --git a/modules/mono/signal_awaiter_utils.h b/modules/mono/signal_awaiter_utils.h
index 1a62f36625..532aa3e327 100644
--- a/modules/mono/signal_awaiter_utils.h
+++ b/modules/mono/signal_awaiter_utils.h
@@ -68,7 +68,7 @@ public:
};
class EventSignalCallable : public CallableCustom {
- Object *owner;
+ Object *owner = nullptr;
const CSharpScript::EventSignal *event_signal;
public:
diff --git a/modules/mono/utils/osx_utils.cpp b/modules/mono/utils/osx_utils.cpp
index 835c611709..abb59420eb 100644
--- a/modules/mono/utils/osx_utils.cpp
+++ b/modules/mono/utils/osx_utils.cpp
@@ -34,8 +34,8 @@
#include "core/string/print_string.h"
-#include <CoreFoundation/CoreFoundation.h>
-#include <CoreServices/CoreServices.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <CoreServices/CoreServices.h>
bool osx_is_app_bundle_installed(const String &p_bundle_id) {
CFStringRef bundle_id = CFStringCreateWithCString(nullptr, p_bundle_id.utf8(), kCFStringEncodingUTF8);
diff --git a/modules/mono/utils/string_utils.cpp b/modules/mono/utils/string_utils.cpp
index dd29299330..e6975611d2 100644
--- a/modules/mono/utils/string_utils.cpp
+++ b/modules/mono/utils/string_utils.cpp
@@ -167,15 +167,13 @@ String escape_csharp_keyword(const String &p_name) {
Error read_all_file_utf8(const String &p_path, String &r_content) {
Vector<uint8_t> sourcef;
Error err;
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err);
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ, &err);
ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot open file '" + p_path + "'.");
uint64_t len = f->get_length();
sourcef.resize(len + 1);
uint8_t *w = sourcef.ptrw();
uint64_t r = f->get_buffer(w, len);
- f->close();
- memdelete(f);
ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN);
w[len] = 0;
diff --git a/modules/msdfgen/register_types.cpp b/modules/msdfgen/register_types.cpp
index 69855d93fe..2d3a2a0c69 100644
--- a/modules/msdfgen/register_types.cpp
+++ b/modules/msdfgen/register_types.cpp
@@ -30,6 +30,14 @@
#include "register_types.h"
-void register_msdfgen_types() {}
+void initialize_msdfgen_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
-void unregister_msdfgen_types() {}
+void uninitialize_msdfgen_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/msdfgen/register_types.h b/modules/msdfgen/register_types.h
index 0e2fed2ce8..749204f390 100644
--- a/modules/msdfgen/register_types.h
+++ b/modules/msdfgen/register_types.h
@@ -31,7 +31,9 @@
#ifndef MSDFGEN_REGISTER_TYPES_H
#define MSDFGEN_REGISTER_TYPES_H
-void register_msdfgen_types();
-void unregister_msdfgen_types();
+#include "modules/register_module_types.h"
+
+void initialize_msdfgen_module(ModuleInitializationLevel p_level);
+void uninitialize_msdfgen_module(ModuleInitializationLevel p_level);
#endif // MSDFGEN_REGISTER_TYPES_H
diff --git a/modules/navigation/editor/navigation_mesh_editor_plugin.h b/modules/navigation/editor/navigation_mesh_editor_plugin.h
index 3c3e804fd2..bc9e4185b7 100644
--- a/modules/navigation/editor/navigation_mesh_editor_plugin.h
+++ b/modules/navigation/editor/navigation_mesh_editor_plugin.h
@@ -42,14 +42,14 @@ class NavigationMeshEditor : public Control {
GDCLASS(NavigationMeshEditor, Control);
- AcceptDialog *err_dialog;
+ AcceptDialog *err_dialog = nullptr;
- HBoxContainer *bake_hbox;
- Button *button_bake;
- Button *button_reset;
- Label *bake_info;
+ HBoxContainer *bake_hbox = nullptr;
+ Button *button_bake = nullptr;
+ Button *button_reset = nullptr;
+ Label *bake_info = nullptr;
- NavigationRegion3D *node;
+ NavigationRegion3D *node = nullptr;
void _bake_pressed();
void _clear_pressed();
@@ -68,7 +68,7 @@ public:
class NavigationMeshEditorPlugin : public EditorPlugin {
GDCLASS(NavigationMeshEditorPlugin, EditorPlugin);
- NavigationMeshEditor *navigation_mesh_editor;
+ NavigationMeshEditor *navigation_mesh_editor = nullptr;
public:
virtual String get_name() const override { return "NavigationMesh"; }
diff --git a/modules/navigation/godot_navigation_server.cpp b/modules/navigation/godot_navigation_server.cpp
index f3da85063a..42aad77979 100644
--- a/modules/navigation/godot_navigation_server.cpp
+++ b/modules/navigation/godot_navigation_server.cpp
@@ -40,43 +40,43 @@
/// an instance of that struct with the submitted parameters.
/// Then, that struct is stored in an array; the `sync` function consume that array.
-#define COMMAND_1(F_NAME, T_0, D_0) \
- struct MERGE(F_NAME, _command) : public SetCommand { \
- T_0 d_0; \
- MERGE(F_NAME, _command) \
- (T_0 p_d_0) : \
- d_0(p_d_0) {} \
- virtual void exec(GodotNavigationServer *server) { \
- server->MERGE(_cmd_, F_NAME)(d_0); \
- } \
- }; \
- void GodotNavigationServer::F_NAME(T_0 D_0) const { \
- auto cmd = memnew(MERGE(F_NAME, _command)( \
- D_0)); \
- add_command(cmd); \
- } \
+#define COMMAND_1(F_NAME, T_0, D_0) \
+ struct MERGE(F_NAME, _command) : public SetCommand { \
+ T_0 d_0; \
+ MERGE(F_NAME, _command) \
+ (T_0 p_d_0) : \
+ d_0(p_d_0) {} \
+ virtual void exec(GodotNavigationServer *server) override { \
+ server->MERGE(_cmd_, F_NAME)(d_0); \
+ } \
+ }; \
+ void GodotNavigationServer::F_NAME(T_0 D_0) const { \
+ auto cmd = memnew(MERGE(F_NAME, _command)( \
+ D_0)); \
+ add_command(cmd); \
+ } \
void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0)
-#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \
- struct MERGE(F_NAME, _command) : public SetCommand { \
- T_0 d_0; \
- T_1 d_1; \
- MERGE(F_NAME, _command) \
- ( \
- T_0 p_d_0, \
- T_1 p_d_1) : \
- d_0(p_d_0), \
- d_1(p_d_1) {} \
- virtual void exec(GodotNavigationServer *server) { \
- server->MERGE(_cmd_, F_NAME)(d_0, d_1); \
- } \
- }; \
- void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1) const { \
- auto cmd = memnew(MERGE(F_NAME, _command)( \
- D_0, \
- D_1)); \
- add_command(cmd); \
- } \
+#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \
+ struct MERGE(F_NAME, _command) : public SetCommand { \
+ T_0 d_0; \
+ T_1 d_1; \
+ MERGE(F_NAME, _command) \
+ ( \
+ T_0 p_d_0, \
+ T_1 p_d_1) : \
+ d_0(p_d_0), \
+ d_1(p_d_1) {} \
+ virtual void exec(GodotNavigationServer *server) override { \
+ server->MERGE(_cmd_, F_NAME)(d_0, d_1); \
+ } \
+ }; \
+ void GodotNavigationServer::F_NAME(T_0 D_0, T_1 D_1) const { \
+ auto cmd = memnew(MERGE(F_NAME, _command)( \
+ D_0, \
+ D_1)); \
+ add_command(cmd); \
+ } \
void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1)
#define COMMAND_4(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3) \
@@ -95,7 +95,7 @@
d_1(p_d_1), \
d_2(p_d_2), \
d_3(p_d_3) {} \
- virtual void exec(GodotNavigationServer *server) { \
+ virtual void exec(GodotNavigationServer *server) override { \
server->MERGE(_cmd_, F_NAME)(d_0, d_1, d_2, d_3); \
} \
}; \
@@ -109,9 +109,7 @@
} \
void GodotNavigationServer::MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3)
-GodotNavigationServer::GodotNavigationServer() :
- NavigationServer3D() {
-}
+GodotNavigationServer::GodotNavigationServer() {}
GodotNavigationServer::~GodotNavigationServer() {
flush_queries();
@@ -235,6 +233,38 @@ RID GodotNavigationServer::map_get_closest_point_owner(RID p_map, const Vector3
return map->get_closest_point_owner(p_point);
}
+Array GodotNavigationServer::map_get_regions(RID p_map) const {
+ Array regions_rids;
+ const NavMap *map = map_owner.get_or_null(p_map);
+ ERR_FAIL_COND_V(map == nullptr, regions_rids);
+ for (NavRegion *region : map->get_regions()) {
+ regions_rids.push_back(region->get_self());
+ }
+ return regions_rids;
+}
+
+Array GodotNavigationServer::map_get_agents(RID p_map) const {
+ Array agents_rids;
+ const NavMap *map = map_owner.get_or_null(p_map);
+ ERR_FAIL_COND_V(map == nullptr, agents_rids);
+ for (RvoAgent *agent : map->get_agents()) {
+ agents_rids.push_back(agent->get_self());
+ }
+ return agents_rids;
+}
+
+RID GodotNavigationServer::region_get_map(RID p_region) const {
+ NavRegion *region = region_owner.get_or_null(p_region);
+ ERR_FAIL_COND_V(region == nullptr, RID());
+ return region->get_map()->get_self();
+}
+
+RID GodotNavigationServer::agent_get_map(RID p_agent) const {
+ RvoAgent *agent = agent_owner.get_or_null(p_agent);
+ ERR_FAIL_COND_V(agent == nullptr, RID());
+ return agent->get_map()->get_self();
+}
+
RID GodotNavigationServer::region_create() const {
GodotNavigationServer *mut_this = const_cast<GodotNavigationServer *>(this);
MutexLock lock(mut_this->operations_mutex);
diff --git a/modules/navigation/godot_navigation_server.h b/modules/navigation/godot_navigation_server.h
index c555a358db..89e7311e51 100644
--- a/modules/navigation/godot_navigation_server.h
+++ b/modules/navigation/godot_navigation_server.h
@@ -45,16 +45,16 @@
#define MERGE_INTERNAL(A, B) A##B
#define MERGE(A, B) MERGE_INTERNAL(A, B)
-#define COMMAND_1(F_NAME, T_0, D_0) \
- virtual void F_NAME(T_0 D_0) const; \
+#define COMMAND_1(F_NAME, T_0, D_0) \
+ virtual void F_NAME(T_0 D_0) const override; \
void MERGE(_cmd_, F_NAME)(T_0 D_0)
-#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \
- virtual void F_NAME(T_0 D_0, T_1 D_1) const; \
+#define COMMAND_2(F_NAME, T_0, D_0, T_1, D_1) \
+ virtual void F_NAME(T_0 D_0, T_1 D_1) const override; \
void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1)
-#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \
- virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const; \
+#define COMMAND_4_DEF(F_NAME, T_0, D_0, T_1, D_1, T_2, D_2, T_3, D_3, D_3_DEF) \
+ virtual void F_NAME(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3 = D_3_DEF) const override; \
void MERGE(_cmd_, F_NAME)(T_0 D_0, T_1 D_1, T_2 D_2, T_3 D_3)
class GodotNavigationServer;
@@ -85,39 +85,44 @@ public:
void add_command(SetCommand *command) const;
- virtual RID map_create() const;
+ virtual RID map_create() const override;
COMMAND_2(map_set_active, RID, p_map, bool, p_active);
- virtual bool map_is_active(RID p_map) const;
+ virtual bool map_is_active(RID p_map) const override;
COMMAND_2(map_set_up, RID, p_map, Vector3, p_up);
- virtual Vector3 map_get_up(RID p_map) const;
+ virtual Vector3 map_get_up(RID p_map) const override;
COMMAND_2(map_set_cell_size, RID, p_map, real_t, p_cell_size);
- virtual real_t map_get_cell_size(RID p_map) const;
+ virtual real_t map_get_cell_size(RID p_map) const override;
COMMAND_2(map_set_edge_connection_margin, RID, p_map, real_t, p_connection_margin);
- virtual real_t map_get_edge_connection_margin(RID p_map) const;
+ virtual real_t map_get_edge_connection_margin(RID p_map) const override;
- virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const;
+ virtual Vector<Vector3> map_get_path(RID p_map, Vector3 p_origin, Vector3 p_destination, bool p_optimize, uint32_t p_layers = 1) const override;
- virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const;
- virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const;
- virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const;
- virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const;
+ virtual Vector3 map_get_closest_point_to_segment(RID p_map, const Vector3 &p_from, const Vector3 &p_to, const bool p_use_collision = false) const override;
+ virtual Vector3 map_get_closest_point(RID p_map, const Vector3 &p_point) const override;
+ virtual Vector3 map_get_closest_point_normal(RID p_map, const Vector3 &p_point) const override;
+ virtual RID map_get_closest_point_owner(RID p_map, const Vector3 &p_point) const override;
- virtual RID region_create() const;
+ virtual Array map_get_regions(RID p_map) const override;
+ virtual Array map_get_agents(RID p_map) const override;
+
+ virtual RID region_create() const override;
COMMAND_2(region_set_map, RID, p_region, RID, p_map);
+ virtual RID region_get_map(RID p_region) const override;
COMMAND_2(region_set_layers, RID, p_region, uint32_t, p_layers);
- virtual uint32_t region_get_layers(RID p_region) const;
+ virtual uint32_t region_get_layers(RID p_region) const override;
COMMAND_2(region_set_transform, RID, p_region, Transform3D, p_transform);
COMMAND_2(region_set_navmesh, RID, p_region, Ref<NavigationMesh>, p_nav_mesh);
- virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const;
- virtual int region_get_connections_count(RID p_region) const;
- virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const;
- virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const;
+ virtual void region_bake_navmesh(Ref<NavigationMesh> r_mesh, Node *p_node) const override;
+ virtual int region_get_connections_count(RID p_region) const override;
+ virtual Vector3 region_get_connection_pathway_start(RID p_region, int p_connection_id) const override;
+ virtual Vector3 region_get_connection_pathway_end(RID p_region, int p_connection_id) const override;
- virtual RID agent_create() const;
+ virtual RID agent_create() const override;
COMMAND_2(agent_set_map, RID, p_agent, RID, p_map);
+ virtual RID agent_get_map(RID p_agent) const override;
COMMAND_2(agent_set_neighbor_dist, RID, p_agent, real_t, p_dist);
COMMAND_2(agent_set_max_neighbors, RID, p_agent, int, p_count);
COMMAND_2(agent_set_time_horizon, RID, p_agent, real_t, p_time);
@@ -127,15 +132,15 @@ public:
COMMAND_2(agent_set_target_velocity, RID, p_agent, Vector3, p_velocity);
COMMAND_2(agent_set_position, RID, p_agent, Vector3, p_position);
COMMAND_2(agent_set_ignore_y, RID, p_agent, bool, p_ignore);
- virtual bool agent_is_map_changed(RID p_agent) const;
+ virtual bool agent_is_map_changed(RID p_agent) const override;
COMMAND_4_DEF(agent_set_callback, RID, p_agent, Object *, p_receiver, StringName, p_method, Variant, p_udata, Variant());
COMMAND_1(free, RID, p_object);
- virtual void set_active(bool p_active) const;
+ virtual void set_active(bool p_active) const override;
void flush_queries();
- virtual void process(real_t p_delta_time);
+ virtual void process(real_t p_delta_time) override;
};
#undef COMMAND_1
diff --git a/modules/navigation/nav_map.cpp b/modules/navigation/nav_map.cpp
index 1151df6390..344475fb37 100644
--- a/modules/navigation/nav_map.cpp
+++ b/modules/navigation/nav_map.cpp
@@ -30,7 +30,6 @@
#include "nav_map.h"
-#include "core/os/threaded_array_processor.h"
#include "nav_region.h"
#include "rvo_agent.h"
@@ -142,10 +141,10 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
bool is_reachable = true;
while (true) {
- gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
-
// Takes the current least_cost_poly neighbors (iterating over its edges) and compute the traveled_distance.
- for (size_t i = 0; i < least_cost_poly->poly->edges.size(); i++) {
+ for (size_t i = 0; i < navigation_polys[least_cost_id].poly->edges.size(); i++) {
+ gd::NavigationPoly *least_cost_poly = &navigation_polys[least_cost_id];
+
const gd::Edge &edge = least_cost_poly->poly->edges[i];
// Iterate over connections in this edge, then compute the new optimized travel distance assigned to this polygon.
@@ -226,6 +225,7 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
navigation_polys.push_back(np);
to_visit.clear();
to_visit.push_back(0);
+ least_cost_id = 0;
reachable_end = nullptr;
@@ -245,6 +245,8 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
}
+ ERR_BREAK(least_cost_id == -1);
+
// Stores the further reachable end polygon, in case our goal is not reachable.
if (is_reachable) {
float d = navigation_polys[least_cost_id].entry.distance_to(p_destination);
@@ -254,8 +256,6 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
}
}
- ERR_BREAK(least_cost_id == -1);
-
// Check if we reached the end
if (navigation_polys[least_cost_id].poly == end_poly) {
found_route = true;
@@ -351,11 +351,15 @@ Vector<Vector3> NavMap::get_path(Vector3 p_origin, Vector3 p_destination, bool p
// Add mid points
int np_id = least_cost_id;
- while (np_id != -1) {
- path.push_back(navigation_polys[np_id].entry);
+ while (np_id != -1 && navigation_polys[np_id].back_navigation_poly_id != -1) {
+ int prev = navigation_polys[np_id].back_navigation_edge;
+ int prev_n = (navigation_polys[np_id].back_navigation_edge + 1) % navigation_polys[np_id].poly->points.size();
+ Vector3 point = (navigation_polys[np_id].poly->points[prev].pos + navigation_polys[np_id].poly->points[prev_n].pos) * 0.5;
+ path.push_back(point);
np_id = navigation_polys[np_id].back_navigation_poly_id;
}
+ path.push_back(begin_point);
path.reverse();
}
@@ -537,7 +541,7 @@ void NavMap::sync() {
}
// Group all edges per key.
- Map<gd::EdgeKey, Vector<gd::Edge::Connection>> connections;
+ HashMap<gd::EdgeKey, Vector<gd::Edge::Connection>, gd::EdgeKey> connections;
for (size_t poly_id(0); poly_id < polygons.size(); poly_id++) {
gd::Polygon &poly(polygons[poly_id]);
@@ -545,7 +549,7 @@ void NavMap::sync() {
int next_point = (p + 1) % poly.points.size();
gd::EdgeKey ek(poly.points[p].key, poly.points[next_point].key);
- Map<gd::EdgeKey, Vector<gd::Edge::Connection>>::Element *connection = connections.find(ek);
+ HashMap<gd::EdgeKey, Vector<gd::Edge::Connection>, gd::EdgeKey>::Iterator connection = connections.find(ek);
if (!connection) {
connections[ek] = Vector<gd::Edge::Connection>();
}
@@ -669,7 +673,10 @@ void NavMap::compute_single_step(uint32_t index, RvoAgent **agent) {
void NavMap::step(real_t p_deltatime) {
deltatime = p_deltatime;
if (controlled_agents.size() > 0) {
- thread_process_array(
+ if (step_work_pool.get_thread_count() == 0) {
+ step_work_pool.init();
+ }
+ step_work_pool.do_work(
controlled_agents.size(),
this,
&NavMap::compute_single_step,
@@ -714,3 +721,10 @@ void NavMap::clip_path(const std::vector<gd::NavigationPoly> &p_navigation_polys
}
}
}
+
+NavMap::NavMap() {
+}
+
+NavMap::~NavMap() {
+ step_work_pool.finish();
+}
diff --git a/modules/navigation/nav_map.h b/modules/navigation/nav_map.h
index f46297a7ce..0ebdea30e1 100644
--- a/modules/navigation/nav_map.h
+++ b/modules/navigation/nav_map.h
@@ -34,7 +34,8 @@
#include "nav_rid.h"
#include "core/math/math_defs.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
+#include "core/templates/thread_work_pool.h"
#include "nav_utils.h"
#include <KdTree.h>
@@ -80,8 +81,12 @@ class NavMap : public NavRid {
/// Change the id each time the map is updated.
uint32_t map_update_id = 0;
+ /// Pooled threads for computing steps
+ ThreadWorkPool step_work_pool;
+
public:
- NavMap() {}
+ NavMap();
+ ~NavMap();
void set_up(Vector3 p_up);
Vector3 get_up() const {
diff --git a/modules/navigation/nav_utils.h b/modules/navigation/nav_utils.h
index 0c02885b10..a9f4e0e2fc 100644
--- a/modules/navigation/nav_utils.h
+++ b/modules/navigation/nav_utils.h
@@ -32,8 +32,9 @@
#define NAV_UTILS_H
#include "core/math/vector3.h"
+#include "core/templates/hash_map.h"
+#include "core/templates/hashfuncs.h"
#include "core/templates/vector.h"
-
#include <vector>
class NavRegion;
@@ -49,15 +50,18 @@ union PointKey {
};
uint64_t key = 0;
- bool operator<(const PointKey &p_key) const { return key < p_key.key; }
};
struct EdgeKey {
PointKey a;
PointKey b;
- bool operator<(const EdgeKey &p_key) const {
- return (a.key == p_key.a.key) ? (b.key < p_key.b.key) : (a.key < p_key.a.key);
+ static uint32_t hash(const EdgeKey &p_val) {
+ return hash_one_uint64(p_val.a.key) ^ hash_one_uint64(p_val.b.key);
+ }
+
+ bool operator==(const EdgeKey &p_key) const {
+ return (a.key == p_key.a.key) && (b.key == p_key.b.key);
}
EdgeKey(const PointKey &p_a = PointKey(), const PointKey &p_b = PointKey()) :
@@ -89,7 +93,7 @@ struct Edge {
};
struct Polygon {
- NavRegion *owner;
+ NavRegion *owner = nullptr;
/// The points of this `Polygon`
std::vector<Point> points;
diff --git a/modules/navigation/navigation_mesh_generator.cpp b/modules/navigation/navigation_mesh_generator.cpp
index 61c3cefc7a..5cbaded6c1 100644
--- a/modules/navigation/navigation_mesh_generator.cpp
+++ b/modules/navigation/navigation_mesh_generator.cpp
@@ -34,7 +34,6 @@
#include "core/math/convex_hull.h"
#include "core/os/thread.h"
-#include "scene/3d/collision_shape_3d.h"
#include "scene/3d/mesh_instance_3d.h"
#include "scene/3d/multimesh_instance_3d.h"
#include "scene/3d/physics_body_3d.h"
@@ -124,6 +123,28 @@ void NavigationMeshGenerator::_add_mesh(const Ref<Mesh> &p_mesh, const Transform
}
}
+void NavigationMeshGenerator::_add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) {
+ Vector<Vector3> mesh_vertices = p_array[Mesh::ARRAY_VERTEX];
+ const Vector3 *vr = mesh_vertices.ptr();
+
+ Vector<int> mesh_indices = p_array[Mesh::ARRAY_INDEX];
+ const int *ir = mesh_indices.ptr();
+
+ const int face_count = mesh_indices.size() / 3;
+ const int current_vertex_count = p_vertices.size() / 3;
+
+ for (int j = 0; j < mesh_vertices.size(); j++) {
+ _add_vertex(p_xform.xform(vr[j]), p_vertices);
+ }
+
+ for (int j = 0; j < face_count; j++) {
+ // CCW
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 0]));
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 2]));
+ p_indices.push_back(current_vertex_count + (ir[j * 3 + 1]));
+ }
+}
+
void NavigationMeshGenerator::_add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices) {
int face_count = p_faces.size() / 3;
int current_vertex_count = p_vertices.size() / 3;
@@ -180,50 +201,48 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
StaticBody3D *static_body = Object::cast_to<StaticBody3D>(p_node);
if (static_body->get_collision_layer() & p_collision_mask) {
- for (int i = 0; i < p_node->get_child_count(); ++i) {
- Node *child = p_node->get_child(i);
- if (Object::cast_to<CollisionShape3D>(child)) {
- CollisionShape3D *col_shape = Object::cast_to<CollisionShape3D>(child);
-
- Transform3D transform = p_navmesh_transform * static_body->get_global_transform() * col_shape->get_transform();
+ List<uint32_t> shape_owners;
+ static_body->get_shape_owners(&shape_owners);
+ for (uint32_t shape_owner : shape_owners) {
+ const int shape_count = static_body->shape_owner_get_shape_count(shape_owner);
+ for (int i = 0; i < shape_count; i++) {
+ Ref<Shape3D> s = static_body->shape_owner_get_shape(shape_owner, i);
+ if (s.is_null()) {
+ continue;
+ }
- Ref<Mesh> mesh;
- Ref<Shape3D> s = col_shape->get_shape();
+ const Transform3D transform = p_navmesh_transform * static_body->get_global_transform() * static_body->shape_owner_get_transform(shape_owner);
BoxShape3D *box = Object::cast_to<BoxShape3D>(*s);
if (box) {
- Ref<BoxMesh> box_mesh;
- box_mesh.instantiate();
- box_mesh->set_size(box->get_size());
- mesh = box_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(arr, box->get_size());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
CapsuleShape3D *capsule = Object::cast_to<CapsuleShape3D>(*s);
if (capsule) {
- Ref<CapsuleMesh> capsule_mesh;
- capsule_mesh.instantiate();
- capsule_mesh->set_radius(capsule->get_radius());
- capsule_mesh->set_height(capsule->get_height());
- mesh = capsule_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CapsuleMesh::create_mesh_array(arr, capsule->get_radius(), capsule->get_height());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
CylinderShape3D *cylinder = Object::cast_to<CylinderShape3D>(*s);
if (cylinder) {
- Ref<CylinderMesh> cylinder_mesh;
- cylinder_mesh.instantiate();
- cylinder_mesh->set_height(cylinder->get_height());
- cylinder_mesh->set_bottom_radius(cylinder->get_radius());
- cylinder_mesh->set_top_radius(cylinder->get_radius());
- mesh = cylinder_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CylinderMesh::create_mesh_array(arr, cylinder->get_radius(), cylinder->get_radius(), cylinder->get_height());
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
SphereShape3D *sphere = Object::cast_to<SphereShape3D>(*s);
if (sphere) {
- Ref<SphereMesh> sphere_mesh;
- sphere_mesh.instantiate();
- sphere_mesh->set_radius(sphere->get_radius());
- sphere_mesh->set_height(sphere->get_radius() * 2.0);
- mesh = sphere_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ SphereMesh::create_mesh_array(arr, sphere->get_radius(), sphere->get_radius() * 2.0);
+ _add_mesh_array(arr, transform, p_vertices, p_indices);
}
ConcavePolygonShape3D *concave_polygon = Object::cast_to<ConcavePolygonShape3D>(*s);
@@ -254,10 +273,6 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
_add_faces(faces, transform, p_vertices, p_indices);
}
}
-
- if (mesh.is_valid()) {
- _add_mesh(mesh, transform, p_vertices, p_indices);
- }
}
}
}
@@ -284,44 +299,39 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
RID shape = shapes[i + 1];
PhysicsServer3D::ShapeType type = PhysicsServer3D::get_singleton()->shape_get_type(shape);
Variant data = PhysicsServer3D::get_singleton()->shape_get_data(shape);
- Ref<Mesh> mesh;
switch (type) {
case PhysicsServer3D::SHAPE_SPHERE: {
real_t radius = data;
- Ref<SphereMesh> sphere_mesh;
- sphere_mesh.instantiate();
- sphere_mesh->set_radius(radius);
- sphere_mesh->set_height(radius * 2.0);
- mesh = sphere_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ SphereMesh::create_mesh_array(arr, radius, radius * 2.0);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
} break;
case PhysicsServer3D::SHAPE_BOX: {
Vector3 extents = data;
- Ref<BoxMesh> box_mesh;
- box_mesh.instantiate();
- box_mesh->set_size(2.0 * extents);
- mesh = box_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ BoxMesh::create_mesh_array(arr, extents * 2.0);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
} break;
case PhysicsServer3D::SHAPE_CAPSULE: {
Dictionary dict = data;
real_t radius = dict["radius"];
real_t height = dict["height"];
- Ref<CapsuleMesh> capsule_mesh;
- capsule_mesh.instantiate();
- capsule_mesh->set_radius(radius);
- capsule_mesh->set_height(height);
- mesh = capsule_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CapsuleMesh::create_mesh_array(arr, radius, height);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
} break;
case PhysicsServer3D::SHAPE_CYLINDER: {
Dictionary dict = data;
real_t radius = dict["radius"];
real_t height = dict["height"];
- Ref<CylinderMesh> cylinder_mesh;
- cylinder_mesh.instantiate();
- cylinder_mesh->set_height(height);
- cylinder_mesh->set_bottom_radius(radius);
- cylinder_mesh->set_top_radius(radius);
- mesh = cylinder_mesh;
+ Array arr;
+ arr.resize(RS::ARRAY_MAX);
+ CylinderMesh::create_mesh_array(arr, radius, radius, height);
+ _add_mesh_array(arr, shapes[i], p_vertices, p_indices);
} break;
case PhysicsServer3D::SHAPE_CONVEX_POLYGON: {
PackedVector3Array vertices = data;
@@ -354,10 +364,6 @@ void NavigationMeshGenerator::_parse_geometry(const Transform3D &p_navmesh_trans
WARN_PRINT("Unsupported collision shape type.");
} break;
}
-
- if (mesh.is_valid()) {
- _add_mesh(mesh, shapes[i], p_vertices, p_indices);
- }
}
}
}
@@ -439,7 +445,7 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
cfg.minRegionArea = (int)(p_nav_mesh->get_region_min_size() * p_nav_mesh->get_region_min_size());
cfg.mergeRegionArea = (int)(p_nav_mesh->get_region_merge_size() * p_nav_mesh->get_region_merge_size());
cfg.maxVertsPerPoly = (int)p_nav_mesh->get_verts_per_poly();
- cfg.detailSampleDist = p_nav_mesh->get_detail_sample_distance() < 0.9f ? 0 : p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance();
+ cfg.detailSampleDist = MAX(p_nav_mesh->get_cell_size() * p_nav_mesh->get_detail_sample_distance(), 0.1f);
cfg.detailSampleMaxError = p_nav_mesh->get_cell_height() * p_nav_mesh->get_detail_sample_max_error();
cfg.bmin[0] = bmin[0];
@@ -456,6 +462,14 @@ void NavigationMeshGenerator::_build_recast_navigation_mesh(
#endif
rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
+ // ~30000000 seems to be around sweetspot where Editor baking breaks
+ if ((cfg.width * cfg.height) > 30000000) {
+ WARN_PRINT("NavigationMesh baking process will likely fail."
+ "\nSource geometry is suspiciously big for the current Cell Size and Cell Height in the NavMesh Resource bake settings."
+ "\nIf baking does not fail, the resulting NavigationMesh will create serious pathfinding performance issues."
+ "\nIt is advised to increase Cell Size and/or Cell Height in the NavMesh Resource bake settings or reduce the size / scale of the source geometry.");
+ }
+
#ifdef TOOLS_ENABLED
if (ep) {
ep->step(TTR("Creating heightfield..."), 3);
diff --git a/modules/navigation/navigation_mesh_generator.h b/modules/navigation/navigation_mesh_generator.h
index 21f7a4941b..8cc1531b53 100644
--- a/modules/navigation/navigation_mesh_generator.h
+++ b/modules/navigation/navigation_mesh_generator.h
@@ -51,6 +51,7 @@ protected:
static void _add_vertex(const Vector3 &p_vec3, Vector<float> &p_vertices);
static void _add_mesh(const Ref<Mesh> &p_mesh, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices);
+ static void _add_mesh_array(const Array &p_array, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices);
static void _add_faces(const PackedVector3Array &p_faces, const Transform3D &p_xform, Vector<float> &p_vertices, Vector<int> &p_indices);
static void _parse_geometry(const Transform3D &p_navmesh_transform, Node *p_node, Vector<float> &p_vertices, Vector<int> &p_indices, NavigationMesh::ParsedGeometryType p_generate_from, uint32_t p_collision_mask, bool p_recurse_children);
diff --git a/modules/navigation/register_types.cpp b/modules/navigation/register_types.cpp
index 218f2c2937..62ae2c7f02 100644
--- a/modules/navigation/register_types.cpp
+++ b/modules/navigation/register_types.cpp
@@ -51,21 +51,29 @@ NavigationServer3D *new_server() {
return memnew(GodotNavigationServer);
}
-void register_navigation_types() {
- NavigationServer3DManager::set_default_server(new_server);
+void initialize_navigation_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ NavigationServer3DManager::set_default_server(new_server);
#ifndef _3D_DISABLED
- _nav_mesh_generator = memnew(NavigationMeshGenerator);
- GDREGISTER_CLASS(NavigationMeshGenerator);
- Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", NavigationMeshGenerator::get_singleton()));
+ _nav_mesh_generator = memnew(NavigationMeshGenerator);
+ GDREGISTER_CLASS(NavigationMeshGenerator);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationMeshGenerator", NavigationMeshGenerator::get_singleton()));
#endif
+ }
#ifdef TOOLS_ENABLED
- EditorPlugins::add_by_type<NavigationMeshEditorPlugin>();
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<NavigationMeshEditorPlugin>();
+ }
#endif
}
-void unregister_navigation_types() {
+void uninitialize_navigation_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
+
#ifndef _3D_DISABLED
if (_nav_mesh_generator) {
memdelete(_nav_mesh_generator);
diff --git a/modules/navigation/register_types.h b/modules/navigation/register_types.h
index 11fa5769d7..c4dbd19ed3 100644
--- a/modules/navigation/register_types.h
+++ b/modules/navigation/register_types.h
@@ -31,7 +31,9 @@
#ifndef NAVIGATION_REGISTER_TYPES_H
#define NAVIGATION_REGISTER_TYPES_H
-void register_navigation_types();
-void unregister_navigation_types();
+#include "modules/register_module_types.h"
+
+void initialize_navigation_module(ModuleInitializationLevel p_level);
+void uninitialize_navigation_module(ModuleInitializationLevel p_level);
#endif // NAVIGATION_REGISTER_TYPES_H
diff --git a/modules/noise/SCsub b/modules/noise/SCsub
index 3e8395b9b1..1430aa0c4e 100644
--- a/modules/noise/SCsub
+++ b/modules/noise/SCsub
@@ -27,6 +27,7 @@ env.modules_sources += thirdparty_obj
module_obj = []
env_noise.add_source_files(module_obj, "*.cpp")
+env_noise.add_source_files(module_obj, "editor/*.cpp")
env.modules_sources += module_obj
# Needed to force rebuilding the module files when the thirdparty library is updated.
diff --git a/modules/noise/doc_classes/FastNoiseLite.xml b/modules/noise/doc_classes/FastNoiseLite.xml
index b6d91850c4..6ca4ba2d46 100644
--- a/modules/noise/doc_classes/FastNoiseLite.xml
+++ b/modules/noise/doc_classes/FastNoiseLite.xml
@@ -16,12 +16,9 @@
<member name="cellular_jitter" type="float" setter="set_cellular_jitter" getter="get_cellular_jitter" default="0.45">
Maximum distance a point can move off of its grid position. Set to [code]0[/code] for an even grid.
</member>
- <member name="cellular_return_type" type="int" setter="set_cellular_return_type" getter="get_cellular_return_type" enum="FastNoiseLite.CellularReturnType" default="0">
+ <member name="cellular_return_type" type="int" setter="set_cellular_return_type" getter="get_cellular_return_type" enum="FastNoiseLite.CellularReturnType" default="1">
Return type from cellular noise calculations. See [enum CellularReturnType].
</member>
- <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp">
- A [Gradient] which is used to map the luminance of each pixel to a color value.
- </member>
<member name="domain_warp_amplitude" type="float" setter="set_domain_warp_amplitude" getter="get_domain_warp_amplitude" default="30.0">
Sets the maximum warp distance from the origin.
</member>
@@ -69,9 +66,6 @@
<member name="frequency" type="float" setter="set_frequency" getter="get_frequency" default="0.01">
The frequency for all noise types. Low frequency results in smooth noise while high frequency results in rougher, more granular noise.
</member>
- <member name="in_3d_space" type="bool" setter="set_in_3d_space" getter="is_in_3d_space" default="false">
- Determines whether the noise image returned by [method Noise.get_image] is calculated in 3d space. May result in reduced contrast.
- </member>
<member name="noise_type" type="int" setter="set_noise_type" getter="get_noise_type" enum="FastNoiseLite.NoiseType" default="1">
The noise algorithm used. See [enum NoiseType].
</member>
diff --git a/modules/noise/doc_classes/Noise.xml b/modules/noise/doc_classes/Noise.xml
index db0dec18d2..5af204575c 100644
--- a/modules/noise/doc_classes/Noise.xml
+++ b/modules/noise/doc_classes/Noise.xml
@@ -11,23 +11,24 @@
<tutorials>
</tutorials>
<methods>
- <method name="get_image">
+ <method name="get_image" qualifiers="const">
<return type="Image" />
<argument index="0" name="width" type="int" />
<argument index="1" name="height" type="int" />
<argument index="2" name="invert" type="bool" default="false" />
+ <argument index="3" name="in_3d_space" type="bool" default="false" />
<description>
Returns a 2D [Image] noise image.
</description>
</method>
- <method name="get_noise_1d">
+ <method name="get_noise_1d" qualifiers="const">
<return type="float" />
<argument index="0" name="x" type="float" />
<description>
Returns the 1D noise value at the given (x) coordinate.
</description>
</method>
- <method name="get_noise_2d">
+ <method name="get_noise_2d" qualifiers="const">
<return type="float" />
<argument index="0" name="x" type="float" />
<argument index="1" name="y" type="float" />
@@ -35,14 +36,14 @@
Returns the 2D noise value at the given position.
</description>
</method>
- <method name="get_noise_2dv">
+ <method name="get_noise_2dv" qualifiers="const">
<return type="float" />
<argument index="0" name="v" type="Vector2" />
<description>
Returns the 2D noise value at the given position.
</description>
</method>
- <method name="get_noise_3d">
+ <method name="get_noise_3d" qualifiers="const">
<return type="float" />
<argument index="0" name="x" type="float" />
<argument index="1" name="y" type="float" />
@@ -51,19 +52,20 @@
Returns the 3D noise value at the given position.
</description>
</method>
- <method name="get_noise_3dv">
+ <method name="get_noise_3dv" qualifiers="const">
<return type="float" />
<argument index="0" name="v" type="Vector3" />
<description>
Returns the 3D noise value at the given position.
</description>
</method>
- <method name="get_seamless_image">
+ <method name="get_seamless_image" qualifiers="const">
<return type="Image" />
<argument index="0" name="width" type="int" />
<argument index="1" name="height" type="int" />
<argument index="2" name="invert" type="bool" default="false" />
- <argument index="3" name="skirt" type="float" default="0.1" />
+ <argument index="3" name="in_3d_space" type="bool" default="false" />
+ <argument index="4" name="skirt" type="float" default="0.1" />
<description>
Returns a seamless 2D [Image] noise image.
</description>
diff --git a/modules/noise/doc_classes/NoiseTexture.xml b/modules/noise/doc_classes/NoiseTexture.xml
index 63630eccde..62a223b387 100644
--- a/modules/noise/doc_classes/NoiseTexture.xml
+++ b/modules/noise/doc_classes/NoiseTexture.xml
@@ -24,9 +24,20 @@
<member name="bump_strength" type="float" setter="set_bump_strength" getter="get_bump_strength" default="8.0">
Strength of the bump maps used in this texture. A higher value will make the bump maps appear larger while a lower value will make them appear softer.
</member>
+ <member name="color_ramp" type="Gradient" setter="set_color_ramp" getter="get_color_ramp">
+ A [Gradient] which is used to map the luminance of each pixel to a color value.
+ </member>
+ <member name="generate_mipmaps" type="bool" setter="set_generate_mipmaps" getter="is_generating_mipmaps" default="true">
+ Determines whether mipmaps are generated for this texture.
+ Enabling this results in less texture aliasing, but the noise texture generation may take longer.
+ Requires (anisotropic) mipmap filtering to be enabled for a material to have an effect.
+ </member>
<member name="height" type="int" setter="set_height" getter="get_height" default="512">
Height of the generated texture.
</member>
+ <member name="in_3d_space" type="bool" setter="set_in_3d_space" getter="is_in_3d_space" default="false">
+ Determines whether the noise image is calculated in 3D space. May result in reduced contrast.
+ </member>
<member name="invert" type="bool" setter="set_invert" getter="get_invert" default="false">
If [code]true[/code], inverts the noise texture. White becomes black, black becomes white.
</member>
diff --git a/modules/noise/editor/noise_editor_plugin.cpp b/modules/noise/editor/noise_editor_plugin.cpp
new file mode 100644
index 0000000000..32c3f0aad4
--- /dev/null
+++ b/modules/noise/editor/noise_editor_plugin.cpp
@@ -0,0 +1,149 @@
+/*************************************************************************/
+/* noise_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "noise_editor_plugin.h"
+
+#ifdef TOOLS_ENABLED
+
+#include "editor/editor_scale.h"
+
+#include "modules/noise/noise.h"
+#include "modules/noise/noise_texture.h"
+
+class NoisePreview : public Control {
+ GDCLASS(NoisePreview, Control)
+
+ static const int PREVIEW_HEIGHT = 150;
+ static const int PADDING_3D_SPACE_SWITCH = 2;
+
+ Ref<Noise> _noise;
+ Size2i _preview_texture_size;
+
+ TextureRect *_texture_rect = nullptr;
+ Button *_3d_space_switch = nullptr;
+
+public:
+ NoisePreview() {
+ set_custom_minimum_size(Size2(0, EDSCALE * PREVIEW_HEIGHT));
+
+ _texture_rect = memnew(TextureRect);
+ _texture_rect->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ _texture_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_COVERED);
+ add_child(_texture_rect);
+
+ _3d_space_switch = memnew(Button);
+ _3d_space_switch->set_text(TTR("3D"));
+ _3d_space_switch->set_tooltip(TTR("Toggles whether the noise preview is computed in 3D space."));
+ _3d_space_switch->set_toggle_mode(true);
+ _3d_space_switch->set_offset(SIDE_LEFT, PADDING_3D_SPACE_SWITCH);
+ _3d_space_switch->set_offset(SIDE_TOP, PADDING_3D_SPACE_SWITCH);
+ _3d_space_switch->connect("pressed", callable_mp(this, &NoisePreview::_on_3d_button_pressed));
+ add_child(_3d_space_switch);
+ }
+
+ void set_noise(Ref<Noise> noise) {
+ if (_noise == noise) {
+ return;
+ }
+ _noise = noise;
+ if (_noise.is_valid()) {
+ if (_noise->has_meta("_preview_in_3d_space_")) {
+ _3d_space_switch->set_pressed(true);
+ }
+
+ update_preview();
+ }
+ }
+
+private:
+ void _on_3d_button_pressed() {
+ if (_3d_space_switch->is_pressed()) {
+ _noise->set_meta("_preview_in_3d_space_", true);
+ } else {
+ _noise->remove_meta("_preview_in_3d_space_");
+ }
+ }
+
+ void _notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_RESIZED: {
+ _preview_texture_size = get_size();
+ update_preview();
+ } break;
+ }
+ }
+
+ void update_preview() {
+ if (MIN(_preview_texture_size.width, _preview_texture_size.height) > 0) {
+ Ref<NoiseTexture> tex;
+ tex.instantiate();
+ tex->set_width(_preview_texture_size.width);
+ tex->set_height(_preview_texture_size.height);
+ tex->set_in_3d_space(_3d_space_switch->is_pressed());
+ tex->set_noise(_noise);
+ _texture_rect->set_texture(tex);
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+class NoiseEditorInspectorPlugin : public EditorInspectorPlugin {
+ GDCLASS(NoiseEditorInspectorPlugin, EditorInspectorPlugin)
+public:
+ bool can_handle(Object *p_object) override {
+ return Object::cast_to<Noise>(p_object) != nullptr;
+ }
+
+ void parse_begin(Object *p_object) override {
+ Noise *noise_ptr = Object::cast_to<Noise>(p_object);
+ if (noise_ptr) {
+ Ref<Noise> noise(noise_ptr);
+
+ NoisePreview *viewer = memnew(NoisePreview);
+ viewer->set_noise(noise);
+ add_custom_control(viewer);
+ }
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////
+
+String NoiseEditorPlugin::get_name() const {
+ return Noise::get_class_static();
+}
+
+NoiseEditorPlugin::NoiseEditorPlugin() {
+ Ref<NoiseEditorInspectorPlugin> plugin;
+ plugin.instantiate();
+ add_inspector_plugin(plugin);
+}
+
+#endif // TOOLS_ENABLED
diff --git a/modules/noise/editor/noise_editor_plugin.h b/modules/noise/editor/noise_editor_plugin.h
new file mode 100644
index 0000000000..55a01deb2d
--- /dev/null
+++ b/modules/noise/editor/noise_editor_plugin.h
@@ -0,0 +1,49 @@
+/*************************************************************************/
+/* noise_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 NOISE_EDITOR_PLUGIN_H
+#define NOISE_EDITOR_PLUGIN_H
+
+#ifdef TOOLS_ENABLED
+
+#include "editor/editor_plugin.h"
+
+class NoiseEditorPlugin : public EditorPlugin {
+ GDCLASS(NoiseEditorPlugin, EditorPlugin)
+
+public:
+ String get_name() const override;
+
+ NoiseEditorPlugin();
+};
+
+#endif // TOOLS_ENABLED
+
+#endif // NOISE_EDITOR_PLUGIN_H
diff --git a/modules/noise/fastnoise_lite.cpp b/modules/noise/fastnoise_lite.cpp
index 974b5c55bb..a8d38dee62 100644
--- a/modules/noise/fastnoise_lite.cpp
+++ b/modules/noise/fastnoise_lite.cpp
@@ -31,31 +31,29 @@
#include "fastnoise_lite.h"
FastNoiseLite::FastNoiseLite() {
- // Most defaults copied from the library.
- set_noise_type(TYPE_SIMPLEX_SMOOTH);
- set_seed(0);
- set_frequency(0.01);
- set_in_3d_space(false);
-
- set_fractal_type(FRACTAL_FBM);
- set_fractal_octaves(5);
- set_fractal_lacunarity(2.0);
- set_fractal_gain(0.5);
- set_fractal_weighted_strength(0.0);
- set_fractal_ping_pong_strength(2.0);
-
- set_cellular_distance_function(DISTANCE_EUCLIDEAN);
- set_cellular_return_type(RETURN_CELL_VALUE);
- set_cellular_jitter(0.45);
-
- set_domain_warp_enabled(false);
- set_domain_warp_type(DOMAIN_WARP_SIMPLEX);
- set_domain_warp_amplitude(30.0);
- set_domain_warp_frequency(0.05);
- set_domain_warp_fractal_type(DOMAIN_WARP_FRACTAL_PROGRESSIVE);
- set_domain_warp_fractal_octaves(5);
- set_domain_warp_fractal_lacunarity(6);
- set_domain_warp_fractal_gain(0.5);
+ _noise.SetNoiseType((_FastNoiseLite::NoiseType)noise_type);
+ _noise.SetSeed(seed);
+ _noise.SetFrequency(frequency);
+
+ _noise.SetFractalType((_FastNoiseLite::FractalType)fractal_type);
+ _noise.SetFractalOctaves(fractal_octaves);
+ _noise.SetFractalLacunarity(fractal_lacunarity);
+ _noise.SetFractalGain(fractal_gain);
+ _noise.SetFractalWeightedStrength(fractal_weighted_strength);
+ _noise.SetFractalPingPongStrength(fractal_ping_pong_strength);
+
+ _noise.SetCellularDistanceFunction((_FastNoiseLite::CellularDistanceFunction)cellular_distance_function);
+ _noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)cellular_return_type);
+ _noise.SetCellularJitter(cellular_jitter);
+
+ _domain_warp_noise.SetDomainWarpType((_FastNoiseLite::DomainWarpType)domain_warp_type);
+ _domain_warp_noise.SetSeed(seed);
+ _domain_warp_noise.SetDomainWarpAmp(domain_warp_amplitude);
+ _domain_warp_noise.SetFrequency(domain_warp_frequency);
+ _domain_warp_noise.SetFractalType(_FastNoiseLite::FractalType_None);
+ _domain_warp_noise.SetFractalOctaves(domain_warp_fractal_octaves);
+ _domain_warp_noise.SetFractalLacunarity(domain_warp_fractal_lacunarity);
+ _domain_warp_noise.SetFractalGain(domain_warp_fractal_gain);
}
FastNoiseLite::~FastNoiseLite() {
@@ -77,6 +75,7 @@ FastNoiseLite::NoiseType FastNoiseLite::get_noise_type() const {
void FastNoiseLite::set_seed(int p_seed) {
seed = p_seed;
_noise.SetSeed(p_seed);
+ _domain_warp_noise.SetSeed(p_seed);
emit_changed();
}
@@ -94,14 +93,6 @@ real_t FastNoiseLite::get_frequency() const {
return frequency;
}
-void FastNoiseLite::set_in_3d_space(bool p_enable) {
- in_3d_space = p_enable;
- emit_changed();
-}
-bool FastNoiseLite::is_in_3d_space() const {
- return in_3d_space;
-}
-
void FastNoiseLite::set_offset(Vector3 p_offset) {
offset = p_offset;
emit_changed();
@@ -111,46 +102,6 @@ Vector3 FastNoiseLite::get_offset() const {
return offset;
}
-void FastNoiseLite::set_color_ramp(const Ref<Gradient> &p_gradient) {
- color_ramp = p_gradient;
- if (color_ramp.is_valid()) {
- color_ramp->connect(SNAME("changed"), callable_mp(this, &FastNoiseLite::_changed));
- emit_changed();
- }
-}
-
-Ref<Gradient> FastNoiseLite::get_color_ramp() const {
- return color_ramp;
-}
-
-// Noise functions.
-
-real_t FastNoiseLite::get_noise_1d(real_t p_x) {
- return get_noise_2d(p_x, 0.0);
-}
-
-real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) {
- return get_noise_2d(p_v.x, p_v.y);
-}
-
-real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) {
- if (domain_warp_enabled) {
- _domain_warp_noise.DomainWarp(p_x, p_y);
- }
- return _noise.GetNoise(p_x + offset.x, p_y + offset.y);
-}
-
-real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) {
- return get_noise_3d(p_v.x, p_v.y, p_v.z);
-}
-
-real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) {
- if (domain_warp_enabled) {
- _domain_warp_noise.DomainWarp(p_x, p_y, p_z);
- }
- return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z);
-}
-
// Fractal.
void FastNoiseLite::set_fractal_type(FractalType p_type) {
@@ -204,12 +155,12 @@ real_t FastNoiseLite::get_fractal_weighted_strength() const {
}
void FastNoiseLite::set_fractal_ping_pong_strength(real_t p_ping_pong_strength) {
- fractal_pinp_pong_strength = p_ping_pong_strength;
+ fractal_ping_pong_strength = p_ping_pong_strength;
_noise.SetFractalPingPongStrength(p_ping_pong_strength);
emit_changed();
}
real_t FastNoiseLite::get_fractal_ping_pong_strength() const {
- return fractal_pinp_pong_strength;
+ return fractal_ping_pong_strength;
}
// Cellular.
@@ -237,7 +188,6 @@ real_t FastNoiseLite::get_cellular_jitter() const {
void FastNoiseLite::set_cellular_return_type(CellularReturnType p_ret) {
cellular_return_type = p_ret;
_noise.SetCellularReturnType((_FastNoiseLite::CellularReturnType)p_ret);
-
emit_changed();
}
@@ -345,68 +295,32 @@ real_t FastNoiseLite::get_domain_warp_fractal_gain() const {
return domain_warp_fractal_gain;
}
-// Textures.
+// Noise interface functions.
-Ref<Image> FastNoiseLite::get_image(int p_width, int p_height, bool p_invert) {
- bool grayscale = color_ramp.is_null();
-
- Vector<uint8_t> data;
- data.resize(p_width * p_height * (grayscale ? 1 : 4));
-
- uint8_t *wd8 = data.ptrw();
+real_t FastNoiseLite::get_noise_1d(real_t p_x) const {
+ return get_noise_2d(p_x, 0.0);
+}
- // Get all values and identify min/max values.
- Vector<real_t> values;
- values.resize(p_width * p_height);
- real_t min_val = 100;
- real_t max_val = -100;
+real_t FastNoiseLite::get_noise_2dv(Vector2 p_v) const {
+ return get_noise_2d(p_v.x, p_v.y);
+}
- for (int y = 0, i = 0; y < p_height; y++) {
- for (int x = 0; x < p_width; x++, i++) {
- values.set(i, is_in_3d_space() ? get_noise_3d(x, y, 0.0) : get_noise_2d(x, y));
- if (values[i] > max_val) {
- max_val = values[i];
- }
- if (values[i] < min_val) {
- min_val = values[i];
- }
- }
+real_t FastNoiseLite::get_noise_2d(real_t p_x, real_t p_y) const {
+ if (domain_warp_enabled) {
+ _domain_warp_noise.DomainWarp(p_x, p_y);
}
+ return _noise.GetNoise(p_x + offset.x, p_y + offset.y);
+}
- // Normalize values and write to texture.
- uint8_t value;
- for (int i = 0, x = 0; i < p_height; i++) {
- for (int j = 0; j < p_width; j++, x++) {
- if (max_val == min_val) {
- value = 0;
- } else {
- value = uint8_t(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255));
- }
- if (p_invert) {
- value = 255 - value;
- }
- if (grayscale) {
- wd8[x] = value;
- } else {
- float luminance = value / 255.0;
- Color ramp_color = color_ramp->get_color_at_offset(luminance);
- wd8[x * 4 + 0] = uint8_t(CLAMP(ramp_color.r * 255, 0, 255));
- wd8[x * 4 + 1] = uint8_t(CLAMP(ramp_color.g * 255, 0, 255));
- wd8[x * 4 + 2] = uint8_t(CLAMP(ramp_color.b * 255, 0, 255));
- wd8[x * 4 + 3] = uint8_t(CLAMP(ramp_color.a * 255, 0, 255));
- }
- }
- }
- if (grayscale) {
- return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
- } else {
- return memnew(Image(p_width, p_height, false, Image::FORMAT_RGBA8, data));
- }
+real_t FastNoiseLite::get_noise_3dv(Vector3 p_v) const {
+ return get_noise_3d(p_v.x, p_v.y, p_v.z);
}
-Ref<Image> FastNoiseLite::get_seamless_image(int p_width, int p_height, bool p_invert, real_t p_blend_skirt) {
- // Just return parent function. This is here only so Godot will properly document this function.
- return Noise::get_seamless_image(p_width, p_height, p_invert, p_blend_skirt);
+real_t FastNoiseLite::get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const {
+ if (domain_warp_enabled) {
+ _domain_warp_noise.DomainWarp(p_x, p_y, p_z);
+ }
+ return _noise.GetNoise(p_x + offset.x, p_y + offset.y, p_z + offset.z);
}
void FastNoiseLite::_changed() {
@@ -418,108 +332,103 @@ void FastNoiseLite::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_noise_type", "type"), &FastNoiseLite::set_noise_type);
ClassDB::bind_method(D_METHOD("get_noise_type"), &FastNoiseLite::get_noise_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type");
ClassDB::bind_method(D_METHOD("set_seed", "seed"), &FastNoiseLite::set_seed);
ClassDB::bind_method(D_METHOD("get_seed"), &FastNoiseLite::get_seed);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
ClassDB::bind_method(D_METHOD("set_frequency", "freq"), &FastNoiseLite::set_frequency);
ClassDB::bind_method(D_METHOD("get_frequency"), &FastNoiseLite::get_frequency);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".001,1"), "set_frequency", "get_frequency");
-
- ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &FastNoiseLite::set_in_3d_space);
- ClassDB::bind_method(D_METHOD("is_in_3d_space"), &FastNoiseLite::is_in_3d_space);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space");
ClassDB::bind_method(D_METHOD("set_offset", "offset"), &FastNoiseLite::set_offset);
ClassDB::bind_method(D_METHOD("get_offset"), &FastNoiseLite::get_offset);
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,1"), "set_offset", "get_offset");
-
- ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &FastNoiseLite::set_color_ramp);
- ClassDB::bind_method(D_METHOD("get_color_ramp"), &FastNoiseLite::get_color_ramp);
- ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
// Fractal.
- ADD_GROUP("Fractal", "fractal_");
ClassDB::bind_method(D_METHOD("set_fractal_type", "type"), &FastNoiseLite::set_fractal_type);
ClassDB::bind_method(D_METHOD("get_fractal_type"), &FastNoiseLite::get_fractal_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,PingPong"), "set_fractal_type", "get_fractal_type");
ClassDB::bind_method(D_METHOD("set_fractal_octaves", "octave_count"), &FastNoiseLite::set_fractal_octaves);
ClassDB::bind_method(D_METHOD("get_fractal_octaves"), &FastNoiseLite::get_fractal_octaves);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_fractal_octaves", "get_fractal_octaves");
ClassDB::bind_method(D_METHOD("set_fractal_lacunarity", "lacunarity"), &FastNoiseLite::set_fractal_lacunarity);
ClassDB::bind_method(D_METHOD("get_fractal_lacunarity"), &FastNoiseLite::get_fractal_lacunarity);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity");
ClassDB::bind_method(D_METHOD("set_fractal_gain", "gain"), &FastNoiseLite::set_fractal_gain);
ClassDB::bind_method(D_METHOD("get_fractal_gain"), &FastNoiseLite::get_fractal_gain);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_gain"), "set_fractal_gain", "get_fractal_gain");
ClassDB::bind_method(D_METHOD("set_fractal_weighted_strength", "weighted_strength"), &FastNoiseLite::set_fractal_weighted_strength);
ClassDB::bind_method(D_METHOD("get_fractal_weighted_strength"), &FastNoiseLite::get_fractal_weighted_strength);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_weighted_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fractal_weighted_strength", "get_fractal_weighted_strength");
ClassDB::bind_method(D_METHOD("set_fractal_ping_pong_strength", "ping_pong_strength"), &FastNoiseLite::set_fractal_ping_pong_strength);
ClassDB::bind_method(D_METHOD("get_fractal_ping_pong_strength"), &FastNoiseLite::get_fractal_ping_pong_strength);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength");
// Cellular.
- ADD_GROUP("Cellular", "cellular_");
ClassDB::bind_method(D_METHOD("set_cellular_distance_function", "func"), &FastNoiseLite::set_cellular_distance_function);
ClassDB::bind_method(D_METHOD("get_cellular_distance_function"), &FastNoiseLite::get_cellular_distance_function);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM, "Euclidean,EuclideanSquared,Manhattan,Hybrid"), "set_cellular_distance_function", "get_cellular_distance_function");
ClassDB::bind_method(D_METHOD("set_cellular_jitter", "jitter"), &FastNoiseLite::set_cellular_jitter);
ClassDB::bind_method(D_METHOD("get_cellular_jitter"), &FastNoiseLite::get_cellular_jitter);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter"), "set_cellular_jitter", "get_cellular_jitter");
ClassDB::bind_method(D_METHOD("set_cellular_return_type", "ret"), &FastNoiseLite::set_cellular_return_type);
ClassDB::bind_method(D_METHOD("get_cellular_return_type"), &FastNoiseLite::get_cellular_return_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, "CellValue,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"), "set_cellular_return_type", "get_cellular_return_type");
// Domain warp.
- ADD_GROUP("Domain Warp", "domain_warp_");
-
ClassDB::bind_method(D_METHOD("set_domain_warp_enabled", "domain_warp_enabled"), &FastNoiseLite::set_domain_warp_enabled);
ClassDB::bind_method(D_METHOD("is_domain_warp_enabled"), &FastNoiseLite::is_domain_warp_enabled);
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "domain_warp_enabled"), "set_domain_warp_enabled", "is_domain_warp_enabled");
ClassDB::bind_method(D_METHOD("set_domain_warp_type", "domain_warp_type"), &FastNoiseLite::set_domain_warp_type);
ClassDB::bind_method(D_METHOD("get_domain_warp_type"), &FastNoiseLite::get_domain_warp_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_type", PROPERTY_HINT_ENUM, "Simplex,SimplexReduced,BasicGrid"), "set_domain_warp_type", "get_domain_warp_type");
ClassDB::bind_method(D_METHOD("set_domain_warp_amplitude", "domain_warp_amplitude"), &FastNoiseLite::set_domain_warp_amplitude);
ClassDB::bind_method(D_METHOD("get_domain_warp_amplitude"), &FastNoiseLite::get_domain_warp_amplitude);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_amplitude"), "set_domain_warp_amplitude", "get_domain_warp_amplitude");
ClassDB::bind_method(D_METHOD("set_domain_warp_frequency", "domain_warp_frequency"), &FastNoiseLite::set_domain_warp_frequency);
ClassDB::bind_method(D_METHOD("get_domain_warp_frequency"), &FastNoiseLite::get_domain_warp_frequency);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_frequency"), "set_domain_warp_frequency", "get_domain_warp_frequency");
ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_type", "domain_warp_fractal_type"), &FastNoiseLite::set_domain_warp_fractal_type);
ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_type"), &FastNoiseLite::get_domain_warp_fractal_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_type", PROPERTY_HINT_ENUM, "None,Progressive,Independent"), "set_domain_warp_fractal_type", "get_domain_warp_fractal_type");
ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_octaves", "domain_warp_octave_count"), &FastNoiseLite::set_domain_warp_fractal_octaves);
ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_octaves"), &FastNoiseLite::get_domain_warp_fractal_octaves);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_domain_warp_fractal_octaves", "get_domain_warp_fractal_octaves");
ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_lacunarity", "domain_warp_lacunarity"), &FastNoiseLite::set_domain_warp_fractal_lacunarity);
ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_lacunarity"), &FastNoiseLite::get_domain_warp_fractal_lacunarity);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_lacunarity"), "set_domain_warp_fractal_lacunarity", "get_domain_warp_fractal_lacunarity");
ClassDB::bind_method(D_METHOD("set_domain_warp_fractal_gain", "domain_warp_gain"), &FastNoiseLite::set_domain_warp_fractal_gain);
ClassDB::bind_method(D_METHOD("get_domain_warp_fractal_gain"), &FastNoiseLite::get_domain_warp_fractal_gain);
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_gain"), "set_domain_warp_fractal_gain", "get_domain_warp_fractal_gain");
ClassDB::bind_method(D_METHOD("_changed"), &FastNoiseLite::_changed);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "noise_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Smooth,Cellular,Perlin,Value Cubic,Value"), "set_noise_type", "get_noise_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "seed"), "set_seed", "get_seed");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "frequency", PROPERTY_HINT_RANGE, ".001,1"), "set_frequency", "get_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "offset", PROPERTY_HINT_RANGE, "-999999999,999999999,0.01"), "set_offset", "get_offset");
+
+ ADD_GROUP("Fractal", "fractal_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_type", PROPERTY_HINT_ENUM, "None,FBM,Ridged,Ping-Pong"), "set_fractal_type", "get_fractal_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_fractal_octaves", "get_fractal_octaves");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_lacunarity"), "set_fractal_lacunarity", "get_fractal_lacunarity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_gain"), "set_fractal_gain", "get_fractal_gain");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_weighted_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_fractal_weighted_strength", "get_fractal_weighted_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fractal_ping_pong_strength"), "set_fractal_ping_pong_strength", "get_fractal_ping_pong_strength");
+
+ ADD_GROUP("Cellular", "cellular_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_distance_function", PROPERTY_HINT_ENUM, "Euclidean,Euclidean Squared,Manhattan,Hybrid"), "set_cellular_distance_function", "get_cellular_distance_function");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "cellular_jitter"), "set_cellular_jitter", "get_cellular_jitter");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "cellular_return_type", PROPERTY_HINT_ENUM, "Cell Value,Distance,Distance2,Distance2Add,Distance2Sub,Distance2Mul,Distance2Div"), "set_cellular_return_type", "get_cellular_return_type");
+
+ ADD_GROUP("Domain Warp", "domain_warp_");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "domain_warp_enabled"), "set_domain_warp_enabled", "is_domain_warp_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_type", PROPERTY_HINT_ENUM, "Simplex,Simplex Reduced,Basic Grid"), "set_domain_warp_type", "get_domain_warp_type");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_amplitude"), "set_domain_warp_amplitude", "get_domain_warp_amplitude");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_frequency"), "set_domain_warp_frequency", "get_domain_warp_frequency");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_type", PROPERTY_HINT_ENUM, "None,Progressive,Independent"), "set_domain_warp_fractal_type", "get_domain_warp_fractal_type");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "domain_warp_fractal_octaves", PROPERTY_HINT_RANGE, "1,10,1"), "set_domain_warp_fractal_octaves", "get_domain_warp_fractal_octaves");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_lacunarity"), "set_domain_warp_fractal_lacunarity", "get_domain_warp_fractal_lacunarity");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "domain_warp_fractal_gain"), "set_domain_warp_fractal_gain", "get_domain_warp_fractal_gain");
+
BIND_ENUM_CONSTANT(TYPE_VALUE);
BIND_ENUM_CONSTANT(TYPE_VALUE_CUBIC);
BIND_ENUM_CONSTANT(TYPE_PERLIN);
diff --git a/modules/noise/fastnoise_lite.h b/modules/noise/fastnoise_lite.h
index 4635e26d28..0a4251868b 100644
--- a/modules/noise/fastnoise_lite.h
+++ b/modules/noise/fastnoise_lite.h
@@ -99,36 +99,33 @@ private:
_FastNoiseLite _domain_warp_noise;
Vector3 offset;
- NoiseType noise_type;
- Ref<Gradient> color_ramp;
+ NoiseType noise_type = TYPE_SIMPLEX_SMOOTH;
- int seed;
- real_t frequency;
- bool in_3d_space;
+ int seed = 0;
+ real_t frequency = 0.01;
// Fractal specific.
- FractalType fractal_type;
- int fractal_octaves;
- real_t fractal_lacunarity;
- real_t fractal_gain;
- real_t fractal_weighted_strength;
- real_t fractal_pinp_pong_strength;
+ FractalType fractal_type = FRACTAL_FBM;
+ int fractal_octaves = 5;
+ real_t fractal_lacunarity = 2;
+ real_t fractal_gain = 0.5;
+ real_t fractal_weighted_strength = 0;
+ real_t fractal_ping_pong_strength = 2;
// Cellular specific.
- CellularDistanceFunction cellular_distance_function;
- CellularReturnType cellular_return_type;
- real_t cellular_jitter;
+ CellularDistanceFunction cellular_distance_function = DISTANCE_EUCLIDEAN;
+ CellularReturnType cellular_return_type = RETURN_DISTANCE;
+ real_t cellular_jitter = 0.45;
// Domain warp specific.
- bool domain_warp_enabled;
- DomainWarpType domain_warp_type;
- real_t domain_warp_frequency;
- real_t domain_warp_amplitude;
-
- DomainWarpFractalType domain_warp_fractal_type;
- int domain_warp_fractal_octaves;
- real_t domain_warp_fractal_lacunarity;
- real_t domain_warp_fractal_gain;
+ bool domain_warp_enabled = false;
+ DomainWarpType domain_warp_type = DOMAIN_WARP_SIMPLEX;
+ real_t domain_warp_amplitude = 30.0;
+ real_t domain_warp_frequency = 0.05;
+ DomainWarpFractalType domain_warp_fractal_type = DOMAIN_WARP_FRACTAL_PROGRESSIVE;
+ int domain_warp_fractal_octaves = 5;
+ real_t domain_warp_fractal_lacunarity = 6;
+ real_t domain_warp_fractal_gain = 0.5;
public:
FastNoiseLite();
@@ -145,15 +142,9 @@ public:
void set_frequency(real_t p_freq);
real_t get_frequency() const;
- void set_in_3d_space(bool p_enable);
- bool is_in_3d_space() const;
-
void set_offset(Vector3 p_offset);
Vector3 get_offset() const;
- void set_color_ramp(const Ref<Gradient> &p_gradient);
- Ref<Gradient> get_color_ramp() const;
-
// Fractal specific.
void set_fractal_type(FractalType p_type);
@@ -212,17 +203,13 @@ public:
real_t get_domain_warp_fractal_gain() const;
// Interface methods.
+ real_t get_noise_1d(real_t p_x) const override;
- Ref<Image> get_image(int p_width, int p_height, bool p_invert = false) override;
- Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, real_t p_blend_skirt = 0.1) override;
-
- real_t get_noise_1d(real_t p_x) override;
-
- real_t get_noise_2dv(Vector2 p_v) override;
- real_t get_noise_2d(real_t p_x, real_t p_y) override;
+ real_t get_noise_2dv(Vector2 p_v) const override;
+ real_t get_noise_2d(real_t p_x, real_t p_y) const override;
- real_t get_noise_3dv(Vector3 p_v) override;
- real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) override;
+ real_t get_noise_3dv(Vector3 p_v) const override;
+ real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const override;
void _changed();
};
diff --git a/modules/noise/noise.cpp b/modules/noise/noise.cpp
index 430e8c87cf..d14b63f7c8 100644
--- a/modules/noise/noise.cpp
+++ b/modules/noise/noise.cpp
@@ -30,13 +30,15 @@
#include "noise.h"
-Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, real_t p_blend_skirt) {
+Ref<Image> Noise::get_seamless_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space, real_t p_blend_skirt) const {
+ ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
+
int skirt_width = p_width * p_blend_skirt;
int skirt_height = p_height * p_blend_skirt;
int src_width = p_width + skirt_width;
int src_height = p_height + skirt_height;
- Ref<Image> src = get_image(src_width, src_height, p_invert);
+ Ref<Image> src = get_image(src_width, src_height, p_invert, p_in_3d_space);
bool grayscale = (src->get_format() == Image::FORMAT_L8);
if (grayscale) {
return _generate_seamless_image<uint8_t>(src, p_width, p_height, p_invert, p_blend_skirt);
@@ -54,6 +56,52 @@ uint8_t Noise::_alpha_blend<uint8_t>(uint8_t p_bg, uint8_t p_fg, int p_alpha) co
return (uint8_t)((alpha * p_fg + inv_alpha * p_bg) >> 8);
}
+Ref<Image> Noise::get_image(int p_width, int p_height, bool p_invert, bool p_in_3d_space) const {
+ ERR_FAIL_COND_V(p_width <= 0 || p_height <= 0, Ref<Image>());
+
+ Vector<uint8_t> data;
+ data.resize(p_width * p_height);
+
+ uint8_t *wd8 = data.ptrw();
+
+ // Get all values and identify min/max values.
+ Vector<real_t> values;
+ values.resize(p_width * p_height);
+ real_t min_val = 1000;
+ real_t max_val = -1000;
+
+ for (int y = 0, i = 0; y < p_height; y++) {
+ for (int x = 0; x < p_width; x++, i++) {
+ values.set(i, p_in_3d_space ? get_noise_3d(x, y, 0.0) : get_noise_2d(x, y));
+ if (values[i] > max_val) {
+ max_val = values[i];
+ }
+ if (values[i] < min_val) {
+ min_val = values[i];
+ }
+ }
+ }
+
+ // Normalize values and write to texture.
+ uint8_t value;
+ for (int i = 0, x = 0; i < p_height; i++) {
+ for (int j = 0; j < p_width; j++, x++) {
+ if (max_val == min_val) {
+ value = 0;
+ } else {
+ value = uint8_t(CLAMP((values[x] - min_val) / (max_val - min_val) * 255.f, 0, 255));
+ }
+ if (p_invert) {
+ value = 255 - value;
+ }
+
+ wd8[x] = value;
+ }
+ }
+
+ return memnew(Image(p_width, p_height, false, Image::FORMAT_L8, data));
+}
+
void Noise::_bind_methods() {
// Noise functions.
ClassDB::bind_method(D_METHOD("get_noise_1d", "x"), &Noise::get_noise_1d);
@@ -63,6 +111,6 @@ void Noise::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_noise_3dv", "v"), &Noise::get_noise_3dv);
// Textures.
- ClassDB::bind_method(D_METHOD("get_image", "width", "height", "invert"), &Noise::get_image, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "skirt"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(0.1));
+ ClassDB::bind_method(D_METHOD("get_image", "width", "height", "invert", "in_3d_space"), &Noise::get_image, DEFVAL(false), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("get_seamless_image", "width", "height", "invert", "in_3d_space", "skirt"), &Noise::get_seamless_image, DEFVAL(false), DEFVAL(false), DEFVAL(0.1));
}
diff --git a/modules/noise/noise.h b/modules/noise/noise.h
index c05bc057da..8083334388 100644
--- a/modules/noise/noise.h
+++ b/modules/noise/noise.h
@@ -39,7 +39,7 @@ class Noise : public Resource {
// Helper struct for get_seamless_image(). See comments in .cpp for usage.
template <typename T>
struct img_buff {
- T *img;
+ T *img = nullptr;
int width; // Array dimensions & default modulo for image.
int height;
int offset_x; // Offset index location on image (wrapped by specified modulo).
@@ -81,7 +81,7 @@ class Noise : public Resource {
};
template <typename T>
- Ref<Image> _generate_seamless_image(Ref<Image> p_src, int p_width, int p_height, bool p_invert, real_t p_blend_skirt) {
+ Ref<Image> _generate_seamless_image(Ref<Image> p_src, int p_width, int p_height, bool p_invert, real_t p_blend_skirt) const {
/*
To make a seamless image, we swap the quadrants so the edges are perfect matches.
We initially get a 10% larger image so we have an overlap we can use to blend over the seams.
@@ -101,6 +101,7 @@ class Noise : public Resource {
on Source it's translated to
corner of Q1/s3 unless the ALT_XY modulo moves it to Q4
*/
+ ERR_FAIL_COND_V(p_blend_skirt < 0, Ref<Image>());
int skirt_width = MAX(1, p_width * p_blend_skirt);
int skirt_height = MAX(1, p_height * p_blend_skirt);
@@ -224,16 +225,16 @@ public:
// Virtual destructor so we can delete any Noise derived object when referenced as a Noise*.
virtual ~Noise() {}
- virtual real_t get_noise_1d(real_t p_x) = 0;
+ virtual real_t get_noise_1d(real_t p_x) const = 0;
- virtual real_t get_noise_2dv(Vector2 p_v) = 0;
- virtual real_t get_noise_2d(real_t p_x, real_t p_y) = 0;
+ virtual real_t get_noise_2dv(Vector2 p_v) const = 0;
+ virtual real_t get_noise_2d(real_t p_x, real_t p_y) const = 0;
- virtual real_t get_noise_3dv(Vector3 p_v) = 0;
- virtual real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) = 0;
+ virtual real_t get_noise_3dv(Vector3 p_v) const = 0;
+ virtual real_t get_noise_3d(real_t p_x, real_t p_y, real_t p_z) const = 0;
- virtual Ref<Image> get_image(int p_width, int p_height, bool p_invert = false) = 0;
- virtual Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, real_t p_blend_skirt = 0.1);
+ virtual Ref<Image> get_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false) const;
+ virtual Ref<Image> get_seamless_image(int p_width, int p_height, bool p_invert = false, bool p_in_3d_space = false, real_t p_blend_skirt = 0.1) const;
};
#endif // NOISE_H
diff --git a/modules/noise/noise_texture.cpp b/modules/noise/noise_texture.cpp
index 3721043a09..e9d16e548c 100644
--- a/modules/noise/noise_texture.cpp
+++ b/modules/noise/noise_texture.cpp
@@ -47,15 +47,22 @@ NoiseTexture::~NoiseTexture() {
}
void NoiseTexture::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture);
+ ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture);
+ ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done);
+
ClassDB::bind_method(D_METHOD("set_width", "width"), &NoiseTexture::set_width);
ClassDB::bind_method(D_METHOD("set_height", "height"), &NoiseTexture::set_height);
- ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
- ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
-
ClassDB::bind_method(D_METHOD("set_invert", "invert"), &NoiseTexture::set_invert);
ClassDB::bind_method(D_METHOD("get_invert"), &NoiseTexture::get_invert);
+ ClassDB::bind_method(D_METHOD("set_in_3d_space", "enable"), &NoiseTexture::set_in_3d_space);
+ ClassDB::bind_method(D_METHOD("is_in_3d_space"), &NoiseTexture::is_in_3d_space);
+
+ ClassDB::bind_method(D_METHOD("set_generate_mipmaps", "invert"), &NoiseTexture::set_generate_mipmaps);
+ ClassDB::bind_method(D_METHOD("is_generating_mipmaps"), &NoiseTexture::is_generating_mipmaps);
+
ClassDB::bind_method(D_METHOD("set_seamless", "seamless"), &NoiseTexture::set_seamless);
ClassDB::bind_method(D_METHOD("get_seamless"), &NoiseTexture::get_seamless);
@@ -68,17 +75,22 @@ void NoiseTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bump_strength", "bump_strength"), &NoiseTexture::set_bump_strength);
ClassDB::bind_method(D_METHOD("get_bump_strength"), &NoiseTexture::get_bump_strength);
- ClassDB::bind_method(D_METHOD("_update_texture"), &NoiseTexture::_update_texture);
- ClassDB::bind_method(D_METHOD("_generate_texture"), &NoiseTexture::_generate_texture);
- ClassDB::bind_method(D_METHOD("_thread_done", "image"), &NoiseTexture::_thread_done);
+ ClassDB::bind_method(D_METHOD("set_color_ramp", "gradient"), &NoiseTexture::set_color_ramp);
+ ClassDB::bind_method(D_METHOD("get_color_ramp"), &NoiseTexture::get_color_ramp);
+
+ ClassDB::bind_method(D_METHOD("set_noise", "noise"), &NoiseTexture::set_noise);
+ ClassDB::bind_method(D_METHOD("get_noise"), &NoiseTexture::get_noise);
ADD_PROPERTY(PropertyInfo(Variant::INT, "width", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::INT, "height", PROPERTY_HINT_RANGE, "1,2048,1,or_greater"), "set_height", "get_height");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "invert"), "set_invert", "get_invert");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "in_3d_space"), "set_in_3d_space", "is_in_3d_space");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "generate_mipmaps"), "set_generate_mipmaps", "is_generating_mipmaps");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "seamless"), "set_seamless", "get_seamless");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "seamless_blend_skirt", PROPERTY_HINT_RANGE, "0.05,1,0.001"), "set_seamless_blend_skirt", "get_seamless_blend_skirt");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "as_normal_map"), "set_as_normal_map", "is_normal_map");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bump_strength", PROPERTY_HINT_RANGE, "0,32,0.1,or_greater"), "set_bump_strength", "get_bump_strength");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "color_ramp", PROPERTY_HINT_RESOURCE_TYPE, "Gradient"), "set_color_ramp", "get_color_ramp");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "noise", PROPERTY_HINT_RESOURCE_TYPE, "Noise"), "set_noise", "get_noise");
}
@@ -119,7 +131,7 @@ void NoiseTexture::_thread_done(const Ref<Image> &p_image) {
}
void NoiseTexture::_thread_function(void *p_ud) {
- NoiseTexture *tex = (NoiseTexture *)p_ud;
+ NoiseTexture *tex = static_cast<NoiseTexture *>(p_ud);
tex->call_deferred(SNAME("_thread_done"), tex->_generate_texture());
}
@@ -143,18 +155,42 @@ Ref<Image> NoiseTexture::_generate_texture() {
Ref<Image> image;
if (seamless) {
- image = ref_noise->get_seamless_image(size.x, size.y, invert, seamless_blend_skirt);
+ image = ref_noise->get_seamless_image(size.x, size.y, invert, in_3d_space, seamless_blend_skirt);
} else {
- image = ref_noise->get_image(size.x, size.y, invert);
+ image = ref_noise->get_image(size.x, size.y, invert, in_3d_space);
+ }
+ if (color_ramp.is_valid()) {
+ image = _modulate_with_gradient(image, color_ramp);
}
-
if (as_normal_map) {
image->bump_map_to_normal_map(bump_strength);
}
+ if (generate_mipmaps) {
+ image->generate_mipmaps();
+ }
return image;
}
+Ref<Image> NoiseTexture::_modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient) {
+ int width = p_image->get_width();
+ int height = p_image->get_height();
+
+ Ref<Image> new_image;
+ new_image.instantiate();
+ new_image->create(width, height, false, Image::FORMAT_RGBA8);
+
+ for (int row = 0; row < height; row++) {
+ for (int col = 0; col < width; col++) {
+ Color pixel_color = p_image->get_pixel(col, row);
+ Color ramp_color = color_ramp->get_color_at_offset(pixel_color.get_luminance());
+ new_image->set_pixel(col, row, ramp_color);
+ }
+ }
+
+ return new_image;
+}
+
void NoiseTexture::_update_texture() {
bool use_thread = true;
if (first_time) {
@@ -227,6 +263,29 @@ bool NoiseTexture::get_invert() const {
return invert;
}
+void NoiseTexture::set_in_3d_space(bool p_enable) {
+ if (p_enable == in_3d_space) {
+ return;
+ }
+ in_3d_space = p_enable;
+ _queue_update();
+}
+bool NoiseTexture::is_in_3d_space() const {
+ return in_3d_space;
+}
+
+void NoiseTexture::set_generate_mipmaps(bool p_enable) {
+ if (p_enable == generate_mipmaps) {
+ return;
+ }
+ generate_mipmaps = p_enable;
+ _queue_update();
+}
+
+bool NoiseTexture::is_generating_mipmaps() const {
+ return generate_mipmaps;
+}
+
void NoiseTexture::set_seamless(bool p_seamless) {
if (p_seamless == seamless) {
return;
@@ -241,6 +300,8 @@ bool NoiseTexture::get_seamless() {
}
void NoiseTexture::set_seamless_blend_skirt(real_t p_blend_skirt) {
+ ERR_FAIL_COND(p_blend_skirt < 0.05 || p_blend_skirt > 1);
+
if (p_blend_skirt == seamless_blend_skirt) {
return;
}
@@ -278,6 +339,24 @@ float NoiseTexture::get_bump_strength() {
return bump_strength;
}
+void NoiseTexture::set_color_ramp(const Ref<Gradient> &p_gradient) {
+ if (p_gradient == color_ramp) {
+ return;
+ }
+ if (color_ramp.is_valid()) {
+ color_ramp->disconnect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+ }
+ color_ramp = p_gradient;
+ if (color_ramp.is_valid()) {
+ color_ramp->connect(CoreStringNames::get_singleton()->changed, callable_mp(this, &NoiseTexture::_queue_update));
+ }
+ _queue_update();
+}
+
+Ref<Gradient> NoiseTexture::get_color_ramp() const {
+ return color_ramp;
+}
+
int NoiseTexture::get_width() const {
return size.x;
}
diff --git a/modules/noise/noise_texture.h b/modules/noise/noise_texture.h
index 2a94df39d4..6c088562a1 100644
--- a/modules/noise/noise_texture.h
+++ b/modules/noise/noise_texture.h
@@ -51,15 +51,18 @@ private:
mutable RID texture;
uint32_t flags = 0;
- Ref<Noise> noise;
+ Size2i size = Size2i(512, 512);
bool invert = false;
- Vector2i size = Vector2i(512, 512);
- Vector2 noise_offset;
+ bool in_3d_space = false;
+ bool generate_mipmaps = true;
bool seamless = false;
real_t seamless_blend_skirt = 0.1;
bool as_normal_map = false;
float bump_strength = 8.0;
+ Ref<Gradient> color_ramp;
+ Ref<Noise> noise;
+
void _thread_done(const Ref<Image> &p_image);
static void _thread_function(void *p_ud);
@@ -68,6 +71,8 @@ private:
void _update_texture();
void _set_texture_image(const Ref<Image> &p_image);
+ Ref<Image> _modulate_with_gradient(Ref<Image> p_image, Ref<Gradient> p_gradient);
+
protected:
static void _bind_methods();
virtual void _validate_property(PropertyInfo &property) const override;
@@ -82,6 +87,12 @@ public:
void set_invert(bool p_invert);
bool get_invert() const;
+ void set_in_3d_space(bool p_enable);
+ bool is_in_3d_space() const;
+
+ void set_generate_mipmaps(bool p_enable);
+ bool is_generating_mipmaps() const;
+
void set_seamless(bool p_seamless);
bool get_seamless();
@@ -94,6 +105,9 @@ public:
void set_bump_strength(float p_bump_strength);
float get_bump_strength();
+ void set_color_ramp(const Ref<Gradient> &p_gradient);
+ Ref<Gradient> get_color_ramp() const;
+
int get_width() const override;
int get_height() const override;
diff --git a/modules/noise/register_types.cpp b/modules/noise/register_types.cpp
index 81bb0317c1..d0cfc4e944 100644
--- a/modules/noise/register_types.cpp
+++ b/modules/noise/register_types.cpp
@@ -34,11 +34,27 @@
#include "noise.h"
#include "noise_texture.h"
-void register_noise_types() {
- GDREGISTER_CLASS(NoiseTexture);
- GDREGISTER_ABSTRACT_CLASS(Noise);
- GDREGISTER_CLASS(FastNoiseLite);
+#ifdef TOOLS_ENABLED
+#include "editor/editor_plugin.h"
+#include "editor/noise_editor_plugin.h"
+#endif
+
+void initialize_noise_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_CLASS(NoiseTexture);
+ GDREGISTER_ABSTRACT_CLASS(Noise);
+ GDREGISTER_CLASS(FastNoiseLite);
+ }
+
+#ifdef TOOLS_ENABLED
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorPlugins::add_by_type<NoiseEditorPlugin>();
+ }
+#endif
}
-void unregister_noise_types() {
+void uninitialize_noise_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/noise/register_types.h b/modules/noise/register_types.h
index e441a48518..dfe5a480de 100644
--- a/modules/noise/register_types.h
+++ b/modules/noise/register_types.h
@@ -31,7 +31,9 @@
#ifndef NOISE_REGISTER_TYPES_H
#define NOISE_REGISTER_TYPES_H
-void register_noise_types();
-void unregister_noise_types();
+#include "modules/register_module_types.h"
+
+void initialize_noise_module(ModuleInitializationLevel p_level);
+void uninitialize_noise_module(ModuleInitializationLevel p_level);
#endif // NOISE_REGISTER_TYPES_H
diff --git a/modules/ogg/register_types.cpp b/modules/ogg/register_types.cpp
index 3d04351032..01f04aa3d5 100644
--- a/modules/ogg/register_types.cpp
+++ b/modules/ogg/register_types.cpp
@@ -32,9 +32,17 @@
#include "ogg_packet_sequence.h"
-void register_ogg_types() {
+void initialize_ogg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(OGGPacketSequence);
GDREGISTER_CLASS(OGGPacketSequencePlayback);
}
-void unregister_ogg_types() {}
+void uninitialize_ogg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/ogg/register_types.h b/modules/ogg/register_types.h
index 6ef7dc93ca..9065d26d07 100644
--- a/modules/ogg/register_types.h
+++ b/modules/ogg/register_types.h
@@ -31,7 +31,9 @@
#ifndef OGG_REGISTER_TYPES_H
#define OGG_REGISTER_TYPES_H
-void register_ogg_types();
-void unregister_ogg_types();
+#include "modules/register_module_types.h"
+
+void initialize_ogg_module(ModuleInitializationLevel p_level);
+void uninitialize_ogg_module(ModuleInitializationLevel p_level);
#endif // OGG_REGISTER_TYPES_H
diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub
index 32cab1bef1..ff320236a7 100644
--- a/modules/openxr/SCsub
+++ b/modules/openxr/SCsub
@@ -83,5 +83,8 @@ if env["vulkan"]:
env.modules_sources += module_obj
+if env["tools"]:
+ SConscript("editor/SCsub")
+
# Needed to force rebuilding the module files when the thirdparty library is updated.
env.Depends(module_obj, thirdparty_obj)
diff --git a/modules/openxr/action_map/openxr_action.cpp b/modules/openxr/action_map/openxr_action.cpp
index 59ee3f4292..359975a480 100644
--- a/modules/openxr/action_map/openxr_action.cpp
+++ b/modules/openxr/action_map/openxr_action.cpp
@@ -29,6 +29,7 @@
/*************************************************************************/
#include "openxr_action.h"
+#include "openxr_action_set.h"
void OpenXRAction::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_localized_name", "localized_name"), &OpenXRAction::set_localized_name);
@@ -62,6 +63,16 @@ Ref<OpenXRAction> OpenXRAction::new_action(const char *p_name, const char *p_loc
return action;
}
+String OpenXRAction::get_name_with_set() const {
+ String name = get_name();
+
+ if (action_set != nullptr) {
+ name = action_set->get_name() + "/" + name;
+ }
+
+ return name;
+}
+
void OpenXRAction::set_localized_name(const String p_localized_name) {
localized_name = p_localized_name;
}
@@ -86,6 +97,18 @@ PackedStringArray OpenXRAction::get_toplevel_paths() const {
return toplevel_paths;
}
+void OpenXRAction::add_toplevel_path(const String p_toplevel_path) {
+ if (!toplevel_paths.has(p_toplevel_path)) {
+ toplevel_paths.push_back(p_toplevel_path);
+ }
+}
+
+void OpenXRAction::rem_toplevel_path(const String p_toplevel_path) {
+ if (toplevel_paths.has(p_toplevel_path)) {
+ toplevel_paths.erase(p_toplevel_path);
+ }
+}
+
void OpenXRAction::parse_toplevel_paths(const String p_toplevel_paths) {
toplevel_paths = p_toplevel_paths.split(",", false);
}
diff --git a/modules/openxr/action_map/openxr_action.h b/modules/openxr/action_map/openxr_action.h
index e2cfe79e64..5e57f89133 100644
--- a/modules/openxr/action_map/openxr_action.h
+++ b/modules/openxr/action_map/openxr_action.h
@@ -33,6 +33,8 @@
#include "core/io/resource.h"
+class OpenXRActionSet;
+
class OpenXRAction : public Resource {
GDCLASS(OpenXRAction, Resource);
@@ -43,6 +45,7 @@ public:
OPENXR_ACTION_VECTOR2,
OPENXR_ACTION_POSE,
OPENXR_ACTION_HAPTIC,
+ OPENXR_ACTION_MAX
};
private:
@@ -52,21 +55,31 @@ private:
PackedStringArray toplevel_paths;
protected:
+ friend class OpenXRActionSet;
+
+ OpenXRActionSet *action_set = nullptr; // action belongs to this action set.
+
static void _bind_methods();
public:
- static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths);
+ static Ref<OpenXRAction> new_action(const char *p_name, const char *p_localized_name, const ActionType p_action_type, const char *p_toplevel_paths); // Helper function to add and configure an action
+ OpenXRActionSet *get_action_set() const { return action_set; } // Get the action set this action belongs to
+
+ String get_name_with_set() const; // Retrieve the name of this action as <action_set>/<action>
+
+ void set_localized_name(const String p_localized_name); // Set the localized name of this action
+ String get_localized_name() const; // Get the localized name of this action
- void set_localized_name(const String p_localized_name);
- String get_localized_name() const;
+ void set_action_type(const ActionType p_action_type); // Set the type of this action
+ ActionType get_action_type() const; // Get the type of this action
- void set_action_type(const ActionType p_action_type);
- ActionType get_action_type() const;
+ void set_toplevel_paths(const PackedStringArray p_toplevel_paths); // Set the toplevel paths of this action
+ PackedStringArray get_toplevel_paths() const; // Get the toplevel paths of this action
- void set_toplevel_paths(const PackedStringArray p_toplevel_paths);
- PackedStringArray get_toplevel_paths() const;
+ void add_toplevel_path(const String p_toplevel_path); // Add a top level path to this action
+ void rem_toplevel_path(const String p_toplevel_path); // Remove a toplevel path from this action
- void parse_toplevel_paths(const String p_toplevel_paths);
+ void parse_toplevel_paths(const String p_toplevel_paths); // Parse and set the top level paths from a comma separated string
};
VARIANT_ENUM_CAST(OpenXRAction::ActionType);
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index e14c68079d..366e131369 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -35,6 +35,9 @@ void OpenXRActionMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_action_sets"), &OpenXRActionMap::get_action_sets);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "action_sets", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRActionSet", PROPERTY_USAGE_NO_EDITOR), "set_action_sets", "get_action_sets");
+ ClassDB::bind_method(D_METHOD("get_action_set_count"), &OpenXRActionMap::get_action_set_count);
+ ClassDB::bind_method(D_METHOD("find_action_set", "name"), &OpenXRActionMap::find_action_set);
+ ClassDB::bind_method(D_METHOD("get_action_set", "idx"), &OpenXRActionMap::get_action_set);
ClassDB::bind_method(D_METHOD("add_action_set", "action_set"), &OpenXRActionMap::add_action_set);
ClassDB::bind_method(D_METHOD("remove_action_set", "action_set"), &OpenXRActionMap::remove_action_set);
@@ -42,6 +45,9 @@ void OpenXRActionMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_interaction_profiles"), &OpenXRActionMap::get_interaction_profiles);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "interaction_profiles", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRInteractionProfile", PROPERTY_USAGE_NO_EDITOR), "set_interaction_profiles", "get_interaction_profiles");
+ ClassDB::bind_method(D_METHOD("get_interaction_profile_count"), &OpenXRActionMap::get_interaction_profile_count);
+ ClassDB::bind_method(D_METHOD("find_interaction_profile", "name"), &OpenXRActionMap::find_interaction_profile);
+ ClassDB::bind_method(D_METHOD("get_interaction_profile", "idx"), &OpenXRActionMap::get_interaction_profile);
ClassDB::bind_method(D_METHOD("add_interaction_profile", "interaction_profile"), &OpenXRActionMap::add_interaction_profile);
ClassDB::bind_method(D_METHOD("remove_interaction_profile", "interaction_profile"), &OpenXRActionMap::remove_interaction_profile);
@@ -49,13 +55,41 @@ void OpenXRActionMap::_bind_methods() {
}
void OpenXRActionMap::set_action_sets(Array p_action_sets) {
- action_sets = p_action_sets;
+ action_sets.clear();
+
+ for (int i = 0; i < p_action_sets.size(); i++) {
+ Ref<OpenXRActionSet> action_set = p_action_sets[i];
+ if (action_set.is_valid() && action_sets.find(action_set) == -1) {
+ action_sets.push_back(action_set);
+ }
+ }
}
Array OpenXRActionMap::get_action_sets() const {
return action_sets;
}
+int OpenXRActionMap::get_action_set_count() const {
+ return action_sets.size();
+}
+
+Ref<OpenXRActionSet> OpenXRActionMap::find_action_set(String p_name) const {
+ for (int i = 0; i < action_sets.size(); i++) {
+ Ref<OpenXRActionSet> action_set = action_sets[i];
+ if (action_set->get_name() == p_name) {
+ return action_set;
+ }
+ }
+
+ return Ref<OpenXRActionSet>();
+}
+
+Ref<OpenXRActionSet> OpenXRActionMap::get_action_set(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, action_sets.size(), Ref<OpenXRActionSet>());
+
+ return action_sets[p_idx];
+}
+
void OpenXRActionMap::add_action_set(Ref<OpenXRActionSet> p_action_set) {
ERR_FAIL_COND(p_action_set.is_null());
@@ -72,13 +106,41 @@ void OpenXRActionMap::remove_action_set(Ref<OpenXRActionSet> p_action_set) {
}
void OpenXRActionMap::set_interaction_profiles(Array p_interaction_profiles) {
- interaction_profiles = p_interaction_profiles;
+ interaction_profiles.clear();
+
+ for (int i = 0; i < p_interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = p_interaction_profiles[i];
+ if (interaction_profile.is_valid() && interaction_profiles.find(interaction_profile) == -1) {
+ interaction_profiles.push_back(interaction_profile);
+ }
+ }
}
Array OpenXRActionMap::get_interaction_profiles() const {
return interaction_profiles;
}
+int OpenXRActionMap::get_interaction_profile_count() const {
+ return interaction_profiles.size();
+}
+
+Ref<OpenXRInteractionProfile> OpenXRActionMap::find_interaction_profile(String p_path) const {
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i];
+ if (interaction_profile->get_interaction_profile_path() == p_path) {
+ return interaction_profile;
+ }
+ }
+
+ return Ref<OpenXRInteractionProfile>();
+}
+
+Ref<OpenXRInteractionProfile> OpenXRActionMap::get_interaction_profile(int p_idx) const {
+ ERR_FAIL_INDEX_V(p_idx, interaction_profiles.size(), Ref<OpenXRInteractionProfile>());
+
+ return interaction_profiles[p_idx];
+}
+
void OpenXRActionMap::add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile) {
ERR_FAIL_COND(p_interaction_profile.is_null());
@@ -178,27 +240,6 @@ void OpenXRActionMap::create_default_action_sets() {
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
add_interaction_profile(profile);
- // Create our HP MR controller profile
- profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller");
- profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
- profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
- profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
- // hpmr controllers have no select button we can use
- profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
- // hpmr controllers only register click, not touch, on our a/b/x/y buttons
- profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
- profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
- profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
- profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
- profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
- profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
- // primary on our hpmr controller is our thumbstick
- profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
- profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
- // No secondary on our hpmr controller
- profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
- add_interaction_profile(profile);
-
// Create our Meta touch controller profile
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/oculus/touch_controller");
profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
@@ -249,12 +290,185 @@ void OpenXRActionMap::create_default_action_sets() {
profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
add_interaction_profile(profile);
+
+ // Note, the following profiles are all part of extensions.
+ // We include these regardless of whether the extension is active.
+ // We want our action map to be as complete as possible so our game is as portable as possible.
+ // It is very possible these will in due time become core.
+
+ // Create our HP MR controller profile
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/hp/mixed_reality_controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ // hpmr controllers have no select button we can use
+ profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
+ // hpmr controllers only register click, not touch, on our a/b/x/y buttons
+ profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
+ profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(grip, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
+ profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/value,/user/hand/right/input/squeeze/value");
+ // primary on our hpmr controller is our thumbstick
+ profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
+ // No secondary on our hpmr controller
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
+
+ // Create our Samsung Odyssey controller profile,
+ // Note that this controller is only identified specifically on WMR, on SteamVR this is identified as a normal WMR controller.
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/samsung/odyssey_controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ // Odyssey controllers have no select button we can use
+ profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click,/user/hand/right/input/menu/click");
+ // Odyssey controller has no a/b/x/y buttons
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ // primary on our Odyssey controller is our thumbstick, no touch
+ profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
+ // secondary on our Odyssey controller is our trackpad
+ profile->add_new_binding(secondary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
+ profile->add_new_binding(secondary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
+ profile->add_new_binding(secondary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
+
+ // Create our Vive Cosmos controller
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_cosmos_controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");
+ profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select
+ profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
+ profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
+ profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ // primary on our Cosmos controller is our thumbstick
+ profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
+ profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
+ // No secondary on our cosmos controller
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
+
+ // Create our Vive Focus 3 controller
+ // Note, Vive Focus 3 currently is not yet supported as a stand alone device
+ // however HTC currently has a beta OpenXR runtime in testing we may support in the near future
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_focus3_controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click");
+ profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select
+ profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand
+ profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
+ profile->add_new_binding(trigger_touch, "/user/hand/left/input/trigger/touch,/user/hand/right/input/trigger/touch");
+ profile->add_new_binding(grip, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ profile->add_new_binding(grip_click, "/user/hand/left/input/squeeze/click,/user/hand/right/input/squeeze/click");
+ // primary on our Focus 3 controller is our thumbstick
+ profile->add_new_binding(primary, "/user/hand/left/input/thumbstick,/user/hand/right/input/thumbstick");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/thumbstick/click,/user/hand/right/input/thumbstick/click");
+ profile->add_new_binding(primary_touch, "/user/hand/left/input/thumbstick/touch,/user/hand/right/input/thumbstick/touch");
+ // We only have a thumb rest
+ profile->add_new_binding(secondary_touch, "/user/hand/left/input/thumbrest/touch,/user/hand/right/input/thumbrest/touch");
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
+
+ // Create our Huawei controller
+ profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/huawei/controller");
+ profile->add_new_binding(default_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(aim_pose, "/user/hand/left/input/aim/pose,/user/hand/right/input/aim/pose");
+ profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose");
+ profile->add_new_binding(menu_button, "/user/hand/left/input/home/click,/user/hand/right/input/home/click");
+ profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value");
+ profile->add_new_binding(trigger_click, "/user/hand/left/input/trigger/click,/user/hand/right/input/trigger/click");
+ // primary on our Huawei controller is our trackpad
+ profile->add_new_binding(primary, "/user/hand/left/input/trackpad,/user/hand/right/input/trackpad");
+ profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
+ profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
+ profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
}
void OpenXRActionMap::create_editor_action_sets() {
// TODO implement
}
+Ref<OpenXRAction> OpenXRActionMap::get_action(const String p_path) const {
+ PackedStringArray paths = p_path.split("/", false);
+ ERR_FAIL_COND_V(paths.size() != 2, Ref<OpenXRAction>());
+
+ Ref<OpenXRActionSet> action_set = find_action_set(paths[0]);
+ if (action_set.is_valid()) {
+ return action_set->get_action(paths[1]);
+ }
+
+ return Ref<OpenXRAction>();
+}
+
+void OpenXRActionMap::remove_action(const String p_path) {
+ Ref<OpenXRAction> action = get_action(p_path);
+ if (action.is_valid()) {
+ OpenXRActionSet *action_set = action->get_action_set();
+ if (action_set != nullptr) {
+ // Remove the action from this action set
+ action_set->remove_action(action);
+ }
+
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = interaction_profiles[i];
+
+ // Remove any bindings for this action
+ interaction_profile->remove_binding_for_action(action);
+ }
+ }
+}
+
+PackedStringArray OpenXRActionMap::get_top_level_paths(Ref<OpenXRAction> p_action) {
+ PackedStringArray arr;
+
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> ip = interaction_profiles[i];
+ const OpenXRDefs::InteractionProfile *profile = OpenXRDefs::get_profile(ip->get_interaction_profile_path());
+
+ if (profile != nullptr) {
+ for (int j = 0; j < ip->get_binding_count(); j++) {
+ Ref<OpenXRIPBinding> binding = ip->get_binding(j);
+ if (binding->get_action() == p_action) {
+ PackedStringArray paths = binding->get_paths();
+
+ for (int k = 0; k < paths.size(); k++) {
+ const OpenXRDefs::IOPath *io_path = profile->get_io_path(paths[k]);
+ if (io_path != nullptr) {
+ String top_path = String(io_path->top_level_path->openxr_path);
+
+ if (!arr.has(top_path)) {
+ arr.push_back(top_path);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ print_line("Toplevel paths for", p_action->get_name_with_set(), "are", arr);
+
+ return arr;
+}
+
OpenXRActionMap::~OpenXRActionMap() {
action_sets.clear();
interaction_profiles.clear();
diff --git a/modules/openxr/action_map/openxr_action_map.h b/modules/openxr/action_map/openxr_action_map.h
index 866e170468..dcd8fc71aa 100644
--- a/modules/openxr/action_map/openxr_action_map.h
+++ b/modules/openxr/action_map/openxr_action_map.h
@@ -33,6 +33,7 @@
#include "core/io/resource.h"
+#include "openxr_action.h"
#include "openxr_action_set.h"
#include "openxr_interaction_profile.h"
@@ -47,20 +48,33 @@ protected:
static void _bind_methods();
public:
- void set_action_sets(Array p_action_sets);
- Array get_action_sets() const;
+ void set_action_sets(Array p_action_sets); // Set our actions sets by providing an array with action sets (for loading from resource)
+ Array get_action_sets() const; // Get our action sets as an array (for saving to resource)
- void add_action_set(Ref<OpenXRActionSet> p_action_set);
- void remove_action_set(Ref<OpenXRActionSet> p_action_set);
+ int get_action_set_count() const; // Retrieve the number of action sets we have
+ Ref<OpenXRActionSet> find_action_set(String p_name) const; // Find an action set by name
+ Ref<OpenXRActionSet> get_action_set(int p_idx) const; // Retrieve an action set by index
+ void add_action_set(Ref<OpenXRActionSet> p_action_set); // Add an action set to our action map
+ void remove_action_set(Ref<OpenXRActionSet> p_action_set); // Remove an action set from our action map
- void set_interaction_profiles(Array p_interaction_profiles);
- Array get_interaction_profiles() const;
+ void set_interaction_profiles(Array p_interaction_profiles); // Set our interaction profiles by providing an array (for loading from resource)
+ Array get_interaction_profiles() const; // Get our interaction profiles as an array (for saving to resource)
- void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile);
- void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile);
+ int get_interaction_profile_count() const; // Retrieve the number of interaction profiles we have
+ Ref<OpenXRInteractionProfile> find_interaction_profile(String p_path) const; // Find an interaction profile by path
+ Ref<OpenXRInteractionProfile> get_interaction_profile(int p_idx) const; // Retrieve an interaction profile by index
+ void add_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // Add an interaction profile to our action map
+ void remove_interaction_profile(Ref<OpenXRInteractionProfile> p_interaction_profile); // remove an interaction profile from our action map
- void create_default_action_sets();
- void create_editor_action_sets();
+ void create_default_action_sets(); // Create our default action set for runtime
+ void create_editor_action_sets(); // Create our action set for the editor
+
+ // Helper functions for editor
+ Ref<OpenXRAction> get_action(const String p_path) const; // Retrieve an action using <action name>/<action> as our parameter
+ void remove_action(const String p_path); // Remove action from action set, also removes it from interaction profiles
+ PackedStringArray get_top_level_paths(Ref<OpenXRAction> p_action); // Determines the top level paths based on where an action is bound in interaction profiles
+
+ // TODO add validation to display in the interface that checks if we have action sets with the same name or if we have interaction profiles for the same path
~OpenXRActionMap();
};
diff --git a/modules/openxr/action_map/openxr_action_set.cpp b/modules/openxr/action_map/openxr_action_set.cpp
index 465a709b60..be45218300 100644
--- a/modules/openxr/action_map/openxr_action_set.cpp
+++ b/modules/openxr/action_map/openxr_action_set.cpp
@@ -39,6 +39,7 @@ void OpenXRActionSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_priority"), &OpenXRActionSet::get_priority);
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority"), "set_priority", "get_priority");
+ ClassDB::bind_method(D_METHOD("get_action_count"), &OpenXRActionSet::get_action_count);
ClassDB::bind_method(D_METHOD("set_actions", "actions"), &OpenXRActionSet::set_actions);
ClassDB::bind_method(D_METHOD("get_actions"), &OpenXRActionSet::get_actions);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "actions", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction", PROPERTY_USAGE_NO_EDITOR), "set_actions", "get_actions");
@@ -75,18 +76,54 @@ int OpenXRActionSet::get_priority() const {
return priority;
}
+int OpenXRActionSet::get_action_count() const {
+ return actions.size();
+}
+
+void OpenXRActionSet::clear_actions() {
+ // Actions held within our action set should be released and destroyed but just in case they are still used some where else
+ for (int i = 0; i < actions.size(); i++) {
+ Ref<OpenXRAction> action = actions[i];
+ action->action_set = nullptr;
+ }
+ actions.clear();
+}
+
void OpenXRActionSet::set_actions(Array p_actions) {
- actions = p_actions;
+ // Any actions not retained in p_actions should be freed automatically, those held within our Array will have be relinked to our action set.
+ clear_actions();
+
+ for (int i = 0; i < p_actions.size(); i++) {
+ // add them anew so we verify our action_set pointer
+ add_action(p_actions[i]);
+ }
}
Array OpenXRActionSet::get_actions() const {
return actions;
}
+Ref<OpenXRAction> OpenXRActionSet::get_action(const String p_name) const {
+ for (int i = 0; i < actions.size(); i++) {
+ Ref<OpenXRAction> action = actions[i];
+ if (action->get_name() == p_name) {
+ return action;
+ }
+ }
+
+ return Ref<OpenXRAction>();
+}
+
void OpenXRActionSet::add_action(Ref<OpenXRAction> p_action) {
ERR_FAIL_COND(p_action.is_null());
if (actions.find(p_action) == -1) {
+ if (p_action->action_set && p_action->action_set != this) {
+ // action should only relate to our action set
+ p_action->action_set->remove_action(p_action);
+ }
+
+ p_action->action_set = this;
actions.push_back(p_action);
}
}
@@ -95,6 +132,9 @@ void OpenXRActionSet::remove_action(Ref<OpenXRAction> p_action) {
int idx = actions.find(p_action);
if (idx != -1) {
actions.remove_at(idx);
+
+ ERR_FAIL_COND_MSG(p_action->action_set != this, "Removing action that belongs to this action set but had incorrect action set pointer."); // this should never happen!
+ p_action->action_set = nullptr;
}
}
@@ -107,5 +147,5 @@ Ref<OpenXRAction> OpenXRActionSet::add_new_action(const char *p_name, const char
}
OpenXRActionSet::~OpenXRActionSet() {
- actions.clear();
+ clear_actions();
}
diff --git a/modules/openxr/action_map/openxr_action_set.h b/modules/openxr/action_map/openxr_action_set.h
index 012a088b1c..b1d7168894 100644
--- a/modules/openxr/action_map/openxr_action_set.h
+++ b/modules/openxr/action_map/openxr_action_set.h
@@ -43,26 +43,31 @@ private:
int priority = 0;
Array actions;
+ void clear_actions();
protected:
static void _bind_methods();
public:
- static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0);
+ static Ref<OpenXRActionSet> new_action_set(const char *p_name, const char *p_localized_name, const int p_priority = 0); // Helper function for adding and setting up an action set
- void set_localized_name(const String p_localized_name);
- String get_localized_name() const;
+ void set_localized_name(const String p_localized_name); // Set the localized name of this action set
+ String get_localized_name() const; // Get the localized name of this action set
- void set_priority(const int p_priority);
- int get_priority() const;
+ void set_priority(const int p_priority); // Set the priority of this action set
+ int get_priority() const; // Get the priority of this action set
- void set_actions(Array p_actions);
- Array get_actions() const;
+ int get_action_count() const; // Retrieve the number of actions in our action set
+ void set_actions(Array p_actions); // Set our actions using an array of actions (for loading a resource)
+ Array get_actions() const; // Get our actions as an array (for saving a resource)
- void add_action(Ref<OpenXRAction> p_action);
- void remove_action(Ref<OpenXRAction> p_action);
+ Ref<OpenXRAction> get_action(const String p_name) const; // Retrieve an action by name
+ void add_action(Ref<OpenXRAction> p_action); // Add a new action to our action set
+ void remove_action(Ref<OpenXRAction> p_action); // remove a action from our action set
- Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths);
+ Ref<OpenXRAction> add_new_action(const char *p_name, const char *p_localized_name, const OpenXRAction::ActionType p_action_type, const char *p_toplevel_paths); // Helper function for adding and setting up an action
+
+ // TODO add validation to display in the interface that checks if we have duplicate action names within our action set
~OpenXRActionSet();
};
diff --git a/modules/openxr/action_map/openxr_defs.cpp b/modules/openxr/action_map/openxr_defs.cpp
new file mode 100644
index 0000000000..e10326449c
--- /dev/null
+++ b/modules/openxr/action_map/openxr_defs.cpp
@@ -0,0 +1,493 @@
+/*************************************************************************/
+/* openxr_defs.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_defs.h"
+
+// Our top level paths to which devices can be bound
+OpenXRDefs::TopLevelPath OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_TOP_LEVEL_PATH_MAX] = {
+ { "Left hand controller", "/user/hand/left" },
+ { "Right hand controller", "/user/hand/right" },
+};
+
+// Fallback Khronos simple controller
+OpenXRDefs::IOPath OpenXRDefs::simple_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Select click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/select/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Select click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/select/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Original HTC Vive wands
+OpenXRDefs::IOPath OpenXRDefs::vive_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Microsoft motion controller (original WMR controllers)
+OpenXRDefs::IOPath OpenXRDefs::motion_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// HP MR controller (newer G2 controllers)
+OpenXRDefs::IOPath OpenXRDefs::hpmr_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Meta touch controller (original touch controllers, Quest 1 and Quest 2 controllers)
+OpenXRDefs::IOPath OpenXRDefs::touch_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "X touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Valve index controller
+OpenXRDefs::IOPath OpenXRDefs::index_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Squeeze", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad force", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/force", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad force", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/force", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Samsung odyssey controller
+OpenXRDefs::IOPath OpenXRDefs::odyssey_io_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Vive Cosmos controller
+OpenXRDefs::IOPath OpenXRDefs::vive_cosmos_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Shoulder click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/shoulder/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Vive Focus 3 controller
+OpenXRDefs::IOPath OpenXRDefs::vive_focus3_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Menu click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/menu/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "System click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/system/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "X click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/x/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Y click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/y/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "A click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/a/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "B click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/b/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/touch ", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Squeeze touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/squeeze/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Thumbstick click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Thumbstick touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbstick/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Thumbrest touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/thumbrest/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+// Huawei controller
+OpenXRDefs::IOPath OpenXRDefs::huawei_controller_paths[] = {
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Grip pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/grip/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+ { "Aim pose", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/aim/pose", OpenXRAction::OPENXR_ACTION_POSE },
+
+ { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Home click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/home/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Back click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/back/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Volume up click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_up/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Volume down click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/volume_down/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trigger", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/value", OpenXRAction::OPENXR_ACTION_FLOAT },
+ { "Trigger click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trigger/click", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad", OpenXRAction::OPENXR_ACTION_VECTOR2 },
+ { "Trackpad click", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/click", OpenXRAction::OPENXR_ACTION_BOOL },
+ { "Trackpad touch", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/input/trackpad/touch", OpenXRAction::OPENXR_ACTION_BOOL },
+
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_LEFT_HAND], "/user/hand/left/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+ { "Haptic output", &OpenXRDefs::available_top_level_paths[OpenXRDefs::OPENXR_RIGHT_HAND], "/user/hand/right/output/haptic", OpenXRAction::OPENXR_ACTION_HAPTIC },
+};
+
+OpenXRDefs::InteractionProfile OpenXRDefs::available_interaction_profiles[] = {
+ {
+ "Simple controller", // display_name
+ "/interaction_profiles/khr/simple_controller", // openxr_path
+ simple_io_paths, // io_paths
+ sizeof(simple_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "HTC Vive wand", // display_name
+ "/interaction_profiles/htc/vive_controller", // openxr_path
+ vive_io_paths, // io_paths
+ sizeof(vive_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "MS Motion controller", // display_name
+ "/interaction_profiles/microsoft/motion_controller", // openxr_path
+ motion_io_paths, // io_paths
+ sizeof(motion_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "HPMR controller", // display_name
+ "/interaction_profiles/hp/mixed_reality_controller", // openxr_path
+ hpmr_io_paths, // io_paths
+ sizeof(hpmr_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Touch controller", // display_name
+ "/interaction_profiles/oculus/touch_controller", // openxr_path
+ touch_io_paths, // io_paths
+ sizeof(touch_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Index controller", // display_name
+ "/interaction_profiles/valve/index_controller", // openxr_path
+ index_io_paths, // io_paths
+ sizeof(index_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Samsung Odyssey controller", // display_name
+ "/interaction_profiles/samsung/odyssey_controller", // openxr_path
+ odyssey_io_paths, // io_paths
+ sizeof(odyssey_io_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Vive Cosmos controller", // display_name
+ "/interaction_profiles/htc/vive_cosmos_controller", // openxr_path
+ vive_cosmos_paths, // io_paths
+ sizeof(vive_cosmos_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Vive Focus 3 controller", // display_name
+ "/interaction_profiles/htc/vive_focus3_controller", // openxr_path
+ vive_focus3_paths, // io_paths
+ sizeof(vive_focus3_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+ {
+ "Huawei controller", // display_name
+ "/interaction_profiles/huawei/controller", // openxr_path
+ huawei_controller_paths, // io_paths
+ sizeof(huawei_controller_paths) / sizeof(OpenXRDefs::IOPath) // io_path_count
+ },
+};
+
+int OpenXRDefs::available_interaction_profile_count = sizeof(OpenXRDefs::available_interaction_profiles) / sizeof(OpenXRDefs::InteractionProfile);
+
+const OpenXRDefs::TopLevelPath *OpenXRDefs::get_top_level_path(const String p_top_level_path) {
+ for (int i = 0; i < OPENXR_TOP_LEVEL_PATH_MAX; i++) {
+ if (available_top_level_paths[i].openxr_path == p_top_level_path) {
+ return &OpenXRDefs::available_top_level_paths[i];
+ }
+ }
+
+ return nullptr;
+}
+
+const OpenXRDefs::InteractionProfile *OpenXRDefs::get_profile(const String p_interaction_profile_path) {
+ for (int i = 0; i < available_interaction_profile_count; i++) {
+ if (available_interaction_profiles[i].openxr_path == p_interaction_profile_path) {
+ return &available_interaction_profiles[i];
+ }
+ }
+
+ return nullptr;
+}
+
+const OpenXRDefs::IOPath *OpenXRDefs::InteractionProfile::get_io_path(const String p_io_path) const {
+ for (int i = 0; i < available_interaction_profiles[i].io_path_count; i++) {
+ if (io_paths[i].openxr_path == p_io_path) {
+ return &io_paths[i];
+ }
+ }
+
+ return nullptr;
+}
+
+const OpenXRDefs::IOPath *OpenXRDefs::get_io_path(const String p_interaction_profile_path, const String p_io_path) {
+ const OpenXRDefs::InteractionProfile *profile = OpenXRDefs::get_profile(p_interaction_profile_path);
+ if (profile != nullptr) {
+ return profile->get_io_path(p_io_path);
+ }
+
+ return nullptr;
+}
+
+PackedStringArray OpenXRDefs::get_interaction_profile_paths() {
+ PackedStringArray arr;
+
+ for (int i = 0; i < available_interaction_profile_count; i++) {
+ arr.push_back(available_interaction_profiles[i].openxr_path);
+ }
+
+ return arr;
+}
diff --git a/modules/openxr/action_map/openxr_defs.h b/modules/openxr/action_map/openxr_defs.h
new file mode 100644
index 0000000000..dbda4757f1
--- /dev/null
+++ b/modules/openxr/action_map/openxr_defs.h
@@ -0,0 +1,103 @@
+/*************************************************************************/
+/* openxr_defs.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_DEFS_H
+#define OPENXR_DEFS_H
+
+#include "openxr_action.h"
+
+///////////////////////////////////////////////////////////////////////////
+// Stores available interaction profiles
+//
+// OpenXR defines and hardcodes all the supported input devices and their
+// paths as part of the OpenXR spec. When support for new devices is
+// introduced this often starts life as extensions that need to be enabled
+// until they are adopted into the core. As there is no interface to
+// enumerate the possibly paths, and that any OpenXR runtime would likely
+// limit such enumeration to those input devices supported by that runtime
+// there is no other option than to hardcode this.
+//
+// Note on action type that automatic conversions between boolean and float
+// are supported but otherwise action types should match between action and
+// input/output paths.
+
+class OpenXRDefs {
+public:
+ enum TOP_LEVEL_PATH {
+ OPENXR_LEFT_HAND,
+ OPENXR_RIGHT_HAND,
+ OPENXR_TOP_LEVEL_PATH_MAX
+ };
+
+ struct TopLevelPath {
+ const char *display_name; // User friendly display name (i.e. Left controller)
+ const char *openxr_path; // Path in OpenXR (i.e. /user/hand/left)
+ };
+
+ struct IOPath {
+ const char *display_name; // User friendly display name (i.e. Grip pose (left controller))
+ const TopLevelPath *top_level_path; // Top level path identifying the usage of the device in relation to this input/output
+ const char *openxr_path; // Path in OpenXR (i.e. /user/hand/left/input/grip/pose)
+ const OpenXRAction::ActionType action_type; // Type of input/output
+ };
+
+ struct InteractionProfile {
+ const char *display_name; // User friendly display name (i.e. Simple controller)
+ const char *openxr_path; // Path in OpenXR (i.e. /interaction_profiles/khr/simple_controller)
+ const IOPath *io_paths; // Inputs and outputs for this device
+ const int io_path_count; // Number of inputs and outputs for this device
+
+ const IOPath *get_io_path(const String p_io_path) const;
+ };
+
+private:
+ static TopLevelPath available_top_level_paths[OPENXR_TOP_LEVEL_PATH_MAX];
+ static IOPath simple_io_paths[];
+ static IOPath vive_io_paths[];
+ static IOPath motion_io_paths[];
+ static IOPath hpmr_io_paths[];
+ static IOPath touch_io_paths[];
+ static IOPath index_io_paths[];
+ static IOPath odyssey_io_paths[];
+ static IOPath vive_cosmos_paths[];
+ static IOPath vive_focus3_paths[];
+ static IOPath huawei_controller_paths[];
+ static InteractionProfile available_interaction_profiles[];
+ static int available_interaction_profile_count;
+
+public:
+ static const TopLevelPath *get_top_level_path(const String p_top_level_path);
+ static const InteractionProfile *get_profile(const String p_interaction_profile_path);
+ static const IOPath *get_io_path(const String p_interaction_profile_path, const String p_io_path);
+
+ static PackedStringArray get_interaction_profile_paths();
+};
+
+#endif // !OPENXR_DEFS_H
diff --git a/modules/openxr/action_map/openxr_interaction_profile.cpp b/modules/openxr/action_map/openxr_interaction_profile.cpp
index bc33814f17..342c36cdff 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.cpp
+++ b/modules/openxr/action_map/openxr_interaction_profile.cpp
@@ -35,9 +35,14 @@ void OpenXRIPBinding::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_action"), &OpenXRIPBinding::get_action);
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "action", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRAction"), "set_action", "get_action");
+ ClassDB::bind_method(D_METHOD("get_path_count"), &OpenXRIPBinding::get_path_count);
ClassDB::bind_method(D_METHOD("set_paths", "paths"), &OpenXRIPBinding::set_paths);
ClassDB::bind_method(D_METHOD("get_paths"), &OpenXRIPBinding::get_paths);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "paths", PROPERTY_HINT_ARRAY_TYPE, "STRING"), "set_paths", "get_paths");
+
+ ClassDB::bind_method(D_METHOD("has_path"), &OpenXRIPBinding::has_path);
+ ClassDB::bind_method(D_METHOD("add_path", "path"), &OpenXRIPBinding::add_path);
+ ClassDB::bind_method(D_METHOD("remove_path", "path"), &OpenXRIPBinding::remove_path);
}
Ref<OpenXRIPBinding> OpenXRIPBinding::new_binding(const Ref<OpenXRAction> p_action, const char *p_paths) {
@@ -59,6 +64,10 @@ Ref<OpenXRAction> OpenXRIPBinding::get_action() const {
return action;
}
+int OpenXRIPBinding::get_path_count() const {
+ return paths.size();
+}
+
void OpenXRIPBinding::set_paths(const PackedStringArray p_paths) {
paths = p_paths;
}
@@ -71,6 +80,22 @@ void OpenXRIPBinding::parse_paths(const String p_paths) {
paths = p_paths.split(",", false);
}
+bool OpenXRIPBinding::has_path(const String p_path) const {
+ return paths.has(p_path);
+}
+
+void OpenXRIPBinding::add_path(const String p_path) {
+ if (!paths.has(p_path)) {
+ paths.push_back(p_path);
+ }
+}
+
+void OpenXRIPBinding::remove_path(const String p_path) {
+ if (paths.has(p_path)) {
+ paths.erase(p_path);
+ }
+}
+
OpenXRIPBinding::~OpenXRIPBinding() {
action.unref();
}
@@ -80,6 +105,8 @@ void OpenXRInteractionProfile::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_interaction_profile_path"), &OpenXRInteractionProfile::get_interaction_profile_path);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "interaction_profile_path"), "set_interaction_profile_path", "get_interaction_profile_path");
+ ClassDB::bind_method(D_METHOD("get_binding_count"), &OpenXRInteractionProfile::get_binding_count);
+ ClassDB::bind_method(D_METHOD("get_binding", "index"), &OpenXRInteractionProfile::get_binding);
ClassDB::bind_method(D_METHOD("set_bindings", "bindings"), &OpenXRInteractionProfile::set_bindings);
ClassDB::bind_method(D_METHOD("get_bindings"), &OpenXRInteractionProfile::get_bindings);
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "bindings", PROPERTY_HINT_RESOURCE_TYPE, "OpenXRIPBinding", PROPERTY_USAGE_NO_EDITOR), "set_bindings", "get_bindings");
@@ -101,18 +128,43 @@ String OpenXRInteractionProfile::get_interaction_profile_path() const {
return interaction_profile_path;
}
+int OpenXRInteractionProfile::get_binding_count() const {
+ return bindings.size();
+}
+
+Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding(int p_index) const {
+ ERR_FAIL_INDEX_V(p_index, bindings.size(), Ref<OpenXRIPBinding>());
+
+ return bindings[p_index];
+}
+
void OpenXRInteractionProfile::set_bindings(Array p_bindings) {
bindings = p_bindings;
+
+ // TODO add check here that our bindings don't contain duplicate actions
}
Array OpenXRInteractionProfile::get_bindings() const {
return bindings;
}
+Ref<OpenXRIPBinding> OpenXRInteractionProfile::get_binding_for_action(const Ref<OpenXRAction> p_action) const {
+ for (int i = 0; i < bindings.size(); i++) {
+ Ref<OpenXRIPBinding> binding = bindings[i];
+ if (binding->get_action() == p_action) {
+ return binding;
+ }
+ }
+
+ return Ref<OpenXRIPBinding>();
+}
+
void OpenXRInteractionProfile::add_binding(Ref<OpenXRIPBinding> p_binding) {
ERR_FAIL_COND(p_binding.is_null());
if (bindings.find(p_binding) == -1) {
+ ERR_FAIL_COND_MSG(get_binding_for_action(p_binding->get_action()).is_valid(), "There is already a binding for this action in this interaction profile");
+
bindings.push_back(p_binding);
}
}
@@ -131,6 +183,15 @@ void OpenXRInteractionProfile::add_new_binding(const Ref<OpenXRAction> p_action,
add_binding(binding);
}
+void OpenXRInteractionProfile::remove_binding_for_action(const Ref<OpenXRAction> p_action) {
+ for (int i = bindings.size() - 1; i >= 0; i--) {
+ Ref<OpenXRIPBinding> binding = bindings[i];
+ if (binding->get_action() == p_action) {
+ remove_binding(binding);
+ }
+ }
+}
+
OpenXRInteractionProfile::~OpenXRInteractionProfile() {
bindings.clear();
}
diff --git a/modules/openxr/action_map/openxr_interaction_profile.h b/modules/openxr/action_map/openxr_interaction_profile.h
index abbc429e7d..46b1bda50f 100644
--- a/modules/openxr/action_map/openxr_interaction_profile.h
+++ b/modules/openxr/action_map/openxr_interaction_profile.h
@@ -34,6 +34,7 @@
#include "core/io/resource.h"
#include "openxr_action.h"
+#include "openxr_defs.h"
class OpenXRIPBinding : public Resource {
GDCLASS(OpenXRIPBinding, Resource);
@@ -46,15 +47,22 @@ protected:
static void _bind_methods();
public:
- static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths);
+ static Ref<OpenXRIPBinding> new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Helper function for adding a new binding
- void set_action(const Ref<OpenXRAction> p_action);
- Ref<OpenXRAction> get_action() const;
+ void set_action(const Ref<OpenXRAction> p_action); // Set the action for this binding
+ Ref<OpenXRAction> get_action() const; // Get the action for this binding
- void set_paths(const PackedStringArray p_paths);
- PackedStringArray get_paths() const;
+ int get_path_count() const; // Get the number of io paths
+ void set_paths(const PackedStringArray p_paths); // Set our paths (for loading from resource)
+ PackedStringArray get_paths() const; // Get our paths (for saving to resource)
- void parse_paths(const String p_paths);
+ void parse_paths(const String p_paths); // Parse a comma separated string of io paths.
+
+ bool has_path(const String p_path) const; // Has this io path
+ void add_path(const String p_path); // Add an io path
+ void remove_path(const String p_path); // Remove an io path
+
+ // TODO add validation that we can display in the interface that checks if no two paths belong to the same top level path
~OpenXRIPBinding();
};
@@ -70,18 +78,22 @@ protected:
static void _bind_methods();
public:
- static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path);
+ static Ref<OpenXRInteractionProfile> new_profile(const char *p_input_profile_path); // Helper function to create a new interaction profile
- void set_interaction_profile_path(const String p_input_profile_path);
- String get_interaction_profile_path() const;
+ void set_interaction_profile_path(const String p_input_profile_path); // Set our input profile path
+ String get_interaction_profile_path() const; // get our input profile path
- void set_bindings(Array p_bindings);
- Array get_bindings() const;
+ int get_binding_count() const; // Retrieve the number of bindings in this profile path
+ Ref<OpenXRIPBinding> get_binding(int p_index) const;
+ void set_bindings(Array p_bindings); // Set the bindings (for loading from a resource)
+ Array get_bindings() const; // Get the bindings (for saving to a resource)
- void add_binding(Ref<OpenXRIPBinding> p_binding);
- void remove_binding(Ref<OpenXRIPBinding> p_binding);
+ Ref<OpenXRIPBinding> get_binding_for_action(const Ref<OpenXRAction> p_action) const; // Get our binding record for a given action
+ void add_binding(Ref<OpenXRIPBinding> p_binding); // Add a binding object
+ void remove_binding(Ref<OpenXRIPBinding> p_binding); // Remove a binding object
- void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths);
+ void add_new_binding(const Ref<OpenXRAction> p_action, const char *p_paths); // Create a new binding for this profile
+ void remove_binding_for_action(const Ref<OpenXRAction> p_action); // Remove all bindings for this action
~OpenXRInteractionProfile();
};
diff --git a/modules/openxr/doc_classes/OpenXRActionMap.xml b/modules/openxr/doc_classes/OpenXRActionMap.xml
index 4dd2b83ca7..a29d10be41 100644
--- a/modules/openxr/doc_classes/OpenXRActionMap.xml
+++ b/modules/openxr/doc_classes/OpenXRActionMap.xml
@@ -31,6 +31,46 @@
Setup this action set with our default actions.
</description>
</method>
+ <method name="find_action_set" qualifiers="const">
+ <return type="OpenXRActionSet" />
+ <argument index="0" name="name" type="String" />
+ <description>
+ Retrieve an action set by name.
+ </description>
+ </method>
+ <method name="find_interaction_profile" qualifiers="const">
+ <return type="OpenXRInteractionProfile" />
+ <argument index="0" name="name" type="String" />
+ <description>
+ Find an interaction profile by its name (path).
+ </description>
+ </method>
+ <method name="get_action_set" qualifiers="const">
+ <return type="OpenXRActionSet" />
+ <argument index="0" name="idx" type="int" />
+ <description>
+ Retrieve the action set at this index.
+ </description>
+ </method>
+ <method name="get_action_set_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Retrieve the number of actions sets in our action map.
+ </description>
+ </method>
+ <method name="get_interaction_profile" qualifiers="const">
+ <return type="OpenXRInteractionProfile" />
+ <argument index="0" name="idx" type="int" />
+ <description>
+ Get the interaction profile at this index.
+ </description>
+ </method>
+ <method name="get_interaction_profile_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Retrieve the number of interaction profiles in our action map.
+ </description>
+ </method>
<method name="remove_action_set">
<return type="void" />
<argument index="0" name="action_set" type="OpenXRActionSet" />
@@ -48,8 +88,10 @@
</methods>
<members>
<member name="action_sets" type="Array" setter="set_action_sets" getter="get_action_sets" default="[]">
+ Collection of [OpenXRActionSet]s that are part of this action map.
</member>
<member name="interaction_profiles" type="Array" setter="set_interaction_profiles" getter="get_interaction_profiles" default="[]">
+ Collection of [OpenXRInteractionProfile]s that are part of this action map.
</member>
</members>
</class>
diff --git a/modules/openxr/doc_classes/OpenXRActionSet.xml b/modules/openxr/doc_classes/OpenXRActionSet.xml
index 5a87de463e..55cc0aaad4 100644
--- a/modules/openxr/doc_classes/OpenXRActionSet.xml
+++ b/modules/openxr/doc_classes/OpenXRActionSet.xml
@@ -5,8 +5,7 @@
</brief_description>
<description>
Action sets in OpenXR define a collection of actions that can be activated in unison. This allows games to easily change between different states that require different inputs or need to reinterpret inputs. For instance we could have an action set that is active when a menu is open, an action set that is active when the player is freely walking around and an action set that is active when the player is controlling a vehicle.
- Action sets can contain the same actions, or actions with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active.
- Note that the name of the resource is used to identify the action set within OpenXR.
+ Action sets can contain the same action with the same name, if such action sets are active at the same time the action set with the highest priority defines which binding is active.
</description>
<tutorials>
</tutorials>
@@ -18,6 +17,12 @@
Add an action to this action set.
</description>
</method>
+ <method name="get_action_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Retrieve the number of actions in our action set.
+ </description>
+ </method>
<method name="remove_action">
<return type="void" />
<argument index="0" name="action" type="OpenXRAction" />
diff --git a/modules/openxr/doc_classes/OpenXRIPBinding.xml b/modules/openxr/doc_classes/OpenXRIPBinding.xml
index 3fdcde5eb5..9e1176874a 100644
--- a/modules/openxr/doc_classes/OpenXRIPBinding.xml
+++ b/modules/openxr/doc_classes/OpenXRIPBinding.xml
@@ -4,13 +4,42 @@
Defines a binding between an [OpenXRAction] and an XR input or output.
</brief_description>
<description>
- This binding resource binds an OpenXR action to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger".
+ This binding resource binds an [OpenXRAction] to inputs or outputs. As most controllers have left hand and right versions that are handled by the same interaction profile we can specify multiple bindings. For instance an action "Fire" could be bound to both "/user/hand/left/input/trigger" and "/user/hand/right/input/trigger".
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="add_path">
+ <return type="void" />
+ <argument index="0" name="path" type="String" />
+ <description>
+ Add an input/output path to this binding.
+ </description>
+ </method>
+ <method name="get_path_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Get the number of input/output paths in this binding.
+ </description>
+ </method>
+ <method name="has_path" qualifiers="const">
+ <return type="bool" />
+ <argument index="0" name="arg0" type="String" />
+ <description>
+ Returns [code]true[/code] if this input/output path is part of this binding.
+ </description>
+ </method>
+ <method name="remove_path">
+ <return type="void" />
+ <argument index="0" name="path" type="String" />
+ <description>
+ Removes this input/output path from this binding.
+ </description>
+ </method>
+ </methods>
<members>
<member name="action" type="OpenXRAction" setter="set_action" getter="get_action">
- Action that is bound to these paths.
+ [OpenXRAction] that is bound to these paths.
</member>
<member name="paths" type="PackedStringArray" setter="set_paths" getter="get_paths" default="PackedStringArray()">
Paths that define the inputs or outputs bound on the device.
diff --git a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
index a8629caae4..71c0db44ed 100644
--- a/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
+++ b/modules/openxr/doc_classes/OpenXRInteractionProfile.xml
@@ -9,6 +9,21 @@
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="get_binding" qualifiers="const">
+ <return type="OpenXRIPBinding" />
+ <argument index="0" name="index" type="int" />
+ <description>
+ Retrieve the binding at this index.
+ </description>
+ </method>
+ <method name="get_binding_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Get the number of bindings in this interaction profile.
+ </description>
+ </method>
+ </methods>
<members>
<member name="bindings" type="Array" setter="set_bindings" getter="get_bindings" default="[]">
Action bindings for this interaction profile.
diff --git a/modules/openxr/editor/SCsub b/modules/openxr/editor/SCsub
new file mode 100644
index 0000000000..ccf67a80d0
--- /dev/null
+++ b/modules/openxr/editor/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.modules_sources, "*.cpp")
diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp
new file mode 100644
index 0000000000..e2a4f67f16
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_editor.cpp
@@ -0,0 +1,112 @@
+/*************************************************************************/
+/* openxr_action_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_action_editor.h"
+
+void OpenXRActionEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_editor")));
+}
+
+void OpenXRActionEditor::_theme_changed() {
+ rem_action->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+}
+
+void OpenXRActionEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ _theme_changed();
+ } break;
+ }
+}
+
+void OpenXRActionEditor::_on_action_name_changed(const String p_new_text) {
+ // TODO validate if entry is allowed
+
+ // If our localized name matches our action name, set this too
+ if (action->get_name() == action->get_localized_name()) {
+ action->set_localized_name(p_new_text);
+ action_localized_name->set_text(p_new_text);
+ }
+ action->set_name(p_new_text);
+}
+
+void OpenXRActionEditor::_on_action_localized_name_changed(const String p_new_text) {
+ action->set_localized_name(p_new_text);
+}
+
+void OpenXRActionEditor::_on_item_selected(int p_idx) {
+ ERR_FAIL_COND(p_idx < 0);
+ ERR_FAIL_COND(p_idx >= OpenXRAction::OPENXR_ACTION_MAX);
+
+ action->set_action_type(OpenXRAction::ActionType(p_idx));
+}
+
+void OpenXRActionEditor::_on_remove_action() {
+ emit_signal("remove", this);
+}
+
+OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) {
+ action = p_action;
+
+ set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ action_name = memnew(LineEdit);
+ action_name->set_text(action->get_name());
+ action_name->set_custom_minimum_size(Size2(150.0, 0.0));
+ action_name->connect("text_changed", callable_mp(this, &OpenXRActionEditor::_on_action_name_changed));
+ add_child(action_name);
+
+ action_localized_name = memnew(LineEdit);
+ action_localized_name->set_text(action->get_localized_name());
+ action_localized_name->set_custom_minimum_size(Size2(150.0, 0.0));
+ action_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ action_localized_name->connect("text_changed", callable_mp(this, &OpenXRActionEditor::_on_action_localized_name_changed));
+ add_child(action_localized_name);
+
+ action_type = memnew(OptionButton);
+ action_type->add_item("Bool", OpenXRAction::OPENXR_ACTION_BOOL);
+ action_type->add_item("Float", OpenXRAction::OPENXR_ACTION_FLOAT);
+ action_type->add_item("Vector2", OpenXRAction::OPENXR_ACTION_VECTOR2);
+ action_type->add_item("Pose", OpenXRAction::OPENXR_ACTION_POSE);
+ action_type->add_item("Haptic", OpenXRAction::OPENXR_ACTION_HAPTIC);
+ action_type->select(int(action->get_action_type()));
+ action_type->set_custom_minimum_size(Size2(100.0, 0.0));
+ action_type->connect("item_selected", callable_mp(this, &OpenXRActionEditor::_on_item_selected));
+ add_child(action_type);
+
+ // maybe add dropdown to edit our toplevel paths, or do we deduce them from our suggested bindings?
+
+ rem_action = memnew(Button);
+ rem_action->set_tooltip(TTR("Remove action"));
+ rem_action->connect("pressed", callable_mp(this, &OpenXRActionEditor::_on_remove_action));
+ rem_action->set_flat(true);
+ add_child(rem_action);
+}
diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h
new file mode 100644
index 0000000000..6e1b7ab779
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_editor.h
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* openxr_action_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_ACTION_EDITOR_H
+#define OPENXR_ACTION_EDITOR_H
+
+#include "../action_map/openxr_action.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/text_edit.h"
+
+class OpenXRActionEditor : public HBoxContainer {
+ GDCLASS(OpenXRActionEditor, HBoxContainer);
+
+private:
+ Ref<OpenXRAction> action;
+
+ LineEdit *action_name = nullptr;
+ LineEdit *action_localized_name = nullptr;
+ OptionButton *action_type = nullptr;
+ Button *rem_action = nullptr;
+
+ void _theme_changed();
+ void _on_action_name_changed(const String p_new_text);
+ void _on_action_localized_name_changed(const String p_new_text);
+ void _on_item_selected(int p_idx);
+ void _on_remove_action();
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ Ref<OpenXRAction> get_action() { return action; };
+ OpenXRActionEditor(Ref<OpenXRAction> p_action);
+};
+
+#endif // !OPENXR_ACTION_EDITOR_H
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
new file mode 100644
index 0000000000..6e9a2e1b61
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -0,0 +1,370 @@
+/*************************************************************************/
+/* openxr_action_map_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_action_map_editor.h"
+
+#include "core/config/project_settings.h"
+#include "editor/editor_file_dialog.h"
+#include "editor/editor_node.h"
+#include "editor/editor_scale.h"
+#include "editor/editor_settings.h"
+
+// TODO implement redo/undo system
+
+void OpenXRActionMapEditor::_bind_methods() {
+ ClassDB::bind_method("_add_action_set_editor", &OpenXRActionMapEditor::_add_action_set_editor);
+ ClassDB::bind_method("_update_action_sets", &OpenXRActionMapEditor::_update_action_sets);
+
+ ClassDB::bind_method("_add_interaction_profile_editor", &OpenXRActionMapEditor::_add_interaction_profile_editor);
+ ClassDB::bind_method("_update_interaction_profiles", &OpenXRActionMapEditor::_update_interaction_profiles);
+
+ ClassDB::bind_method(D_METHOD("_add_action_set", "name"), &OpenXRActionMapEditor::_add_action_set);
+ ClassDB::bind_method(D_METHOD("_set_focus_on_action_set", "action_set"), &OpenXRActionMapEditor::_set_focus_on_action_set);
+ ClassDB::bind_method(D_METHOD("_remove_action_set", "name"), &OpenXRActionMapEditor::_remove_action_set);
+}
+
+void OpenXRActionMapEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ for (int i = 0; i < tabs->get_child_count(); i++) {
+ Control *tab = static_cast<Control *>(tabs->get_child(i));
+ if (tab) {
+ tab->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ }
+ }
+ } break;
+
+ case NOTIFICATION_READY: {
+ _update_action_sets();
+ _update_interaction_profiles();
+ } break;
+ }
+}
+
+OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set_editor(Ref<OpenXRActionSet> p_action_set) {
+ ERR_FAIL_COND_V(p_action_set.is_null(), nullptr);
+
+ OpenXRActionSetEditor *action_set_editor = memnew(OpenXRActionSetEditor(action_map, p_action_set));
+ action_set_editor->connect("remove", callable_mp(this, &OpenXRActionMapEditor::_on_remove_action_set));
+ action_set_editor->connect("action_removed", callable_mp(this, &OpenXRActionMapEditor::_on_action_removed));
+ actionsets_vb->add_child(action_set_editor);
+
+ return action_set_editor;
+}
+
+void OpenXRActionMapEditor::_update_action_sets() {
+ // out with the old...
+ while (actionsets_vb->get_child_count() > 0) {
+ memdelete(actionsets_vb->get_child(0));
+ }
+
+ // in with the new...
+ if (action_map.is_valid()) {
+ Array action_sets = action_map->get_action_sets();
+ for (int i = 0; i < action_sets.size(); i++) {
+ Ref<OpenXRActionSet> action_set = action_sets[i];
+ _add_action_set_editor(action_set);
+ }
+ }
+}
+
+OpenXRInteractionProfileEditorBase *OpenXRActionMapEditor::_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile) {
+ ERR_FAIL_COND_V(p_interaction_profile.is_null(), nullptr);
+
+ String profile_path = p_interaction_profile->get_interaction_profile_path();
+
+ // need to instance the correct editor for our profile
+ OpenXRInteractionProfileEditorBase *new_profile_editor = nullptr;
+ if (profile_path == "placeholder_text") {
+ // instance specific editor for this type
+ } else {
+ // instance generic editor
+ new_profile_editor = memnew(OpenXRInteractionProfileEditor(action_map, p_interaction_profile));
+ }
+
+ // now add it in..
+ ERR_FAIL_NULL_V(new_profile_editor, nullptr);
+ tabs->add_child(new_profile_editor);
+ new_profile_editor->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ tabs->set_tab_button_icon(tabs->get_tab_count() - 1, get_theme_icon(SNAME("close"), SNAME("TabBar")));
+
+ interaction_profiles.push_back(new_profile_editor);
+
+ return new_profile_editor;
+}
+
+void OpenXRActionMapEditor::_update_interaction_profiles() {
+ // out with the old...
+ while (interaction_profiles.size() > 0) {
+ Node *interaction_profile = interaction_profiles[0];
+ interaction_profiles.remove_at(0);
+
+ tabs->remove_child(interaction_profile);
+ interaction_profile->queue_delete();
+ }
+
+ // in with the new...
+ if (action_map.is_valid()) {
+ Array new_interaction_profiles = action_map->get_interaction_profiles();
+ for (int i = 0; i < new_interaction_profiles.size(); i++) {
+ Ref<OpenXRInteractionProfile> interaction_profile = new_interaction_profiles[i];
+ _add_interaction_profile_editor(interaction_profile);
+ }
+ }
+}
+
+OpenXRActionSetEditor *OpenXRActionMapEditor::_add_action_set(String p_name) {
+ ERR_FAIL_COND_V(action_map.is_null(), nullptr);
+ Ref<OpenXRActionSet> new_action_set;
+
+ // add our new action set
+ new_action_set.instantiate();
+ new_action_set->set_name(p_name);
+ new_action_set->set_localized_name(p_name);
+ action_map->add_action_set(new_action_set);
+
+ // update our editor right away
+ return _add_action_set_editor(new_action_set);
+}
+
+void OpenXRActionMapEditor::_remove_action_set(String p_name) {
+ ERR_FAIL_COND(action_map.is_null());
+ Ref<OpenXRActionSet> action_set = action_map->find_action_set(p_name);
+ ERR_FAIL_COND(action_set.is_null());
+
+ if (action_set->get_action_count() > 0) {
+ // we should remove these and add to our redo/undo step before calling _remove_action_set
+ WARN_PRINT("Action set still has associated actions before being removed!");
+ }
+
+ // now we remove it
+ action_map->remove_action_set(action_set);
+}
+
+void OpenXRActionMapEditor::_on_add_action_set() {
+ ERR_FAIL_COND(action_map.is_null());
+ String new_name = "New";
+ int count = 0;
+
+ while (action_map->find_action_set(new_name).is_valid()) {
+ new_name = "New_" + itos(count++);
+ }
+
+ OpenXRActionSetEditor *new_action_set_editor = _add_action_set(new_name);
+
+ // Make sure our action set is the current tab
+ tabs->set_current_tab(0);
+
+ call_deferred("_set_focus_on_action_set", new_action_set_editor);
+}
+
+void OpenXRActionMapEditor::_set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor) {
+ // Scroll down to our new entry
+ actionsets_scroll->ensure_control_visible(p_action_set_editor);
+
+ // Set focus on this entry
+ p_action_set_editor->set_focus_on_entry();
+}
+
+void OpenXRActionMapEditor::_on_remove_action_set(Object *p_action_set_editor) {
+ ERR_FAIL_COND(action_map.is_null());
+
+ OpenXRActionSetEditor *action_set_editor = Object::cast_to<OpenXRActionSetEditor>(p_action_set_editor);
+ ERR_FAIL_NULL(action_set_editor);
+ ERR_FAIL_COND(action_set_editor->get_parent() != actionsets_vb);
+ Ref<OpenXRActionSet> action_set = action_set_editor->get_action_set();
+ ERR_FAIL_COND(action_set.is_null());
+
+ action_map->remove_action_set(action_set);
+ actionsets_vb->remove_child(action_set_editor);
+ action_set_editor->queue_delete();
+}
+
+void OpenXRActionMapEditor::_on_action_removed() {
+ // make sure our interaction profiles are updated
+ _update_interaction_profiles();
+}
+
+void OpenXRActionMapEditor::_on_add_interaction_profile() {
+ ERR_FAIL_COND(action_map.is_null());
+
+ PackedStringArray already_selected;
+
+ for (int i = 0; i < action_map->get_interaction_profile_count(); i++) {
+ already_selected.push_back(action_map->get_interaction_profile(i)->get_interaction_profile_path());
+ }
+
+ select_interaction_profile_dialog->open(already_selected);
+}
+
+void OpenXRActionMapEditor::_on_interaction_profile_selected(const String p_path) {
+ ERR_FAIL_COND(action_map.is_null());
+
+ Ref<OpenXRInteractionProfile> new_profile;
+ new_profile.instantiate();
+ new_profile->set_interaction_profile_path(p_path);
+ action_map->add_interaction_profile(new_profile);
+
+ _add_interaction_profile_editor(new_profile);
+
+ tabs->set_current_tab(tabs->get_tab_count() - 1);
+}
+
+void OpenXRActionMapEditor::_load_action_map(const String p_path, bool p_create_new_if_missing) {
+ action_map = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_IGNORE);
+ if (action_map.is_null()) {
+ if (p_create_new_if_missing) {
+ action_map.instantiate();
+ action_map->create_default_action_sets();
+ } else {
+ EditorNode::get_singleton()->show_warning(TTR("Invalid file, not an OpenXR action map."));
+
+ edited_path = "";
+ header_label->set_text("");
+ return;
+ }
+ }
+
+ edited_path = p_path;
+ header_label->set_text(TTR("OpenXR Action map:") + " " + p_path.get_file());
+}
+
+void OpenXRActionMapEditor::_on_save_action_map() {
+ Error err = ResourceSaver::save(edited_path, action_map);
+ if (err != OK) {
+ EditorNode::get_singleton()->show_warning(vformat(TTR("Error saving file: %s"), edited_path));
+ return;
+ }
+
+ _update_action_sets();
+ _update_interaction_profiles();
+}
+
+void OpenXRActionMapEditor::_on_reset_to_default_layout() {
+ // create a new one
+ action_map.unref();
+ action_map.instantiate();
+ action_map->create_default_action_sets();
+
+ _update_action_sets();
+ _update_interaction_profiles();
+}
+
+void OpenXRActionMapEditor::_on_tabs_tab_changed(int p_tab) {
+}
+
+void OpenXRActionMapEditor::_on_tab_button_pressed(int p_tab) {
+ OpenXRInteractionProfileEditorBase *profile_editor = static_cast<OpenXRInteractionProfileEditorBase *>(tabs->get_tab_control(p_tab));
+ ERR_FAIL_NULL(profile_editor);
+
+ Ref<OpenXRInteractionProfile> interaction_profile = profile_editor->get_interaction_profile();
+ ERR_FAIL_COND(interaction_profile.is_null());
+
+ action_map->remove_interaction_profile(interaction_profile);
+ tabs->remove_child(profile_editor);
+ profile_editor->queue_delete();
+}
+
+void OpenXRActionMapEditor::open_action_map(String p_path) {
+ EditorNode::get_singleton()->make_bottom_panel_item_visible(this);
+
+ _load_action_map(p_path);
+
+ _update_action_sets();
+ _update_interaction_profiles();
+}
+
+OpenXRActionMapEditor::OpenXRActionMapEditor() {
+ set_custom_minimum_size(Size2(0.0, 300.0));
+
+ top_hb = memnew(HBoxContainer);
+ add_child(top_hb);
+
+ header_label = memnew(Label);
+ header_label->set_text(String(TTR("Action Map")));
+ header_label->set_clip_text(true);
+ header_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ top_hb->add_child(header_label);
+
+ add_action_set = memnew(Button);
+ add_action_set->set_text(TTR("Add Action Set"));
+ add_action_set->set_tooltip(TTR("Add an action set."));
+ add_action_set->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_action_set));
+ top_hb->add_child(add_action_set);
+
+ add_interaction_profile = memnew(Button);
+ add_interaction_profile->set_text(TTR("Add profile"));
+ add_interaction_profile->set_tooltip(TTR("Add an interaction profile."));
+ add_interaction_profile->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_add_interaction_profile));
+ top_hb->add_child(add_interaction_profile);
+
+ VSeparator *vseparator = memnew(VSeparator);
+ top_hb->add_child(vseparator);
+
+ save_as = memnew(Button);
+ save_as->set_text(TTR("Save"));
+ save_as->set_tooltip(TTR("Save this OpenXR action map."));
+ save_as->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_save_action_map));
+ top_hb->add_child(save_as);
+
+ _default = memnew(Button);
+ _default->set_text(TTR("Reset to Default"));
+ _default->set_tooltip(TTR("Reset to default OpenXR action map."));
+ _default->connect("pressed", callable_mp(this, &OpenXRActionMapEditor::_on_reset_to_default_layout));
+ top_hb->add_child(_default);
+
+ tabs = memnew(TabContainer);
+ tabs->set_h_size_flags(SIZE_EXPAND_FILL);
+ tabs->set_v_size_flags(SIZE_EXPAND_FILL);
+ tabs->connect("tab_changed", callable_mp(this, &OpenXRActionMapEditor::_on_tabs_tab_changed));
+ tabs->connect("tab_button_pressed", callable_mp(this, &OpenXRActionMapEditor::_on_tab_button_pressed));
+ add_child(tabs);
+
+ actionsets_scroll = memnew(ScrollContainer);
+ actionsets_scroll->set_h_size_flags(SIZE_EXPAND_FILL);
+ actionsets_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ actionsets_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
+ tabs->add_child(actionsets_scroll);
+ actionsets_scroll->set_name(TTR("Action Sets"));
+
+ actionsets_vb = memnew(VBoxContainer);
+ actionsets_vb->set_h_size_flags(SIZE_EXPAND_FILL);
+ actionsets_scroll->add_child(actionsets_vb);
+
+ select_interaction_profile_dialog = memnew(OpenXRSelectInteractionProfileDialog);
+ select_interaction_profile_dialog->connect("interaction_profile_selected", callable_mp(this, &OpenXRActionMapEditor::_on_interaction_profile_selected));
+ add_child(select_interaction_profile_dialog);
+
+ _load_action_map(ProjectSettings::get_singleton()->get("xr/openxr/default_action_map"));
+}
+
+OpenXRActionMapEditor::~OpenXRActionMapEditor() {
+}
diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h
new file mode 100644
index 0000000000..dfc941b500
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_map_editor.h
@@ -0,0 +1,100 @@
+/*************************************************************************/
+/* openxr_action_map_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_ACTION_MAP_EDITOR_H
+#define OPENXR_ACTION_MAP_EDITOR_H
+
+#include "../action_map/openxr_action_map.h"
+#include "../editor/openxr_action_set_editor.h"
+#include "../editor/openxr_interaction_profile_editor.h"
+#include "../editor/openxr_select_interaction_profile_dialog.h"
+
+#include "editor/editor_plugin.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/label.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/tab_container.h"
+
+class OpenXRActionMapEditor : public VBoxContainer {
+ GDCLASS(OpenXRActionMapEditor, VBoxContainer);
+
+private:
+ String edited_path;
+ Ref<OpenXRActionMap> action_map;
+ Vector<Node *> interaction_profiles;
+
+ HBoxContainer *top_hb = nullptr;
+ Label *header_label = nullptr;
+ Button *add_action_set = nullptr;
+ Button *add_interaction_profile = nullptr;
+ Button *load = nullptr;
+ Button *save_as = nullptr;
+ Button *_default = nullptr;
+ TabContainer *tabs = nullptr;
+ ScrollContainer *actionsets_scroll = nullptr;
+ VBoxContainer *actionsets_vb = nullptr;
+ OpenXRSelectInteractionProfileDialog *select_interaction_profile_dialog = nullptr;
+
+ OpenXRActionSetEditor *_add_action_set_editor(Ref<OpenXRActionSet> p_action_set);
+ void _update_action_sets();
+ OpenXRInteractionProfileEditorBase *_add_interaction_profile_editor(Ref<OpenXRInteractionProfile> p_interaction_profile);
+ void _update_interaction_profiles();
+
+ OpenXRActionSetEditor *_add_action_set(String p_name);
+ void _remove_action_set(String p_name);
+
+ void _on_add_action_set();
+ void _set_focus_on_action_set(OpenXRActionSetEditor *p_action_set_editor);
+ void _on_remove_action_set(Object *p_action_set_editor);
+ void _on_action_removed();
+
+ void _on_add_interaction_profile();
+ void _on_interaction_profile_selected(const String p_path);
+
+ void _load_action_map(const String p_path, bool p_create_new_if_missing = false);
+ void _on_save_action_map();
+ void _on_reset_to_default_layout();
+
+ void _on_tabs_tab_changed(int p_tab);
+ void _on_tab_button_pressed(int p_tab);
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void open_action_map(String p_path);
+
+ OpenXRActionMapEditor();
+ ~OpenXRActionMapEditor();
+};
+
+#endif // !OPENXR_ACTION_MAP_EDITOR_H
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
new file mode 100644
index 0000000000..7bf8557c5b
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -0,0 +1,218 @@
+/*************************************************************************/
+/* openxr_action_set_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_action_set_editor.h"
+#include "openxr_action_editor.h"
+
+void OpenXRActionSetEditor::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("remove", PropertyInfo(Variant::OBJECT, "action_set_editor")));
+ ADD_SIGNAL(MethodInfo("action_removed"));
+}
+
+void OpenXRActionSetEditor::_set_fold_icon() {
+ if (is_expanded) {
+ fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowDown"), SNAME("EditorIcons")));
+ } else {
+ fold_btn->set_icon(get_theme_icon(SNAME("GuiTreeArrowRight"), SNAME("EditorIcons")));
+ }
+}
+
+void OpenXRActionSetEditor::_theme_changed() {
+ _set_fold_icon();
+ add_action->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ rem_action_set->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+}
+
+void OpenXRActionSetEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ _theme_changed();
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ } break;
+ }
+}
+
+OpenXRActionEditor *OpenXRActionSetEditor::_add_action_editor(Ref<OpenXRAction> p_action) {
+ OpenXRActionEditor *action_editor = memnew(OpenXRActionEditor(p_action));
+ action_editor->connect("remove", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action));
+ actions_vb->add_child(action_editor);
+
+ return action_editor;
+}
+
+void OpenXRActionSetEditor::_update_actions() {
+ // out with the old...
+ while (actions_vb->get_child_count() > 0) {
+ memdelete(actions_vb->get_child(0));
+ }
+
+ // in with the new...
+ Array actions = action_set->get_actions();
+ for (int i = 0; i < actions.size(); i++) {
+ Ref<OpenXRAction> action = actions[i];
+ _add_action_editor(action);
+ }
+}
+
+void OpenXRActionSetEditor::_on_toggle_expand() {
+ is_expanded = !is_expanded;
+ actions_vb->set_visible(is_expanded);
+ _set_fold_icon();
+}
+
+void OpenXRActionSetEditor::_on_action_set_name_changed(const String p_new_text) {
+ // TODO validate if entry is allowed
+
+ // If our localized name matches our action set name, set this too
+ if (action_set->get_name() == action_set->get_localized_name()) {
+ action_set->set_localized_name(p_new_text);
+ action_set_localized_name->set_text(p_new_text);
+ }
+ action_set->set_name(p_new_text);
+}
+
+void OpenXRActionSetEditor::_on_action_set_localized_name_changed(const String p_new_text) {
+ action_set->set_localized_name(p_new_text);
+}
+
+void OpenXRActionSetEditor::_on_action_set_priority_changed(const String p_new_text) {
+ int64_t value = p_new_text.to_int();
+
+ action_set->set_priority(value);
+}
+
+void OpenXRActionSetEditor::_on_add_action() {
+ Ref<OpenXRAction> new_action;
+
+ new_action.instantiate();
+ new_action->set_name("New");
+ new_action->set_localized_name("New");
+ action_set->add_action(new_action);
+
+ _add_action_editor(new_action);
+
+ // TODO handle focus
+}
+
+void OpenXRActionSetEditor::_on_remove_action_set() {
+ emit_signal("remove", this);
+}
+
+void OpenXRActionSetEditor::_on_remove_action(Object *p_action_editor) {
+ OpenXRActionEditor *action_editor = Object::cast_to<OpenXRActionEditor>(p_action_editor);
+ ERR_FAIL_NULL(action_editor);
+ ERR_FAIL_COND(action_editor->get_parent() != actions_vb);
+ Ref<OpenXRAction> action = action_editor->get_action();
+ ERR_FAIL_COND(action.is_null());
+
+ // TODO add undo/redo action
+
+ // TODO find where this action is used by our interaction profiles and remove it there
+
+ // And remove it....
+ action_map->remove_action(action->get_name_with_set()); // remove it from the set and any interaction profile it relates to
+ actions_vb->remove_child(action_editor);
+ action_editor->queue_delete();
+
+ // Let action map editor know so we can update our interaction profiles
+ emit_signal("action_removed");
+}
+
+void OpenXRActionSetEditor::set_focus_on_entry() {
+ ERR_FAIL_NULL(action_set_name);
+ action_set_name->grab_focus();
+}
+
+OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) {
+ action_map = p_action_map;
+ action_set = p_action_set;
+
+ set_h_size_flags(Control::SIZE_EXPAND_FILL);
+
+ panel = memnew(PanelContainer);
+ panel->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ add_child(panel);
+
+ HBoxContainer *panel_hb = memnew(HBoxContainer);
+ panel_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ panel->add_child(panel_hb);
+
+ fold_btn = memnew(Button);
+ fold_btn->set_v_size_flags(Control::SIZE_SHRINK_BEGIN);
+ fold_btn->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_toggle_expand));
+ fold_btn->set_flat(true);
+ panel_hb->add_child(fold_btn);
+
+ main_vb = memnew(VBoxContainer);
+ main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ panel_hb->add_child(main_vb);
+
+ action_set_hb = memnew(HBoxContainer);
+ action_set_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vb->add_child(action_set_hb);
+
+ action_set_name = memnew(LineEdit);
+ action_set_name->set_text(action_set->get_name());
+ action_set_name->set_custom_minimum_size(Size2(150.0, 0.0));
+ action_set_name->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_name_changed));
+ action_set_hb->add_child(action_set_name);
+
+ action_set_localized_name = memnew(LineEdit);
+ action_set_localized_name->set_text(action_set->get_localized_name());
+ action_set_localized_name->set_custom_minimum_size(Size2(150.0, 0.0));
+ action_set_localized_name->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ action_set_localized_name->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_localized_name_changed));
+ action_set_hb->add_child(action_set_localized_name);
+
+ action_set_priority = memnew(TextEdit);
+ action_set_priority->set_text(itos(action_set->get_priority()));
+ action_set_priority->set_custom_minimum_size(Size2(50.0, 0.0));
+ action_set_priority->connect("text_changed", callable_mp(this, &OpenXRActionSetEditor::_on_action_set_priority_changed));
+ action_set_hb->add_child(action_set_priority);
+
+ add_action = memnew(Button);
+ add_action->set_tooltip("Add Action.");
+ add_action->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_add_action));
+ add_action->set_flat(true);
+ action_set_hb->add_child(add_action);
+
+ rem_action_set = memnew(Button);
+ rem_action_set->set_tooltip("Remove Action Set.");
+ rem_action_set->connect("pressed", callable_mp(this, &OpenXRActionSetEditor::_on_remove_action_set));
+ rem_action_set->set_flat(true);
+ action_set_hb->add_child(rem_action_set);
+
+ actions_vb = memnew(VBoxContainer);
+ actions_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ main_vb->add_child(actions_vb);
+
+ _update_actions();
+}
diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h
new file mode 100644
index 0000000000..f3960dcbf9
--- /dev/null
+++ b/modules/openxr/editor/openxr_action_set_editor.h
@@ -0,0 +1,88 @@
+/*************************************************************************/
+/* openxr_action_set_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_ACTION_SET_EDITOR_H
+#define OPENXR_ACTION_SET_EDITOR_H
+
+#include "../action_map/openxr_action_map.h"
+#include "../action_map/openxr_action_set.h"
+#include "openxr_action_editor.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/panel_container.h"
+#include "scene/gui/text_edit.h"
+
+class OpenXRActionSetEditor : public HBoxContainer {
+ GDCLASS(OpenXRActionSetEditor, HBoxContainer);
+
+private:
+ Ref<OpenXRActionMap> action_map;
+ Ref<OpenXRActionSet> action_set;
+
+ bool is_expanded = true;
+
+ PanelContainer *panel = nullptr;
+ Button *fold_btn = nullptr;
+ VBoxContainer *main_vb = nullptr;
+ HBoxContainer *action_set_hb = nullptr;
+ LineEdit *action_set_name = nullptr;
+ LineEdit *action_set_localized_name = nullptr;
+ TextEdit *action_set_priority = nullptr;
+ Button *add_action = nullptr;
+ Button *rem_action_set = nullptr;
+ VBoxContainer *actions_vb = nullptr;
+
+ void _set_fold_icon();
+ void _theme_changed();
+ OpenXRActionEditor *_add_action_editor(Ref<OpenXRAction> p_action);
+ void _update_actions();
+
+ void _on_toggle_expand();
+ void _on_action_set_name_changed(const String p_new_text);
+ void _on_action_set_localized_name_changed(const String p_new_text);
+ void _on_action_set_priority_changed(const String p_new_text);
+ void _on_add_action();
+ void _on_remove_action_set();
+
+ void _on_remove_action(Object *p_action_editor);
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ Ref<OpenXRActionSet> get_action_set() { return action_set; };
+ void set_focus_on_entry();
+
+ OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set);
+};
+
+#endif // !OPENXR_ACTION_SET_EDITOR_H
diff --git a/modules/openxr/editor/openxr_editor_plugin.cpp b/modules/openxr/editor/openxr_editor_plugin.cpp
new file mode 100644
index 0000000000..b87b538511
--- /dev/null
+++ b/modules/openxr/editor/openxr_editor_plugin.cpp
@@ -0,0 +1,58 @@
+/*************************************************************************/
+/* openxr_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_editor_plugin.h"
+
+#include "../action_map/openxr_action_map.h"
+#include "editor/editor_node.h"
+
+void OpenXREditorPlugin::edit(Object *p_node) {
+ if (Object::cast_to<OpenXRActionMap>(p_node)) {
+ String path = Object::cast_to<OpenXRActionMap>(p_node)->get_path();
+ if (path.is_resource_file()) {
+ action_map_editor->open_action_map(path);
+ }
+ }
+}
+
+bool OpenXREditorPlugin::handles(Object *p_node) const {
+ return (Object::cast_to<OpenXRActionMap>(p_node) != nullptr);
+}
+
+void OpenXREditorPlugin::make_visible(bool p_visible) {
+}
+
+OpenXREditorPlugin::OpenXREditorPlugin() {
+ action_map_editor = memnew(OpenXRActionMapEditor);
+ EditorNode::get_singleton()->add_bottom_panel_item(TTR("OpenXR Action Map"), action_map_editor);
+}
+
+OpenXREditorPlugin::~OpenXREditorPlugin() {
+}
diff --git a/modules/openxr/editor/openxr_editor_plugin.h b/modules/openxr/editor/openxr_editor_plugin.h
new file mode 100644
index 0000000000..af8ee7d54c
--- /dev/null
+++ b/modules/openxr/editor/openxr_editor_plugin.h
@@ -0,0 +1,53 @@
+/*************************************************************************/
+/* openxr_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_EDITOR_PLUGIN_H
+#define OPENXR_EDITOR_PLUGIN_H
+
+#include "editor/editor_plugin.h"
+#include "openxr_action_map_editor.h"
+
+class OpenXREditorPlugin : public EditorPlugin {
+ GDCLASS(OpenXREditorPlugin, EditorPlugin);
+
+ OpenXRActionMapEditor *action_map_editor = nullptr;
+
+public:
+ virtual String get_name() const override { return "OpenXRPlugin"; }
+ bool has_main_screen() const override { return false; }
+ virtual void edit(Object *p_node) override;
+ virtual bool handles(Object *p_node) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ OpenXREditorPlugin();
+ ~OpenXREditorPlugin();
+};
+
+#endif // !OPENXR_EDITOR_PLUGIN_H
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
new file mode 100644
index 0000000000..24ac5494dd
--- /dev/null
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
@@ -0,0 +1,274 @@
+/*************************************************************************/
+/* openxr_interaction_profile_editor.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_interaction_profile_editor.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/panel_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/text_edit.h"
+
+///////////////////////////////////////////////////////////////////////////
+// Interaction profile editor base
+
+void OpenXRInteractionProfileEditorBase::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("_add_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_add_binding);
+ ClassDB::bind_method(D_METHOD("_remove_binding", "action", "path"), &OpenXRInteractionProfileEditorBase::_remove_binding);
+ ClassDB::bind_method(D_METHOD("_update_interaction_profile"), &OpenXRInteractionProfileEditorBase::_update_interaction_profile);
+}
+
+void OpenXRInteractionProfileEditorBase::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE: {
+ _update_interaction_profile();
+ } break;
+
+ case NOTIFICATION_THEME_CHANGED: {
+ _theme_changed();
+ } break;
+ }
+}
+
+void OpenXRInteractionProfileEditorBase::_add_binding(const String p_action, const String p_path) {
+ ERR_FAIL_COND(action_map.is_null());
+ ERR_FAIL_COND(interaction_profile.is_null());
+
+ Ref<OpenXRAction> action = action_map->get_action(p_action);
+ ERR_FAIL_COND(action.is_null());
+
+ Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action);
+ if (binding.is_null()) {
+ // create a new binding
+ binding.instantiate();
+ binding->set_action(action);
+ interaction_profile->add_binding(binding);
+ }
+
+ binding->add_path(p_path);
+
+ // Update our toplevel paths
+ action->set_toplevel_paths(action_map->get_top_level_paths(action));
+
+ call_deferred("_update_interaction_profile");
+}
+
+void OpenXRInteractionProfileEditorBase::_remove_binding(const String p_action, const String p_path) {
+ ERR_FAIL_COND(action_map.is_null());
+ ERR_FAIL_COND(interaction_profile.is_null());
+
+ Ref<OpenXRAction> action = action_map->get_action(p_action);
+ ERR_FAIL_COND(action.is_null());
+
+ Ref<OpenXRIPBinding> binding = interaction_profile->get_binding_for_action(action);
+ if (binding.is_valid()) {
+ binding->remove_path(p_path);
+
+ if (binding->get_path_count() == 0) {
+ interaction_profile->remove_binding(binding);
+ }
+
+ // Update our toplevel paths
+ action->set_toplevel_paths(action_map->get_top_level_paths(action));
+
+ call_deferred("_update_interaction_profile");
+ }
+}
+
+OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) {
+ action_map = p_action_map;
+ interaction_profile = p_interaction_profile;
+ String profile_path = interaction_profile->get_interaction_profile_path();
+ String profile_name = profile_path;
+
+ profile_def = OpenXRDefs::get_profile(profile_path);
+ if (profile_def != nullptr) {
+ profile_name = profile_def->display_name;
+ }
+
+ set_name(profile_name);
+ set_h_size_flags(SIZE_EXPAND_FILL);
+ set_v_size_flags(SIZE_EXPAND_FILL);
+}
+
+///////////////////////////////////////////////////////////////////////////
+// Default interaction profile editor
+
+void OpenXRInteractionProfileEditor::select_action_for(const String p_io_path) {
+ selecting_for_io_path = p_io_path;
+ select_action_dialog->open();
+}
+
+void OpenXRInteractionProfileEditor::action_selected(const String p_action) {
+ _add_binding(p_action, selecting_for_io_path);
+ selecting_for_io_path = "";
+}
+
+void OpenXRInteractionProfileEditor::_add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path) {
+ HBoxContainer *path_hb = memnew(HBoxContainer);
+ path_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ p_container->add_child(path_hb);
+
+ Label *path_label = memnew(Label);
+ path_label->set_text(p_io_path->display_name);
+ path_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ path_hb->add_child(path_label);
+
+ Label *type_label = memnew(Label);
+ switch (p_io_path->action_type) {
+ case OpenXRAction::OPENXR_ACTION_BOOL: {
+ type_label->set_text(TTR("Boolean"));
+ } break;
+ case OpenXRAction::OPENXR_ACTION_FLOAT: {
+ type_label->set_text(TTR("Float"));
+ } break;
+ case OpenXRAction::OPENXR_ACTION_VECTOR2: {
+ type_label->set_text(TTR("Vector2"));
+ } break;
+ case OpenXRAction::OPENXR_ACTION_POSE: {
+ type_label->set_text(TTR("Pose"));
+ } break;
+ case OpenXRAction::OPENXR_ACTION_HAPTIC: {
+ type_label->set_text(TTR("Haptic"));
+ } break;
+ default: {
+ type_label->set_text(TTR("Unknown"));
+ } break;
+ }
+ type_label->set_custom_minimum_size(Size2(50.0, 0.0));
+ path_hb->add_child(type_label);
+
+ Button *path_add = memnew(Button);
+ path_add->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ path_add->set_flat(true);
+ Vector<Variant> add_binds;
+ add_binds.push_back(String(p_io_path->openxr_path));
+ path_add->connect("pressed", callable_mp(this, &OpenXRInteractionProfileEditor::select_action_for), add_binds);
+ path_hb->add_child(path_add);
+
+ if (interaction_profile.is_valid()) {
+ String io_path = String(p_io_path->openxr_path);
+ Array bindings = interaction_profile->get_bindings();
+ for (int i = 0; i < bindings.size(); i++) {
+ Ref<OpenXRIPBinding> binding = bindings[i];
+ if (binding->has_path(io_path)) {
+ Ref<OpenXRAction> action = binding->get_action();
+
+ HBoxContainer *action_hb = memnew(HBoxContainer);
+ action_hb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ p_container->add_child(action_hb);
+
+ Control *indent_node = memnew(Control);
+ indent_node->set_custom_minimum_size(Size2(10.0, 0.0));
+ action_hb->add_child(indent_node);
+
+ Label *action_label = memnew(Label);
+ action_label->set_text(action->get_name_with_set() + ": " + action->get_localized_name());
+ action_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ action_hb->add_child(action_label);
+
+ Button *action_rem = memnew(Button);
+ action_rem->set_flat(true);
+ action_rem->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ Vector<Variant> remove_binds;
+ remove_binds.push_back(action->get_name_with_set());
+ remove_binds.push_back(String(p_io_path->openxr_path));
+ action_rem->connect("pressed", callable_mp((OpenXRInteractionProfileEditorBase *)this, &OpenXRInteractionProfileEditorBase::_remove_binding), remove_binds);
+ action_hb->add_child(action_rem);
+ }
+ }
+ }
+}
+
+void OpenXRInteractionProfileEditor::_update_interaction_profile() {
+ ERR_FAIL_NULL(profile_def);
+
+ // out with the old...
+ while (main_hb->get_child_count() > 0) {
+ memdelete(main_hb->get_child(0));
+ }
+
+ // in with the new...
+
+ // Determine toplevel paths
+ Vector<const OpenXRDefs::TopLevelPath *> top_level_paths;
+ for (int i = 0; i < profile_def->io_path_count; i++) {
+ const OpenXRDefs::IOPath *io_path = &profile_def->io_paths[i];
+
+ if (!top_level_paths.has(io_path->top_level_path)) {
+ top_level_paths.push_back(io_path->top_level_path);
+ }
+ }
+
+ for (int i = 0; i < top_level_paths.size(); i++) {
+ PanelContainer *panel = memnew(PanelContainer);
+ panel->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ main_hb->add_child(panel);
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+
+ VBoxContainer *container = memnew(VBoxContainer);
+ panel->add_child(container);
+
+ Label *label = memnew(Label);
+ label->set_text(top_level_paths[i]->display_name);
+ container->add_child(label);
+
+ for (int j = 0; j < profile_def->io_path_count; j++) {
+ const OpenXRDefs::IOPath *io_path = &profile_def->io_paths[j];
+ if (io_path->top_level_path == top_level_paths[i]) {
+ _add_io_path(container, io_path);
+ }
+ }
+ }
+}
+
+void OpenXRInteractionProfileEditor::_theme_changed() {
+ for (int i = 0; i < main_hb->get_child_count(); i++) {
+ Control *panel = static_cast<Control *>(main_hb->get_child(i));
+ if (panel) {
+ panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("panel"), SNAME("TabContainer")));
+ }
+ }
+}
+
+OpenXRInteractionProfileEditor::OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) :
+ OpenXRInteractionProfileEditorBase(p_action_map, p_interaction_profile) {
+ // TODO background of scrollbox should be darker with our VBoxContainers we're adding in _update_interaction_profile the normal color
+
+ main_hb = memnew(HBoxContainer);
+ add_child(main_hb);
+
+ select_action_dialog = memnew(OpenXRSelectActionDialog(p_action_map));
+ select_action_dialog->connect("action_selected", callable_mp(this, &OpenXRInteractionProfileEditor::action_selected));
+ add_child(select_action_dialog);
+
+ _update_interaction_profile();
+}
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h
new file mode 100644
index 0000000000..f50da1a003
--- /dev/null
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.h
@@ -0,0 +1,83 @@
+/*************************************************************************/
+/* openxr_interaction_profile_editor.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_INTERACTION_PROFILE_EDITOR_H
+#define OPENXR_INTERACTION_PROFILE_EDITOR_H
+
+#include "../action_map/openxr_action_map.h"
+#include "../action_map/openxr_defs.h"
+#include "../action_map/openxr_interaction_profile.h"
+#include "scene/gui/scroll_container.h"
+
+#include "openxr_select_action_dialog.h"
+
+class OpenXRInteractionProfileEditorBase : public ScrollContainer {
+ GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer);
+
+protected:
+ Ref<OpenXRInteractionProfile> interaction_profile;
+ Ref<OpenXRActionMap> action_map;
+
+ static void _bind_methods();
+ void _notification(int p_what);
+
+ const OpenXRDefs::InteractionProfile *profile_def = nullptr;
+
+public:
+ Ref<OpenXRInteractionProfile> get_interaction_profile() { return interaction_profile; }
+
+ virtual void _update_interaction_profile() {}
+ virtual void _theme_changed() {}
+ void _add_binding(const String p_action, const String p_path);
+ void _remove_binding(const String p_action, const String p_path);
+
+ OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
+};
+
+class OpenXRInteractionProfileEditor : public OpenXRInteractionProfileEditorBase {
+ GDCLASS(OpenXRInteractionProfileEditor, OpenXRInteractionProfileEditorBase);
+
+private:
+ String selecting_for_io_path;
+ HBoxContainer *main_hb = nullptr;
+ OpenXRSelectActionDialog *select_action_dialog = nullptr;
+
+ void _add_io_path(VBoxContainer *p_container, const OpenXRDefs::IOPath *p_io_path);
+
+public:
+ void select_action_for(const String p_io_path);
+ void action_selected(const String p_action);
+
+ virtual void _update_interaction_profile() override;
+ virtual void _theme_changed() override;
+ OpenXRInteractionProfileEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile);
+};
+
+#endif // !OPENXR_INTERACTION_PROFILE_EDITOR_H
diff --git a/modules/openxr/editor/openxr_select_action_dialog.cpp b/modules/openxr/editor/openxr_select_action_dialog.cpp
new file mode 100644
index 0000000000..c2a2965200
--- /dev/null
+++ b/modules/openxr/editor/openxr_select_action_dialog.cpp
@@ -0,0 +1,135 @@
+/*************************************************************************/
+/* openxr_select_action_dialog.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_select_action_dialog.h"
+#include "editor/editor_node.h"
+
+void OpenXRSelectActionDialog::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("action_selected", PropertyInfo(Variant::STRING, "action")));
+}
+
+void OpenXRSelectActionDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ } break;
+ }
+}
+
+void OpenXRSelectActionDialog::_on_select_action(const String p_action) {
+ if (selected_action != "") {
+ NodePath button_path = action_buttons[selected_action];
+ Button *button = static_cast<Button *>(get_node(button_path));
+ if (button != nullptr) {
+ button->set_flat(true);
+ }
+ }
+
+ selected_action = p_action;
+
+ if (selected_action != "") {
+ NodePath button_path = action_buttons[selected_action];
+ Button *button = static_cast<Button *>(get_node(button_path));
+ if (button != nullptr) {
+ button->set_flat(false);
+ }
+ }
+}
+
+void OpenXRSelectActionDialog::open() {
+ ERR_FAIL_COND(action_map.is_null());
+
+ // out with the old...
+ while (main_vb->get_child_count() > 0) {
+ memdelete(main_vb->get_child(0));
+ }
+
+ selected_action = "";
+ action_buttons.clear();
+
+ Array action_sets = action_map->get_action_sets();
+ for (int i = 0; i < action_sets.size(); i++) {
+ Ref<OpenXRActionSet> action_set = action_sets[i];
+
+ Label *action_set_label = memnew(Label);
+ action_set_label->set_text(action_set->get_localized_name());
+ main_vb->add_child(action_set_label);
+
+ Array actions = action_set->get_actions();
+ for (int j = 0; j < actions.size(); j++) {
+ Ref<OpenXRAction> action = actions[j];
+
+ HBoxContainer *action_hb = memnew(HBoxContainer);
+ main_vb->add_child(action_hb);
+
+ Control *indent_node = memnew(Control);
+ indent_node->set_custom_minimum_size(Size2(10.0, 0.0));
+ action_hb->add_child(indent_node);
+
+ Button *action_button = memnew(Button);
+ String action_name = action->get_name_with_set();
+ Vector<Variant> binds;
+ binds.push_back(action_name);
+ action_button->set_flat(true);
+ action_button->set_text(action->get_name() + ": " + action->get_localized_name());
+ action_button->connect("pressed", callable_mp(this, &OpenXRSelectActionDialog::_on_select_action), binds);
+ action_hb->add_child(action_button);
+
+ action_buttons[action_name] = action_button->get_path();
+ }
+ }
+
+ popup_centered();
+}
+
+void OpenXRSelectActionDialog::ok_pressed() {
+ if (selected_action == "") {
+ return;
+ }
+
+ emit_signal("action_selected", selected_action);
+
+ hide();
+}
+
+OpenXRSelectActionDialog::OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map) {
+ action_map = p_action_map;
+
+ set_title(TTR("Select an action"));
+
+ scroll = memnew(ScrollContainer);
+ scroll->set_custom_minimum_size(Size2(600.0, 400.0));
+ add_child(scroll);
+
+ main_vb = memnew(VBoxContainer);
+ main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ scroll->add_child(main_vb);
+}
diff --git a/modules/openxr/editor/openxr_select_action_dialog.h b/modules/openxr/editor/openxr_select_action_dialog.h
new file mode 100644
index 0000000000..ea2c30373b
--- /dev/null
+++ b/modules/openxr/editor/openxr_select_action_dialog.h
@@ -0,0 +1,67 @@
+/*************************************************************************/
+/* openxr_select_action_dialog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_SELECT_ACTION_DIALOG_H
+#define OPENXR_SELECT_ACTION_DIALOG_H
+
+#include "../action_map/openxr_action_map.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/text_edit.h"
+
+class OpenXRSelectActionDialog : public ConfirmationDialog {
+ GDCLASS(OpenXRSelectActionDialog, ConfirmationDialog);
+
+private:
+ Ref<OpenXRActionMap> action_map;
+ String selected_action;
+ Dictionary action_buttons;
+
+ VBoxContainer *main_vb = nullptr;
+ ScrollContainer *scroll = nullptr;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void _on_select_action(const String p_action);
+ void open();
+ virtual void ok_pressed() override;
+
+ OpenXRSelectActionDialog(Ref<OpenXRActionMap> p_action_map);
+};
+
+#endif // !OPENXR_SELECT_ACTION_DIALOG_H
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
new file mode 100644
index 0000000000..12b110f146
--- /dev/null
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.cpp
@@ -0,0 +1,125 @@
+/*************************************************************************/
+/* openxr_select_interaction_profile_dialog.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 "openxr_select_interaction_profile_dialog.h"
+
+void OpenXRSelectInteractionProfileDialog::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("interaction_profile_selected", PropertyInfo(Variant::STRING, "interaction_profile")));
+}
+
+void OpenXRSelectInteractionProfileDialog::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ } break;
+ }
+}
+
+void OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile(const String p_interaction_profile) {
+ if (selected_interaction_profile != "") {
+ NodePath button_path = ip_buttons[selected_interaction_profile];
+ Button *button = static_cast<Button *>(get_node(button_path));
+ if (button != nullptr) {
+ button->set_flat(true);
+ }
+ }
+
+ selected_interaction_profile = p_interaction_profile;
+
+ if (selected_interaction_profile != "") {
+ NodePath button_path = ip_buttons[selected_interaction_profile];
+ Button *button = static_cast<Button *>(get_node(button_path));
+ if (button != nullptr) {
+ button->set_flat(false);
+ }
+ }
+}
+
+void OpenXRSelectInteractionProfileDialog::open(PackedStringArray p_do_not_include) {
+ int available_count = 0;
+
+ // out with the old...
+ while (main_vb->get_child_count() > 0) {
+ memdelete(main_vb->get_child(0));
+ }
+
+ selected_interaction_profile = "";
+ ip_buttons.clear();
+
+ // in with the new
+ PackedStringArray interaction_profiles = OpenXRDefs::get_interaction_profile_paths();
+ for (int i = 0; i < interaction_profiles.size(); i++) {
+ String path = interaction_profiles[i];
+ if (!p_do_not_include.has(path)) {
+ Button *ip_button = memnew(Button);
+ Vector<Variant> binds;
+ binds.push_back(path);
+ ip_button->set_flat(true);
+ ip_button->set_text(OpenXRDefs::get_profile(path)->display_name);
+ ip_button->connect("pressed", callable_mp(this, &OpenXRSelectInteractionProfileDialog::_on_select_interaction_profile), binds);
+ main_vb->add_child(ip_button);
+
+ ip_buttons[path] = ip_button->get_path();
+ available_count++;
+ }
+ }
+
+ if (available_count == 0) {
+ // give warning that we have all profiles selected
+
+ } else {
+ // TODO maybe if we only have one, auto select it?
+
+ popup_centered();
+ }
+}
+
+void OpenXRSelectInteractionProfileDialog::ok_pressed() {
+ if (selected_interaction_profile == "") {
+ return;
+ }
+
+ emit_signal("interaction_profile_selected", selected_interaction_profile);
+
+ hide();
+}
+
+OpenXRSelectInteractionProfileDialog::OpenXRSelectInteractionProfileDialog() {
+ set_title("Select an interaction profile");
+
+ scroll = memnew(ScrollContainer);
+ scroll->set_custom_minimum_size(Size2(600.0, 400.0));
+ add_child(scroll);
+
+ main_vb = memnew(VBoxContainer);
+ // main_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ scroll->add_child(main_vb);
+}
diff --git a/modules/openxr/editor/openxr_select_interaction_profile_dialog.h b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
new file mode 100644
index 0000000000..d177861ff3
--- /dev/null
+++ b/modules/openxr/editor/openxr_select_interaction_profile_dialog.h
@@ -0,0 +1,66 @@
+/*************************************************************************/
+/* openxr_select_interaction_profile_dialog.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 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 OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
+#define OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
+
+#include "../action_map/openxr_defs.h"
+#include "scene/gui/box_container.h"
+#include "scene/gui/button.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/label.h"
+#include "scene/gui/line_edit.h"
+#include "scene/gui/scroll_container.h"
+#include "scene/gui/separator.h"
+#include "scene/gui/text_edit.h"
+
+class OpenXRSelectInteractionProfileDialog : public ConfirmationDialog {
+ GDCLASS(OpenXRSelectInteractionProfileDialog, ConfirmationDialog);
+
+private:
+ String selected_interaction_profile;
+ Dictionary ip_buttons;
+
+ VBoxContainer *main_vb = nullptr;
+ ScrollContainer *scroll = nullptr;
+
+protected:
+ static void _bind_methods();
+ void _notification(int p_what);
+
+public:
+ void _on_select_interaction_profile(const String p_interaction_profile);
+ void open(PackedStringArray p_do_not_include);
+ virtual void ok_pressed() override;
+
+ OpenXRSelectInteractionProfileDialog();
+};
+
+#endif // !OPENXR_SELECT_INTERACTION_PROFILE_DIALOG_H
diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h
index 5242ee6063..0f7c0ba0bc 100644
--- a/modules/openxr/extensions/openxr_extension_wrapper.h
+++ b/modules/openxr/extensions/openxr_extension_wrapper.h
@@ -33,25 +33,26 @@
#include "core/error/error_macros.h"
#include "core/math/camera_matrix.h"
-#include "core/templates/map.h"
+#include "core/templates/hash_map.h"
#include "core/templates/rid.h"
#include "thirdparty/openxr/src/common/xr_linear.h"
#include <openxr/openxr.h>
class OpenXRAPI;
+class OpenXRActionMap;
class OpenXRExtensionWrapper {
protected:
- OpenXRAPI *openxr_api;
+ OpenXRAPI *openxr_api = nullptr;
// Store extension we require.
// If bool pointer is a nullptr this means this extension is mandatory and initialisation will fail if it is not available
// If bool pointer is set, value will be set to true or false depending on whether extension is available
- Map<const char *, bool *> request_extensions;
+ HashMap<String, bool *> request_extensions;
public:
- virtual Map<const char *, bool *> get_request_extensions() {
+ virtual HashMap<String, bool *> get_request_extensions() {
return request_extensions;
}
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp
index c7c840fdf3..2ddf3b8a7d 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.cpp
+++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp
@@ -30,10 +30,12 @@
#include "core/string/print_string.h"
-#include "modules/openxr/extensions/openxr_vulkan_extension.h"
-#include "modules/openxr/openxr_api.h"
-#include "modules/openxr/openxr_util.h"
+#include "../extensions/openxr_vulkan_extension.h"
+#include "../openxr_api.h"
+#include "../openxr_util.h"
+#include "servers/rendering/renderer_rd/effects/copy_effects.h"
#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_rd/storage_rd/texture_storage.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/rendering_server.h"
@@ -439,7 +441,7 @@ bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target
ERR_FAIL_COND_V(p_from_render_target.is_null(), false);
ERR_FAIL_NULL_V(RendererStorageRD::base_singleton, false);
- RID source_image = RendererStorageRD::base_singleton->render_target_get_rd_texture(p_from_render_target);
+ RID source_image = RendererRD::TextureStorage::get_singleton()->render_target_get_rd_texture(p_from_render_target);
ERR_FAIL_COND_V(source_image.is_null(), false);
RID depth_image; // TODO implement
@@ -449,11 +451,9 @@ bool OpenXRVulkanExtension::copy_render_target_to_image(RID p_from_render_target
ERR_FAIL_COND_V(fb.is_null(), false);
// Our vulkan extension can only be used in conjunction with our vulkan renderer.
- // We need access to the effects object in order to have access to our copy logic.
- // Breaking all the rules but there is no nice way to do this.
- EffectsRD *effects = RendererStorageRD::base_singleton->get_effects();
- ERR_FAIL_NULL_V(effects, false);
- effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview);
+ RendererRD::CopyEffects *copy_effects = RendererRD::CopyEffects::get_singleton();
+ ERR_FAIL_NULL_V(copy_effects, false);
+ copy_effects->copy_to_fb_rect(source_image, fb, Rect2i(), false, false, false, false, depth_image, data->is_multiview);
return true;
}
diff --git a/modules/openxr/extensions/openxr_vulkan_extension.h b/modules/openxr/extensions/openxr_vulkan_extension.h
index cf55ae264f..1e34fe1f80 100644
--- a/modules/openxr/extensions/openxr_vulkan_extension.h
+++ b/modules/openxr/extensions/openxr_vulkan_extension.h
@@ -78,11 +78,11 @@ private:
bool check_graphics_api_support(XrVersion p_desired_version);
- VkInstance vulkan_instance;
- VkPhysicalDevice vulkan_physical_device;
- VkDevice vulkan_device;
- uint32_t vulkan_queue_family_index;
- uint32_t vulkan_queue_index;
+ VkInstance vulkan_instance = nullptr;
+ VkPhysicalDevice vulkan_physical_device = nullptr;
+ VkDevice vulkan_device = nullptr;
+ uint32_t vulkan_queue_family_index = 0;
+ uint32_t vulkan_queue_index = 0;
XrResult xrGetVulkanGraphicsRequirements2KHR(XrInstance p_instance, XrSystemId p_system_id, XrGraphicsRequirementsVulkanKHR *p_graphics_requirements);
XrResult xrCreateVulkanInstanceKHR(XrInstance p_instance, const XrVulkanInstanceCreateInfoKHR *p_create_info, VkInstance *r_vulkan_instance, VkResult *r_vulkan_result);
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index 7752878d82..6e94e3b444 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -48,14 +48,14 @@
#include "extensions/openxr_vulkan_extension.h"
#endif
-#include "modules/openxr/openxr_interface.h"
+#include "openxr_interface.h"
OpenXRAPI *OpenXRAPI::singleton = nullptr;
-bool OpenXRAPI::openxr_is_enabled() {
+bool OpenXRAPI::openxr_is_enabled(bool p_check_run_in_editor) {
// @TODO we need an overrule switch so we can force enable openxr, i.e run "godot --openxr_enabled"
- if (Engine::get_singleton()->is_editor_hint()) {
+ if (Engine::get_singleton()->is_editor_hint() && p_check_run_in_editor) {
#ifdef TOOLS_ENABLED
// Disabled for now, using XR inside of the editor we'll be working on during the coming months.
return false;
@@ -170,13 +170,20 @@ bool OpenXRAPI::load_supported_extensions() {
return true;
}
-bool OpenXRAPI::is_extension_supported(const char *p_extension) const {
+bool OpenXRAPI::is_extension_supported(const String &p_extension) const {
for (uint32_t i = 0; i < num_supported_extensions; i++) {
- if (strcmp(supported_extensions[i].extensionName, p_extension)) {
+ if ((supported_extensions[i].extensionName == p_extension) == 0) {
+#ifdef DEBUG
+ print_line("OpenXR: requested extension", p_extension, "is supported");
+#endif
return true;
}
}
+#ifdef DEBUG
+ print_line("OpenXR: requested extension", p_extension, "is not supported");
+#endif
+
return false;
}
@@ -197,9 +204,9 @@ bool OpenXRAPI::create_instance() {
// Create our OpenXR instance, this will query any registered extension wrappers for extensions we need to enable.
// Append the extensions requested by the registered extension wrappers.
- Map<const char *, bool *> requested_extensions;
+ HashMap<String, bool *> requested_extensions;
for (OpenXRExtensionWrapper *wrapper : registered_extension_wrappers) {
- Map<const char *, bool *> wrapper_request_extensions = wrapper->get_request_extensions();
+ const HashMap<String, bool *> &wrapper_request_extensions = wrapper->get_request_extensions();
// requested_extensions.insert(wrapper_request_extensions.begin(), wrapper_request_extensions.end());
for (auto &requested_extension : wrapper_request_extensions) {
@@ -207,8 +214,17 @@ bool OpenXRAPI::create_instance() {
}
}
+ // Add optional extensions for controllers that may be supported.
+ // Overkill to create extension classes for this.
+ requested_extensions[XR_EXT_HP_MIXED_REALITY_CONTROLLER_EXTENSION_NAME] = &ext_hp_mixed_reality_available;
+ requested_extensions[XR_EXT_SAMSUNG_ODYSSEY_CONTROLLER_EXTENSION_NAME] = &ext_samsung_odyssey_available;
+ requested_extensions[XR_HTC_VIVE_COSMOS_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_cosmos_available;
+ requested_extensions[XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_vive_focus3_available;
+ requested_extensions[XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME] = &ext_huawei_controller_available;
+
// Check which extensions are supported
enabled_extensions.clear();
+
for (auto &requested_extension : requested_extensions) {
if (!is_extension_supported(requested_extension.key)) {
if (requested_extension.value == nullptr) {
@@ -223,13 +239,18 @@ bool OpenXRAPI::create_instance() {
*requested_extension.value = true;
// and record that we want to enable it
- enabled_extensions.push_back(requested_extension.key);
+ enabled_extensions.push_back(requested_extension.key.ascii());
} else {
// record that we want to enable this
- enabled_extensions.push_back(requested_extension.key);
+ enabled_extensions.push_back(requested_extension.key.ascii());
}
}
+ Vector<const char *> extension_ptrs;
+ for (int i = 0; i < enabled_extensions.size(); i++) {
+ extension_ptrs.push_back(enabled_extensions[i].get_data());
+ }
+
// Get our project name
String project_name = GLOBAL_GET("application/config/name");
@@ -249,8 +270,8 @@ bool OpenXRAPI::create_instance() {
application_info, // applicationInfo
0, // enabledApiLayerCount, need to find out if we need support for this?
nullptr, // enabledApiLayerNames
- uint32_t(enabled_extensions.size()), // enabledExtensionCount
- enabled_extensions.ptr() // enabledExtensionNames
+ uint32_t(extension_ptrs.size()), // enabledExtensionCount
+ extension_ptrs.ptr() // enabledExtensionNames
};
copy_string_to_char_buffer(project_name, instance_create_info.applicationInfo.applicationName, XR_MAX_APPLICATION_NAME_SIZE);
@@ -408,7 +429,7 @@ bool OpenXRAPI::load_supported_view_configuration_views(XrViewConfigurationType
for (uint32_t i = 0; i < view_count; i++) {
view_configuration_views[i].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
- view_configuration_views[i].next = NULL;
+ view_configuration_views[i].next = nullptr;
}
result = xrEnumerateViewConfigurationViews(instance, system_id, p_configuration_type, view_count, &view_count, view_configuration_views);
@@ -680,10 +701,10 @@ bool OpenXRAPI::create_main_swapchain() {
for (uint32_t i = 0; i < view_count; i++) {
views[i].type = XR_TYPE_VIEW;
- views[i].next = NULL;
+ views[i].next = nullptr;
projection_views[i].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
- projection_views[i].next = NULL;
+ projection_views[i].next = nullptr;
projection_views[i].subImage.swapchain = swapchain;
projection_views[i].subImage.imageArrayIndex = i;
projection_views[i].subImage.imageRect.offset.x = 0;
@@ -986,7 +1007,7 @@ bool OpenXRAPI::initialize(const String &p_rendering_driver) {
ERR_FAIL_V(false);
#endif
} else if (p_rendering_driver == "opengl3") {
-#ifdef OPENGL3_ENABLED
+#ifdef GLES3_ENABLED
// graphics_extension = memnew(OpenXROpenGLExtension(this));
// register_extension_wrapper(graphics_extension);
ERR_FAIL_V_MSG(false, "OpenXR: OpenGL is not supported at this time.");
@@ -1081,7 +1102,7 @@ Size2 OpenXRAPI::get_recommended_target_size() {
return target_size;
}
-XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
+XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity) {
XrResult result;
ERR_FAIL_COND_V(!running, XRPose::XR_TRACKING_CONFIDENCE_NONE);
@@ -1147,7 +1168,7 @@ bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) {
}
// we don't have valid view info
- if (views == NULL || !view_pose_valid) {
+ if (views == nullptr || !view_pose_valid) {
return false;
}
@@ -1167,7 +1188,7 @@ bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z
}
// we don't have valid view info
- if (views == NULL || !view_pose_valid) {
+ if (views == nullptr || !view_pose_valid) {
return false;
}
@@ -2282,7 +2303,7 @@ Vector2 OpenXRAPI::get_action_vector2(RID p_action, RID p_tracker) {
return result_state.isActive ? Vector2(result_state.currentState.x, result_state.currentState.y) : Vector2();
}
-XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
+XRPose::TrackingConfidence OpenXRAPI::get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity) {
ERR_FAIL_COND_V(session == XR_NULL_HANDLE, XRPose::XR_TRACKING_CONFIDENCE_NONE);
Action *action = action_owner.get_or_null(p_action);
ERR_FAIL_NULL_V(action, XRPose::XR_TRACKING_CONFIDENCE_NONE);
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 1a1508e993..bd71f0e1c2 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -37,7 +37,7 @@
#include "core/math/vector2.h"
#include "core/os/memory.h"
#include "core/string/ustring.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "core/templates/rid_owner.h"
#include "core/templates/vector.h"
#include "servers/xr/xr_pose.h"
@@ -73,7 +73,13 @@ private:
uint32_t num_supported_extensions = 0;
XrExtensionProperties *supported_extensions = nullptr;
Vector<OpenXRExtensionWrapper *> registered_extension_wrappers;
- Vector<const char *> enabled_extensions;
+ Vector<CharString> enabled_extensions;
+
+ bool ext_hp_mixed_reality_available = false;
+ bool ext_samsung_odyssey_available = false;
+ bool ext_vive_cosmos_available = false;
+ bool ext_vive_focus3_available = false;
+ bool ext_huawei_controller_available = false;
// composition layer providers
Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
@@ -98,9 +104,9 @@ private:
// state
XrInstance instance = XR_NULL_HANDLE;
- XrSystemId system_id;
+ XrSystemId system_id = 0;
String system_name;
- uint32_t vendor_id;
+ uint32_t vendor_id = 0;
XrSystemTrackingProperties tracking_properties;
XrSession session = XR_NULL_HANDLE;
XrSessionState session_state = XR_SESSION_STATE_UNKNOWN;
@@ -126,7 +132,7 @@ private:
bool load_layer_properties();
bool load_supported_extensions();
- bool is_extension_supported(const char *p_extension) const;
+ bool is_extension_supported(const String &p_extension) const;
// instance
bool create_instance();
@@ -222,7 +228,7 @@ protected:
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 r_angular_velocity);
public:
- static bool openxr_is_enabled();
+ static bool openxr_is_enabled(bool p_check_run_in_editor = true);
static OpenXRAPI *get_singleton();
String get_error_string(XrResult result);
@@ -241,7 +247,7 @@ public:
bool can_render() { return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && view_pose_valid && frame_state.shouldRender; };
Size2 get_recommended_target_size();
- XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
+ XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity);
bool get_view_transform(uint32_t p_view, Transform3D &r_transform);
bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, CameraMatrix &p_camera_matrix);
bool process();
@@ -279,7 +285,7 @@ public:
bool get_action_bool(RID p_action, RID p_tracker);
float get_action_float(RID p_action, RID p_tracker);
Vector2 get_action_vector2(RID p_action, RID p_tracker);
- XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
+ XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, const Vector3 &r_angular_velocity);
bool trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns);
OpenXRAPI();
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 41ce8c019e..ab06583932 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -113,7 +113,7 @@ void OpenXRInterface::_load_action_map() {
// process our action map
if (action_map.is_valid()) {
- Map<Ref<OpenXRAction>, Action *> xr_actions;
+ HashMap<Ref<OpenXRAction>, Action *> xr_actions;
Array action_sets = action_map->get_action_sets();
for (int i = 0; i < action_sets.size(); i++) {
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 47ee1316e7..c765f169dc 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -38,45 +38,71 @@
#include "action_map/openxr_action_set.h"
#include "action_map/openxr_interaction_profile.h"
-OpenXRAPI *openxr_api = nullptr;
-Ref<OpenXRInterface> openxr_interface;
+#ifdef TOOLS_ENABLED
-void preregister_openxr_types() {
- // For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon.
+#include "editor/editor_node.h"
+#include "editor/openxr_editor_plugin.h"
- if (OpenXRAPI::openxr_is_enabled()) {
- openxr_api = memnew(OpenXRAPI);
- ERR_FAIL_NULL(openxr_api);
+static void _editor_init() {
+ if (OpenXRAPI::openxr_is_enabled(false)) {
+ // Only add our OpenXR action map editor if OpenXR is enabled for our project
- if (!openxr_api->initialize(Main::get_rendering_driver_name())) {
- memdelete(openxr_api);
- openxr_api = nullptr;
- return;
- }
+ OpenXREditorPlugin *openxr_plugin = memnew(OpenXREditorPlugin());
+ EditorNode::get_singleton()->add_editor_plugin(openxr_plugin);
}
}
-void register_openxr_types() {
- GDREGISTER_CLASS(OpenXRInterface);
+#endif
+
+static OpenXRAPI *openxr_api = nullptr;
+static Ref<OpenXRInterface> openxr_interface;
- GDREGISTER_CLASS(OpenXRAction);
- GDREGISTER_CLASS(OpenXRActionSet);
- GDREGISTER_CLASS(OpenXRActionMap);
- GDREGISTER_CLASS(OpenXRIPBinding);
- GDREGISTER_CLASS(OpenXRInteractionProfile);
+void initialize_openxr_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ // For now we create our openxr device here. If we merge it with openxr_interface we'll create that here soon.
- XRServer *xr_server = XRServer::get_singleton();
- if (xr_server) {
- openxr_interface.instantiate();
- xr_server->add_interface(openxr_interface);
+ if (OpenXRAPI::openxr_is_enabled()) {
+ openxr_api = memnew(OpenXRAPI);
+ ERR_FAIL_NULL(openxr_api);
- if (openxr_interface->initialize_on_startup()) {
- openxr_interface->initialize();
+ if (!openxr_api->initialize(Main::get_rendering_driver_name())) {
+ memdelete(openxr_api);
+ openxr_api = nullptr;
+ return;
+ }
}
}
+
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
+ GDREGISTER_CLASS(OpenXRInterface);
+
+ GDREGISTER_CLASS(OpenXRAction);
+ GDREGISTER_CLASS(OpenXRActionSet);
+ GDREGISTER_CLASS(OpenXRActionMap);
+ GDREGISTER_CLASS(OpenXRIPBinding);
+ GDREGISTER_CLASS(OpenXRInteractionProfile);
+
+ XRServer *xr_server = XRServer::get_singleton();
+ if (xr_server) {
+ openxr_interface.instantiate();
+ xr_server->add_interface(openxr_interface);
+
+ if (openxr_interface->initialize_on_startup()) {
+ openxr_interface->initialize();
+ }
+ }
+
+#ifdef TOOLS_ENABLED
+ EditorNode::add_init_callback(_editor_init);
+#endif
+ }
}
-void unregister_openxr_types() {
+void uninitialize_openxr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (openxr_interface.is_valid()) {
// uninitialize just in case
if (openxr_interface->is_initialized()) {
diff --git a/modules/openxr/register_types.h b/modules/openxr/register_types.h
index fb42770750..1b3d98422d 100644
--- a/modules/openxr/register_types.h
+++ b/modules/openxr/register_types.h
@@ -33,8 +33,9 @@
#define MODULE_OPENXR_HAS_PREREGISTER
-void preregister_openxr_types();
-void register_openxr_types();
-void unregister_openxr_types();
+#include "modules/register_module_types.h"
+
+void initialize_openxr_module(ModuleInitializationLevel p_level);
+void uninitialize_openxr_module(ModuleInitializationLevel p_level);
#endif // OPENXR_REGISTER_TYPES_H
diff --git a/modules/raycast/lightmap_raycaster.cpp b/modules/raycast/lightmap_raycaster.cpp
index ecc256bff9..7e7c3f9067 100644
--- a/modules/raycast/lightmap_raycaster.cpp
+++ b/modules/raycast/lightmap_raycaster.cpp
@@ -152,8 +152,8 @@ void LightmapRaycasterEmbree::commit() {
rtcCommitScene(embree_scene);
}
-void LightmapRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) {
- for (Set<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
+void LightmapRaycasterEmbree::set_mesh_filter(const RBSet<int> &p_mesh_ids) {
+ for (RBSet<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
}
rtcCommitScene(embree_scene);
@@ -161,7 +161,7 @@ void LightmapRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) {
}
void LightmapRaycasterEmbree::clear_mesh_filter() {
- for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
+ for (RBSet<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
}
rtcCommitScene(embree_scene);
diff --git a/modules/raycast/lightmap_raycaster.h b/modules/raycast/lightmap_raycaster.h
index c420e617e5..4c52758fd8 100644
--- a/modules/raycast/lightmap_raycaster.h
+++ b/modules/raycast/lightmap_raycaster.h
@@ -52,8 +52,8 @@ private:
static void filter_function(const struct RTCFilterFunctionNArguments *p_args);
- Map<unsigned int, AlphaTextureData> alpha_textures;
- Set<int> filter_meshes;
+ HashMap<unsigned int, AlphaTextureData> alpha_textures;
+ RBSet<int> filter_meshes;
public:
virtual bool intersect(Ray &p_ray) override;
@@ -64,7 +64,7 @@ public:
virtual void set_mesh_alpha_texture(Ref<Image> p_alpha_texture, unsigned int p_id) override;
virtual void commit() override;
- virtual void set_mesh_filter(const Set<int> &p_mesh_ids) override;
+ virtual void set_mesh_filter(const RBSet<int> &p_mesh_ids) override;
virtual void clear_mesh_filter() override;
static LightmapRaycaster *create_embree_raycaster();
diff --git a/modules/raycast/raycast_occlusion_cull.cpp b/modules/raycast/raycast_occlusion_cull.cpp
index 2e0d17fb28..c165354c7b 100644
--- a/modules/raycast/raycast_occlusion_cull.cpp
+++ b/modules/raycast/raycast_occlusion_cull.cpp
@@ -85,7 +85,7 @@ void RaycastOcclusionCull::RaycastHZBuffer::update_camera_rays(const Transform3D
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_dir = -p_cam_transform.basis.get_column(2);
td.camera_orthogonal = p_cam_orthogonal;
CameraMatrix inv_camera_matrix = p_cam_projection.inverse();
@@ -223,7 +223,7 @@ void RaycastOcclusionCull::occluder_set_mesh(RID p_occluder, const PackedVector3
occluder->vertices = p_vertices;
occluder->indices = p_indices;
- for (Set<InstanceID>::Element *E = occluder->users.front(); E; E = E->next()) {
+ for (RBSet<InstanceID>::Element *E = occluder->users.front(); E; E = E->next()) {
RID scenario_rid = E->get().scenario;
RID instance_rid = E->get().instance;
ERR_CONTINUE(!scenarios.has(scenario_rid));
@@ -454,10 +454,9 @@ bool RaycastOcclusionCull::Scenario::update(ThreadWorkPool &p_thread_pool) {
next_scene = rtcNewScene(raycast_singleton->ebr_device);
rtcSetSceneBuildQuality(next_scene, RTCBuildQuality(raycast_singleton->build_quality));
- 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.get_or_null(occ_inst->occluder);
+ for (const KeyValue<RID, OccluderInstance> &E : instances) {
+ const OccluderInstance *occ_inst = &E.value;
+ const Occluder *occ = raycast_singleton->occluder_owner.get_or_null(occ_inst->occluder);
if (!occ || !occ_inst->enabled) {
continue;
@@ -548,7 +547,7 @@ 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.ptr(), buffer.camera_rays_tile_count, p_thread_pool);
- buffer.sort_rays(-p_cam_transform.basis.get_axis(2), p_cam_orthogonal);
+ buffer.sort_rays(-p_cam_transform.basis.get_column(2), p_cam_orthogonal);
buffer.update_mips();
}
@@ -573,9 +572,8 @@ void RaycastOcclusionCull::set_build_quality(RS::ViewportOcclusionCullingBuildQu
build_quality = p_quality;
- const RID *scenario_rid = nullptr;
- while ((scenario_rid = scenarios.next(scenario_rid))) {
- scenarios[*scenario_rid].dirty = true;
+ for (KeyValue<RID, Scenario> &K : scenarios) {
+ K.value.dirty = true;
}
}
@@ -596,9 +594,8 @@ RaycastOcclusionCull::RaycastOcclusionCull() {
}
RaycastOcclusionCull::~RaycastOcclusionCull() {
- const RID *scenario_rid = nullptr;
- while ((scenario_rid = scenarios.next(scenario_rid))) {
- Scenario &scenario = scenarios[*scenario_rid];
+ for (KeyValue<RID, Scenario> &K : scenarios) {
+ Scenario &scenario = K.value;
if (scenario.commit_thread) {
scenario.commit_thread->wait_to_finish();
memdelete(scenario.commit_thread);
diff --git a/modules/raycast/raycast_occlusion_cull.h b/modules/raycast/raycast_occlusion_cull.h
index a22e52dd17..779f6fb3c4 100644
--- a/modules/raycast/raycast_occlusion_cull.h
+++ b/modules/raycast/raycast_occlusion_cull.h
@@ -101,7 +101,7 @@ private:
struct Occluder {
PackedVector3Array vertices;
PackedInt32Array indices;
- Set<InstanceID> users;
+ RBSet<InstanceID> users;
};
struct OccluderInstance {
@@ -115,7 +115,7 @@ private:
struct Scenario {
struct RaycastThreadData {
- CameraRayTile *rays;
+ CameraRayTile *rays = nullptr;
const uint32_t *masks;
};
@@ -124,7 +124,7 @@ private:
uint32_t vertex_count;
Transform3D xform;
const Vector3 *read;
- Vector3 *write;
+ Vector3 *write = nullptr;
};
Thread *commit_thread = nullptr;
@@ -136,7 +136,7 @@ private:
int current_scene_idx = 0;
HashMap<RID, OccluderInstance> instances;
- Set<RID> dirty_instances; // To avoid duplicates
+ RBSet<RID> dirty_instances; // To avoid duplicates
LocalVector<RID> dirty_instances_array; // To iterate and split into threads
LocalVector<RID> removed_instances;
diff --git a/modules/raycast/register_types.cpp b/modules/raycast/register_types.cpp
index 053039a85b..42de1d971d 100644
--- a/modules/raycast/register_types.cpp
+++ b/modules/raycast/register_types.cpp
@@ -36,7 +36,11 @@
RaycastOcclusionCull *raycast_occlusion_cull = nullptr;
-void register_raycast_types() {
+void initialize_raycast_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
LightmapRaycasterEmbree::make_default_raycaster();
StaticRaycasterEmbree::make_default_raycaster();
@@ -44,7 +48,11 @@ void register_raycast_types() {
raycast_occlusion_cull = memnew(RaycastOcclusionCull);
}
-void unregister_raycast_types() {
+void uninitialize_raycast_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (raycast_occlusion_cull) {
memdelete(raycast_occlusion_cull);
}
diff --git a/modules/raycast/register_types.h b/modules/raycast/register_types.h
index 0abc5eb63a..a917285390 100644
--- a/modules/raycast/register_types.h
+++ b/modules/raycast/register_types.h
@@ -28,5 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
-void register_raycast_types();
-void unregister_raycast_types();
+#include "modules/register_module_types.h"
+
+void initialize_raycast_module(ModuleInitializationLevel p_level);
+void uninitialize_raycast_module(ModuleInitializationLevel p_level);
diff --git a/modules/raycast/static_raycaster.cpp b/modules/raycast/static_raycaster.cpp
index 9df6d5ff43..f2e944a82d 100644
--- a/modules/raycast/static_raycaster.cpp
+++ b/modules/raycast/static_raycaster.cpp
@@ -94,8 +94,8 @@ 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()) {
+void StaticRaycasterEmbree::set_mesh_filter(const RBSet<int> &p_mesh_ids) {
+ for (RBSet<int>::Element *E = p_mesh_ids.front(); E; E = E->next()) {
rtcDisableGeometry(rtcGetGeometry(embree_scene, E->get()));
}
rtcCommitScene(embree_scene);
@@ -103,7 +103,7 @@ void StaticRaycasterEmbree::set_mesh_filter(const Set<int> &p_mesh_ids) {
}
void StaticRaycasterEmbree::clear_mesh_filter() {
- for (Set<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
+ for (RBSet<int>::Element *E = filter_meshes.front(); E; E = E->next()) {
rtcEnableGeometry(rtcGetGeometry(embree_scene, E->get()));
}
rtcCommitScene(embree_scene);
diff --git a/modules/raycast/static_raycaster.h b/modules/raycast/static_raycaster.h
index cce19ba60d..b52b5bccfc 100644
--- a/modules/raycast/static_raycaster.h
+++ b/modules/raycast/static_raycaster.h
@@ -41,7 +41,7 @@ private:
static RTCDevice embree_device;
RTCScene embree_scene;
- Set<int> filter_meshes;
+ RBSet<int> filter_meshes;
public:
virtual bool intersect(Ray &p_ray) override;
@@ -50,7 +50,7 @@ public:
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 set_mesh_filter(const RBSet<int> &p_mesh_ids) override;
virtual void clear_mesh_filter() override;
static StaticRaycaster *create_embree_raycaster();
diff --git a/modules/regex/regex.cpp b/modules/regex/regex.cpp
index ee1137b71f..bbe92139e0 100644
--- a/modules/regex/regex.cpp
+++ b/modules/regex/regex.cpp
@@ -52,9 +52,9 @@ int RegExMatch::_find(const Variant &p_name) const {
return i;
} else if (p_name.get_type() == Variant::STRING) {
- const Map<String, int>::Element *found = names.find((String)p_name);
+ HashMap<String, int>::ConstIterator found = names.find((String)p_name);
if (found) {
- return found->value();
+ return found->value;
}
}
@@ -75,8 +75,8 @@ int RegExMatch::get_group_count() const {
Dictionary RegExMatch::get_names() const {
Dictionary result;
- for (const Map<String, int>::Element *i = names.front(); i != nullptr; i = i->next()) {
- result[i->key()] = i->value();
+ for (const KeyValue<String, int> &E : names) {
+ result[E.key] = E.value;
}
return result;
diff --git a/modules/regex/regex.h b/modules/regex/regex.h
index a745c50a58..1455188670 100644
--- a/modules/regex/regex.h
+++ b/modules/regex/regex.h
@@ -33,7 +33,7 @@
#include "core/object/ref_counted.h"
#include "core/string/ustring.h"
-#include "core/templates/map.h"
+#include "core/templates/rb_map.h"
#include "core/templates/vector.h"
#include "core/variant/array.h"
#include "core/variant/dictionary.h"
@@ -48,7 +48,7 @@ class RegExMatch : public RefCounted {
String subject;
Vector<Range> data;
- Map<String, int> names;
+ HashMap<String, int> names;
friend class RegEx;
@@ -71,7 +71,7 @@ public:
class RegEx : public RefCounted {
GDCLASS(RegEx, RefCounted);
- void *general_ctx;
+ void *general_ctx = nullptr;
void *code = nullptr;
String pattern;
diff --git a/modules/regex/register_types.cpp b/modules/regex/register_types.cpp
index 9289a724d8..2103c57f77 100644
--- a/modules/regex/register_types.cpp
+++ b/modules/regex/register_types.cpp
@@ -32,10 +32,17 @@
#include "core/object/class_db.h"
#include "regex.h"
-void register_regex_types() {
+void initialize_regex_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(RegExMatch);
GDREGISTER_CLASS(RegEx);
}
-void unregister_regex_types() {
+void uninitialize_regex_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/regex/register_types.h b/modules/regex/register_types.h
index b2d5009ef4..c3edf23562 100644
--- a/modules/regex/register_types.h
+++ b/modules/regex/register_types.h
@@ -31,7 +31,9 @@
#ifndef REGEX_REGISTER_TYPES_H
#define REGEX_REGISTER_TYPES_H
-void register_regex_types();
-void unregister_regex_types();
+#include "modules/register_module_types.h"
+
+void initialize_regex_module(ModuleInitializationLevel p_level);
+void uninitialize_regex_module(ModuleInitializationLevel p_level);
#endif // REGEX_REGISTER_TYPES_H
diff --git a/modules/register_module_types.h b/modules/register_module_types.h
index bc9aeb31ab..cfd1b355d4 100644
--- a/modules/register_module_types.h
+++ b/modules/register_module_types.h
@@ -31,8 +31,16 @@
#ifndef REGISTER_MODULE_TYPES_H
#define REGISTER_MODULE_TYPES_H
-void preregister_module_types();
-void register_module_types();
-void unregister_module_types();
+#include "core/extension/gdnative_interface.h"
+
+enum ModuleInitializationLevel {
+ MODULE_INITIALIZATION_LEVEL_CORE = GDNATIVE_INITIALIZATION_CORE,
+ MODULE_INITIALIZATION_LEVEL_SERVERS = GDNATIVE_INITIALIZATION_SERVERS,
+ MODULE_INITIALIZATION_LEVEL_SCENE = GDNATIVE_INITIALIZATION_SCENE,
+ MODULE_INITIALIZATION_LEVEL_EDITOR = GDNATIVE_INITIALIZATION_EDITOR
+};
+
+void initialize_modules(ModuleInitializationLevel p_level);
+void uninitialize_modules(ModuleInitializationLevel p_level);
#endif // REGISTER_MODULE_TYPES_H
diff --git a/modules/squish/register_types.cpp b/modules/squish/register_types.cpp
index 1dc2e11ab9..a80419e0eb 100644
--- a/modules/squish/register_types.cpp
+++ b/modules/squish/register_types.cpp
@@ -32,8 +32,16 @@
#include "image_decompress_squish.h"
-void register_squish_types() {
+void initialize_squish_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Image::_image_decompress_bc = image_decompress_squish;
}
-void unregister_squish_types() {}
+void uninitialize_squish_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/squish/register_types.h b/modules/squish/register_types.h
index ed1c6b0716..5e9a4dfd50 100644
--- a/modules/squish/register_types.h
+++ b/modules/squish/register_types.h
@@ -31,7 +31,9 @@
#ifndef SQUISH_REGISTER_TYPES_H
#define SQUISH_REGISTER_TYPES_H
-void register_squish_types();
-void unregister_squish_types();
+#include "modules/register_module_types.h"
+
+void initialize_squish_module(ModuleInitializationLevel p_level);
+void uninitialize_squish_module(ModuleInitializationLevel p_level);
#endif // SQUISH_REGISTER_TYPES_H
diff --git a/modules/svg/image_loader_svg.cpp b/modules/svg/image_loader_svg.cpp
index 79ef2de929..dcb1f1d744 100644
--- a/modules/svg/image_loader_svg.cpp
+++ b/modules/svg/image_loader_svg.cpp
@@ -94,7 +94,7 @@ void ImageLoaderSVG::create_image_from_string(Ref<Image> p_image, String p_strin
ERR_FAIL_MSG("ImageLoaderSVG can't create image.");
}
- res = sw_canvas->push(move(picture));
+ res = sw_canvas->push(std::move(picture));
if (res != tvg::Result::Success) {
memfree(buffer);
ERR_FAIL_MSG("ImageLoaderSVG can't create image.");
@@ -136,7 +136,7 @@ void ImageLoaderSVG::get_recognized_extensions(List<String> *p_extensions) const
p_extensions->push_back("svg");
}
-Error ImageLoaderSVG::load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) {
+Error ImageLoaderSVG::load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) {
String svg = p_fileaccess->get_as_utf8_string();
create_image_from_string(p_image, svg, p_scale, false, false);
ERR_FAIL_COND_V(p_image->is_empty(), FAILED);
diff --git a/modules/svg/image_loader_svg.h b/modules/svg/image_loader_svg.h
index d0bd71d92d..94c17fda43 100644
--- a/modules/svg/image_loader_svg.h
+++ b/modules/svg/image_loader_svg.h
@@ -42,7 +42,7 @@ public:
void set_replace_colors(Dictionary p_replace_colors) { replace_colors = p_replace_colors; }
void create_image_from_string(Ref<Image> p_image, String p_string, float p_scale, bool p_upsample, bool p_convert_color);
- virtual Error load_image(Ref<Image> p_image, FileAccess *p_fileaccess, bool p_force_linear, float p_scale) override;
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> p_fileaccess, bool p_force_linear, float p_scale) override;
virtual void get_recognized_extensions(List<String> *p_extensions) const override;
};
diff --git a/modules/svg/register_types.cpp b/modules/svg/register_types.cpp
index b59c815056..5b4d1d31ca 100644
--- a/modules/svg/register_types.cpp
+++ b/modules/svg/register_types.cpp
@@ -36,7 +36,11 @@
static ImageLoaderSVG *image_loader_svg = nullptr;
-void register_svg_types() {
+void initialize_svg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
tvg::CanvasEngine tvgEngine = tvg::CanvasEngine::Sw;
if (tvg::Initializer::init(tvgEngine, 1) != tvg::Result::Success) {
return;
@@ -45,7 +49,11 @@ void register_svg_types() {
ImageLoader::add_image_format_loader(image_loader_svg);
}
-void unregister_svg_types() {
+void uninitialize_svg_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
if (!image_loader_svg) {
return;
}
diff --git a/modules/svg/register_types.h b/modules/svg/register_types.h
index 11fd9e7007..66f3e94600 100644
--- a/modules/svg/register_types.h
+++ b/modules/svg/register_types.h
@@ -31,7 +31,9 @@
#ifndef SVG_REGISTER_TYPES_H
#define SVG_REGISTER_TYPES_H
-void register_svg_types();
-void unregister_svg_types();
+#include "modules/register_module_types.h"
+
+void initialize_svg_module(ModuleInitializationLevel p_level);
+void uninitialize_svg_module(ModuleInitializationLevel p_level);
#endif // SVG_REGISTER_TYPES_H
diff --git a/modules/text_server_adv/register_types.cpp b/modules/text_server_adv/register_types.cpp
index ed00bdfbf9..6a26584506 100644
--- a/modules/text_server_adv/register_types.cpp
+++ b/modules/text_server_adv/register_types.cpp
@@ -32,7 +32,11 @@
#include "text_server_adv.h"
-void preregister_text_server_adv_types() {
+void initialize_text_server_adv_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
+
GDREGISTER_CLASS(TextServerAdvanced);
TextServerManager *tsman = TextServerManager::get_singleton();
if (tsman) {
@@ -42,10 +46,10 @@ void preregister_text_server_adv_types() {
}
}
-void register_text_server_adv_types() {
-}
-
-void unregister_text_server_adv_types() {
+void uninitialize_text_server_adv_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
}
#ifdef GDEXTENSION
@@ -61,8 +65,9 @@ extern "C" {
GDNativeBool GDN_EXPORT textserver_advanced_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) {
GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
- init_obj.register_server_initializer(&preregister_text_server_adv_types);
- init_obj.register_server_terminator(&unregister_text_server_adv_types);
+ init_obj.register_initializer(&initialize_text_server_adv_module);
+ init_obj.register_terminator(&uninitialize_text_server_adv_module);
+ init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SERVERS);
return init_obj.init();
}
diff --git a/modules/text_server_adv/register_types.h b/modules/text_server_adv/register_types.h
index d2b49fce6e..dfe20c860c 100644
--- a/modules/text_server_adv/register_types.h
+++ b/modules/text_server_adv/register_types.h
@@ -31,10 +31,14 @@
#ifndef TEXT_SERVER_ADV_REGISTER_TYPES_H
#define TEXT_SERVER_ADV_REGISTER_TYPES_H
-#define MODULE_TEXT_SERVER_ADV_HAS_PREREGISTER
+#ifdef GDEXTENSION
+#include <godot_cpp/core/class_db.hpp>
+using namespace godot;
+#else
+#include "modules/register_module_types.h"
+#endif
-void preregister_text_server_adv_types();
-void register_text_server_adv_types();
-void unregister_text_server_adv_types();
+void initialize_text_server_adv_module(ModuleInitializationLevel p_level);
+void uninitialize_text_server_adv_module(ModuleInitializationLevel p_level);
#endif // TEXT_SERVER_ADV_REGISTER_TYPES_H
diff --git a/modules/text_server_adv/script_iterator.cpp b/modules/text_server_adv/script_iterator.cpp
index 06e934c67d..3331254b20 100644
--- a/modules/text_server_adv/script_iterator.cpp
+++ b/modules/text_server_adv/script_iterator.cpp
@@ -51,7 +51,7 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
}
int paren_size = PAREN_STACK_DEPTH;
- ParenStackEntry *paren_stack = (ParenStackEntry *)memalloc(paren_size * sizeof(ParenStackEntry));
+ ParenStackEntry *paren_stack = static_cast<ParenStackEntry *>(memalloc(paren_size * sizeof(ParenStackEntry)));
int script_start;
int script_end = p_start;
@@ -77,7 +77,7 @@ ScriptIterator::ScriptIterator(const String &p_string, int p_start, int p_length
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 = static_cast<ParenStackEntry *>(memrealloc(paren_stack, paren_size * sizeof(ParenStackEntry)));
}
paren_stack[paren_sp].pair_index = ch;
paren_stack[paren_sp].script_code = script_code;
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index e02ddbb3f4..bd14b15561 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -89,12 +89,12 @@ TextServerAdvanced::bmp_font_t *TextServerAdvanced::_bmp_font_create(TextServerA
}
void TextServerAdvanced::_bmp_font_destroy(void *p_data) {
- bmp_font_t *bm_font = reinterpret_cast<bmp_font_t *>(p_data);
+ bmp_font_t *bm_font = static_cast<bmp_font_t *>(p_data);
memdelete(bm_font);
}
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);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -114,7 +114,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_nominal_glyph(hb_font_t *p_font, void *p_
}
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);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -128,7 +128,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_advance(hb_font_t *p_font, vo
}
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);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -142,7 +142,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_v_advance(hb_font_t *p_font, vo
}
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);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return 0;
@@ -156,7 +156,7 @@ hb_position_t TextServerAdvanced::_bmp_get_glyph_h_kerning(hb_font_t *p_font, vo
}
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);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -173,7 +173,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_v_origin(hb_font_t *p_font, void *p
}
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);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -192,7 +192,7 @@ hb_bool_t TextServerAdvanced::_bmp_get_glyph_extents(hb_font_t *p_font, void *p_
}
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);
+ const bmp_font_t *bm_font = static_cast<const bmp_font_t *>(p_font_data);
if (!bm_font->face) {
return false;
@@ -410,7 +410,6 @@ bool TextServerAdvanced::load_support_data(const String &p_filename) {
}
uint64_t len = f->get_length();
PackedByteArray icu_data = f->get_buffer(len);
- f->close();
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(icu_data.ptr(), &err);
@@ -461,9 +460,8 @@ bool TextServerAdvanced::save_support_data(const String &p_filename) const {
icu_data.resize(U_ICUDATA_SIZE);
memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
f->store_buffer(icu_data);
- f->close();
- return true;
+ return true;
#else
return false;
#endif
@@ -768,12 +766,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
for (int i = 0; i < p_data->textures.size(); i++) {
const FontTexture &ct = p_data->textures[i];
- if (RenderingServer::get_singleton() != nullptr) {
- if (ct.texture->get_format() != p_image_format) {
- continue;
- }
- }
-
if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
continue;
}
@@ -815,12 +807,6 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
ret.y = 0;
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
- if (mw > texsize) {
- texsize = mw; // Special case, adapt to it?
- }
- if (mh > texsize) {
- texsize = mh; // Special case, adapt to it?
- }
#ifdef GDEXTENSION
texsize = Math::next_power_of_2(texsize);
@@ -832,6 +818,20 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
} else {
texsize = MIN(texsize, 1024);
}
+ if (mw > texsize) { // Special case, adapt to it?
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(mw);
+#else
+ texsize = next_power_of_2(mw);
+#endif
+ }
+ if (mh > texsize) { // Special case, adapt to it?
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(mh);
+#else
+ texsize = next_power_of_2(mh);
+#endif
+ }
FontTexture tex;
tex.texture_w = texsize;
@@ -878,8 +878,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
struct MSContext {
msdfgen::Point2 position;
- msdfgen::Shape *shape;
- msdfgen::Contour *contour;
+ msdfgen::Shape *shape = nullptr;
+ msdfgen::Contour *contour = nullptr;
};
class DistancePixelConversion {
@@ -908,7 +908,7 @@ static msdfgen::Point2 ft_point2(const FT_Vector &vector) {
}
static int ft_move_to(const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
if (!(context->contour && context->contour->edges.empty())) {
context->contour = &context->shape->addContour();
}
@@ -917,7 +917,7 @@ static int ft_move_to(const FT_Vector *to, void *user) {
}
static int ft_line_to(const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
msdfgen::Point2 endpoint = ft_point2(*to);
if (endpoint != context->position) {
context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));
@@ -927,21 +927,21 @@ static int ft_line_to(const FT_Vector *to, void *user) {
}
static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));
context->position = ft_point2(*to);
return 0;
}
static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));
context->position = ft_point2(*to);
return 0;
}
void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
- MSDFThreadData *td = (MSDFThreadData *)p_td;
+ MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
@@ -994,11 +994,11 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
int w = (bounds.r - bounds.l);
int h = (bounds.t - bounds.b);
- int mw = w + p_rect_margin * 2;
- int mh = h + p_rect_margin * 2;
+ int mw = w + p_rect_margin * 4;
+ int mh = h + p_rect_margin * 4;
- ERR_FAIL_COND_V(mw > 1024, FontGlyph());
- ERR_FAIL_COND_V(mh > 1024, FontGlyph());
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
@@ -1029,7 +1029,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * 4;
+ int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
@@ -1039,20 +1039,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
}
}
- // Blit to image and texture.
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata);
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img);
- }
- }
- }
+ tex.dirty = true;
// Update height array.
int32_t *offw = tex.offsets.ptrw();
@@ -1062,8 +1049,9 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
chr.texture_idx = tex_pos.index;
- chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = Vector2(bounds.l, -bounds.t);
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
+ chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);
+
chr.rect.size = chr.uv_rect.size;
}
return chr;
@@ -1075,11 +1063,11 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
int w = bitmap.width;
int h = bitmap.rows;
- int mw = w + p_rect_margin * 2;
- int mh = h + p_rect_margin * 2;
+ int mw = w + p_rect_margin * 4;
+ int mh = h + p_rect_margin * 4;
- ERR_FAIL_COND_V(mw > 1024, FontGlyph());
- ERR_FAIL_COND_V(mh > 1024, FontGlyph());
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
@@ -1096,7 +1084,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * color_size;
+ int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
switch (bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
@@ -1124,21 +1112,7 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
}
}
- // Blit to image and texture.
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata);
-
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img);
- }
- }
- }
+ tex.dirty = true;
// Update height array.
int32_t *offw = tex.offsets.ptrw();
@@ -1151,8 +1125,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_bitma
chr.texture_idx = tex_pos.index;
chr.found = true;
- chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling;
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
+ chr.rect.position = Vector2(xofs - p_rect_margin, -yofs - p_rect_margin) * p_data->scale / p_data->oversampling;
chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
return chr;
}
@@ -1355,7 +1329,7 @@ _FORCE_INLINE_ bool TextServerAdvanced::_ensure_cache_for_size(FontDataAdvanced
fd->underline_position = (-FT_MulFix(fd->face->underline_position, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
fd->underline_thickness = (FT_MulFix(fd->face->underline_thickness, fd->face->size->metrics.y_scale) / 64.0) / fd->oversampling * fd->scale;
- hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform.elements[0][1]);
+ hb_font_set_synthetic_slant(fd->hb_handle, p_font_data->transform.columns[0][1]);
if (!p_font_data->face_init) {
// Get style flags and name.
@@ -1823,6 +1797,29 @@ bool TextServerAdvanced::font_is_antialiased(const RID &p_font_rid) const {
return fd->antialiased;
}
+void TextServerAdvanced::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->mipmaps != p_generate_mipmaps) {
+ for (KeyValue<Vector2i, FontDataForSizeAdvanced *> &E : fd->cache) {
+ for (int i = 0; i < E.value->textures.size(); i++) {
+ E.value->textures.write[i].dirty = true;
+ }
+ }
+ fd->mipmaps = p_generate_mipmaps;
+ }
+}
+
+bool TextServerAdvanced::font_get_generate_mipmaps(const RID &p_font_rid) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->mipmaps;
+}
+
void TextServerAdvanced::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1885,9 +1882,7 @@ void TextServerAdvanced::font_set_fixed_size(const RID &p_font_rid, int64_t p_fi
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->fixed_size != p_fixed_size) {
- fd->fixed_size = p_fixed_size;
- }
+ fd->fixed_size = p_fixed_size;
}
int64_t TextServerAdvanced::font_get_fixed_size(const RID &p_font_rid) const {
@@ -1941,9 +1936,7 @@ void TextServerAdvanced::font_set_subpixel_positioning(const RID &p_font_rid, Te
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->subpixel_positioning != p_subpixel) {
- fd->subpixel_positioning = p_subpixel;
- }
+ fd->subpixel_positioning = p_subpixel;
}
TextServer::SubpixelPositioning TextServerAdvanced::font_get_subpixel_positioning(const RID &p_font_rid) const {
@@ -2179,6 +2172,11 @@ void TextServerAdvanced::font_set_scale(const RID &p_font_rid, int64_t p_size, d
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+#ifdef MODULE_FREETYPE_ENABLED
+ if (fd->cache[size]->face) {
+ return; // Do not override scale for dynamic fonts, it's calculated automatically.
+ }
+#endif
fd->cache[size]->scale = p_scale;
}
@@ -2306,11 +2304,15 @@ void TextServerAdvanced::font_set_texture_image(const RID &p_font_rid, const Vec
Ref<Image> img;
img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata);
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
tex.texture = Ref<ImageTexture>();
tex.texture.instantiate();
tex.texture->create_from_image(img);
+ tex.dirty = false;
}
Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
@@ -2325,7 +2327,7 @@ Ref<Image> TextServerAdvanced::font_get_texture_image(const RID &p_font_rid, con
const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
Ref<Image> img;
img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata);
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
return img;
}
@@ -2369,9 +2371,8 @@ Array TextServerAdvanced::font_get_glyph_list(const RID &p_font_rid, const Vecto
Array ret;
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- const int32_t *E = nullptr;
- while ((E = gl.next(E))) {
- ret.push_back(*E);
+ for (const KeyValue<int32_t, FontGlyph> &E : gl) {
+ ret.push_back(E.key);
}
return ret;
}
@@ -2589,6 +2590,86 @@ void TextServerAdvanced::font_set_glyph_texture_idx(const RID &p_font_rid, const
gl[p_glyph].found = true;
}
+RID TextServerAdvanced::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, RID());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return RID(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID());
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (gl[p_glyph].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
+ return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid();
+ }
+ }
+
+ return RID();
+}
+
+Size2 TextServerAdvanced::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+ FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Size2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return Size2(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2());
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (gl[p_glyph].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
+ return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size();
+ }
+ }
+
+ return Size2();
+}
+
Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
FontDataAdvanced *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -2598,36 +2679,45 @@ Dictionary TextServerAdvanced::font_get_glyph_contours(const RID &p_font_rid, in
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
+#ifdef MODULE_FREETYPE_ENABLED
PackedVector3Array points;
PackedInt32Array contours;
- bool orientation;
-#ifdef MODULE_FREETYPE_ENABLED
+
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
int error = FT_Load_Glyph(fd->cache[size]->face, index, FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
ERR_FAIL_COND_V(error, Dictionary());
- double h = fd->cache[size]->ascent;
+ if (fd->embolden != 0.f) {
+ FT_Pos strength = fd->embolden * p_size * 4; // 26.6 fractional units (1 / 64).
+ FT_Outline_Embolden(&fd->cache[size]->face->glyph->outline, strength);
+ }
+
+ if (fd->transform != Transform2D()) {
+ FT_Matrix mat = { FT_Fixed(fd->transform[0][0] * 65536), FT_Fixed(fd->transform[0][1] * 65536), FT_Fixed(fd->transform[1][0] * 65536), FT_Fixed(fd->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536).
+ FT_Outline_Transform(&fd->cache[size]->face->glyph->outline, &mat);
+ }
+
double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
if (fd->msdf) {
scale = scale * (double)p_size / (double)fd->msdf_source_size;
}
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; 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])));
+ points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, -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++) {
contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
}
- orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
-#else
- return Dictionary();
-#endif
+ bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
Dictionary out;
out["points"] = points;
out["contours"] = contours;
out["orientation"] = orientation;
return out;
+#else
+ return Dictionary();
+#endif
}
Array TextServerAdvanced::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
@@ -2688,7 +2778,7 @@ Vector2 TextServerAdvanced::font_get_kerning(const RID &p_font_rid, int64_t p_si
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- const Map<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map;
+ const HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> &kern = fd->cache[size]->kerning_map;
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
@@ -2746,7 +2836,7 @@ bool TextServerAdvanced::font_has_char(const RID &p_font_rid, int64_t p_char) co
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false);
}
- FontDataForSizeAdvanced *at_size = fd->cache.front()->get();
+ FontDataForSizeAdvanced *at_size = fd->cache.begin()->value;
#ifdef MODULE_FREETYPE_ENABLED
if (at_size && at_size->face) {
@@ -2764,7 +2854,7 @@ String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String());
}
- FontDataForSizeAdvanced *at_size = fd->cache.front()->get();
+ FontDataForSizeAdvanced *at_size = fd->cache.begin()->value;
String chars;
#ifdef MODULE_FREETYPE_ENABLED
@@ -2782,9 +2872,8 @@ String TextServerAdvanced::font_get_supported_chars(const RID &p_font_rid) const
#endif
if (at_size) {
const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
- const int32_t *E = nullptr;
- while ((E = gl.next(E))) {
- chars = chars + String::chr(*E);
+ for (const KeyValue<int32_t, FontGlyph> &E : gl) {
+ chars = chars + String::chr(E.key);
}
}
return chars;
@@ -2890,6 +2979,22 @@ void TextServerAdvanced::font_draw_glyph(const RID &p_font_rid, const RID &p_can
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
+ if (fd->cache[size]->textures[gl.texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
@@ -2953,6 +3058,22 @@ void TextServerAdvanced::font_draw_glyph_outline(const RID &p_font_rid, const RI
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
+ if (fd->cache[size]->textures[gl.texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
@@ -3146,6 +3267,19 @@ void TextServerAdvanced::font_set_global_oversampling(double p_oversampling) {
/* Shaped text buffer interface */
/*************************************************************************/
+int64_t TextServerAdvanced::_convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const {
+ int64_t limit = p_pos;
+ if (p_utf32.length() != p_utf16.length()) {
+ const UChar *data = p_utf16.ptr();
+ for (int i = 0; i < p_pos; i++) {
+ if (U16_IS_LEAD(data[i])) {
+ limit--;
+ }
+ }
+ }
+ return limit;
+}
+
int64_t TextServerAdvanced::_convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const {
int64_t limit = p_pos;
if (p_sd->text.length() != p_sd->utf16.length()) {
@@ -3308,7 +3442,9 @@ void TextServerAdvanced::shaped_text_set_bidi_override(const RID &p_shaped, cons
}
sd->bidi_override.clear();
for (int i = 0; i < p_override.size(); i++) {
- sd->bidi_override.push_back(p_override[i]);
+ if (p_override[i].get_type() == Variant::VECTOR2I) {
+ sd->bidi_override.push_back(p_override[i]);
+ }
}
invalidate(sd, false);
}
@@ -3876,9 +4012,9 @@ double TextServerAdvanced::shaped_text_fit_to_width(const RID &p_shaped, double
}
}
}
- double adv_remain = 0;
if ((space_count > 0) && ((p_jst_flags & JUSTIFICATION_WORD_BOUND) == JUSTIFICATION_WORD_BOUND)) {
double delta_width_per_space = (p_width - justification_width) / space_count;
+ double adv_remain = 0;
for (int i = start_pos; i <= end_pos; i++) {
Glyph &gl = sd->glyphs.write[i];
if (gl.count > 0) {
@@ -4448,7 +4584,7 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(const RID &p_shape
Glyph *sd_glyphs = sd->glyphs.ptrw();
int sd_size = sd->glyphs.size();
- if (sd->jstops.size() > 0) {
+ if (!sd->jstops.is_empty()) {
for (int i = 0; i < sd_size; i++) {
if (sd_glyphs[i].count > 0) {
char32_t c = sd->text[sd_glyphs[i].start - sd->start];
@@ -4638,6 +4774,8 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
}
RID f = p_fonts[p_fb_index];
+ FontDataAdvanced *fd = font_owner.get_or_null(f);
+ Vector2i fss = _get_size(fd, fs);
hb_font_t *hb_font = _font_get_hb_handle(f, fs);
double scale = font_get_scale(f, fs);
double sp_sp = font_get_spacing(f, fs, SPACING_SPACE);
@@ -4719,6 +4857,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_star
gl.index = glyph_info[i].codepoint;
if (gl.index != 0) {
+ _ensure_glyph(fd, fss, gl.index);
if (p_sd->orientation == ORIENTATION_HORIZONTAL) {
if (subpos) {
gl.advance = glyph_pos[i].x_advance / (64.0 / scale) + ea;
@@ -5441,6 +5580,53 @@ String TextServerAdvanced::string_to_lower(const String &p_string, const String
return String::utf16(lower.ptr(), len);
}
+PackedInt32Array TextServerAdvanced::string_get_word_breaks(const String &p_string, const String &p_language) const {
+ // Convert to UTF-16.
+ Char16String utf16 = p_string.utf16();
+
+ RBSet<int> breaks;
+ UErrorCode err = U_ZERO_ERROR;
+ UBreakIterator *bi = ubrk_open(UBRK_LINE, p_language.ascii().get_data(), (const UChar *)utf16.ptr(), utf16.length(), &err);
+ if (U_FAILURE(err)) {
+ // No data loaded - use fallback.
+ for (int i = 0; i < p_string.length(); i++) {
+ char32_t c = p_string[i];
+ if (is_whitespace(c) || is_linebreak(c)) {
+ breaks.insert(i);
+ }
+ }
+ } else {
+ while (ubrk_next(bi) != UBRK_DONE) {
+ int pos = _convert_pos(p_string, utf16, ubrk_current(bi)) - 1;
+ if (pos != p_string.length() - 1) {
+ breaks.insert(pos);
+ }
+ }
+ }
+ ubrk_close(bi);
+
+ PackedInt32Array ret;
+ for (int i = 0; i < p_string.length(); i++) {
+ char32_t c = p_string[i];
+ if (c == 0xfffc) {
+ continue;
+ }
+ if (u_ispunct(c) && c != 0x005F) {
+ ret.push_back(i);
+ continue;
+ }
+ if (is_underscore(c)) {
+ ret.push_back(i);
+ continue;
+ }
+ if (breaks.has(i)) {
+ ret.push_back(i);
+ continue;
+ }
+ }
+ return ret;
+}
+
TextServerAdvanced::TextServerAdvanced() {
_insert_num_systems_lang();
_insert_feature_sets();
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index bb3968ee3f..897c27b6fa 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -67,7 +67,6 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/templates/hash_map.hpp>
-#include <godot_cpp/templates/map.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
#include <godot_cpp/templates/set.hpp>
#include <godot_cpp/templates/thread_work_pool.hpp>
@@ -78,6 +77,7 @@ using namespace godot;
#else
// Headers for building as built-in module.
+#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "core/templates/thread_work_pool.h"
#include "scene/resources/texture.h"
@@ -126,15 +126,15 @@ class TextServerAdvanced : public TextServerExtension {
_THREAD_SAFE_CLASS_
struct NumSystemData {
- Set<StringName> lang;
+ RBSet<StringName> lang;
String digits;
String percent_sign;
String exp;
};
Vector<NumSystemData> num_systems;
- Map<StringName, int32_t> feature_sets;
- Map<int32_t, StringName> feature_sets_inv;
+ HashMap<StringName, int32_t> feature_sets;
+ HashMap<int32_t, StringName> feature_sets_inv;
void _insert_num_systems_lang();
void _insert_feature_sets();
@@ -159,6 +159,7 @@ class TextServerAdvanced : public TextServerExtension {
int texture_h = 0;
PackedInt32Array offsets;
Ref<ImageTexture> texture;
+ bool dirty = true;
};
struct FontTexturePosition {
@@ -190,8 +191,7 @@ class TextServerAdvanced : public TextServerExtension {
Vector<FontTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
- Map<Vector2i, Vector2> kerning_map;
-
+ HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> kerning_map;
hb_font_t *hb_handle = nullptr;
#ifdef MODULE_FREETYPE_ENABLED
@@ -215,6 +215,7 @@ class TextServerAdvanced : public TextServerExtension {
Mutex mutex;
bool antialiased = true;
+ bool mipmaps = false;
bool msdf = false;
int msdf_range = 14;
int msdf_source_size = 48;
@@ -231,17 +232,17 @@ class TextServerAdvanced : public TextServerExtension {
String font_name;
String style_name;
- Map<Vector2i, FontDataForSizeAdvanced *> cache;
+ HashMap<Vector2i, FontDataForSizeAdvanced *, VariantHasher, VariantComparator> cache;
bool face_init = false;
- Set<uint32_t> supported_scripts;
+ RBSet<uint32_t> supported_scripts;
Dictionary supported_features;
Dictionary supported_varaitions;
Dictionary feature_overrides;
// Language/script support override.
- Map<String, bool> language_support_overrides;
- Map<String, bool> script_support_overrides;
+ HashMap<String, bool> language_support_overrides;
+ HashMap<String, bool> script_support_overrides;
PackedByteArray data;
const uint8_t *data_ptr;
@@ -332,7 +333,7 @@ class TextServerAdvanced : public TextServerExtension {
InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
Rect2 rect;
};
- Map<Variant, EmbeddedObject> objects;
+ HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects;
/* Shaped data */
TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
@@ -391,11 +392,13 @@ class TextServerAdvanced : public TextServerExtension {
mutable RID_PtrOwner<ShapedTextDataAdvanced> shaped_owner;
void _realign(ShapedTextDataAdvanced *p_sd) const;
+ int64_t _convert_pos(const String &p_utf32, const Char16String &p_utf16, int64_t p_pos) const;
int64_t _convert_pos(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
int64_t _convert_pos_inv(const ShapedTextDataAdvanced *p_sd, int64_t p_pos) const;
bool _shape_substr(ShapedTextDataAdvanced *p_new_sd, const ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_length) const;
void _shape_run(ShapedTextDataAdvanced *p_sd, int64_t p_start, int64_t p_end, hb_script_t p_script, hb_direction_t p_direction, Array p_fonts, int64_t p_span, int64_t p_fb_index);
Glyph _shape_single_glyph(ShapedTextDataAdvanced *p_sd, char32_t p_char, hb_script_t p_script, hb_direction_t p_direction, const RID &p_font, int64_t p_font_size);
+
_FORCE_INLINE_ void _add_featuers(const Dictionary &p_source, Vector<hb_feature_t> &r_ftrs);
// HarfBuzz bitmap font interface.
@@ -482,6 +485,9 @@ public:
virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override;
virtual bool font_is_antialiased(const RID &p_font_rid) const override;
+ virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override;
+ virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override;
+
virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override;
virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override;
@@ -566,6 +572,9 @@ public:
virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override;
+ virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+
virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override;
virtual Array font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const override;
@@ -678,6 +687,8 @@ public:
virtual String parse_number(const String &p_string, const String &p_language = "") const override;
virtual String percent_sign(const String &p_language = "") const override;
+ virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
+
virtual String strip_diacritics(const String &p_string) const override;
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
diff --git a/modules/text_server_fb/register_types.cpp b/modules/text_server_fb/register_types.cpp
index 1044c3f872..fa7b87fc17 100644
--- a/modules/text_server_fb/register_types.cpp
+++ b/modules/text_server_fb/register_types.cpp
@@ -32,7 +32,11 @@
#include "text_server_fb.h"
-void preregister_text_server_fb_types() {
+void initialize_text_server_fb_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
+
GDREGISTER_CLASS(TextServerFallback);
TextServerManager *tsman = TextServerManager::get_singleton();
if (tsman) {
@@ -42,10 +46,10 @@ void preregister_text_server_fb_types() {
}
}
-void register_text_server_fb_types() {
-}
-
-void unregister_text_server_fb_types() {
+void uninitialize_text_server_fb_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ return;
+ }
}
#ifdef GDEXTENSION
@@ -61,8 +65,9 @@ extern "C" {
GDNativeBool GDN_EXPORT textserver_fallback_init(const GDNativeInterface *p_interface, const GDNativeExtensionClassLibraryPtr p_library, GDNativeInitialization *r_initialization) {
GDExtensionBinding::InitObject init_obj(p_interface, p_library, r_initialization);
- init_obj.register_server_initializer(&preregister_text_server_fb_types);
- init_obj.register_server_terminator(&unregister_text_server_fb_types);
+ init_obj.register_initializer(&initialize_text_server_fb_module);
+ init_obj.register_terminator(&uninitialize_text_server_fb_module);
+ init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SERVERS);
return init_obj.init();
}
diff --git a/modules/text_server_fb/register_types.h b/modules/text_server_fb/register_types.h
index 8652a8e9db..229aec2266 100644
--- a/modules/text_server_fb/register_types.h
+++ b/modules/text_server_fb/register_types.h
@@ -31,10 +31,14 @@
#ifndef TEXT_SERVER_FB_REGISTER_TYPES_H
#define TEXT_SERVER_FB_REGISTER_TYPES_H
-#define MODULE_TEXT_SERVER_FB_HAS_PREREGISTER
+#ifdef GDEXTENSION
+#include <godot_cpp/core/class_db.hpp>
+using namespace godot;
+#else
+#include "modules/register_module_types.h"
+#endif
-void preregister_text_server_fb_types();
-void register_text_server_fb_types();
-void unregister_text_server_fb_types();
+void initialize_text_server_fb_module(ModuleInitializationLevel p_level);
+void uninitialize_text_server_fb_module(ModuleInitializationLevel p_level);
#endif // TEXT_SERVER_FB_REGISTER_TYPES_H
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 6c2e5a6084..c53ca7766a 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -209,12 +209,6 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
for (int i = 0; i < p_data->textures.size(); i++) {
const FontTexture &ct = p_data->textures[i];
- if (RenderingServer::get_singleton() != nullptr) {
- if (ct.texture->get_format() != p_image_format) {
- continue;
- }
- }
-
if (mw > ct.texture_w || mh > ct.texture_h) { // Too big for this texture.
continue;
}
@@ -256,12 +250,6 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
ret.y = 0;
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
- if (mw > texsize) {
- texsize = mw; // Special case, adapt to it?
- }
- if (mh > texsize) {
- texsize = mh; // Special case, adapt to it?
- }
#ifdef GDEXTENSION
texsize = Math::next_power_of_2(texsize);
@@ -274,6 +262,20 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
} else {
texsize = MIN(texsize, 1024);
}
+ if (mw > texsize) { // Special case, adapt to it?
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(mw);
+#else
+ texsize = next_power_of_2(mw);
+#endif
+ }
+ if (mh > texsize) { // Special case, adapt to it?
+#ifdef GDEXTENSION
+ texsize = Math::next_power_of_2(mh);
+#else
+ texsize = next_power_of_2(mh);
+#endif
+ }
FontTexture tex;
tex.texture_w = texsize;
@@ -320,8 +322,8 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
struct MSContext {
msdfgen::Point2 position;
- msdfgen::Shape *shape;
- msdfgen::Contour *contour;
+ msdfgen::Shape *shape = nullptr;
+ msdfgen::Contour *contour = nullptr;
};
class DistancePixelConversion {
@@ -350,7 +352,7 @@ static msdfgen::Point2 ft_point2(const FT_Vector &vector) {
}
static int ft_move_to(const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
if (!(context->contour && context->contour->edges.empty())) {
context->contour = &context->shape->addContour();
}
@@ -359,7 +361,7 @@ static int ft_move_to(const FT_Vector *to, void *user) {
}
static int ft_line_to(const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
msdfgen::Point2 endpoint = ft_point2(*to);
if (endpoint != context->position) {
context->contour->addEdge(new msdfgen::LinearSegment(context->position, endpoint));
@@ -369,21 +371,21 @@ static int ft_line_to(const FT_Vector *to, void *user) {
}
static int ft_conic_to(const FT_Vector *control, const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
context->contour->addEdge(new msdfgen::QuadraticSegment(context->position, ft_point2(*control), ft_point2(*to)));
context->position = ft_point2(*to);
return 0;
}
static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, void *user) {
- MSContext *context = reinterpret_cast<MSContext *>(user);
+ MSContext *context = static_cast<MSContext *>(user);
context->contour->addEdge(new msdfgen::CubicSegment(context->position, ft_point2(*control1), ft_point2(*control2), ft_point2(*to)));
context->position = ft_point2(*to);
return 0;
}
void TextServerFallback::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
- MSDFThreadData *td = (MSDFThreadData *)p_td;
+ MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
@@ -436,11 +438,11 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
int w = (bounds.r - bounds.l);
int h = (bounds.t - bounds.b);
- int mw = w + p_rect_margin * 2;
- int mh = h + p_rect_margin * 2;
+ int mw = w + p_rect_margin * 4;
+ int mh = h + p_rect_margin * 4;
- ERR_FAIL_COND_V(mw > 1024, FontGlyph());
- ERR_FAIL_COND_V(mh > 1024, FontGlyph());
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
FontTexturePosition tex_pos = find_texture_pos_for_glyph(p_data, 4, Image::FORMAT_RGBA8, mw, mh, true);
ERR_FAIL_COND_V(tex_pos.index < 0, FontGlyph());
@@ -471,7 +473,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * 4;
+ int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * 4;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
wr[ofs + 0] = (uint8_t)(CLAMP(image(j, i)[0] * 256.f, 0.f, 255.f));
wr[ofs + 1] = (uint8_t)(CLAMP(image(j, i)[1] * 256.f, 0.f, 255.f));
@@ -481,20 +483,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
}
}
- // Blit to image and texture.
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, 0, Image::FORMAT_RGBA8, tex.imgdata);
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img);
- }
- }
- }
+ tex.dirty = true;
// Update height array.
int32_t *offw = tex.offsets.ptrw();
@@ -504,8 +493,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
chr.texture_idx = tex_pos.index;
- chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = Vector2(bounds.l, -bounds.t);
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
+ chr.rect.position = Vector2(bounds.l - p_rect_margin, -bounds.t - p_rect_margin);
chr.rect.size = chr.uv_rect.size;
}
return chr;
@@ -517,11 +506,11 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
int w = bitmap.width;
int h = bitmap.rows;
- int mw = w + p_rect_margin * 2;
- int mh = h + p_rect_margin * 2;
+ int mw = w + p_rect_margin * 4;
+ int mh = h + p_rect_margin * 4;
- ERR_FAIL_COND_V(mw > 1024, FontGlyph());
- ERR_FAIL_COND_V(mh > 1024, FontGlyph());
+ ERR_FAIL_COND_V(mw > 4096, FontGlyph());
+ ERR_FAIL_COND_V(mh > 4096, FontGlyph());
int color_size = bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
@@ -538,7 +527,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
- int ofs = ((i + tex_pos.y + p_rect_margin) * tex.texture_w + j + tex_pos.x + p_rect_margin) * color_size;
+ int ofs = ((i + tex_pos.y + p_rect_margin * 2) * tex.texture_w + j + tex_pos.x + p_rect_margin * 2) * color_size;
ERR_FAIL_COND_V(ofs >= tex.imgdata.size(), FontGlyph());
switch (bitmap.pixel_mode) {
case FT_PIXEL_MODE_MONO: {
@@ -566,21 +555,7 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
}
}
- // Blit to image and texture.
- {
- if (RenderingServer::get_singleton() != nullptr) {
- Ref<Image> img;
- img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, 0, require_format, tex.imgdata);
-
- if (tex.texture.is_null()) {
- tex.texture.instantiate();
- tex.texture->create_from_image(img);
- } else {
- tex.texture->update(img);
- }
- }
- }
+ tex.dirty = true;
// Update height array.
int32_t *offw = tex.offsets.ptrw();
@@ -593,8 +568,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_bitma
chr.texture_idx = tex_pos.index;
chr.found = true;
- chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w, h);
- chr.rect.position = Vector2(xofs, -yofs) * p_data->scale / p_data->oversampling;
+ chr.uv_rect = Rect2(tex_pos.x + p_rect_margin, tex_pos.y + p_rect_margin, w + p_rect_margin * 2, h + p_rect_margin * 2);
+ chr.rect.position = Vector2(xofs - p_rect_margin, -yofs - p_rect_margin) * p_data->scale / p_data->oversampling;
chr.rect.size = chr.uv_rect.size * p_data->scale / p_data->oversampling;
return chr;
}
@@ -984,6 +959,29 @@ bool TextServerFallback::font_is_antialiased(const RID &p_font_rid) const {
return fd->antialiased;
}
+void TextServerFallback::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND(!fd);
+
+ MutexLock lock(fd->mutex);
+ if (fd->mipmaps != p_generate_mipmaps) {
+ for (KeyValue<Vector2i, FontDataForSizeFallback *> &E : fd->cache) {
+ for (int i = 0; i < E.value->textures.size(); i++) {
+ E.value->textures.write[i].dirty = true;
+ }
+ }
+ fd->mipmaps = p_generate_mipmaps;
+ }
+}
+
+bool TextServerFallback::font_get_generate_mipmaps(const RID &p_font_rid) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, false);
+
+ MutexLock lock(fd->mutex);
+ return fd->mipmaps;
+}
+
void TextServerFallback::font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND(!fd);
@@ -1046,9 +1044,7 @@ void TextServerFallback::font_set_fixed_size(const RID &p_font_rid, int64_t p_fi
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->fixed_size != p_fixed_size) {
- fd->fixed_size = p_fixed_size;
- }
+ fd->fixed_size = p_fixed_size;
}
int64_t TextServerFallback::font_get_fixed_size(const RID &p_font_rid) const {
@@ -1102,9 +1098,7 @@ void TextServerFallback::font_set_subpixel_positioning(const RID &p_font_rid, Te
ERR_FAIL_COND(!fd);
MutexLock lock(fd->mutex);
- if (fd->subpixel_positioning != p_subpixel) {
- fd->subpixel_positioning = p_subpixel;
- }
+ fd->subpixel_positioning = p_subpixel;
}
TextServer::SubpixelPositioning TextServerFallback::font_get_subpixel_positioning(const RID &p_font_rid) const {
@@ -1340,6 +1334,11 @@ void TextServerFallback::font_set_scale(const RID &p_font_rid, int64_t p_size, d
Vector2i size = _get_size(fd, p_size);
ERR_FAIL_COND(!_ensure_cache_for_size(fd, size));
+#ifdef MODULE_FREETYPE_ENABLED
+ if (fd->cache[size]->face) {
+ return; // Do not override scale for dynamic fonts, it's calculated automatically.
+ }
+#endif
fd->cache[size]->scale = p_scale;
}
@@ -1467,11 +1466,15 @@ void TextServerFallback::font_set_texture_image(const RID &p_font_rid, const Vec
Ref<Image> img;
img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata);
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
tex.texture = Ref<ImageTexture>();
tex.texture.instantiate();
tex.texture->create_from_image(img);
+ tex.dirty = false;
}
Ref<Image> TextServerFallback::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const {
@@ -1486,7 +1489,7 @@ Ref<Image> TextServerFallback::font_get_texture_image(const RID &p_font_rid, con
const FontTexture &tex = fd->cache[size]->textures[p_texture_index];
Ref<Image> img;
img.instantiate();
- img->create_from_data(tex.texture_w, tex.texture_h, 0, tex.format, tex.imgdata);
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
return img;
}
@@ -1530,9 +1533,8 @@ Array TextServerFallback::font_get_glyph_list(const RID &p_font_rid, const Vecto
Array ret;
const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
- const int32_t *E = nullptr;
- while ((E = gl.next(E))) {
- ret.push_back(*E);
+ for (const KeyValue<int32_t, FontGlyph> &E : gl) {
+ ret.push_back(E.key);
}
return ret;
}
@@ -1736,6 +1738,86 @@ void TextServerFallback::font_set_glyph_texture_idx(const RID &p_font_rid, const
gl[p_glyph].found = true;
}
+RID TextServerFallback::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, RID());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), RID());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return RID(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), RID());
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (gl[p_glyph].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
+ return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_rid();
+ }
+ }
+
+ return RID();
+}
+
+Size2 TextServerFallback::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const {
+ FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
+ ERR_FAIL_COND_V(!fd, Size2());
+
+ MutexLock lock(fd->mutex);
+ Vector2i size = _get_size_outline(fd, p_size);
+
+ ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Size2());
+ if (!_ensure_glyph(fd, size, p_glyph)) {
+ return Size2(); // Invalid or non graphicl glyph, do not display errors.
+ }
+
+ const HashMap<int32_t, FontGlyph> &gl = fd->cache[size]->glyph_map;
+ ERR_FAIL_COND_V(gl[p_glyph].texture_idx < -1 || gl[p_glyph].texture_idx >= fd->cache[size]->textures.size(), Size2());
+
+ if (RenderingServer::get_singleton() != nullptr) {
+ if (gl[p_glyph].texture_idx != -1) {
+ if (fd->cache[size]->textures[gl[p_glyph].texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl[p_glyph].texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
+ return fd->cache[size]->textures[gl[p_glyph].texture_idx].texture->get_size();
+ }
+ }
+
+ return Size2();
+}
+
Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, int64_t p_size, int64_t p_index) const {
FontDataFallback *fd = font_owner.get_or_null(p_font_rid);
ERR_FAIL_COND_V(!fd, Dictionary());
@@ -1745,36 +1827,45 @@ Dictionary TextServerFallback::font_get_glyph_contours(const RID &p_font_rid, in
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Dictionary());
+#ifdef MODULE_FREETYPE_ENABLED
PackedVector3Array points;
PackedInt32Array contours;
- bool orientation;
-#ifdef MODULE_FREETYPE_ENABLED
+
int32_t index = p_index & 0xffffff; // Remove subpixel shifts.
int error = FT_Load_Glyph(fd->cache[size]->face, FT_Get_Char_Index(fd->cache[size]->face, index), FT_LOAD_NO_BITMAP | (fd->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
ERR_FAIL_COND_V(error, Dictionary());
- double h = fd->cache[size]->ascent;
+ if (fd->embolden != 0.f) {
+ FT_Pos strength = fd->embolden * p_size * 4; // 26.6 fractional units (1 / 64).
+ FT_Outline_Embolden(&fd->cache[size]->face->glyph->outline, strength);
+ }
+
+ if (fd->transform != Transform2D()) {
+ FT_Matrix mat = { FT_Fixed(fd->transform[0][0] * 65536), FT_Fixed(fd->transform[0][1] * 65536), FT_Fixed(fd->transform[1][0] * 65536), FT_Fixed(fd->transform[1][1] * 65536) }; // 16.16 fractional units (1 / 65536).
+ FT_Outline_Transform(&fd->cache[size]->face->glyph->outline, &mat);
+ }
+
double scale = (1.0 / 64.0) / fd->cache[size]->oversampling * fd->cache[size]->scale;
if (fd->msdf) {
scale = scale * (double)p_size / (double)fd->msdf_source_size;
}
for (short i = 0; i < fd->cache[size]->face->glyph->outline.n_points; 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])));
+ points.push_back(Vector3(fd->cache[size]->face->glyph->outline.points[i].x * scale, -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++) {
contours.push_back(fd->cache[size]->face->glyph->outline.contours[i]);
}
- orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
-#else
- return Dictionary();
-#endif
+ bool orientation = (FT_Outline_Get_Orientation(&fd->cache[size]->face->glyph->outline) == FT_ORIENTATION_FILL_RIGHT);
Dictionary out;
out["points"] = points;
out["contours"] = contours;
out["orientation"] = orientation;
return out;
+#else
+ return Dictionary();
+#endif
}
Array TextServerFallback::font_get_kerning_list(const RID &p_font_rid, int64_t p_size) const {
@@ -1835,7 +1926,7 @@ Vector2 TextServerFallback::font_get_kerning(const RID &p_font_rid, int64_t p_si
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, size), Vector2());
- const Map<Vector2i, Vector2> &kern = fd->cache[size]->kerning_map;
+ const HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> &kern = fd->cache[size]->kerning_map;
if (kern.has(p_glyph_pair)) {
if (fd->msdf) {
@@ -1875,7 +1966,7 @@ bool TextServerFallback::font_has_char(const RID &p_font_rid, int64_t p_char) co
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), false);
}
- FontDataForSizeFallback *at_size = fd->cache.front()->get();
+ FontDataForSizeFallback *at_size = fd->cache.begin()->value;
#ifdef MODULE_FREETYPE_ENABLED
if (at_size && at_size->face) {
@@ -1893,7 +1984,7 @@ String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const
if (fd->cache.is_empty()) {
ERR_FAIL_COND_V(!_ensure_cache_for_size(fd, fd->msdf ? Vector2i(fd->msdf_source_size, 0) : Vector2i(16, 0)), String());
}
- FontDataForSizeFallback *at_size = fd->cache.front()->get();
+ FontDataForSizeFallback *at_size = fd->cache.begin()->value;
String chars;
#ifdef MODULE_FREETYPE_ENABLED
@@ -1911,9 +2002,8 @@ String TextServerFallback::font_get_supported_chars(const RID &p_font_rid) const
#endif
if (at_size) {
const HashMap<int32_t, FontGlyph> &gl = at_size->glyph_map;
- const int32_t *E = nullptr;
- while ((E = gl.next(E))) {
- chars = chars + String::chr(*E);
+ for (const KeyValue<int32_t, FontGlyph> &E : gl) {
+ chars = chars + String::chr(E.key);
}
}
return chars;
@@ -2019,6 +2109,22 @@ void TextServerFallback::font_draw_glyph(const RID &p_font_rid, const RID &p_can
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
+ if (fd->cache[size]->textures[gl.texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
@@ -2082,6 +2188,22 @@ void TextServerFallback::font_draw_glyph_outline(const RID &p_font_rid, const RI
}
#endif
if (RenderingServer::get_singleton() != nullptr) {
+ if (fd->cache[size]->textures[gl.texture_idx].dirty) {
+ FontTexture &tex = fd->cache[size]->textures.write[gl.texture_idx];
+ Ref<Image> img;
+ img.instantiate();
+ img->create_from_data(tex.texture_w, tex.texture_h, false, tex.format, tex.imgdata);
+ if (fd->mipmaps) {
+ img->generate_mipmaps();
+ }
+ if (tex.texture.is_null()) {
+ tex.texture.instantiate();
+ tex.texture->create_from_image(img);
+ } else {
+ tex.texture->update(img);
+ }
+ tex.dirty = false;
+ }
RID texture = fd->cache[size]->textures[gl.texture_idx].texture->get_rid();
if (fd->msdf) {
Point2 cpos = p_pos;
@@ -2969,7 +3091,7 @@ bool TextServerFallback::shaped_text_update_breaks(const RID &p_shaped) {
if (sd_glyphs[i].count > 0) {
char32_t c = sd->text[sd_glyphs[i].start - sd->start];
if (c_punct_size == 0) {
- if (is_punct(c)) {
+ if (is_punct(c) && c != 0x005F) {
sd_glyphs[i].flags |= GRAPHEME_IS_PUNCTUATION;
}
} else {
@@ -3513,6 +3635,29 @@ String TextServerFallback::string_to_lower(const String &p_string, const String
return lower;
}
+PackedInt32Array TextServerFallback::string_get_word_breaks(const String &p_string, const String &p_language) const {
+ PackedInt32Array ret;
+ for (int i = 0; i < p_string.length(); i++) {
+ char32_t c = p_string[i];
+ if (c == 0xfffc) {
+ continue;
+ }
+ if (is_punct(c) && c != 0x005F) {
+ ret.push_back(i);
+ continue;
+ }
+ if (is_underscore(c)) {
+ ret.push_back(i);
+ continue;
+ }
+ if (is_whitespace(c) || is_linebreak(c)) {
+ ret.push_back(i);
+ continue;
+ }
+ }
+ return ret;
+}
+
TextServerFallback::TextServerFallback() {
_insert_feature_sets();
};
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index 3944c371b7..0d2fc2628d 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -67,7 +67,6 @@
#include <godot_cpp/classes/ref.hpp>
#include <godot_cpp/templates/hash_map.hpp>
-#include <godot_cpp/templates/map.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
#include <godot_cpp/templates/set.hpp>
#include <godot_cpp/templates/thread_work_pool.hpp>
@@ -80,6 +79,7 @@ using namespace godot;
#include "servers/text/text_server_extension.h"
+#include "core/templates/hash_map.h"
#include "core/templates/rid_owner.h"
#include "core/templates/thread_work_pool.h"
#include "scene/resources/texture.h"
@@ -106,8 +106,8 @@ class TextServerFallback : public TextServerExtension {
GDCLASS(TextServerFallback, TextServerExtension);
_THREAD_SAFE_CLASS_
- Map<StringName, int32_t> feature_sets;
- Map<int32_t, StringName> feature_sets_inv;
+ HashMap<StringName, int32_t> feature_sets;
+ HashMap<int32_t, StringName> feature_sets_inv;
void _insert_feature_sets();
_FORCE_INLINE_ void _insert_feature(const StringName &p_name, int32_t p_tag);
@@ -127,6 +127,7 @@ class TextServerFallback : public TextServerExtension {
int texture_h = 0;
PackedInt32Array offsets;
Ref<ImageTexture> texture;
+ bool dirty = true;
};
struct FontTexturePosition {
@@ -158,7 +159,7 @@ class TextServerFallback : public TextServerExtension {
Vector<FontTexture> textures;
HashMap<int32_t, FontGlyph> glyph_map;
- Map<Vector2i, Vector2> kerning_map;
+ HashMap<Vector2i, Vector2, VariantHasher, VariantComparator> kerning_map;
#ifdef MODULE_FREETYPE_ENABLED
FT_Face face = nullptr;
@@ -178,6 +179,7 @@ class TextServerFallback : public TextServerExtension {
Mutex mutex;
bool antialiased = true;
+ bool mipmaps = false;
bool msdf = false;
int msdf_range = 14;
int msdf_source_size = 48;
@@ -194,15 +196,15 @@ class TextServerFallback : public TextServerExtension {
String font_name;
String style_name;
- Map<Vector2i, FontDataForSizeFallback *> cache;
+ HashMap<Vector2i, FontDataForSizeFallback *, VariantHasher, VariantComparator> cache;
bool face_init = false;
Dictionary supported_varaitions;
Dictionary feature_overrides;
// Language/script support override.
- Map<String, bool> language_support_overrides;
- Map<String, bool> script_support_overrides;
+ HashMap<String, bool> language_support_overrides;
+ HashMap<String, bool> script_support_overrides;
PackedByteArray data;
const uint8_t *data_ptr;
@@ -292,7 +294,7 @@ class TextServerFallback : public TextServerExtension {
InlineAlignment inline_align = INLINE_ALIGNMENT_CENTER;
Rect2 rect;
};
- Map<Variant, EmbeddedObject> objects;
+ HashMap<Variant, EmbeddedObject, VariantHasher, VariantComparator> objects;
/* Shaped data */
TextServer::Direction para_direction = DIRECTION_LTR; // Detected text direction.
@@ -343,8 +345,12 @@ public:
virtual bool has(const RID &p_rid) override;
virtual bool load_support_data(const String &p_filename) override;
- virtual String get_support_data_filename() const override { return ""; };
- virtual String get_support_data_info() const override { return "Not supported"; };
+ 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) const override;
@@ -370,6 +376,9 @@ public:
virtual void font_set_antialiased(const RID &p_font_rid, bool p_antialiased) override;
virtual bool font_is_antialiased(const RID &p_font_rid) const override;
+ virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override;
+ virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override;
+
virtual void font_set_multichannel_signed_distance_field(const RID &p_font_rid, bool p_msdf) override;
virtual bool font_is_multichannel_signed_distance_field(const RID &p_font_rid) const override;
@@ -453,6 +462,8 @@ public:
virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override;
+ virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
+ virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override;
virtual Dictionary font_get_glyph_contours(const RID &p_font, int64_t p_size, int64_t p_index) const override;
@@ -562,6 +573,8 @@ public:
virtual double shaped_text_get_underline_position(const RID &p_shaped) const override;
virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override;
+ virtual PackedInt32Array string_get_word_breaks(const String &p_string, const String &p_language = "") const override;
+
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
diff --git a/modules/tga/image_loader_tga.cpp b/modules/tga/image_loader_tga.cpp
index 5060c1ab35..08ad1ef9f8 100644
--- a/modules/tga/image_loader_tga.cpp
+++ b/modules/tga/image_loader_tga.cpp
@@ -230,7 +230,7 @@ Error ImageLoaderTGA::convert_to_image(Ref<Image> p_image, const uint8_t *p_buff
return OK;
}
-Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderTGA::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -330,7 +330,6 @@ Error ImageLoaderTGA::load_image(Ref<Image> p_image, FileAccess *f, bool p_force
}
}
- f->close();
return err;
}
@@ -339,12 +338,14 @@ void ImageLoaderTGA::get_recognized_extensions(List<String> *p_extensions) const
}
static Ref<Image> _tga_mem_loader_func(const uint8_t *p_tga, int p_size) {
- FileAccessMemory memfile;
- Error open_memfile_error = memfile.open_custom(p_tga, p_size);
+ Ref<FileAccessMemory> memfile;
+ memfile.instantiate();
+ Error open_memfile_error = memfile->open_custom(p_tga, p_size);
ERR_FAIL_COND_V_MSG(open_memfile_error, Ref<Image>(), "Could not create memfile for TGA image buffer.");
+
Ref<Image> img;
img.instantiate();
- Error load_error = ImageLoaderTGA().load_image(img, &memfile, false, 1.0f);
+ Error load_error = ImageLoaderTGA().load_image(img, memfile, false, 1.0f);
ERR_FAIL_COND_V_MSG(load_error, Ref<Image>(), "Failed to load TGA image.");
return img;
}
diff --git a/modules/tga/image_loader_tga.h b/modules/tga/image_loader_tga.h
index 282a2a1662..9b7cbbac77 100644
--- a/modules/tga/image_loader_tga.h
+++ b/modules/tga/image_loader_tga.h
@@ -73,7 +73,7 @@ class ImageLoaderTGA : public ImageFormatLoader {
static Error convert_to_image(Ref<Image> p_image, const uint8_t *p_buffer, const tga_header_s &p_header, const uint8_t *p_palette, const bool p_is_monochrome, size_t p_input_size);
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTGA();
};
diff --git a/modules/tga/register_types.cpp b/modules/tga/register_types.cpp
index 35f9d10956..520ed5f799 100644
--- a/modules/tga/register_types.cpp
+++ b/modules/tga/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderTGA *image_loader_tga = nullptr;
-void register_tga_types() {
+void initialize_tga_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_tga = memnew(ImageLoaderTGA);
ImageLoader::add_image_format_loader(image_loader_tga);
}
-void unregister_tga_types() {
+void uninitialize_tga_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_tga);
}
diff --git a/modules/tga/register_types.h b/modules/tga/register_types.h
index ae91aa560f..37cdab70dd 100644
--- a/modules/tga/register_types.h
+++ b/modules/tga/register_types.h
@@ -31,7 +31,9 @@
#ifndef TGA_REGISTER_TYPES_H
#define TGA_REGISTER_TYPES_H
-void register_tga_types();
-void unregister_tga_types();
+#include "modules/register_module_types.h"
+
+void initialize_tga_module(ModuleInitializationLevel p_level);
+void uninitialize_tga_module(ModuleInitializationLevel p_level);
#endif // TGA_REGISTER_TYPES_H
diff --git a/modules/theora/register_types.cpp b/modules/theora/register_types.cpp
index f658627574..9ed8a86415 100644
--- a/modules/theora/register_types.cpp
+++ b/modules/theora/register_types.cpp
@@ -34,14 +34,22 @@
static Ref<ResourceFormatLoaderTheora> resource_loader_theora;
-void register_theora_types() {
+void initialize_theora_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
resource_loader_theora.instantiate();
ResourceLoader::add_resource_format_loader(resource_loader_theora, true);
GDREGISTER_CLASS(VideoStreamTheora);
}
-void unregister_theora_types() {
+void uninitialize_theora_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
ResourceLoader::remove_resource_format_loader(resource_loader_theora);
resource_loader_theora.unref();
}
diff --git a/modules/theora/register_types.h b/modules/theora/register_types.h
index d0c089ef49..2529b09306 100644
--- a/modules/theora/register_types.h
+++ b/modules/theora/register_types.h
@@ -31,7 +31,9 @@
#ifndef THEORA_REGISTER_TYPES_H
#define THEORA_REGISTER_TYPES_H
-void register_theora_types();
-void unregister_theora_types();
+#include "modules/register_module_types.h"
+
+void initialize_theora_module(ModuleInitializationLevel p_level);
+void uninitialize_theora_module(ModuleInitializationLevel p_level);
#endif // THEORA_REGISTER_TYPES_H
diff --git a/modules/theora/video_stream_theora.cpp b/modules/theora/video_stream_theora.cpp
index 0a4ad96d97..77e370849f 100644
--- a/modules/theora/video_stream_theora.cpp
+++ b/modules/theora/video_stream_theora.cpp
@@ -114,7 +114,7 @@ void VideoStreamPlaybackTheora::video_write() {
}
void VideoStreamPlaybackTheora::clear() {
- if (!file) {
+ if (file.is_null()) {
return;
}
@@ -152,10 +152,7 @@ void VideoStreamPlaybackTheora::clear() {
theora_eos = false;
vorbis_eos = false;
- if (file) {
- memdelete(file);
- }
- file = nullptr;
+ file.unref();
playing = false;
};
@@ -165,11 +162,8 @@ void VideoStreamPlaybackTheora::set_file(const String &p_file) {
th_setup_info *ts = nullptr;
file_name = p_file;
- if (file) {
- memdelete(file);
- }
file = FileAccess::open(p_file, FileAccess::READ);
- ERR_FAIL_COND_MSG(!file, "Cannot open file '" + p_file + "'.");
+ ERR_FAIL_COND_MSG(file.is_null(), "Cannot open file '" + p_file + "'.");
#ifdef THEORA_USE_THREAD_STREAMING
thread_exit = false;
@@ -375,7 +369,7 @@ Ref<Texture2D> VideoStreamPlaybackTheora::get_texture() const {
}
void VideoStreamPlaybackTheora::update(float p_delta) {
- if (!file) {
+ if (file.is_null()) {
return;
}
@@ -506,9 +500,9 @@ void VideoStreamPlaybackTheora::update(float p_delta) {
}
#ifdef THEORA_USE_THREAD_STREAMING
- if (file && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) {
+ if (file.is_valid() && thread_eof && no_theora && theora_eos && ring_buffer.data_left() == 0) {
#else
- if (file && /*!videobuf_ready && */ no_theora && theora_eos) {
+ if (file.is_valid() && /*!videobuf_ready && */ no_theora && theora_eos) {
#endif
//printf("video done, stopping\n");
stop();
@@ -627,7 +621,7 @@ int VideoStreamPlaybackTheora::get_mix_rate() const {
#ifdef THEORA_USE_THREAD_STREAMING
void VideoStreamPlaybackTheora::_streaming_thread(void *ud) {
- VideoStreamPlaybackTheora *vs = (VideoStreamPlaybackTheora *)ud;
+ VideoStreamPlaybackTheora *vs = static_cast<VideoStreamPlaybackTheora *>(ud);
while (!vs->thread_exit) {
//just fill back the buffer
@@ -664,10 +658,6 @@ VideoStreamPlaybackTheora::~VideoStreamPlaybackTheora() {
memdelete(thread_sem);
#endif
clear();
-
- if (file) {
- memdelete(file);
- }
};
void VideoStreamTheora::_bind_methods() {
@@ -679,13 +669,13 @@ void VideoStreamTheora::_bind_methods() {
////////////
-RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
- FileAccess *f = FileAccess::open(p_path, FileAccess::READ);
- if (!f) {
+Ref<Resource> ResourceFormatLoaderTheora::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_use_sub_threads, float *r_progress, CacheMode p_cache_mode) {
+ Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
+ if (f.is_null()) {
if (r_error) {
*r_error = ERR_CANT_OPEN;
}
- return RES();
+ return Ref<Resource>();
}
VideoStreamTheora *stream = memnew(VideoStreamTheora);
@@ -697,8 +687,6 @@ RES ResourceFormatLoaderTheora::load(const String &p_path, const String &p_origi
*r_error = OK;
}
- f->close();
- memdelete(f);
return ogv_stream;
}
diff --git a/modules/theora/video_stream_theora.h b/modules/theora/video_stream_theora.h
index 3bc96908a2..8940ed6aff 100644
--- a/modules/theora/video_stream_theora.h
+++ b/modules/theora/video_stream_theora.h
@@ -56,7 +56,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
Image::Format format = Image::Format::FORMAT_L8;
Vector<uint8_t> frame_data;
int frames_pending = 0;
- FileAccess *file = nullptr;
+ Ref<FileAccess> file;
String file_name;
int audio_frames_wrote = 0;
Point2i size;
@@ -99,7 +99,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
Ref<ImageTexture> texture;
- AudioMixCallback mix_callback;
+ AudioMixCallback mix_callback = nullptr;
void *mix_udata = nullptr;
bool paused = false;
@@ -112,7 +112,7 @@ class VideoStreamPlaybackTheora : public VideoStreamPlayback {
RingBuffer<uint8_t> ring_buffer;
Vector<uint8_t> read_buffer;
bool thread_eof = false;
- Semaphore *thread_sem;
+ Semaphore *thread_sem = nullptr;
Thread thread;
SafeFlag thread_exit;
@@ -186,7 +186,7 @@ public:
class ResourceFormatLoaderTheora : public ResourceFormatLoader {
public:
- virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
+ virtual Ref<Resource> load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_use_sub_threads = false, float *r_progress = nullptr, CacheMode p_cache_mode = CACHE_MODE_REUSE);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
diff --git a/modules/tinyexr/image_loader_tinyexr.cpp b/modules/tinyexr/image_loader_tinyexr.cpp
index 688707a42d..864df765ee 100644
--- a/modules/tinyexr/image_loader_tinyexr.cpp
+++ b/modules/tinyexr/image_loader_tinyexr.cpp
@@ -37,7 +37,7 @@
#include "thirdparty/tinyexr/tinyexr.h"
-Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -47,8 +47,6 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
f->get_buffer(&w[0], src_image_len);
- f->close();
-
// Re-implementation of tinyexr's LoadEXRFromMemory using Godot types to store the Image data
// and Godot's error codes.
// When debugging after updating the thirdparty library, check that we're still in sync with
@@ -232,7 +230,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
}
if (p_force_linear) {
- color = color.to_linear();
+ color = color.srgb_to_linear();
}
*row_w++ = Math::make_half_float(color.r);
@@ -263,7 +261,7 @@ Error ImageLoaderTinyEXR::load_image(Ref<Image> p_image, FileAccess *f, bool p_f
}
if (p_force_linear) {
- color = color.to_linear();
+ color = color.srgb_to_linear();
}
*row_w++ = color.r;
diff --git a/modules/tinyexr/image_loader_tinyexr.h b/modules/tinyexr/image_loader_tinyexr.h
index aba5fdb959..c147861c26 100644
--- a/modules/tinyexr/image_loader_tinyexr.h
+++ b/modules/tinyexr/image_loader_tinyexr.h
@@ -35,7 +35,7 @@
class ImageLoaderTinyEXR : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderTinyEXR();
};
diff --git a/modules/tinyexr/image_saver_tinyexr.cpp b/modules/tinyexr/image_saver_tinyexr.cpp
index 3750994663..5fa6ace827 100644
--- a/modules/tinyexr/image_saver_tinyexr.cpp
+++ b/modules/tinyexr/image_saver_tinyexr.cpp
@@ -275,8 +275,8 @@ Error save_exr(const String &p_path, const Ref<Image> &p_img, bool p_grayscale)
print_error(String("Saving EXR failed. Error: {0}").format(varray(err)));
return ERR_FILE_CANT_WRITE;
} else {
- FileAccessRef ref = FileAccess::open(p_path, FileAccess::WRITE);
- ERR_FAIL_COND_V(!ref, ERR_FILE_CANT_WRITE);
+ Ref<FileAccess> ref = FileAccess::open(p_path, FileAccess::WRITE);
+ ERR_FAIL_COND_V(ref.is_null(), ERR_FILE_CANT_WRITE);
ref->store_buffer(mem, bytes);
free(mem);
}
diff --git a/modules/tinyexr/register_types.cpp b/modules/tinyexr/register_types.cpp
index 0879a55b6e..d49ac23fea 100644
--- a/modules/tinyexr/register_types.cpp
+++ b/modules/tinyexr/register_types.cpp
@@ -35,14 +35,22 @@
static ImageLoaderTinyEXR *image_loader_tinyexr = nullptr;
-void register_tinyexr_types() {
+void initialize_tinyexr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_tinyexr = memnew(ImageLoaderTinyEXR);
ImageLoader::add_image_format_loader(image_loader_tinyexr);
Image::save_exr_func = save_exr;
}
-void unregister_tinyexr_types() {
+void uninitialize_tinyexr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_tinyexr);
Image::save_exr_func = nullptr;
diff --git a/modules/tinyexr/register_types.h b/modules/tinyexr/register_types.h
index 4c34757d8b..bb50e024cb 100644
--- a/modules/tinyexr/register_types.h
+++ b/modules/tinyexr/register_types.h
@@ -31,7 +31,9 @@
#ifndef TINYEXR_REGISTER_TYPES_H
#define TINYEXR_REGISTER_TYPES_H
-void register_tinyexr_types();
-void unregister_tinyexr_types();
+#include "modules/register_module_types.h"
+
+void initialize_tinyexr_module(ModuleInitializationLevel p_level);
+void uninitialize_tinyexr_module(ModuleInitializationLevel p_level);
#endif // TINYEXR_REGISTER_TYPES_H
diff --git a/modules/upnp/register_types.cpp b/modules/upnp/register_types.cpp
index 7345901829..9e041a0c6e 100644
--- a/modules/upnp/register_types.cpp
+++ b/modules/upnp/register_types.cpp
@@ -35,10 +35,17 @@
#include "upnp.h"
#include "upnp_device.h"
-void register_upnp_types() {
+void initialize_upnp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_CLASS(UPNP);
GDREGISTER_CLASS(UPNPDevice);
}
-void unregister_upnp_types() {
+void uninitialize_upnp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/upnp/register_types.h b/modules/upnp/register_types.h
index e4482314f8..ef559cc4e8 100644
--- a/modules/upnp/register_types.h
+++ b/modules/upnp/register_types.h
@@ -31,7 +31,9 @@
#ifndef UPNP_REGISTER_TYPES_H
#define UPNP_REGISTER_TYPES_H
-void register_upnp_types();
-void unregister_upnp_types();
+#include "modules/register_module_types.h"
+
+void initialize_upnp_module(ModuleInitializationLevel p_level);
+void uninitialize_upnp_module(ModuleInitializationLevel p_level);
#endif // UPNP_REGISTER_TYPES_H
diff --git a/modules/vhacd/register_types.cpp b/modules/vhacd/register_types.cpp
index 6242c8faa3..8bb7e780de 100644
--- a/modules/vhacd/register_types.cpp
+++ b/modules/vhacd/register_types.cpp
@@ -89,10 +89,18 @@ static Vector<Vector<Vector3>> convex_decompose(const real_t *p_vertices, int p_
return ret;
}
-void register_vhacd_types() {
+void initialize_vhacd_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Mesh::convex_decomposition_function = convex_decompose;
}
-void unregister_vhacd_types() {
+void uninitialize_vhacd_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
Mesh::convex_decomposition_function = nullptr;
}
diff --git a/modules/vhacd/register_types.h b/modules/vhacd/register_types.h
index e0e34d494d..04ec180cd6 100644
--- a/modules/vhacd/register_types.h
+++ b/modules/vhacd/register_types.h
@@ -31,7 +31,9 @@
#ifndef VHACD_REGISTER_TYPES_H
#define VHACD_REGISTER_TYPES_H
-void register_vhacd_types();
-void unregister_vhacd_types();
+#include "modules/register_module_types.h"
+
+void initialize_vhacd_module(ModuleInitializationLevel p_level);
+void uninitialize_vhacd_module(ModuleInitializationLevel p_level);
#endif // VHACD_REGISTER_TYPES_H
diff --git a/modules/visual_script/doc_classes/VisualScript.xml b/modules/visual_script/doc_classes/VisualScript.xml
index 96310538bf..5807c98d32 100644
--- a/modules/visual_script/doc_classes/VisualScript.xml
+++ b/modules/visual_script/doc_classes/VisualScript.xml
@@ -316,7 +316,7 @@
</method>
<method name="set_scroll">
<return type="void" />
- <argument index="0" name="ofs" type="Vector2" />
+ <argument index="0" name="offset" type="Vector2" />
<description>
Set the screen center to the given position.
</description>
diff --git a/modules/visual_script/editor/visual_script_editor.cpp b/modules/visual_script/editor/visual_script_editor.cpp
index a2e59c9cdf..4847b24f61 100644
--- a/modules/visual_script/editor/visual_script_editor.cpp
+++ b/modules/visual_script/editor/visual_script_editor.cpp
@@ -647,6 +647,14 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons"))
};
+ // Visual script specific theme for MSDF font.
+ Ref<Theme> vstheme;
+ vstheme.instantiate();
+ Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", "EditorFonts");
+ vstheme->set_font("font", "Label", label_font);
+ vstheme->set_font("font", "LineEdit", label_font);
+ vstheme->set_font("font", "Button", label_font);
+
Ref<Texture2D> seq_port = Control::get_theme_icon(SNAME("VisualShaderPort"), SNAME("EditorIcons"));
List<int> node_ids;
script->get_node_list(&node_ids);
@@ -960,9 +968,8 @@ void VisualScriptEditor::_update_graph(int p_only_id) {
slot_idx++;
}
-
graph->add_child(gnode);
-
+ gnode->set_theme(vstheme);
if (gnode->is_comment()) {
graph->move_child(gnode, 0);
}
@@ -1603,12 +1610,12 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
List<VisualScript::DataConnection> data_connections;
script->get_data_connection_list(&data_connections);
- HashMap<int, Set<int>> conn_map;
+ HashMap<int, RBSet<int>> conn_map;
for (const VisualScript::DataConnection &E : data_connections) {
if (E.from_node == p_id && E.from_port == p_port) {
// Push into the connections map.
if (!conn_map.has(E.to_node)) {
- conn_map.set(E.to_node, Set<int>());
+ conn_map.insert(E.to_node, RBSet<int>());
}
conn_map[E.to_node].insert(E.to_port);
}
@@ -1617,11 +1624,9 @@ void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {
undo_redo->add_do_method(vsn.ptr(), "remove_output_data_port", p_port);
undo_redo->add_do_method(this, "_update_graph", p_id);
- List<int> keys;
- conn_map.get_key_list(&keys);
- for (const int &E : keys) {
- for (const Set<int>::Element *F = conn_map[E].front(); F; F = F->next()) {
- undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E, F->get());
+ for (const KeyValue<int, RBSet<int>> &E : conn_map) {
+ for (const RBSet<int>::Element *F = E.value.front(); F; F = F->next()) {
+ undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E.key, F->get());
}
}
@@ -1762,14 +1767,14 @@ void VisualScriptEditor::_on_nodes_paste() {
return;
}
- Map<int, int> remap;
+ HashMap<int, int> remap;
undo_redo->create_action(TTR("Paste VisualScript Nodes"));
int idc = script->get_available_id() + 1;
- Set<int> to_select;
+ RBSet<int> to_select;
- Set<Vector2> existing_positions;
+ RBSet<Vector2> existing_positions;
{
List<int> nodes;
@@ -1808,12 +1813,12 @@ void VisualScriptEditor::_on_nodes_paste() {
undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);
}
- for (Set<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) {
+ for (RBSet<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) {
undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);
}
- for (Set<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) {
+ for (RBSet<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) {
undo_redo->add_do_method(script.ptr(), "data_connect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);
}
@@ -1883,7 +1888,7 @@ void VisualScriptEditor::_on_nodes_delete() {
}
void VisualScriptEditor::_on_nodes_duplicate() {
- Set<int> to_duplicate;
+ RBSet<int> to_duplicate;
for (int i = 0; i < graph->get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
@@ -1902,17 +1907,17 @@ void VisualScriptEditor::_on_nodes_duplicate() {
undo_redo->create_action(TTR("Duplicate VisualScript Nodes"));
int idc = script->get_available_id() + 1;
- Set<int> to_select;
+ RBSet<int> to_select;
HashMap<int, int> remap;
- for (Set<int>::Element *F = to_duplicate.front(); F; F = F->next()) {
+ for (RBSet<int>::Element *F = to_duplicate.front(); F; F = F->next()) {
// Duplicate from the specific function but place it into the default func as it would lack the connections.
Ref<VisualScriptNode> node = script->get_node(F->get());
Ref<VisualScriptNode> dupe = node->duplicate(true);
int new_id = idc++;
- remap.set(F->get(), new_id);
+ remap.insert(F->get(), new_id);
to_select.insert(new_id);
undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F->get()) + Vector2(20, 20));
@@ -2611,11 +2616,11 @@ void VisualScriptEditor::_button_resource_previewed(const String &p_path, const
void VisualScriptEditor::apply_code() {
}
-RES VisualScriptEditor::get_edited_resource() const {
+Ref<Resource> VisualScriptEditor::get_edited_resource() const {
return script;
}
-void VisualScriptEditor::set_edited_resource(const RES &p_res) {
+void VisualScriptEditor::set_edited_resource(const Ref<Resource> &p_res) {
ERR_FAIL_COND(script.is_valid());
ERR_FAIL_COND(p_res.is_null());
script = p_res;
@@ -2727,7 +2732,7 @@ void VisualScriptEditor::_center_on_node(int p_id) {
if (gn) {
gn->set_selected(true);
- Vector2 new_scroll = gn->get_position_offset() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
+ Vector2 new_scroll = gn->get_position_offset() * graph->get_zoom() - graph->get_size() * 0.5 + gn->get_size() * 0.5;
graph->set_scroll_ofs(new_scroll);
script->set_scroll(new_scroll / EDSCALE);
script->set_edited(true);
@@ -3177,7 +3182,7 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro
}
}
-VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes) {
+VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &visited_nodes) {
VisualScriptNode::TypeGuess tg;
tg.type = Variant::NIL;
@@ -3228,7 +3233,7 @@ VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_ac
}
void VisualScriptEditor::_port_action_menu(int p_option) {
- Set<int> vn;
+ RBSet<int> vn;
switch (p_option) {
case CREATE_CALL_SET_GET: {
@@ -3340,7 +3345,7 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
#endif
Vector2 pos = _get_pos_in_graph(port_action_pos);
- Set<int> vn;
+ RBSet<int> vn;
bool port_node_exists = true;
if (drop_position != Vector2()) {
@@ -3390,6 +3395,8 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH);
n->set_base_path(drop_path);
}
+ } else {
+ n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
}
if (drop_node) {
n->set_base_type(drop_node->get_class());
@@ -3702,8 +3709,13 @@ void VisualScriptEditor::_selected_connect_node(const String &p_text, const Stri
Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_type(base_type);
Object::cast_to<VisualScriptTypeCast>(vnode.ptr())->set_base_script(base_script);
} else if (Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())) {
- Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_type(base_type);
- Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_script(base_script);
+ if (base_type_map.has(base_type)) {
+ Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_basic_type(base_type_map[base_type]);
+ Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
+ } else {
+ Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_type(base_type);
+ Object::cast_to<VisualScriptFunctionCall>(vnode.ptr())->set_base_script(base_script);
+ }
} else if (Object::cast_to<VisualScriptPropertySet>(vnode.ptr())) {
Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_type(base_type);
Object::cast_to<VisualScriptPropertySet>(vnode.ptr())->set_base_script(base_script);
@@ -4089,8 +4101,8 @@ void VisualScriptEditor::_menu_option(int p_what) {
} break;
case EDIT_CREATE_FUNCTION: {
// Create Function.
- Map<int, Ref<VisualScriptNode>> nodes;
- Set<int> selections;
+ HashMap<int, Ref<VisualScriptNode>> nodes;
+ RBSet<int> selections;
for (int i = 0; i < graph->get_child_count(); i++) {
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));
if (gn) {
@@ -4113,18 +4125,18 @@ void VisualScriptEditor::_menu_option(int p_what) {
return; // nothing to be done if there are no valid nodes selected
}
- Set<VisualScript::SequenceConnection> seqmove;
- Set<VisualScript::DataConnection> datamove;
+ RBSet<VisualScript::SequenceConnection> seqmove;
+ RBSet<VisualScript::DataConnection> datamove;
- Set<VisualScript::SequenceConnection> seqext;
- Set<VisualScript::DataConnection> dataext;
+ RBSet<VisualScript::SequenceConnection> seqext;
+ RBSet<VisualScript::DataConnection> dataext;
int start_node = -1;
- Set<int> end_nodes;
+ RBSet<int> end_nodes;
if (nodes.size() == 1) {
- Ref<VisualScriptNode> nd = script->get_node(nodes.front()->key());
+ Ref<VisualScriptNode> nd = script->get_node(nodes.begin()->key);
if (nd.is_valid() && nd->has_input_sequence_port()) {
- start_node = nodes.front()->key();
+ start_node = nodes.begin()->key;
} else {
EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port."));
return;
@@ -4162,8 +4174,8 @@ void VisualScriptEditor::_menu_option(int p_what) {
}
} else {
// Pick the node with input sequence.
- Set<int> nodes_from;
- Set<int> nodes_to;
+ RBSet<int> nodes_from;
+ RBSet<int> nodes_to;
for (const VisualScript::SequenceConnection &E : seqs) {
if (nodes.has(E.from_node) && nodes.has(E.to_node)) {
seqmove.insert(E);
@@ -4189,7 +4201,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
// If we still don't have a start node then,
// run through the nodes and select the first tree node,
// i.e. node without any input sequence but output sequence.
- for (Set<int>::Element *E = nodes_from.front(); E; E = E->next()) {
+ for (RBSet<int>::Element *E = nodes_from.front(); E; E = E->next()) {
if (!nodes_to.has(E->get())) {
start_node = E->get();
}
@@ -4260,11 +4272,11 @@ void VisualScriptEditor::_menu_option(int p_what) {
// Move the nodes.
// Handles reconnection of sequence connections on undo, start here in case of issues.
- for (Set<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) {
+ for (RBSet<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) {
undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E->get().from_node, E->get().from_output, E->get().to_node);
undo_redo->add_undo_method(script.ptr(), "sequence_connect", E->get().from_node, E->get().from_output, E->get().to_node);
}
- for (Set<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) {
+ for (RBSet<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) {
undo_redo->add_do_method(script.ptr(), "data_disconnect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
undo_redo->add_undo_method(script.ptr(), "data_connect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);
}
@@ -4274,7 +4286,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
// Could fail with the new changes, start here when searching for bugs in create function shortcut.
int m = 1;
- for (Set<int>::Element *G = end_nodes.front(); G; G = G->next()) {
+ for (RBSet<int>::Element *G = end_nodes.front(); G; G = G->next()) {
Ref<VisualScriptReturn> ret_node;
ret_node.instantiate();
@@ -4326,7 +4338,7 @@ void VisualScriptEditor::_menu_option(int p_what) {
// This is likely going to be very slow and I am not sure if I should keep it,
// but I hope that it will not be a problem considering that we won't be creating functions so frequently,
// and cyclic connections would be a problem but hopefully we won't let them get to this point.
-void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes) {
+void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const RBSet<int> &p_selected, RBSet<int> &r_end_nodes) {
for (const VisualScript::SequenceConnection &E : p_seqs) {
int from = E.from_node;
int to = E.to_node;
@@ -4570,6 +4582,7 @@ VisualScriptEditor::VisualScriptEditor() {
add_child(graph);
graph->set_v_size_flags(Control::SIZE_EXPAND_FILL);
graph->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+ graph->set_show_zoom_label(true);
graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected));
graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move));
graph->connect("end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move));
@@ -4751,6 +4764,35 @@ VisualScriptEditor::VisualScriptEditor() {
popup_menu->add_item(TTR("Duplicate"), EDIT_DUPLICATE_NODES);
popup_menu->add_item(TTR("Clear Copy Buffer"), EDIT_CLEAR_COPY_BUFFER);
popup_menu->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option));
+
+ base_type_map.insert("String", Variant::STRING);
+ base_type_map.insert("Vector2", Variant::VECTOR2);
+ base_type_map.insert("Vector2i", Variant::VECTOR2I);
+ base_type_map.insert("Rect2", Variant::RECT2);
+ base_type_map.insert("Rect2i", Variant::RECT2I);
+ base_type_map.insert("Vector3", Variant::VECTOR3);
+ base_type_map.insert("Vector3i", Variant::VECTOR3I);
+ base_type_map.insert("Transform2D", Variant::TRANSFORM2D);
+ base_type_map.insert("Plane", Variant::PLANE);
+ base_type_map.insert("Quaternion", Variant::QUATERNION);
+ base_type_map.insert("AABB", Variant::AABB);
+ base_type_map.insert("Basis", Variant::BASIS);
+ base_type_map.insert("Transform3D", Variant::TRANSFORM3D);
+ base_type_map.insert("Color", Variant::COLOR);
+ base_type_map.insert("NodePath", Variant::NODE_PATH);
+ base_type_map.insert("RID", Variant::RID);
+ base_type_map.insert("Callable", Variant::CALLABLE);
+ base_type_map.insert("Dictionary", Variant::DICTIONARY);
+ base_type_map.insert("Array", Variant::ARRAY);
+ base_type_map.insert("PackedByteArray", Variant::PACKED_BYTE_ARRAY);
+ base_type_map.insert("PackedInt32Array", Variant::PACKED_INT32_ARRAY);
+ base_type_map.insert("PackedFloat32Array", Variant::PACKED_FLOAT32_ARRAY);
+ base_type_map.insert("PackedInt64Array", Variant::PACKED_INT64_ARRAY);
+ base_type_map.insert("PackedFloat64Array", Variant::PACKED_FLOAT64_ARRAY);
+ base_type_map.insert("PackedStringArray", Variant::PACKED_STRING_ARRAY);
+ base_type_map.insert("PackedVector2Array", Variant::PACKED_VECTOR2_ARRAY);
+ base_type_map.insert("PackedVector3Array", Variant::PACKED_VECTOR3_ARRAY);
+ base_type_map.insert("PackedColorArray", Variant::PACKED_COLOR_ARRAY);
}
VisualScriptEditor::~VisualScriptEditor() {
@@ -4759,7 +4801,7 @@ VisualScriptEditor::~VisualScriptEditor() {
memdelete(variable_editor);
}
-static ScriptEditorBase *create_editor(const RES &p_resource) {
+static ScriptEditorBase *create_editor(const Ref<Resource> &p_resource) {
if (Object::cast_to<VisualScript>(*p_resource)) {
return memnew(VisualScriptEditor);
}
@@ -4803,7 +4845,7 @@ Ref<VisualScriptNode> VisualScriptCustomNodes::create_node_custom(const String &
}
VisualScriptCustomNodes *VisualScriptCustomNodes::singleton = nullptr;
-Map<String, REF> VisualScriptCustomNodes::custom_nodes;
+HashMap<String, Ref<RefCounted>> VisualScriptCustomNodes::custom_nodes;
VisualScriptCustomNodes::VisualScriptCustomNodes() {
singleton = this;
diff --git a/modules/visual_script/editor/visual_script_editor.h b/modules/visual_script/editor/visual_script_editor.h
index 5b355a71df..c7fd8c4a78 100644
--- a/modules/visual_script/editor/visual_script_editor.h
+++ b/modules/visual_script/editor/visual_script_editor.h
@@ -142,8 +142,9 @@ class VisualScriptEditor : public ScriptEditorBase {
Vector<Pair<Variant::Type, String>> args;
};
- Map<StringName, Color> node_colors;
+ HashMap<StringName, Color> node_colors;
HashMap<StringName, Ref<StyleBox>> node_styles;
+ HashMap<StringName, Variant::Type> base_type_map;
void _update_graph_connections();
void _update_graph(int p_only_id = -1);
@@ -158,11 +159,11 @@ class VisualScriptEditor : public ScriptEditorBase {
String _validate_name(const String &p_name) const;
struct Clipboard {
- Map<int, Ref<VisualScriptNode>> nodes;
- Map<int, Vector2> nodes_positions;
+ HashMap<int, Ref<VisualScriptNode>> nodes;
+ HashMap<int, Vector2> nodes_positions;
- Set<VisualScript::SequenceConnection> sequence_connections;
- Set<VisualScript::DataConnection> data_connections;
+ RBSet<VisualScript::SequenceConnection> sequence_connections;
+ RBSet<VisualScript::DataConnection> data_connections;
};
static Clipboard *clipboard;
@@ -212,7 +213,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _end_node_move();
void _move_node(int p_id, const Vector2 &p_to);
- void _get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes);
+ void _get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const RBSet<int> &p_selected, RBSet<int> &r_end_nodes);
void _node_moved(Vector2 p_from, Vector2 p_to, int p_id);
void _remove_node(int p_id);
@@ -286,7 +287,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _draw_color_over_button(Object *obj, Color p_color);
void _button_resource_previewed(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud);
- VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &p_visited_nodes);
+ VisualScriptNode::TypeGuess _guess_output_type(int p_port_action_node, int p_port_action_output, RBSet<int> &p_visited_nodes);
void _member_rmb_selected(const Vector2 &p_pos);
void _member_option(int p_option);
@@ -302,8 +303,8 @@ public:
virtual void set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) override;
virtual void apply_code() override;
- virtual RES get_edited_resource() const override;
- virtual void set_edited_resource(const RES &p_res) override;
+ virtual Ref<Resource> get_edited_resource() const override;
+ virtual void set_edited_resource(const Ref<Resource> &p_res) override;
virtual void enable_editor() override;
virtual Vector<String> get_functions() override;
virtual void reload_text() override;
@@ -358,7 +359,7 @@ protected:
static void _bind_methods();
static VisualScriptCustomNodes *singleton;
- static Map<String, REF> custom_nodes;
+ static HashMap<String, Ref<RefCounted>> custom_nodes;
static Ref<VisualScriptNode> create_node_custom(const String &p_name);
public:
diff --git a/modules/visual_script/editor/visual_script_property_selector.cpp b/modules/visual_script/editor/visual_script_property_selector.cpp
index 31406a2a6f..7557d12526 100644
--- a/modules/visual_script/editor/visual_script_property_selector.cpp
+++ b/modules/visual_script/editor/visual_script_property_selector.cpp
@@ -86,6 +86,13 @@ void VisualScriptPropertySelector::_update_results_s(String p_string) {
_update_results();
}
+void VisualScriptPropertySelector::_update_results_search_all() {
+ if (search_classes->is_pressed()) {
+ scope_combo->select(COMBO_ALL);
+ }
+ _update_results();
+}
+
void VisualScriptPropertySelector::_update_results() {
_update_icons();
search_runner = Ref<SearchRunner>(memnew(SearchRunner(this, results_tree)));
@@ -102,11 +109,7 @@ void VisualScriptPropertySelector::_confirmed() {
}
void VisualScriptPropertySelector::_item_selected() {
- if (results_tree->get_selected()->has_meta("description")) {
- help_bit->set_text(results_tree->get_selected()->get_meta("description"));
- } else {
- help_bit->set_text("No description available");
- }
+ help_bit->set_text(results_tree->get_selected()->get_meta("description", "No description available"));
}
void VisualScriptPropertySelector::_hide_requested() {
@@ -167,7 +170,7 @@ void VisualScriptPropertySelector::select_method_from_base_type(const String &p_
search_properties->set_pressed(false);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -179,7 +182,7 @@ void VisualScriptPropertySelector::select_method_from_base_type(const String &p_
void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_base_script, bool p_virtuals_only, const bool p_connecting, bool clear_text) {
set_title(TTR("Select from base type"));
base_type = p_base;
- base_script = p_base_script.lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name
+ base_script = p_base_script.trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name
type = Variant::NIL;
connecting = p_connecting;
@@ -201,8 +204,7 @@ void VisualScriptPropertySelector::select_from_base_type(const String &p_base, c
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- // When class is Input only show inheritors
- scope_combo->select(0); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated"
+ scope_combo->select(COMBO_RELATED);
results_tree->clear();
show_window(.5f);
@@ -215,7 +217,7 @@ void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_scrip
ERR_FAIL_COND(p_script.is_null());
base_type = p_script->get_instance_base_type();
- base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name
+ base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name
type = Variant::NIL;
script = p_script->get_instance_id();
connecting = p_connecting;
@@ -234,7 +236,7 @@ void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_scrip
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -264,7 +266,7 @@ void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type,
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated" //id5 "Search All"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -294,7 +296,7 @@ void VisualScriptPropertySelector::select_from_action(const String &p_type, cons
search_properties->set_pressed(false);
search_theme_items->set_pressed(false);
- scope_combo->select(0); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated" //id5 "Search All"
+ scope_combo->select(COMBO_RELATED);
results_tree->clear();
show_window(.5f);
@@ -310,7 +312,7 @@ void VisualScriptPropertySelector::select_from_instance(Object *p_instance, cons
if (p_script == nullptr) {
base_script = "";
} else {
- base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name
+ base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name
}
type = Variant::NIL;
@@ -330,7 +332,7 @@ void VisualScriptPropertySelector::select_from_instance(Object *p_instance, cons
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated" //id5 "Search All"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -344,7 +346,7 @@ void VisualScriptPropertySelector::select_from_visual_script(const Ref<Script> &
if (p_script == nullptr) {
base_script = "";
} else {
- base_script = p_script->get_path().lstrip("res://").quote(); // filepath to EditorHelp::get_doc_data().name
+ base_script = p_script->get_path().trim_prefix("res://").quote(); // filepath to EditorHelp::get_doc_data().name
}
type = Variant::NIL;
connecting = false;
@@ -363,7 +365,7 @@ void VisualScriptPropertySelector::select_from_visual_script(const Ref<Script> &
search_properties->set_pressed(true);
search_theme_items->set_pressed(false);
- scope_combo->select(2); //id0 = "Search Related" //id2 = "Search Base" //id3 = "Search Inheriters" //id4 = "Search Unrelated" //id5 "Search All"
+ scope_combo->select(COMBO_BASE);
results_tree->clear();
show_window(.5f);
@@ -418,7 +420,7 @@ VisualScriptPropertySelector::VisualScriptPropertySelector() {
search_classes = memnew(Button);
search_classes->set_flat(true);
search_classes->set_tooltip(TTR("Search Classes"));
- search_classes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results));
+ search_classes->connect("pressed", callable_mp(this, &VisualScriptPropertySelector::_update_results_search_all));
search_classes->set_toggle_mode(true);
search_classes->set_pressed(true);
search_classes->set_focus_mode(Control::FOCUS_NONE);
@@ -724,7 +726,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes_init() {
combined_docs.insert(class_doc.name, class_doc);
}
}
- iterator_doc = combined_docs.front();
+ iterator_doc = combined_docs.begin();
return true;
}
@@ -739,56 +741,53 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_node_classes_build() {
if (vs_nodes.is_empty()) {
return true;
}
- String registerd_node_name = vs_nodes[0];
+ String registered_node_name = vs_nodes[0];
vs_nodes.pop_front();
- Vector<String> path = registerd_node_name.split("/");
+ Vector<String> path = registered_node_name.split("/");
if (path[0] == "constants") {
- _add_class_doc(registerd_node_name, "", "constants");
+ _add_class_doc(registered_node_name, "", "constants");
} else if (path[0] == "custom") {
- _add_class_doc(registerd_node_name, "", "custom");
+ _add_class_doc(registered_node_name, "", "custom");
} else if (path[0] == "data") {
- _add_class_doc(registerd_node_name, "", "data");
+ _add_class_doc(registered_node_name, "", "data");
} else if (path[0] == "flow_control") {
- _add_class_doc(registerd_node_name, "", "flow_control");
+ _add_class_doc(registered_node_name, "", "flow_control");
} else if (path[0] == "functions") {
if (path[1] == "built_in") {
- _add_class_doc(registerd_node_name, "functions", "built_in");
+ _add_class_doc(registered_node_name, "functions", "built_in");
} else if (path[1] == "by_type") {
- if (search_flags & SEARCH_CLASSES) {
- _add_class_doc(registerd_node_name, path[2], "by_type_class");
- }
+ // No action is required.
+ // Using function references from ClassDB to remove confusion for users.
} else if (path[1] == "constructors") {
- if (search_flags & SEARCH_CLASSES) {
- _add_class_doc(registerd_node_name, path[2].substr(0, path[2].find_char('(')), "constructors_class");
- }
+ _add_class_doc(registered_node_name, "", "constructors");
} else if (path[1] == "deconstruct") {
- _add_class_doc(registerd_node_name, "", "deconstruct");
+ _add_class_doc(registered_node_name, "", "deconstruct");
} else if (path[1] == "wait") {
- _add_class_doc(registerd_node_name, "functions", "yield");
+ _add_class_doc(registered_node_name, "functions", "yield");
} else {
- _add_class_doc(registerd_node_name, "functions", "");
+ _add_class_doc(registered_node_name, "functions", "");
}
} else if (path[0] == "index") {
- _add_class_doc(registerd_node_name, "", "index");
+ _add_class_doc(registered_node_name, "", "index");
} else if (path[0] == "operators") {
if (path[1] == "bitwise") {
- _add_class_doc(registerd_node_name, "operators", "bitwise");
+ _add_class_doc(registered_node_name, "operators", "bitwise");
} else if (path[1] == "compare") {
- _add_class_doc(registerd_node_name, "operators", "compare");
+ _add_class_doc(registered_node_name, "operators", "compare");
} else if (path[1] == "logic") {
- _add_class_doc(registerd_node_name, "operators", "logic");
+ _add_class_doc(registered_node_name, "operators", "logic");
} else if (path[1] == "math") {
- _add_class_doc(registerd_node_name, "operators", "math");
+ _add_class_doc(registered_node_name, "operators", "math");
} else {
- _add_class_doc(registerd_node_name, "operators", "");
+ _add_class_doc(registered_node_name, "operators", "");
}
}
return false;
}
bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes() {
- DocData::ClassDoc &class_doc = iterator_doc->value();
+ DocData::ClassDoc &class_doc = iterator_doc->value;
if (
(!_is_class_disabled_by_feature_profile(class_doc.name) && !_is_class_disabled_by_scope(class_doc.name)) ||
_match_visual_script(class_doc)) {
@@ -910,13 +909,13 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_match_classes() {
}
}
- iterator_doc = iterator_doc->next();
+ ++iterator_doc;
return !iterator_doc;
}
bool VisualScriptPropertySelector::SearchRunner::_phase_class_items_init() {
results_tree->clear();
- iterator_match = matches.front();
+ iterator_match = matches.begin();
root_item = results_tree->create_item();
class_items.clear();
@@ -929,7 +928,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_class_items() {
return true;
}
- ClassMatch &match = iterator_match->value();
+ ClassMatch &match = iterator_match->value;
if (search_flags & SEARCH_SHOW_HIERARCHY) {
if (match.required()) {
@@ -941,12 +940,12 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_class_items() {
}
}
- iterator_match = iterator_match->next();
+ ++iterator_match;
return !iterator_match;
}
bool VisualScriptPropertySelector::SearchRunner::_phase_member_items_init() {
- iterator_match = matches.front();
+ iterator_match = matches.begin();
return true;
}
@@ -956,7 +955,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_member_items() {
return true;
}
- ClassMatch &match = iterator_match->value();
+ ClassMatch &match = iterator_match->value;
TreeItem *parent = (search_flags & SEARCH_SHOW_HIERARCHY) ? class_items[match.doc->name] : root_item;
bool constructor_created = false;
@@ -987,7 +986,7 @@ bool VisualScriptPropertySelector::SearchRunner::_phase_member_items() {
_create_theme_property_item(parent, match.doc, match.theme_properties[i]);
}
- iterator_match = iterator_match->next();
+ ++iterator_match;
return !iterator_match;
}
diff --git a/modules/visual_script/editor/visual_script_property_selector.h b/modules/visual_script/editor/visual_script_property_selector.h
index 6b5112f1af..91d81bba47 100644
--- a/modules/visual_script/editor/visual_script_property_selector.h
+++ b/modules/visual_script/editor/visual_script_property_selector.h
@@ -62,23 +62,32 @@ class VisualScriptPropertySelector : public ConfirmationDialog {
SCOPE_ALL = SCOPE_BASE | SCOPE_INHERITERS | SCOPE_UNRELATED
};
- LineEdit *search_box;
+ enum ScopeCombo {
+ COMBO_RELATED,
+ COMBO_SEPARATOR,
+ COMBO_BASE,
+ COMBO_INHERITERS,
+ COMBO_UNRELATED,
+ COMBO_ALL,
+ };
+
+ LineEdit *search_box = nullptr;
- Button *case_sensitive_button;
- Button *hierarchy_button;
+ Button *case_sensitive_button = nullptr;
+ Button *hierarchy_button = nullptr;
- Button *search_visual_script_nodes;
- Button *search_classes;
- Button *search_operators;
+ Button *search_visual_script_nodes = nullptr;
+ Button *search_classes = nullptr;
+ Button *search_operators = nullptr;
- Button *search_methods;
- Button *search_signals;
- Button *search_constants;
- Button *search_properties;
- Button *search_theme_items;
+ Button *search_methods = nullptr;
+ Button *search_signals = nullptr;
+ Button *search_constants = nullptr;
+ Button *search_properties = nullptr;
+ Button *search_theme_items = nullptr;
- OptionButton *scope_combo;
- Tree *results_tree;
+ OptionButton *scope_combo = nullptr;
+ Tree *results_tree = nullptr;
class SearchRunner;
Ref<SearchRunner> search_runner;
@@ -88,13 +97,14 @@ class VisualScriptPropertySelector : public ConfirmationDialog {
void _sbox_input(const Ref<InputEvent> &p_ie);
void _update_results_i(int p_int);
void _update_results_s(String p_string);
+ void _update_results_search_all();
void _update_results();
void _confirmed();
void _item_selected();
void _hide_requested();
- EditorHelpBit *help_bit;
+ EditorHelpBit *help_bit = nullptr;
bool properties = false;
bool visual_script_generic = false;
@@ -104,9 +114,9 @@ class VisualScriptPropertySelector : public ConfirmationDialog {
String base_type;
String base_script;
ObjectID script;
- Object *instance;
+ Object *instance = nullptr;
bool virtuals_only = false;
- VBoxContainer *vbox;
+ VBoxContainer *vbox = nullptr;
protected:
void _notification(int p_what);
@@ -159,25 +169,25 @@ class VisualScriptPropertySelector::SearchRunner : public RefCounted {
}
};
- VisualScriptPropertySelector *selector_ui;
- Control *ui_service;
- Tree *results_tree;
+ VisualScriptPropertySelector *selector_ui = nullptr;
+ Control *ui_service = nullptr;
+ Tree *results_tree = nullptr;
String term;
- int search_flags;
- int scope_flags;
+ int search_flags = 0;
+ int scope_flags = 0;
Ref<Texture2D> empty_icon;
Color disabled_color;
- Map<String, DocData::ClassDoc>::Element *iterator_doc = nullptr;
- Map<String, ClassMatch> matches;
- Map<String, ClassMatch>::Element *iterator_match = nullptr;
+ HashMap<String, DocData::ClassDoc>::Iterator iterator_doc;
+ HashMap<String, ClassMatch> matches;
+ HashMap<String, ClassMatch>::Iterator iterator_match;
TreeItem *root_item = nullptr;
- Map<String, TreeItem *> class_items;
+ HashMap<String, TreeItem *> class_items;
TreeItem *matched_item = nullptr;
float match_highest_score = 0;
- Map<String, DocData::ClassDoc> combined_docs;
+ HashMap<String, DocData::ClassDoc> combined_docs;
List<String> vs_nodes;
bool _is_class_disabled_by_feature_profile(const StringName &p_class);
diff --git a/modules/visual_script/register_types.cpp b/modules/visual_script/register_types.cpp
index d19870921d..04a7442d0a 100644
--- a/modules/visual_script/register_types.cpp
+++ b/modules/visual_script/register_types.cpp
@@ -47,95 +47,104 @@ VisualScriptLanguage *visual_script_language = nullptr;
static VisualScriptCustomNodes *vs_custom_nodes_singleton = nullptr;
#endif
-void register_visual_script_types() {
- visual_script_language = memnew(VisualScriptLanguage);
- //script_language_gd->init();
- ScriptServer::register_language(visual_script_language);
-
- GDREGISTER_CLASS(VisualScript);
- GDREGISTER_ABSTRACT_CLASS(VisualScriptNode);
- GDREGISTER_CLASS(VisualScriptFunctionState);
- GDREGISTER_CLASS(VisualScriptFunction);
- GDREGISTER_ABSTRACT_CLASS(VisualScriptLists);
- GDREGISTER_CLASS(VisualScriptComposeArray);
- GDREGISTER_CLASS(VisualScriptOperator);
- GDREGISTER_CLASS(VisualScriptVariableSet);
- GDREGISTER_CLASS(VisualScriptVariableGet);
- GDREGISTER_CLASS(VisualScriptConstant);
- GDREGISTER_CLASS(VisualScriptIndexGet);
- GDREGISTER_CLASS(VisualScriptIndexSet);
- GDREGISTER_CLASS(VisualScriptGlobalConstant);
- GDREGISTER_CLASS(VisualScriptClassConstant);
- GDREGISTER_CLASS(VisualScriptMathConstant);
- GDREGISTER_CLASS(VisualScriptBasicTypeConstant);
- GDREGISTER_CLASS(VisualScriptEngineSingleton);
- GDREGISTER_CLASS(VisualScriptSceneNode);
- GDREGISTER_CLASS(VisualScriptSceneTree);
- GDREGISTER_CLASS(VisualScriptResourcePath);
- GDREGISTER_CLASS(VisualScriptSelf);
- GDREGISTER_CLASS(VisualScriptCustomNode);
- GDREGISTER_CLASS(VisualScriptSubCall);
- GDREGISTER_CLASS(VisualScriptComment);
- GDREGISTER_CLASS(VisualScriptConstructor);
- GDREGISTER_CLASS(VisualScriptLocalVar);
- GDREGISTER_CLASS(VisualScriptLocalVarSet);
- GDREGISTER_CLASS(VisualScriptInputAction);
- GDREGISTER_CLASS(VisualScriptDeconstruct);
- GDREGISTER_CLASS(VisualScriptPreload);
- GDREGISTER_CLASS(VisualScriptTypeCast);
-
- GDREGISTER_CLASS(VisualScriptFunctionCall);
- GDREGISTER_CLASS(VisualScriptPropertySet);
- GDREGISTER_CLASS(VisualScriptPropertyGet);
- //ClassDB::register_type<VisualScriptScriptCall>();
- GDREGISTER_CLASS(VisualScriptEmitSignal);
-
- GDREGISTER_CLASS(VisualScriptReturn);
- GDREGISTER_CLASS(VisualScriptCondition);
- GDREGISTER_CLASS(VisualScriptWhile);
- GDREGISTER_CLASS(VisualScriptIterator);
- GDREGISTER_CLASS(VisualScriptSequence);
- //GDREGISTER_CLASS(VisualScriptInputFilter);
- GDREGISTER_CLASS(VisualScriptSwitch);
- GDREGISTER_CLASS(VisualScriptSelect);
-
- GDREGISTER_CLASS(VisualScriptYield);
- GDREGISTER_CLASS(VisualScriptYieldSignal);
-
- GDREGISTER_CLASS(VisualScriptBuiltinFunc);
-
- GDREGISTER_CLASS(VisualScriptExpression);
-
- register_visual_script_nodes();
- register_visual_script_func_nodes();
- register_visual_script_builtin_func_node();
- register_visual_script_flow_control_nodes();
- register_visual_script_yield_nodes();
- register_visual_script_expression_node();
+void initialize_visual_script_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ visual_script_language = memnew(VisualScriptLanguage);
+ //script_language_gd->init();
+ ScriptServer::register_language(visual_script_language);
+
+ GDREGISTER_CLASS(VisualScript);
+ GDREGISTER_ABSTRACT_CLASS(VisualScriptNode);
+ GDREGISTER_CLASS(VisualScriptFunctionState);
+ GDREGISTER_CLASS(VisualScriptFunction);
+ GDREGISTER_ABSTRACT_CLASS(VisualScriptLists);
+ GDREGISTER_CLASS(VisualScriptComposeArray);
+ GDREGISTER_CLASS(VisualScriptOperator);
+ GDREGISTER_CLASS(VisualScriptVariableSet);
+ GDREGISTER_CLASS(VisualScriptVariableGet);
+ GDREGISTER_CLASS(VisualScriptConstant);
+ GDREGISTER_CLASS(VisualScriptIndexGet);
+ GDREGISTER_CLASS(VisualScriptIndexSet);
+ GDREGISTER_CLASS(VisualScriptGlobalConstant);
+ GDREGISTER_CLASS(VisualScriptClassConstant);
+ GDREGISTER_CLASS(VisualScriptMathConstant);
+ GDREGISTER_CLASS(VisualScriptBasicTypeConstant);
+ GDREGISTER_CLASS(VisualScriptEngineSingleton);
+ GDREGISTER_CLASS(VisualScriptSceneNode);
+ GDREGISTER_CLASS(VisualScriptSceneTree);
+ GDREGISTER_CLASS(VisualScriptResourcePath);
+ GDREGISTER_CLASS(VisualScriptSelf);
+ GDREGISTER_CLASS(VisualScriptCustomNode);
+ GDREGISTER_CLASS(VisualScriptSubCall);
+ GDREGISTER_CLASS(VisualScriptComment);
+ GDREGISTER_CLASS(VisualScriptConstructor);
+ GDREGISTER_CLASS(VisualScriptLocalVar);
+ GDREGISTER_CLASS(VisualScriptLocalVarSet);
+ GDREGISTER_CLASS(VisualScriptInputAction);
+ GDREGISTER_CLASS(VisualScriptDeconstruct);
+ GDREGISTER_CLASS(VisualScriptPreload);
+ GDREGISTER_CLASS(VisualScriptTypeCast);
+
+ GDREGISTER_CLASS(VisualScriptFunctionCall);
+ GDREGISTER_CLASS(VisualScriptPropertySet);
+ GDREGISTER_CLASS(VisualScriptPropertyGet);
+ //ClassDB::register_type<VisualScriptScriptCall>();
+ GDREGISTER_CLASS(VisualScriptEmitSignal);
+
+ GDREGISTER_CLASS(VisualScriptReturn);
+ GDREGISTER_CLASS(VisualScriptCondition);
+ GDREGISTER_CLASS(VisualScriptWhile);
+ GDREGISTER_CLASS(VisualScriptIterator);
+ GDREGISTER_CLASS(VisualScriptSequence);
+ //GDREGISTER_CLASS(VisualScriptInputFilter);
+ GDREGISTER_CLASS(VisualScriptSwitch);
+ GDREGISTER_CLASS(VisualScriptSelect);
+
+ GDREGISTER_CLASS(VisualScriptYield);
+ GDREGISTER_CLASS(VisualScriptYieldSignal);
+
+ GDREGISTER_CLASS(VisualScriptBuiltinFunc);
+
+ GDREGISTER_CLASS(VisualScriptExpression);
+
+ register_visual_script_nodes();
+ register_visual_script_func_nodes();
+ register_visual_script_builtin_func_node();
+ register_visual_script_flow_control_nodes();
+ register_visual_script_yield_nodes();
+ register_visual_script_expression_node();
+ }
#ifdef TOOLS_ENABLED
- ClassDB::set_current_api(ClassDB::API_EDITOR);
- GDREGISTER_CLASS(VisualScriptCustomNodes);
- ClassDB::set_current_api(ClassDB::API_CORE);
- vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes);
- Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton()));
-
- VisualScriptEditor::register_editor();
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ ClassDB::set_current_api(ClassDB::API_EDITOR);
+ GDREGISTER_CLASS(VisualScriptCustomNodes);
+ ClassDB::set_current_api(ClassDB::API_CORE);
+ vs_custom_nodes_singleton = memnew(VisualScriptCustomNodes);
+ Engine::get_singleton()->add_singleton(Engine::Singleton("VisualScriptCustomNodes", VisualScriptCustomNodes::get_singleton()));
+
+ VisualScriptEditor::register_editor();
+ }
#endif
}
-void unregister_visual_script_types() {
- unregister_visual_script_nodes();
+void uninitialize_visual_script_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SERVERS) {
+ unregister_visual_script_nodes();
- ScriptServer::unregister_language(visual_script_language);
+ ScriptServer::unregister_language(visual_script_language);
+
+ if (visual_script_language) {
+ memdelete(visual_script_language);
+ }
+ }
#ifdef TOOLS_ENABLED
- VisualScriptEditor::free_clipboard();
- if (vs_custom_nodes_singleton) {
- memdelete(vs_custom_nodes_singleton);
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ VisualScriptEditor::free_clipboard();
+ if (vs_custom_nodes_singleton) {
+ memdelete(vs_custom_nodes_singleton);
+ }
}
#endif
- if (visual_script_language) {
- memdelete(visual_script_language);
- }
}
diff --git a/modules/visual_script/register_types.h b/modules/visual_script/register_types.h
index 29768da67f..90f84de11c 100644
--- a/modules/visual_script/register_types.h
+++ b/modules/visual_script/register_types.h
@@ -31,7 +31,9 @@
#ifndef VISUAL_SCRIPT_REGISTER_TYPES_H
#define VISUAL_SCRIPT_REGISTER_TYPES_H
-void register_visual_script_types();
-void unregister_visual_script_types();
+#include "modules/register_module_types.h"
+
+void initialize_visual_script_module(ModuleInitializationLevel p_level);
+void uninitialize_visual_script_module(ModuleInitializationLevel p_level);
#endif // VISUAL_SCRIPT_REGISTER_TYPES_H
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index e8c44e2556..a287b8e69f 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -209,8 +209,9 @@ Vector2 VisualScript::get_scroll() const {
}
void VisualScript::get_function_list(List<StringName> *r_functions) const {
- functions.get_key_list(r_functions);
- // r_functions->sort_custom<StringName::AlphCompare>(); // Don't force sorting.
+ for (const KeyValue<StringName, Function> &E : functions) {
+ r_functions->push_back(E.key);
+ }
}
int VisualScript::get_function_node_id(const StringName &p_name) const {
@@ -229,7 +230,7 @@ void VisualScript::_node_ports_changed(int p_id) {
{
List<SequenceConnection> to_remove;
- for (Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
+ for (RBSet<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id && E->get().from_output >= vsn->get_output_sequence_port_count()) {
to_remove.push_back(E->get());
}
@@ -247,7 +248,7 @@ void VisualScript::_node_ports_changed(int p_id) {
{
List<DataConnection> to_remove;
- for (Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
+ for (RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id && E->get().from_port >= vsn->get_output_value_port_count()) {
to_remove.push_back(E->get());
}
@@ -291,7 +292,7 @@ void VisualScript::remove_node(int p_id) {
{
List<SequenceConnection> to_remove;
- for (Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
+ for (RBSet<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id || E->get().to_node == p_id) {
to_remove.push_back(E->get());
}
@@ -306,7 +307,7 @@ void VisualScript::remove_node(int p_id) {
{
List<DataConnection> to_remove;
- for (Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
+ for (RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().from_node == p_id || E->get().to_node == p_id) {
to_remove.push_back(E->get());
}
@@ -346,7 +347,9 @@ Point2 VisualScript::get_node_position(int p_id) const {
}
void VisualScript::get_node_list(List<int> *r_nodes) const {
- nodes.get_key_list(r_nodes);
+ for (const KeyValue<int, NodeData> &E : nodes) {
+ r_nodes->push_back(E.key);
+ }
}
void VisualScript::sequence_connect(int p_from_node, int p_from_output, int p_to_node) {
@@ -381,7 +384,7 @@ bool VisualScript::has_sequence_connection(int p_from_node, int p_from_output, i
}
void VisualScript::get_sequence_connection_list(List<SequenceConnection> *r_connection) const {
- for (const Set<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
+ for (const RBSet<SequenceConnection>::Element *E = sequence_connections.front(); E; E = E->next()) {
r_connection->push_back(E->get());
}
}
@@ -423,7 +426,7 @@ bool VisualScript::has_data_connection(int p_from_node, int p_from_port, int p_t
}
bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const {
- for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
+ for (const RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().to_node == p_node && E->get().to_port == p_port) {
return true;
}
@@ -432,7 +435,7 @@ bool VisualScript::is_input_value_port_connected(int p_node, int p_port) const {
}
bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port, int *r_node, int *r_port) const {
- for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
+ for (const RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
if (E->get().to_node == p_node && E->get().to_port == p_port) {
*r_node = E->get().from_node;
*r_port = E->get().from_port;
@@ -443,7 +446,7 @@ bool VisualScript::get_input_value_port_connection_source(int p_node, int p_port
}
void VisualScript::get_data_connection_list(List<DataConnection> *r_connection) const {
- for (const Set<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
+ for (const RBSet<DataConnection>::Element *E = data_connections.front(); E; E = E->next()) {
r_connection->push_back(E->get());
}
}
@@ -563,8 +566,9 @@ Dictionary VisualScript::_get_variable_info(const StringName &p_name) const {
}
void VisualScript::get_variable_list(List<StringName> *r_variables) const {
- variables.get_key_list(r_variables);
- // r_variables->sort_custom<StringName::AlphCompare>(); // Don't force it.
+ for (const KeyValue<StringName, Variable> &E : variables) {
+ r_variables->push_back(E.key);
+ }
}
void VisualScript::set_instance_base_type(const StringName &p_type) {
@@ -713,12 +717,11 @@ int VisualScript::get_available_id() const {
// This is infinitely increasing,
// so one might want to implement a better solution,
// if the there is a case for huge number of nodes to be added to visual script.
- List<int> nds;
- nodes.get_key_list(&nds);
+
int max = -1;
- for (const int &E : nds) {
- if (E > max) {
- max = E;
+ for (const KeyValue<int, NodeData> &E : nodes) {
+ if (E.key > max) {
+ max = E.key;
}
}
return (max + 1);
@@ -748,23 +751,20 @@ void VisualScript::_update_placeholders() {
return; // No bother if no placeholders.
}
List<PropertyInfo> pinfo;
- Map<StringName, Variant> values;
+ HashMap<StringName, Variant> values;
- List<StringName> keys;
- variables.get_key_list(&keys);
-
- for (const StringName &E : keys) {
- if (!variables[E]._export) {
+ for (const KeyValue<StringName, Variable> &E : variables) {
+ if (!variables[E.key]._export) {
continue;
}
- PropertyInfo p = variables[E].info;
- p.name = String(E);
+ PropertyInfo p = variables[E.key].info;
+ p.name = String(E.key);
pinfo.push_back(p);
- values[p.name] = variables[E].default_value;
+ values[p.name] = variables[E.key].default_value;
}
- for (Set<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
+ for (RBSet<PlaceHolderScriptInstance *>::Element *E = placeholders.front(); E; E = E->next()) {
E->get()->update(pinfo, values);
}
}
@@ -779,20 +779,17 @@ ScriptInstance *VisualScript::instance_create(Object *p_this) {
placeholders.insert(sins);
List<PropertyInfo> pinfo;
- Map<StringName, Variant> values;
+ HashMap<StringName, Variant> values;
- List<StringName> keys;
- variables.get_key_list(&keys);
-
- for (const StringName &E : keys) {
- if (!variables[E]._export) {
+ for (const KeyValue<StringName, Variable> &E : variables) {
+ if (!variables[E.key]._export) {
continue;
}
- PropertyInfo p = variables[E].info;
- p.name = String(E);
+ PropertyInfo p = variables[E.key].info;
+ p.name = String(E.key);
pinfo.push_back(p);
- values[p.name] = variables[E].default_value;
+ values[p.name] = variables[E.key].default_value;
}
sins->update(pinfo, values);
@@ -872,14 +869,11 @@ bool VisualScript::get_property_default_value(const StringName &p_property, Vari
}
void VisualScript::get_script_method_list(List<MethodInfo> *p_list) const {
- List<StringName> funcs;
- functions.get_key_list(&funcs);
-
- for (const StringName &E : funcs) {
+ for (const KeyValue<StringName, Function> &E : functions) {
MethodInfo mi;
- mi.name = E;
- if (functions[E].func_id >= 0) {
- Ref<VisualScriptFunction> func = nodes[functions[E].func_id].node;
+ mi.name = E.key;
+ if (functions[E.key].func_id >= 0) {
+ Ref<VisualScriptFunction> func = nodes[functions[E.key].func_id].node;
if (func.is_valid()) {
for (int i = 0; i < func->get_argument_count(); i++) {
PropertyInfo arg;
@@ -930,6 +924,9 @@ void VisualScript::get_script_property_list(List<PropertyInfo> *p_list) const {
get_variable_list(&vars);
for (const StringName &E : vars) {
+ if (!variables[E]._export) {
+ continue;
+ }
PropertyInfo pi = variables[E].info;
pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
p_list->push_back(pi);
@@ -942,10 +939,8 @@ int VisualScript::get_member_line(const StringName &p_member) const {
#ifdef TOOLS_ENABLED
bool VisualScript::are_subnodes_edited() const {
- List<int> keys;
- nodes.get_key_list(&keys);
- for (const int &F : keys) {
- if (nodes[F].node->is_edited()) {
+ for (const KeyValue<int, NodeData> &F : nodes) {
+ if (F.value.node->is_edited()) {
return true;
}
}
@@ -1014,15 +1009,13 @@ void VisualScript::_set_data(const Dictionary &p_data) {
// Takes all the rpc methods.
rpc_functions.clear();
- List<StringName> fns;
- functions.get_key_list(&fns);
- for (const StringName &E : fns) {
- if (functions[E].func_id >= 0 && nodes.has(functions[E].func_id)) {
- Ref<VisualScriptFunction> vsf = nodes[functions[E].func_id].node;
+ for (const KeyValue<StringName, Function> &E : functions) {
+ if (E.value.func_id >= 0 && nodes.has(E.value.func_id)) {
+ Ref<VisualScriptFunction> vsf = nodes[E.value.func_id].node;
if (vsf.is_valid()) {
if (vsf->get_rpc_mode() != Multiplayer::RPC_MODE_DISABLED) {
Multiplayer::RPCConfig nd;
- nd.name = E;
+ nd.name = E.key;
nd.rpc_mode = vsf->get_rpc_mode();
nd.transfer_mode = Multiplayer::TRANSFER_MODE_RELIABLE; // TODO
if (rpc_functions.find(nd) == -1) {
@@ -1042,13 +1035,11 @@ Dictionary VisualScript::_get_data() const {
d["base_type"] = base_type;
Array vars;
- List<StringName> var_names;
- variables.get_key_list(&var_names);
- for (const StringName &E : var_names) {
- Dictionary var = _get_variable_info(E);
- var["name"] = E; // Make sure it's the right one.
- var["default_value"] = variables[E].default_value;
- var["export"] = variables[E]._export;
+ for (const KeyValue<StringName, Variable> &E : variables) {
+ Dictionary var = _get_variable_info(E.key);
+ var["name"] = E.key; // Make sure it's the right one.
+ var["default_value"] = E.value.default_value;
+ var["export"] = E.value._export;
vars.push_back(var);
}
d["variables"] = vars;
@@ -1070,28 +1061,24 @@ Dictionary VisualScript::_get_data() const {
d["signals"] = sigs;
Array funcs;
- List<StringName> func_names;
- functions.get_key_list(&func_names);
- for (const StringName &E : func_names) {
+ for (const KeyValue<StringName, Function> &E : functions) {
Dictionary func;
- func["name"] = E;
- func["function_id"] = functions[E].func_id;
+ func["name"] = E.key;
+ func["function_id"] = E.value.func_id;
funcs.push_back(func);
}
d["functions"] = funcs;
Array nds;
- List<int> node_ids;
- nodes.get_key_list(&node_ids);
- for (const int &F : node_ids) {
- nds.push_back(F);
- nds.push_back(nodes[F].pos);
- nds.push_back(nodes[F].node);
+ for (const KeyValue<int, NodeData> &F : nodes) {
+ nds.push_back(F.key);
+ nds.push_back(F.value.pos);
+ nds.push_back(F.value.node);
}
d["nodes"] = nds;
Array seqconns;
- for (const Set<SequenceConnection>::Element *F = sequence_connections.front(); F; F = F->next()) {
+ for (const RBSet<SequenceConnection>::Element *F = sequence_connections.front(); F; F = F->next()) {
seqconns.push_back(F->get().from_node);
seqconns.push_back(F->get().from_output);
seqconns.push_back(F->get().to_node);
@@ -1099,7 +1086,7 @@ Dictionary VisualScript::_get_data() const {
d["sequence_connections"] = seqconns;
Array dataconns;
- for (const Set<DataConnection>::Element *F = data_connections.front(); F; F = F->next()) {
+ for (const RBSet<DataConnection>::Element *F = data_connections.front(); F; F = F->next()) {
dataconns.push_back(F->get().from_node);
dataconns.push_back(F->get().from_port);
dataconns.push_back(F->get().to_node);
@@ -1118,7 +1105,7 @@ void VisualScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("has_function", "name"), &VisualScript::has_function);
ClassDB::bind_method(D_METHOD("remove_function", "name"), &VisualScript::remove_function);
ClassDB::bind_method(D_METHOD("rename_function", "name", "new_name"), &VisualScript::rename_function);
- ClassDB::bind_method(D_METHOD("set_scroll", "ofs"), &VisualScript::set_scroll);
+ ClassDB::bind_method(D_METHOD("set_scroll", "offset"), &VisualScript::set_scroll);
ClassDB::bind_method(D_METHOD("get_scroll"), &VisualScript::get_scroll);
ClassDB::bind_method(D_METHOD("add_node", "id", "node", "position"), &VisualScript::add_node, DEFVAL(Point2()));
@@ -1181,10 +1168,10 @@ bool VisualScript::inherits_script(const Ref<Script> &p_script) const {
return this == p_script.ptr(); // There is no inheritance in visual scripts, so this is enough.
}
-Set<int> VisualScript::get_output_sequence_ports_connected(int from_node) {
+RBSet<int> VisualScript::get_output_sequence_ports_connected(int from_node) {
List<VisualScript::SequenceConnection> *sc = memnew(List<VisualScript::SequenceConnection>);
get_sequence_connection_list(sc);
- Set<int> connected;
+ RBSet<int> connected;
for (List<VisualScript::SequenceConnection>::Element *E = sc->front(); E; E = E->next()) {
if (E->get().from_node == from_node) {
connected.insert(E->get().from_output);
@@ -1196,45 +1183,41 @@ Set<int> VisualScript::get_output_sequence_ports_connected(int from_node) {
VisualScript::~VisualScript() {
// Remove all nodes and stuff that hold data refs.
- List<int> nds;
- nodes.get_key_list(&nds);
- for (const int &E : nds) {
- remove_node(E);
+ for (const KeyValue<int, NodeData> &E : nodes) {
+ remove_node(E.key);
}
}
////////////////////////////////////////////
bool VisualScriptInstance::set(const StringName &p_name, const Variant &p_value) {
- Map<StringName, Variant>::Element *E = variables.find(p_name);
+ HashMap<StringName, Variant>::Iterator E = variables.find(p_name);
if (!E) {
return false;
}
- E->get() = p_value;
+ E->value = p_value;
return true;
}
bool VisualScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
- const Map<StringName, Variant>::Element *E = variables.find(p_name);
+ HashMap<StringName, Variant>::ConstIterator E = variables.find(p_name);
if (!E) {
return false;
}
- r_ret = E->get();
+ r_ret = E->value;
return true;
}
void VisualScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const {
- List<StringName> vars;
- script->variables.get_key_list(&vars);
- for (const StringName &E : vars) {
- if (!script->variables[E]._export) {
+ for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) {
+ if (!E.value._export) {
continue;
}
- PropertyInfo p = script->variables[E].info;
- p.name = String(E);
+ PropertyInfo p = E.value.info;
+ p.name = String(E.key);
p.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
p_properties->push_back(p);
}
@@ -1256,13 +1239,11 @@ Variant::Type VisualScriptInstance::get_property_type(const StringName &p_name,
}
void VisualScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
- List<StringName> fns;
- script->functions.get_key_list(&fns);
- for (const StringName &E : fns) {
+ for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) {
MethodInfo mi;
- mi.name = E;
- if (script->functions[E].func_id >= 0 && script->nodes.has(script->functions[E].func_id)) {
- Ref<VisualScriptFunction> vsf = script->nodes[script->functions[E].func_id].node;
+ mi.name = E.key;
+ if (E.value.func_id >= 0 && script->nodes.has(E.value.func_id)) {
+ Ref<VisualScriptFunction> vsf = script->nodes[E.value.func_id].node;
if (vsf.is_valid()) {
for (int i = 0; i < vsf->get_argument_count(); i++) {
PropertyInfo arg;
@@ -1334,9 +1315,9 @@ void VisualScriptInstance::_dependency_step(VisualScriptNodeInstance *node, int
}
Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p_stack, int p_stack_size, VisualScriptNodeInstance *p_node, int p_flow_stack_pos, int p_pass, bool p_resuming_yield, Callable::CallError &r_error) {
- Map<StringName, Function>::Element *F = functions.find(p_method);
+ HashMap<StringName, Function>::Iterator F = functions.find(p_method);
ERR_FAIL_COND_V(!F, Variant());
- Function *f = &F->get();
+ Function *f = &F->value;
// This call goes separate, so it can be yielded and suspended.
Variant *variant_stack = (Variant *)p_stack;
@@ -1708,7 +1689,7 @@ Variant VisualScriptInstance::_call_internal(const StringName &p_method, void *p
Variant VisualScriptInstance::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
r_error.error = Callable::CallError::CALL_OK; //ok by default
- Map<StringName, Function>::Element *F = functions.find(p_method);
+ HashMap<StringName, Function>::Iterator F = functions.find(p_method);
if (!F) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
return Variant();
@@ -1716,7 +1697,7 @@ Variant VisualScriptInstance::callp(const StringName &p_method, const Variant **
VSDEBUG("CALLING: " + String(p_method));
- Function *f = &F->get();
+ Function *f = &F->value;
int total_stack_size = 0;
@@ -1750,14 +1731,14 @@ Variant VisualScriptInstance::callp(const StringName &p_method, const Variant **
memset(pass_stack, 0, f->pass_stack_size * sizeof(int));
- Map<int, VisualScriptNodeInstance *>::Element *E = instances.find(f->node);
+ HashMap<int, VisualScriptNodeInstance *>::Iterator E = instances.find(f->node);
if (!E) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
ERR_FAIL_V_MSG(Variant(), "No VisualScriptFunction node in function.");
}
- VisualScriptNodeInstance *node = E->get();
+ VisualScriptNodeInstance *node = E->value;
if (flow_stack) {
flow_stack[0] = node->get_id();
@@ -1842,19 +1823,15 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
// Setup variables.
{
- List<StringName> keys;
- script->variables.get_key_list(&keys);
- for (const StringName &E : keys) {
- variables[E] = script->variables[E].default_value;
+ for (const KeyValue<StringName, VisualScript::Variable> &E : script->variables) {
+ variables[E.key] = E.value.default_value;
}
}
// Setup functions from sequence trees.
{
- List<StringName> keys;
- script->functions.get_key_list(&keys);
- for (const StringName &E : keys) {
- const VisualScript::Function vsfn = p_script->functions[E];
+ for (const KeyValue<StringName, VisualScript::Function> &E : script->functions) {
+ const VisualScript::Function &vsfn = E.value;
Function function;
function.node = vsfn.func_id;
function.max_stack = 0;
@@ -1862,10 +1839,10 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
function.pass_stack_size = 0;
function.node_count = 0;
- Map<StringName, int> local_var_indices;
+ HashMap<StringName, int> local_var_indices;
if (function.node < 0) {
- VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E));
+ VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No start node in function: " + String(E.key));
ERR_CONTINUE(function.node < 0);
}
@@ -1873,7 +1850,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
Ref<VisualScriptFunction> func_node = script->get_node(vsfn.func_id);
if (func_node.is_null()) {
- VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E));
+ VisualScriptLanguage::singleton->debug_break_parse(get_script()->get_path(), 0, "No VisualScriptFunction typed start node in function: " + String(E.key));
}
ERR_CONTINUE(!func_node.is_valid());
@@ -1884,15 +1861,15 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
max_input_args = MAX(max_input_args, function.argument_count);
}
// Function nodes graphs.
- Set<VisualScript::SequenceConnection> seqconns;
- Set<VisualScript::DataConnection> dataconns;
- Set<int> node_ids;
+ RBSet<VisualScript::SequenceConnection> seqconns;
+ RBSet<VisualScript::DataConnection> dataconns;
+ RBSet<int> node_ids;
node_ids.insert(function.node);
{
List<int> nd_queue;
nd_queue.push_back(function.node);
while (!nd_queue.is_empty()) {
- for (const Set<VisualScript::SequenceConnection>::Element *F = script->sequence_connections.front(); F; F = F->next()) {
+ for (const RBSet<VisualScript::SequenceConnection>::Element *F = script->sequence_connections.front(); F; F = F->next()) {
if (nd_queue.front()->get() == F->get().from_node && !node_ids.has(F->get().to_node)) {
nd_queue.push_back(F->get().to_node);
node_ids.insert(F->get().to_node);
@@ -1904,22 +1881,21 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
nd_queue.pop_front();
}
HashMap<int, HashMap<int, Pair<int, int>>> dc_lut; // :: to -> to_port -> (from, from_port)
- for (const Set<VisualScript::DataConnection>::Element *F = script->data_connections.front(); F; F = F->next()) {
+ for (const RBSet<VisualScript::DataConnection>::Element *F = script->data_connections.front(); F; F = F->next()) {
dc_lut[F->get().to_node][F->get().to_port] = Pair<int, int>(F->get().from_node, F->get().from_port);
}
- for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) {
+ for (const RBSet<int>::Element *F = node_ids.front(); F; F = F->next()) {
nd_queue.push_back(F->get());
}
List<int> dc_keys;
while (!nd_queue.is_empty()) {
int ky = nd_queue.front()->get();
- dc_lut[ky].get_key_list(&dc_keys);
- for (const int &F : dc_keys) {
+ for (const KeyValue<int, Pair<int, int>> &F : dc_lut[ky]) {
VisualScript::DataConnection dc;
- dc.from_node = dc_lut[ky][F].first;
- dc.from_port = dc_lut[ky][F].second;
+ dc.from_node = F.value.first;
+ dc.from_port = F.value.second;
dc.to_node = ky;
- dc.to_port = F;
+ dc.to_port = F.key;
dataconns.insert(dc);
nd_queue.push_back(dc.from_node);
node_ids.insert(dc.from_node);
@@ -1931,7 +1907,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
//Multiple passes are required to set up this complex thing..
//First create the nodes.
- for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) {
+ for (const RBSet<int>::Element *F = node_ids.front(); F; F = F->next()) {
Ref<VisualScriptNode> node = script->nodes[F->get()].node;
VisualScriptNodeInstance *instance = node->instantiate(this); // Create instance.
@@ -2005,7 +1981,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
function.trash_pos = function.max_stack++; // create pos for trash
// Second pass, do data connections.
- for (const Set<VisualScript::DataConnection>::Element *F = dataconns.front(); F; F = F->next()) {
+ for (const RBSet<VisualScript::DataConnection>::Element *F = dataconns.front(); F; F = F->next()) {
VisualScript::DataConnection dc = F->get();
ERR_CONTINUE(!instances.has(dc.from_node));
VisualScriptNodeInstance *from = instances[dc.from_node];
@@ -2032,7 +2008,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
}
// Third pass, do sequence connections.
- for (const Set<VisualScript::SequenceConnection>::Element *F = seqconns.front(); F; F = F->next()) {
+ for (const RBSet<VisualScript::SequenceConnection>::Element *F = seqconns.front(); F; F = F->next()) {
VisualScript::SequenceConnection sc = F->get();
ERR_CONTINUE(!instances.has(sc.from_node));
VisualScriptNodeInstance *from = instances[sc.from_node];
@@ -2046,7 +2022,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
//fourth pass:
// 1) unassigned input ports to default values
// 2) connect unassigned output ports to trash
- for (const Set<int>::Element *F = node_ids.front(); F; F = F->next()) {
+ for (const RBSet<int>::Element *F = node_ids.front(); F; F = F->next()) {
ERR_CONTINUE(!instances.has(F->get()));
Ref<VisualScriptNode> node = script->nodes[F->get()].node;
@@ -2069,7 +2045,7 @@ void VisualScriptInstance::create(const Ref<VisualScript> &p_script, Object *p_o
}
}
- functions[E] = function;
+ functions[E.key] = function;
}
}
}
@@ -2247,7 +2223,7 @@ Ref<Script> VisualScriptLanguage::make_template(const String &p_template, const
return script;
}
-bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, Set<int> *r_safe_lines) const {
+bool VisualScriptLanguage::validate(const String &p_script, const String &p_path, List<String> *r_functions, List<ScriptLanguage::ScriptError> *r_errors, List<ScriptLanguage::Warning> *r_warnings, RBSet<int> *r_safe_lines) const {
return false;
}
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index d72bdf9128..c28ec2268b 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -214,8 +214,8 @@ private:
HashMap<int, NodeData> nodes; // Can be a sparse map.
- Set<SequenceConnection> sequence_connections;
- Set<DataConnection> data_connections;
+ RBSet<SequenceConnection> sequence_connections;
+ RBSet<DataConnection> data_connections;
Vector2 scroll;
@@ -233,15 +233,15 @@ private:
HashMap<StringName, Function> functions;
HashMap<StringName, Variable> variables;
- Map<StringName, Vector<Argument>> custom_signals;
+ HashMap<StringName, Vector<Argument>> custom_signals;
Vector<Multiplayer::RPCConfig> rpc_functions;
- Map<Object *, VisualScriptInstance *> instances;
+ HashMap<Object *, VisualScriptInstance *> instances;
bool is_tool_script;
#ifdef TOOLS_ENABLED
- Set<PlaceHolderScriptInstance *> placeholders;
+ RBSet<PlaceHolderScriptInstance *> placeholders;
// void _update_placeholder(PlaceHolderScriptInstance *p_placeholder);
virtual void _placeholder_erased(PlaceHolderScriptInstance *p_placeholder) override;
void _update_placeholders();
@@ -283,7 +283,7 @@ public:
void sequence_disconnect(int p_from_node, int p_from_output, int p_to_node);
bool has_sequence_connection(int p_from_node, int p_from_output, int p_to_node) const;
void get_sequence_connection_list(List<SequenceConnection> *r_connection) const;
- Set<int> get_output_sequence_ports_connected(int from_node);
+ RBSet<int> get_output_sequence_ports_connected(int from_node);
void data_connect(int p_from_node, int p_from_port, int p_to_node, int p_to_port);
void data_disconnect(int p_from_node, int p_from_port, int p_to_node, int p_to_port);
@@ -317,7 +317,7 @@ public:
void custom_signal_swap_argument(const StringName &p_func, int p_argidx, int p_with_argidx);
void remove_custom_signal(const StringName &p_name);
void rename_custom_signal(const StringName &p_name, const StringName &p_new_name);
- Set<int> get_output_sequence_ports_connected(const String &edited_func, int from_node);
+ RBSet<int> get_output_sequence_ports_connected(const String &edited_func, int from_node);
void get_custom_signal_list(List<StringName> *r_custom_signals) const;
@@ -376,8 +376,8 @@ class VisualScriptInstance : public ScriptInstance {
Object *owner = nullptr;
Ref<VisualScript> script;
- Map<StringName, Variant> variables; // Using variable path, not script.
- Map<int, VisualScriptNodeInstance *> instances;
+ HashMap<StringName, Variant> variables; // Using variable path, not script.
+ HashMap<int, VisualScriptNodeInstance *> instances;
struct Function {
int node = 0;
@@ -389,7 +389,7 @@ class VisualScriptInstance : public ScriptInstance {
int argument_count = 0;
};
- Map<StringName, Function> functions;
+ HashMap<StringName, Function> functions;
Vector<Variant> default_values;
int max_input_args = 0;
@@ -415,22 +415,22 @@ public:
String to_string(bool *r_valid);
bool set_variable(const StringName &p_variable, const Variant &p_value) {
- Map<StringName, Variant>::Element *E = variables.find(p_variable);
+ HashMap<StringName, Variant>::Iterator E = variables.find(p_variable);
if (!E) {
return false;
}
- E->get() = p_value;
+ E->value = p_value;
return true;
}
bool get_variable(const StringName &p_variable, Variant *r_variable) const {
- const Map<StringName, Variant>::Element *E = variables.find(p_variable);
+ HashMap<StringName, Variant>::ConstIterator E = variables.find(p_variable);
if (!E) {
return false;
}
- *r_variable = E->get();
+ *r_variable = E->value;
return true;
}
@@ -480,7 +480,7 @@ public:
typedef Ref<VisualScriptNode> (*VisualScriptNodeRegisterFunc)(const String &p_type);
class VisualScriptLanguage : public ScriptLanguage {
- Map<String, VisualScriptNodeRegisterFunc> register_funcs;
+ HashMap<String, VisualScriptNodeRegisterFunc> register_funcs;
struct CallLevel {
Variant *stack = nullptr;
@@ -495,7 +495,7 @@ class VisualScriptLanguage : public ScriptLanguage {
String _debug_error;
int _debug_call_stack_pos = 0;
int _debug_max_call_stack;
- CallLevel *_call_stack;
+ CallLevel *_call_stack = nullptr;
public:
StringName notification = "_notification";
@@ -570,7 +570,7 @@ public:
virtual void get_string_delimiters(List<String> *p_delimiters) const override;
virtual bool is_using_templates() override;
virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
- virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override;
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, RBSet<int> *r_safe_lines = nullptr) const override;
virtual Script *create_script() const override;
virtual bool has_named_classes() const override;
virtual bool supports_builtin_mode() const override;
diff --git a/modules/visual_script/visual_script_builtin_funcs.cpp b/modules/visual_script/visual_script_builtin_funcs.cpp
index f6bc855a50..44e792869d 100644
--- a/modules/visual_script/visual_script_builtin_funcs.cpp
+++ b/modules/visual_script/visual_script_builtin_funcs.cpp
@@ -989,7 +989,7 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
}
if (p_inputs[0]->is_ref_counted()) {
- REF r = *p_inputs[0];
+ Ref<RefCounted> r = *p_inputs[0];
if (!r.is_valid()) {
return;
}
@@ -1180,16 +1180,16 @@ void VisualScriptBuiltinFunc::exec_func(BuiltinFunc p_func, const Variant **p_in
class VisualScriptNodeInstanceBuiltinFunc : public VisualScriptNodeInstance {
public:
- VisualScriptBuiltinFunc *node;
- VisualScriptInstance *instance;
+ VisualScriptBuiltinFunc *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
VisualScriptBuiltinFunc::BuiltinFunc func;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
VisualScriptBuiltinFunc::exec_func(func, p_inputs, p_outputs[0], r_error, r_error_str);
return 0;
}
diff --git a/modules/visual_script/visual_script_expression.cpp b/modules/visual_script/visual_script_expression.cpp
index fef159bf87..e0f6436094 100644
--- a/modules/visual_script/visual_script_expression.cpp
+++ b/modules/visual_script/visual_script_expression.cpp
@@ -1299,10 +1299,10 @@ bool VisualScriptExpression::_compile_expression() {
class VisualScriptNodeInstanceExpression : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
- VisualScriptExpression *expression;
+ VisualScriptInstance *instance = nullptr;
+ VisualScriptExpression *expression = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//execute by parsing the tree directly
virtual bool _execute(const Variant **p_inputs, VisualScriptExpression::ENode *p_node, Variant &r_ret, String &r_error_str, Callable::CallError &ce) {
switch (p_node->type) {
@@ -1512,7 +1512,7 @@ public:
return false;
}
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!expression->root || expression->error_set) {
r_error_str = expression->error_str;
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
diff --git a/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index d28744a09f..0e63753720 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -119,15 +119,15 @@ void VisualScriptReturn::_bind_methods() {
class VisualScriptNodeInstanceReturn : public VisualScriptNodeInstance {
public:
- VisualScriptReturn *node;
- VisualScriptInstance *instance;
- bool with_value;
+ VisualScriptReturn *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
+ bool with_value = false;
- virtual int get_working_memory_size() const { return 1; }
+ virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (with_value) {
*p_working_mem = *p_inputs[0];
return STEP_EXIT_FUNCTION_BIT;
@@ -213,14 +213,14 @@ void VisualScriptCondition::_bind_methods() {
class VisualScriptNodeInstanceCondition : public VisualScriptNodeInstance {
public:
- VisualScriptCondition *node;
- VisualScriptInstance *instance;
+ VisualScriptCondition *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 1; }
+ //virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) {
return 2;
} else if (p_inputs[0]->operator bool()) {
@@ -293,14 +293,14 @@ void VisualScriptWhile::_bind_methods() {
class VisualScriptNodeInstanceWhile : public VisualScriptNodeInstance {
public:
- VisualScriptWhile *node;
- VisualScriptInstance *instance;
+ VisualScriptWhile *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 1; }
+ //virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool keep_going = p_inputs[0]->operator bool();
if (keep_going) {
@@ -376,14 +376,14 @@ void VisualScriptIterator::_bind_methods() {
class VisualScriptNodeInstanceIterator : public VisualScriptNodeInstance {
public:
- VisualScriptIterator *node;
- VisualScriptInstance *instance;
+ VisualScriptIterator *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- virtual int get_working_memory_size() const { return 2; }
+ virtual int get_working_memory_size() const override { return 2; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_BEGIN_SEQUENCE) {
p_working_mem[0] = *p_inputs[0];
bool valid;
@@ -508,15 +508,15 @@ void VisualScriptSequence::_bind_methods() {
class VisualScriptNodeInstanceSequence : public VisualScriptNodeInstance {
public:
- VisualScriptSequence *node;
- VisualScriptInstance *instance;
- int steps;
+ VisualScriptSequence *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
+ int steps = 0;
- virtual int get_working_memory_size() const { return 1; }
+ virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_BEGIN_SEQUENCE) {
p_working_mem[0] = 0;
}
@@ -596,14 +596,14 @@ String VisualScriptSwitch::get_text() const {
class VisualScriptNodeInstanceSwitch : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
- int case_count;
+ VisualScriptInstance *instance = nullptr;
+ int case_count = 0;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_CONTINUE_SEQUENCE) {
return case_count; //exit
}
@@ -774,15 +774,15 @@ VisualScriptTypeCast::TypeGuess VisualScriptTypeCast::guess_output_type(TypeGues
class VisualScriptNodeInstanceTypeCast : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
StringName base_type;
String script;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Object *obj = *p_inputs[0];
*p_outputs[0] = Variant();
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index 2c9d23e457..483fc8b6c3 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -720,17 +720,17 @@ class VisualScriptNodeInstanceFunctionCall : public VisualScriptNodeInstance {
public:
VisualScriptFunctionCall::CallMode call_mode;
NodePath node_path;
- int input_args;
- bool validate;
- int returns;
+ int input_args = 0;
+ bool validate = false;
+ int returns = 0;
VisualScriptFunctionCall::RPCCallMode rpc_mode;
StringName function;
StringName singleton;
- VisualScriptFunctionCall *node;
- VisualScriptInstance *instance;
+ VisualScriptFunctionCall *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
@@ -765,7 +765,7 @@ public:
return true;
}
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
switch (call_mode) {
case VisualScriptFunctionCall::CALL_MODE_SELF: {
Object *object = instance->get_owner_ptr();
@@ -1462,13 +1462,13 @@ public:
NodePath node_path;
StringName property;
- VisualScriptPropertySet *node;
- VisualScriptInstance *instance;
+ VisualScriptPropertySet *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
VisualScriptPropertySet::AssignOp assign_op;
StringName index;
- bool needs_get;
+ bool needs_get = false;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
@@ -1529,7 +1529,7 @@ public:
}
}
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
switch (call_mode) {
case VisualScriptPropertySet::CALL_MODE_SELF: {
Object *object = instance->get_owner_ptr();
@@ -2152,10 +2152,10 @@ public:
StringName property;
StringName index;
- VisualScriptPropertyGet *node;
- VisualScriptInstance *instance;
+ VisualScriptPropertyGet *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
switch (call_mode) {
case VisualScriptPropertyGet::CALL_MODE_SELF: {
Object *object = instance->get_owner_ptr();
@@ -2362,16 +2362,16 @@ void VisualScriptEmitSignal::_bind_methods() {
class VisualScriptNodeInstanceEmitSignal : public VisualScriptNodeInstance {
public:
- VisualScriptEmitSignal *node;
- VisualScriptInstance *instance;
- int argcount;
+ VisualScriptEmitSignal *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
+ int argcount = 0;
StringName name;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Object *obj = instance->get_owner_ptr();
obj->emit_signalp(name, p_inputs, argcount);
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index b65b9f090a..ac33526ddc 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -271,12 +271,12 @@ Multiplayer::RPCMode VisualScriptFunction::get_rpc_mode() const {
class VisualScriptNodeInstanceFunction : public VisualScriptNodeInstance {
public:
- VisualScriptFunction *node;
- VisualScriptInstance *instance;
+ VisualScriptFunction *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
int ac = node->get_argument_count();
for (int i = 0; i < ac; i++) {
@@ -777,9 +777,9 @@ String VisualScriptComposeArray::get_text() const {
class VisualScriptComposeArrayNode : public VisualScriptNodeInstance {
public:
int input_count = 0;
- virtual int get_working_memory_size() const { return 0; }
+ virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (input_count > 0) {
Array arr;
for (int i = 0; i < input_count; i++) {
@@ -1097,12 +1097,12 @@ void VisualScriptOperator::_bind_methods() {
class VisualScriptNodeInstanceOperator : public VisualScriptNodeInstance {
public:
- bool unary;
+ bool unary = false;
Variant::Operator op;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool valid;
if (unary) {
Variant::evaluate(op, *p_inputs[0], Variant(), *p_outputs[0], valid);
@@ -1220,9 +1220,9 @@ void VisualScriptSelect::_bind_methods() {
class VisualScriptNodeInstanceSelect : public VisualScriptNodeInstance {
public:
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool cond = *p_inputs[0];
if (cond) {
*p_outputs[0] = *p_inputs[1];
@@ -1328,11 +1328,11 @@ void VisualScriptVariableGet::_bind_methods() {
class VisualScriptNodeInstanceVariableGet : public VisualScriptNodeInstance {
public:
- VisualScriptVariableGet *node;
- VisualScriptInstance *instance;
+ VisualScriptVariableGet *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
StringName variable;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!instance->get_variable(variable, p_outputs[0])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = RTR("VariableGet not found in script: ") + "'" + String(variable) + "'";
@@ -1438,13 +1438,13 @@ void VisualScriptVariableSet::_bind_methods() {
class VisualScriptNodeInstanceVariableSet : public VisualScriptNodeInstance {
public:
- VisualScriptVariableSet *node;
- VisualScriptInstance *instance;
+ VisualScriptVariableSet *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
StringName variable;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!instance->set_variable(variable, *p_inputs[0])) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
r_error_str = RTR("VariableSet not found in script: ") + "'" + String(variable) + "'";
@@ -1561,9 +1561,9 @@ void VisualScriptConstant::_bind_methods() {
class VisualScriptNodeInstanceConstant : public VisualScriptNodeInstance {
public:
Variant constant;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = constant;
return 0;
}
@@ -1654,9 +1654,9 @@ void VisualScriptPreload::_bind_methods() {
class VisualScriptNodeInstancePreload : public VisualScriptNodeInstance {
public:
Ref<Resource> preload;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = preload;
return 0;
}
@@ -1713,9 +1713,9 @@ String VisualScriptIndexGet::get_caption() const {
class VisualScriptNodeInstanceIndexGet : public VisualScriptNodeInstance {
public:
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool valid;
*p_outputs[0] = p_inputs[0]->get(*p_inputs[1], &valid);
@@ -1780,9 +1780,9 @@ String VisualScriptIndexSet::get_caption() const {
class VisualScriptNodeInstanceIndexSet : public VisualScriptNodeInstance {
public:
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
bool valid;
((Variant *)p_inputs[0])->set(*p_inputs[1], *p_inputs[2], &valid);
@@ -1851,10 +1851,9 @@ int VisualScriptGlobalConstant::get_global_constant() {
class VisualScriptNodeInstanceGlobalConstant : public VisualScriptNodeInstance {
public:
- int index;
- //virtual int get_working_memory_size() const { return 0; }
+ int index = 0;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = CoreConstants::get_global_constant_value(index);
return 0;
}
@@ -1963,11 +1962,10 @@ StringName VisualScriptClassConstant::get_base_type() {
class VisualScriptNodeInstanceClassConstant : public VisualScriptNodeInstance {
public:
- int value;
- bool valid;
- //virtual int get_working_memory_size() const { return 0; }
+ int value = 0;
+ bool valid = false;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!valid) {
r_error_str = "Invalid constant name, pick a valid class constant.";
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2098,10 +2096,9 @@ Variant::Type VisualScriptBasicTypeConstant::get_basic_type() const {
class VisualScriptNodeInstanceBasicTypeConstant : public VisualScriptNodeInstance {
public:
Variant value;
- bool valid;
- //virtual int get_working_memory_size() const { return 0; }
+ bool valid = false;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!valid) {
r_error_str = "Invalid constant name, pick a valid basic type constant.";
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2227,10 +2224,9 @@ VisualScriptMathConstant::MathConstant VisualScriptMathConstant::get_math_consta
class VisualScriptNodeInstanceMathConstant : public VisualScriptNodeInstance {
public:
- float value;
- //virtual int get_working_memory_size() const { return 0; }
+ float value = 0.0f;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = value;
return 0;
}
@@ -2320,11 +2316,11 @@ String VisualScriptEngineSingleton::get_singleton() {
class VisualScriptNodeInstanceEngineSingleton : public VisualScriptNodeInstance {
public:
- Object *singleton;
+ Object *singleton = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = singleton;
return 0;
}
@@ -2429,13 +2425,13 @@ NodePath VisualScriptSceneNode::get_node_path() {
class VisualScriptNodeInstanceSceneNode : public VisualScriptNodeInstance {
public:
- VisualScriptSceneNode *node;
- VisualScriptInstance *instance;
+ VisualScriptSceneNode *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
NodePath path;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
if (!node) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2610,12 +2606,12 @@ String VisualScriptSceneTree::get_caption() const {
class VisualScriptNodeInstanceSceneTree : public VisualScriptNodeInstance {
public:
- VisualScriptSceneTree *node;
- VisualScriptInstance *instance;
+ VisualScriptSceneTree *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Node *node = Object::cast_to<Node>(instance->get_owner_ptr());
if (!node) {
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -2709,9 +2705,9 @@ class VisualScriptNodeInstanceResourcePath : public VisualScriptNodeInstance {
public:
String path;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = path;
return 0;
}
@@ -2779,11 +2775,11 @@ String VisualScriptSelf::get_caption() const {
class VisualScriptNodeInstanceSelf : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = instance->get_owner_ptr();
return 0;
}
@@ -2965,14 +2961,14 @@ String VisualScriptCustomNode::get_category() const {
class VisualScriptNodeInstanceCustomNode : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
- VisualScriptCustomNode *node;
- int in_count;
- int out_count;
- int work_mem_size;
-
- virtual int get_working_memory_size() const { return work_mem_size; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ VisualScriptInstance *instance = nullptr;
+ VisualScriptCustomNode *node = nullptr;
+ int in_count = 0;
+ int out_count = 0;
+ int work_mem_size = 0;
+
+ virtual int get_working_memory_size() const override { return work_mem_size; }
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (GDVIRTUAL_IS_OVERRIDDEN_PTR(node, _step)) {
Array in_values;
Array out_values;
@@ -3161,14 +3157,14 @@ String VisualScriptSubCall::get_category() const {
class VisualScriptNodeInstanceSubCall : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
- VisualScriptSubCall *subcall;
- int input_args;
- bool valid;
+ VisualScriptInstance *instance = nullptr;
+ VisualScriptSubCall *subcall = nullptr;
+ int input_args = 0;
+ bool valid = false;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (!valid) {
r_error_str = "Node requires a script with a _subcall(<args>) method to work.";
r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD;
@@ -3281,11 +3277,11 @@ String VisualScriptComment::get_category() const {
class VisualScriptNodeInstanceComment : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
return 0;
}
};
@@ -3380,13 +3376,13 @@ Dictionary VisualScriptConstructor::get_constructor() const {
class VisualScriptNodeInstanceConstructor : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
Variant::Type type;
- int argcount;
+ int argcount = 0;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Callable::CallError ce;
Variant::construct(type, *p_outputs[0], p_inputs, argcount, ce);
if (ce.error != Callable::CallError::CALL_OK) {
@@ -3420,7 +3416,7 @@ VisualScriptConstructor::VisualScriptConstructor() {
type = Variant::NIL;
}
-static Map<String, Pair<Variant::Type, MethodInfo>> constructor_map;
+static HashMap<String, Pair<Variant::Type, MethodInfo>> constructor_map;
static Ref<VisualScriptNode> create_constructor_node(const String &p_name) {
ERR_FAIL_COND_V(!constructor_map.has(p_name), Ref<VisualScriptNode>());
@@ -3497,11 +3493,11 @@ Variant::Type VisualScriptLocalVar::get_var_type() const {
class VisualScriptNodeInstanceLocalVar : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
StringName name;
- virtual int get_working_memory_size() const { return 1; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int get_working_memory_size() const override { return 1; }
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_outputs[0] = *p_working_mem;
return 0;
}
@@ -3604,11 +3600,11 @@ Variant::Type VisualScriptLocalVarSet::get_var_type() const {
class VisualScriptNodeInstanceLocalVarSet : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
StringName name;
- virtual int get_working_memory_size() const { return 1; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int get_working_memory_size() const override { return 1; }
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
*p_working_mem = *p_inputs[0];
*p_outputs[0] = *p_working_mem;
return 0;
@@ -3728,11 +3724,11 @@ VisualScriptInputAction::Mode VisualScriptInputAction::get_action_mode() const {
class VisualScriptNodeInstanceInputAction : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
StringName action;
VisualScriptInputAction::Mode mode;
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
switch (mode) {
case VisualScriptInputAction::MODE_PRESSED: {
*p_outputs[0] = Input::get_singleton()->is_action_pressed(action);
@@ -3906,12 +3902,12 @@ Array VisualScriptDeconstruct::_get_elem_cache() const {
class VisualScriptNodeInstanceDeconstruct : public VisualScriptNodeInstance {
public:
- VisualScriptInstance *instance;
+ VisualScriptInstance *instance = nullptr;
Vector<StringName> outputs;
- //virtual int get_working_memory_size() const { return 0; }
+ //virtual int get_working_memory_size() const override { return 0; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
Variant in = *p_inputs[0];
for (int i = 0; i < outputs.size(); i++) {
diff --git a/modules/visual_script/visual_script_yield_nodes.cpp b/modules/visual_script/visual_script_yield_nodes.cpp
index dcd8815394..96e91a0baf 100644
--- a/modules/visual_script/visual_script_yield_nodes.cpp
+++ b/modules/visual_script/visual_script_yield_nodes.cpp
@@ -93,13 +93,13 @@ String VisualScriptYield::get_text() const {
class VisualScriptNodeInstanceYield : public VisualScriptNodeInstance {
public:
VisualScriptYield::YieldMode mode;
- double wait_time;
+ double wait_time = 0.0;
- virtual int get_working_memory_size() const { return 1; } //yield needs at least 1
+ virtual int get_working_memory_size() const override { return 1; } //yield needs at least 1
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return false; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_RESUME_YIELD) {
return 0; //resuming yield
} else {
@@ -500,17 +500,17 @@ class VisualScriptNodeInstanceYieldSignal : public VisualScriptNodeInstance {
public:
VisualScriptYieldSignal::CallMode call_mode;
NodePath node_path;
- int output_args;
+ int output_args = 0;
StringName signal;
- VisualScriptYieldSignal *node;
- VisualScriptInstance *instance;
+ VisualScriptYieldSignal *node = nullptr;
+ VisualScriptInstance *instance = nullptr;
- virtual int get_working_memory_size() const { return 1; }
+ virtual int get_working_memory_size() const override { return 1; }
//virtual bool is_output_port_unsequenced(int p_idx) const { return false; }
//virtual bool get_output_port_unsequenced(int p_idx,Variant* r_value,Variant* p_working_mem,String &r_error) const { return true; }
- virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) {
+ virtual int step(const Variant **p_inputs, Variant **p_outputs, StartMode p_start_mode, Variant *p_working_mem, Callable::CallError &r_error, String &r_error_str) override {
if (p_start_mode == START_MODE_RESUME_YIELD) {
return 0; //resuming yield
} else {
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
index 5ff5b2339c..b645a48c88 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp
@@ -350,7 +350,6 @@ void AudioStreamOGGVorbis::maybe_update_info() {
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++) {
@@ -369,8 +368,6 @@ void AudioStreamOGGVorbis::maybe_update_info() {
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);
diff --git a/modules/vorbis/register_types.cpp b/modules/vorbis/register_types.cpp
index 1baf7b2edc..7f81f88cdb 100644
--- a/modules/vorbis/register_types.cpp
+++ b/modules/vorbis/register_types.cpp
@@ -33,7 +33,11 @@
#include "audio_stream_ogg_vorbis.h"
#include "resource_importer_ogg_vorbis.h"
-void register_vorbis_types() {
+void initialize_vorbis_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
Ref<ResourceImporterOGGVorbis> ogg_vorbis_importer;
@@ -45,4 +49,8 @@ void register_vorbis_types() {
GDREGISTER_CLASS(AudioStreamPlaybackOGGVorbis);
}
-void unregister_vorbis_types() {}
+void uninitialize_vorbis_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/vorbis/register_types.h b/modules/vorbis/register_types.h
index 666c7e5b9f..74c18b9c04 100644
--- a/modules/vorbis/register_types.h
+++ b/modules/vorbis/register_types.h
@@ -31,7 +31,9 @@
#ifndef VORBIS_REGISTER_TYPES_H
#define VORBIS_REGISTER_TYPES_H
-void register_vorbis_types();
-void unregister_vorbis_types();
+#include "modules/register_module_types.h"
+
+void initialize_vorbis_module(ModuleInitializationLevel p_level);
+void uninitialize_vorbis_module(ModuleInitializationLevel p_level);
#endif // VORBIS_REGISTER_TYPES_H
diff --git a/modules/vorbis/resource_importer_ogg_vorbis.cpp b/modules/vorbis/resource_importer_ogg_vorbis.cpp
index d12e65a96a..7ee6446313 100644
--- a/modules/vorbis/resource_importer_ogg_vorbis.cpp
+++ b/modules/vorbis/resource_importer_ogg_vorbis.cpp
@@ -57,7 +57,7 @@ String ResourceImporterOGGVorbis::get_resource_type() const {
return "AudioStreamOGGVorbis";
}
-bool ResourceImporterOGGVorbis::get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const {
+bool ResourceImporterOGGVorbis::get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const {
return true;
}
@@ -74,13 +74,12 @@ void ResourceImporterOGGVorbis::get_import_options(const String &p_path, List<Im
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "loop_offset"), 0));
}
-Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
+Error ResourceImporterOGGVorbis::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
bool loop = p_options["loop"];
float loop_offset = p_options["loop_offset"];
- FileAccess *f = FileAccess::open(p_source_file, FileAccess::READ);
-
- ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'.");
+ Ref<FileAccess> f = FileAccess::open(p_source_file, FileAccess::READ);
+ ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, "Cannot open file '" + p_source_file + "'.");
uint64_t len = f->get_length();
@@ -90,8 +89,6 @@ Error ResourceImporterOGGVorbis::import(const String &p_source_file, const Strin
f->get_buffer(w, len);
- memdelete(f);
-
Ref<AudioStreamOGGVorbis> ogg_vorbis_stream;
ogg_vorbis_stream.instantiate();
diff --git a/modules/vorbis/resource_importer_ogg_vorbis.h b/modules/vorbis/resource_importer_ogg_vorbis.h
index 07291803a1..3b4a68a1fd 100644
--- a/modules/vorbis/resource_importer_ogg_vorbis.h
+++ b/modules/vorbis/resource_importer_ogg_vorbis.h
@@ -52,9 +52,9 @@ public:
virtual int get_preset_count() const override;
virtual String get_preset_name(int p_idx) const override;
virtual void get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset = 0) const override;
- virtual bool get_option_visibility(const String &p_path, const String &p_option, const Map<StringName, Variant> &p_options) const override;
+ virtual bool get_option_visibility(const String &p_path, const String &p_option, const HashMap<StringName, Variant> &p_options) const override;
- virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
+ virtual Error import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
ResourceImporterOGGVorbis();
};
diff --git a/modules/webp/image_loader_webp.cpp b/modules/webp/image_loader_webp.cpp
index 902e182d83..0e41f6c973 100644
--- a/modules/webp/image_loader_webp.cpp
+++ b/modules/webp/image_loader_webp.cpp
@@ -211,7 +211,7 @@ static Ref<Image> _webp_mem_loader_func(const uint8_t *p_png, int p_size) {
return img;
}
-Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) {
+Error ImageLoaderWEBP::load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale) {
Vector<uint8_t> src_image;
uint64_t src_image_len = f->get_length();
ERR_FAIL_COND_V(src_image_len == 0, ERR_FILE_CORRUPT);
@@ -221,8 +221,6 @@ Error ImageLoaderWEBP::load_image(Ref<Image> p_image, FileAccess *f, bool p_forc
f->get_buffer(&w[0], src_image_len);
- f->close();
-
Error err = webp_load_image_from_buffer(p_image.ptr(), w, src_image_len);
return err;
diff --git a/modules/webp/image_loader_webp.h b/modules/webp/image_loader_webp.h
index 327582ca55..1acd1459a0 100644
--- a/modules/webp/image_loader_webp.h
+++ b/modules/webp/image_loader_webp.h
@@ -35,7 +35,7 @@
class ImageLoaderWEBP : public ImageFormatLoader {
public:
- virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale);
+ virtual Error load_image(Ref<Image> p_image, Ref<FileAccess> f, bool p_force_linear, float p_scale);
virtual void get_recognized_extensions(List<String> *p_extensions) const;
ImageLoaderWEBP();
};
diff --git a/modules/webp/register_types.cpp b/modules/webp/register_types.cpp
index 462c0a0b3d..148e325498 100644
--- a/modules/webp/register_types.cpp
+++ b/modules/webp/register_types.cpp
@@ -34,11 +34,19 @@
static ImageLoaderWEBP *image_loader_webp = nullptr;
-void register_webp_types() {
+void initialize_webp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
image_loader_webp = memnew(ImageLoaderWEBP);
ImageLoader::add_image_format_loader(image_loader_webp);
}
-void unregister_webp_types() {
+void uninitialize_webp_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
memdelete(image_loader_webp);
}
diff --git a/modules/webp/register_types.h b/modules/webp/register_types.h
index 828ef07f9a..6e37dcfb61 100644
--- a/modules/webp/register_types.h
+++ b/modules/webp/register_types.h
@@ -31,7 +31,9 @@
#ifndef WEBP_REGISTER_TYPES_H
#define WEBP_REGISTER_TYPES_H
-void register_webp_types();
-void unregister_webp_types();
+#include "modules/register_module_types.h"
+
+void initialize_webp_module(ModuleInitializationLevel p_level);
+void uninitialize_webp_module(ModuleInitializationLevel p_level);
#endif // WEBP_REGISTER_TYPES_H
diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp
index 283e421e11..09cd538b96 100644
--- a/modules/webrtc/register_types.cpp
+++ b/modules/webrtc/register_types.cpp
@@ -37,7 +37,11 @@
#include "webrtc_data_channel_extension.h"
#include "webrtc_peer_connection_extension.h"
-void register_webrtc_types() {
+void initialize_webrtc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#define SET_HINT(NAME, _VAL_, _MAX_) \
GLOBAL_DEF(NAME, _VAL_); \
ProjectSettings::get_singleton()->set_custom_property_info(NAME, PropertyInfo(Variant::INT, NAME, PROPERTY_HINT_RANGE, "2," #_MAX_ ",1,or_greater"));
@@ -55,4 +59,8 @@ void register_webrtc_types() {
#undef SET_HINT
}
-void unregister_webrtc_types() {}
+void uninitialize_webrtc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/webrtc/register_types.h b/modules/webrtc/register_types.h
index 2e4457beaf..17171d0e0b 100644
--- a/modules/webrtc/register_types.h
+++ b/modules/webrtc/register_types.h
@@ -31,7 +31,9 @@
#ifndef WEBRTC_REGISTER_TYPES_H
#define WEBRTC_REGISTER_TYPES_H
-void register_webrtc_types();
-void unregister_webrtc_types();
+#include "modules/register_module_types.h"
+
+void initialize_webrtc_module(ModuleInitializationLevel p_level);
+void uninitialize_webrtc_module(ModuleInitializationLevel p_level);
#endif // WEBRTC_REGISTER_TYPES_H
diff --git a/modules/webrtc/webrtc_multiplayer_peer.cpp b/modules/webrtc/webrtc_multiplayer_peer.cpp
index 0bc42b104c..6f68b84ad3 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.cpp
+++ b/modules/webrtc/webrtc_multiplayer_peer.cpp
@@ -140,41 +140,41 @@ void WebRTCMultiplayerPeer::poll() {
}
void WebRTCMultiplayerPeer::_find_next_peer() {
- Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(next_packet_peer);
+ HashMap<int, Ref<ConnectedPeer>>::Iterator E = peer_map.find(next_packet_peer);
if (E) {
- E = E->next();
+ ++E;
}
// After last.
while (E) {
- if (!E->get()->connected) {
- E = E->next();
+ if (!E->value->connected) {
+ ++E;
continue;
}
- for (const Ref<WebRTCDataChannel> &F : E->get()->channels) {
+ for (const Ref<WebRTCDataChannel> &F : E->value->channels) {
if (F->get_available_packet_count()) {
- next_packet_peer = E->key();
+ next_packet_peer = E->key;
return;
}
}
- E = E->next();
+ ++E;
}
- E = peer_map.front();
+ E = peer_map.begin();
// Before last
while (E) {
- if (!E->get()->connected) {
- E = E->next();
+ if (!E->value->connected) {
+ ++E;
continue;
}
- for (const Ref<WebRTCDataChannel> &F : E->get()->channels) {
+ for (const Ref<WebRTCDataChannel> &F : E->value->channels) {
if (F->get_available_packet_count()) {
- next_packet_peer = E->key();
+ next_packet_peer = E->key;
return;
}
}
- if (E->key() == (int)next_packet_peer) {
+ if (E->key == (int)next_packet_peer) {
break;
}
- E = E->next();
+ ++E;
}
// No packet found
next_packet_peer = 0;
@@ -354,12 +354,12 @@ Error WebRTCMultiplayerPeer::put_packet(const uint8_t *p_buffer, int p_buffer_si
}
if (target_peer > 0) {
- Map<int, Ref<ConnectedPeer>>::Element *E = peer_map.find(target_peer);
+ HashMap<int, Ref<ConnectedPeer>>::Iterator E = peer_map.find(target_peer);
ERR_FAIL_COND_V_MSG(!E, ERR_INVALID_PARAMETER, "Invalid target peer: " + itos(target_peer) + ".");
- ERR_FAIL_COND_V_MSG(E->value()->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value()->channels.size()));
- ERR_FAIL_COND_V(E->value()->channels[ch].is_null(), ERR_BUG);
- return E->value()->channels[ch]->put_packet(p_buffer, p_buffer_size);
+ ERR_FAIL_COND_V_MSG(E->value->channels.size() <= ch, ERR_INVALID_PARAMETER, vformat("Unable to send packet on channel %d, max channels: %d", ch, E->value->channels.size()));
+ ERR_FAIL_COND_V(E->value->channels[ch].is_null(), ERR_BUG);
+ return E->value->channels[ch]->put_packet(p_buffer, p_buffer_size);
} else {
int exclude = -target_peer;
diff --git a/modules/webrtc/webrtc_multiplayer_peer.h b/modules/webrtc/webrtc_multiplayer_peer.h
index 6675c67867..97550a3e9d 100644
--- a/modules/webrtc/webrtc_multiplayer_peer.h
+++ b/modules/webrtc/webrtc_multiplayer_peer.h
@@ -69,7 +69,7 @@ private:
int next_packet_peer = 0;
bool server_compat = false;
- Map<int, Ref<ConnectedPeer>> peer_map;
+ HashMap<int, Ref<ConnectedPeer>> peer_map;
List<Dictionary> channels_config;
void _peer_to_dict(Ref<ConnectedPeer> p_connected_peer, Dictionary &r_dict);
diff --git a/modules/webrtc/webrtc_peer_connection_js.h b/modules/webrtc/webrtc_peer_connection_js.h
index 3d0b365355..8fa5ea7779 100644
--- a/modules/webrtc/webrtc_peer_connection_js.h
+++ b/modules/webrtc/webrtc_peer_connection_js.h
@@ -63,16 +63,16 @@ private:
static void _on_error(void *p_obj);
public:
- virtual ConnectionState get_connection_state() const;
+ virtual ConnectionState get_connection_state() const override;
- virtual Error initialize(Dictionary configuration = Dictionary());
- virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary());
- virtual Error create_offer();
- virtual Error set_remote_description(String type, String sdp);
- virtual Error set_local_description(String type, String sdp);
- virtual Error add_ice_candidate(String sdpMidName, int sdpMlineIndexName, String sdpName);
- virtual Error poll();
- virtual void close();
+ virtual Error initialize(Dictionary configuration = Dictionary()) override;
+ virtual Ref<WebRTCDataChannel> create_data_channel(String p_channel_name, Dictionary p_channel_config = Dictionary()) override;
+ 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 poll() override;
+ virtual void close() override;
WebRTCPeerConnectionJS();
~WebRTCPeerConnectionJS();
diff --git a/modules/websocket/doc_classes/WebSocketServer.xml b/modules/websocket/doc_classes/WebSocketServer.xml
index ef3279aac4..46b0274de3 100644
--- a/modules/websocket/doc_classes/WebSocketServer.xml
+++ b/modules/websocket/doc_classes/WebSocketServer.xml
@@ -60,6 +60,13 @@
If [code]false[/code] is passed instead (default), you must call [PacketPeer] functions ([code]put_packet[/code], [code]get_packet[/code], etc.), on the [WebSocketPeer] returned via [code]get_peer(id)[/code] to communicate with the peer with given [code]id[/code] (e.g. [code]get_peer(id).get_available_packet_count[/code]).
</description>
</method>
+ <method name="set_extra_headers">
+ <return type="void" />
+ <argument index="0" name="headers" type="PackedStringArray" default="PackedStringArray()" />
+ <description>
+ Sets additional headers to be sent to clients during the HTTP handshake.
+ </description>
+ </method>
<method name="stop">
<return type="void" />
<description>
diff --git a/modules/websocket/emws_client.h b/modules/websocket/emws_client.h
index 61ea0002ea..ca327a56fa 100644
--- a/modules/websocket/emws_client.h
+++ b/modules/websocket/emws_client.h
@@ -53,15 +53,15 @@ private:
static void _esws_on_close(void *obj, int code, const char *reason, int was_clean);
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
- Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>());
- Ref<WebSocketPeer> get_peer(int p_peer_id) const;
- void disconnect_from_host(int p_code = 1000, String p_reason = "");
- IPAddress get_connected_host() const;
- uint16_t get_connected_port() const;
- virtual ConnectionStatus get_connection_status() const;
- int get_max_packet_size() const;
- virtual void poll();
+ Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
+ Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) override;
+ Ref<WebSocketPeer> get_peer(int p_peer_id) const override;
+ void disconnect_from_host(int p_code = 1000, String p_reason = "") override;
+ IPAddress get_connected_host() const override;
+ uint16_t get_connected_port() const override;
+ virtual ConnectionStatus get_connection_status() const override;
+ int get_max_packet_size() const override;
+ virtual void poll() override;
EMWSClient();
~EMWSClient();
};
diff --git a/modules/websocket/emws_peer.h b/modules/websocket/emws_peer.h
index df63d2d801..6bb4552c37 100644
--- a/modules/websocket/emws_peer.h
+++ b/modules/websocket/emws_peer.h
@@ -68,21 +68,21 @@ private:
public:
Error read_msg(const uint8_t *p_data, uint32_t p_size, bool p_is_string);
void set_sock(int p_sock, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size);
- virtual int get_available_packet_count() const;
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
- virtual int get_max_packet_size() const { return _packet_buffer.size(); };
- virtual int get_current_outbound_buffered_amount() const;
+ 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 int get_max_packet_size() const override { return _packet_buffer.size(); };
+ virtual int get_current_outbound_buffered_amount() const override;
- virtual void close(int p_code = 1000, String p_reason = "");
- virtual bool is_connected_to_host() const;
- virtual IPAddress get_connected_host() const;
- virtual uint16_t get_connected_port() const;
+ virtual void close(int p_code = 1000, String p_reason = "") override;
+ virtual bool is_connected_to_host() const override;
+ virtual IPAddress get_connected_host() const override;
+ virtual uint16_t get_connected_port() const override;
- virtual WriteMode get_write_mode() const;
- virtual void set_write_mode(WriteMode p_mode);
- virtual bool was_string_packet() const;
- virtual void set_no_delay(bool p_enabled);
+ virtual WriteMode get_write_mode() const override;
+ virtual void set_write_mode(WriteMode p_mode) override;
+ virtual bool was_string_packet() const override;
+ virtual void set_no_delay(bool p_enabled) override;
EMWSPeer();
~EMWSPeer();
diff --git a/modules/websocket/emws_server.cpp b/modules/websocket/emws_server.cpp
index 53b4a0207d..2033098cad 100644
--- a/modules/websocket/emws_server.cpp
+++ b/modules/websocket/emws_server.cpp
@@ -33,6 +33,9 @@
#include "emws_server.h"
#include "core/os/os.h"
+void EMWSServer::set_extra_headers(const Vector<String> &p_headers) {
+}
+
Error EMWSServer::listen(int p_port, Vector<String> p_protocols, bool gd_mp_api) {
return FAILED;
}
diff --git a/modules/websocket/emws_server.h b/modules/websocket/emws_server.h
index f310c17c9d..ae31d9dbb0 100644
--- a/modules/websocket/emws_server.h
+++ b/modules/websocket/emws_server.h
@@ -41,17 +41,18 @@ class EMWSServer : public WebSocketServer {
GDCIIMPL(EMWSServer, WebSocketServer);
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
- Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false);
- void stop();
- bool is_listening() const;
- bool has_peer(int p_id) const;
- Ref<WebSocketPeer> get_peer(int p_id) const;
- IPAddress get_peer_address(int p_peer_id) const;
- int get_peer_port(int p_peer_id) const;
- void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
- int get_max_packet_size() const;
- virtual void poll();
+ Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
+ void set_extra_headers(const Vector<String> &p_headers) override;
+ Error listen(int p_port, Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override;
+ void stop() override;
+ bool is_listening() const override;
+ bool has_peer(int p_id) const override;
+ Ref<WebSocketPeer> get_peer(int p_id) const override;
+ IPAddress get_peer_address(int p_peer_id) const override;
+ int get_peer_port(int p_peer_id) const override;
+ void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override;
+ int get_max_packet_size() const override;
+ virtual void poll() override;
virtual Vector<String> get_protocols() const;
EMWSServer();
diff --git a/modules/websocket/register_types.cpp b/modules/websocket/register_types.cpp
index 6d63938d4f..f562de111f 100644
--- a/modules/websocket/register_types.cpp
+++ b/modules/websocket/register_types.cpp
@@ -55,25 +55,33 @@ static void _editor_init_callback() {
}
#endif
-void register_websocket_types() {
+void initialize_websocket_module(ModuleInitializationLevel p_level) {
+ if (p_level == MODULE_INITIALIZATION_LEVEL_SCENE) {
#ifdef JAVASCRIPT_ENABLED
- EMWSPeer::make_default();
- EMWSClient::make_default();
- EMWSServer::make_default();
+ EMWSPeer::make_default();
+ EMWSClient::make_default();
+ EMWSServer::make_default();
#else
- WSLPeer::make_default();
- WSLClient::make_default();
- WSLServer::make_default();
+ WSLPeer::make_default();
+ WSLClient::make_default();
+ WSLServer::make_default();
#endif
- GDREGISTER_ABSTRACT_CLASS(WebSocketMultiplayerPeer);
- ClassDB::register_custom_instance_class<WebSocketServer>();
- ClassDB::register_custom_instance_class<WebSocketClient>();
- ClassDB::register_custom_instance_class<WebSocketPeer>();
+ GDREGISTER_ABSTRACT_CLASS(WebSocketMultiplayerPeer);
+ ClassDB::register_custom_instance_class<WebSocketServer>();
+ ClassDB::register_custom_instance_class<WebSocketClient>();
+ ClassDB::register_custom_instance_class<WebSocketPeer>();
+ }
#ifdef TOOLS_ENABLED
- EditorNode::add_init_callback(&_editor_init_callback);
+ if (p_level == MODULE_INITIALIZATION_LEVEL_EDITOR) {
+ EditorNode::add_init_callback(&_editor_init_callback);
+ }
#endif
}
-void unregister_websocket_types() {}
+void uninitialize_websocket_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/modules/websocket/register_types.h b/modules/websocket/register_types.h
index 4ab6c0cfd3..dab42d6ed9 100644
--- a/modules/websocket/register_types.h
+++ b/modules/websocket/register_types.h
@@ -31,7 +31,9 @@
#ifndef WEBSOCKET_REGISTER_TYPES_H
#define WEBSOCKET_REGISTER_TYPES_H
-void register_websocket_types();
-void unregister_websocket_types();
+#include "modules/register_module_types.h"
+
+void initialize_websocket_module(ModuleInitializationLevel p_level);
+void uninitialize_websocket_module(ModuleInitializationLevel p_level);
#endif // WEBSOCKET_REGISTER_TYPES_H
diff --git a/modules/websocket/remote_debugger_peer_websocket.h b/modules/websocket/remote_debugger_peer_websocket.h
index 84f9506625..3227065ded 100644
--- a/modules/websocket/remote_debugger_peer_websocket.h
+++ b/modules/websocket/remote_debugger_peer_websocket.h
@@ -51,14 +51,14 @@ public:
static RemoteDebuggerPeer *create(const String &p_uri);
Error connect_to_host(const String &p_uri);
- bool is_peer_connected();
- int get_max_message_size() const;
- bool has_message();
- Error put_message(const Array &p_arr);
- Array get_message();
- void close();
- void poll();
- bool can_block() const;
+ bool is_peer_connected() override;
+ int get_max_message_size() const override;
+ bool has_message() override;
+ Error put_message(const Array &p_arr) override;
+ Array get_message() override;
+ void close() override;
+ void poll() override;
+ bool can_block() const override;
RemoteDebuggerPeerWebSocket(Ref<WebSocketPeer> p_peer = Ref<WebSocketPeer>());
};
diff --git a/modules/websocket/websocket_multiplayer_peer.h b/modules/websocket/websocket_multiplayer_peer.h
index 43d9d59f38..db529a669d 100644
--- a/modules/websocket/websocket_multiplayer_peer.h
+++ b/modules/websocket/websocket_multiplayer_peer.h
@@ -62,7 +62,7 @@ protected:
};
List<Packet> _incoming_packets;
- Map<int, Ref<WebSocketPeer>> _peer_map;
+ HashMap<int, Ref<WebSocketPeer>> _peer_map;
Packet _current_packet;
bool _is_multiplayer = false;
diff --git a/modules/websocket/websocket_server.cpp b/modules/websocket/websocket_server.cpp
index b3f0140b80..b7851b02c4 100644
--- a/modules/websocket/websocket_server.cpp
+++ b/modules/websocket/websocket_server.cpp
@@ -42,6 +42,7 @@ WebSocketServer::~WebSocketServer() {
void WebSocketServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_listening"), &WebSocketServer::is_listening);
+ ClassDB::bind_method(D_METHOD("set_extra_headers", "headers"), &WebSocketServer::set_extra_headers, DEFVAL(Vector<String>()));
ClassDB::bind_method(D_METHOD("listen", "port", "protocols", "gd_mp_api"), &WebSocketServer::listen, DEFVAL(Vector<String>()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("stop"), &WebSocketServer::stop);
ClassDB::bind_method(D_METHOD("has_peer", "id"), &WebSocketServer::has_peer);
diff --git a/modules/websocket/websocket_server.h b/modules/websocket/websocket_server.h
index f6f3b80045..7bd80851f5 100644
--- a/modules/websocket/websocket_server.h
+++ b/modules/websocket/websocket_server.h
@@ -51,6 +51,7 @@ protected:
uint32_t handshake_timeout = 3000;
public:
+ virtual void set_extra_headers(const Vector<String> &p_headers) = 0;
virtual Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) = 0;
virtual void stop() = 0;
virtual bool is_listening() const = 0;
diff --git a/modules/websocket/wsl_client.cpp b/modules/websocket/wsl_client.cpp
index 1ef571b6ee..478dbb9d47 100644
--- a/modules/websocket/wsl_client.cpp
+++ b/modules/websocket/wsl_client.cpp
@@ -91,6 +91,7 @@ void WSLClient::_do_handshake() {
data->id = 1;
_peer->make_context(data, _in_buf_size, _in_pkt_size, _out_buf_size, _out_pkt_size);
_peer->set_no_delay(true);
+ _status = CONNECTION_CONNECTED;
_on_connect(protocol);
break;
}
@@ -103,15 +104,16 @@ bool WSLClient::_verify_headers(String &r_protocol) {
String s = (char *)_resp_buf;
Vector<String> psa = s.split("\r\n");
int len = psa.size();
- ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers, got: " + itos(len) + ", expected >= 4.");
+ ERR_FAIL_COND_V_MSG(len < 4, false, "Not enough response headers. Got: " + itos(len) + ", expected >= 4.");
Vector<String> req = psa[0].split(" ", false);
- ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code.");
+ ERR_FAIL_COND_V_MSG(req.size() < 2, false, "Invalid protocol or status code. Got '" + psa[0] + "', expected 'HTTP/1.1 101'.");
// Wrong protocol
- ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1" || req[1] != "101", false, "Invalid protocol or status code.");
+ ERR_FAIL_COND_V_MSG(req[0] != "HTTP/1.1", false, "Invalid protocol. Got: '" + req[0] + "', expected 'HTTP/1.1'.");
+ ERR_FAIL_COND_V_MSG(req[1] != "101", false, "Invalid status code. Got: '" + req[1] + "', expected '101'.");
- Map<String, String> headers;
+ HashMap<String, String> headers;
for (int i = 1; i < len; i++) {
Vector<String> header = psa[i].split(":", false, 1);
ERR_FAIL_COND_V_MSG(header.size() != 2, false, "Invalid header -> " + psa[i] + ".");
@@ -137,9 +139,11 @@ bool WSLClient::_verify_headers(String &r_protocol) {
#undef WSL_CHECK
if (_protocols.size() == 0) {
// We didn't request a custom protocol
- ERR_FAIL_COND_V(headers.has("sec-websocket-protocol"), false);
+ ERR_FAIL_COND_V_MSG(headers.has("sec-websocket-protocol"), false, "Received unrequested sub-protocol -> " + headers["sec-websocket-protocol"]);
} else {
- ERR_FAIL_COND_V(!headers.has("sec-websocket-protocol"), false);
+ // We requested at least one custom protocol but didn't receive one
+ ERR_FAIL_COND_V_MSG(!headers.has("sec-websocket-protocol"), false, "Requested sub-protocol(s) but received none.");
+ // Check received sub-protocol was one of those requested.
r_protocol = headers["sec-websocket-protocol"];
bool valid = false;
for (int i = 0; i < _protocols.size(); i++) {
@@ -150,6 +154,7 @@ bool WSLClient::_verify_headers(String &r_protocol) {
break;
}
if (!valid) {
+ ERR_FAIL_V_MSG(false, "Received unrequested sub-protocol -> " + r_protocol);
return false;
}
}
@@ -227,6 +232,7 @@ Error WSLClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
}
request += "\r\n";
_request = request.utf8();
+ _status = CONNECTION_CONNECTING;
return OK;
}
@@ -273,6 +279,7 @@ void WSLClient::poll() {
return; // Not connected.
}
+ _tcp->poll();
switch (_tcp->get_status()) {
case StreamPeerTCP::STATUS_NONE:
// Clean close
@@ -332,21 +339,19 @@ Ref<WebSocketPeer> WSLClient::get_peer(int p_peer_id) const {
}
MultiplayerPeer::ConnectionStatus WSLClient::get_connection_status() const {
+ // This is surprising, but keeps the current behaviour to allow clean close requests.
+ // TODO Refactor WebSocket and split Client/Server/Multiplayer like done in other peers.
if (_peer->is_connected_to_host()) {
return CONNECTION_CONNECTED;
}
-
- if (_tcp->is_connected_to_host() || _resolver_id != IP::RESOLVER_INVALID_ID) {
- return CONNECTION_CONNECTING;
- }
-
- return CONNECTION_DISCONNECTED;
+ return _status;
}
void WSLClient::disconnect_from_host(int p_code, String p_reason) {
_peer->close(p_code, p_reason);
_connection = Ref<StreamPeer>(nullptr);
_tcp = Ref<StreamPeerTCP>(memnew(StreamPeerTCP));
+ _status = CONNECTION_DISCONNECTED;
_key = "";
_host = "";
diff --git a/modules/websocket/wsl_client.h b/modules/websocket/wsl_client.h
index d846e6be00..22d7ffa839 100644
--- a/modules/websocket/wsl_client.h
+++ b/modules/websocket/wsl_client.h
@@ -52,6 +52,7 @@ private:
Ref<WSLPeer> _peer;
Ref<StreamPeerTCP> _tcp;
Ref<StreamPeer> _connection;
+ ConnectionStatus _status = CONNECTION_DISCONNECTED;
CharString _request;
int _requested = 0;
@@ -59,11 +60,9 @@ private:
uint8_t _resp_buf[WSL_MAX_HEADER_SIZE];
int _resp_pos = 0;
- String _response;
-
String _key;
String _host;
- uint16_t _port;
+ uint16_t _port = 0;
Array _ip_candidates;
Vector<String> _protocols;
bool _use_ssl = false;
@@ -73,15 +72,15 @@ private:
bool _verify_headers(String &r_protocol);
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
- Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>());
- int get_max_packet_size() const;
- Ref<WebSocketPeer> get_peer(int p_peer_id) const;
- void disconnect_from_host(int p_code = 1000, String p_reason = "");
- IPAddress get_connected_host() const;
- uint16_t get_connected_port() const;
- virtual ConnectionStatus get_connection_status() const;
- virtual void poll();
+ Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
+ Error connect_to_host(String p_host, String p_path, uint16_t p_port, bool p_ssl, const Vector<String> p_protocol = Vector<String>(), const Vector<String> p_custom_headers = Vector<String>()) override;
+ int get_max_packet_size() const override;
+ Ref<WebSocketPeer> get_peer(int p_peer_id) const override;
+ void disconnect_from_host(int p_code = 1000, String p_reason = "") override;
+ IPAddress get_connected_host() const override;
+ uint16_t get_connected_port() const override;
+ virtual ConnectionStatus get_connection_status() const override;
+ virtual void poll() override;
WSLClient();
~WSLClient();
diff --git a/modules/websocket/wsl_peer.cpp b/modules/websocket/wsl_peer.cpp
index d277eedace..15df4d039c 100644
--- a/modules/websocket/wsl_peer.cpp
+++ b/modules/websocket/wsl_peer.cpp
@@ -146,17 +146,17 @@ void wsl_msg_recv_callback(wslay_event_context_ptr ctx, const struct wslay_event
if (!peer_data->valid || peer_data->closing) {
return;
}
- WSLPeer *peer = (WSLPeer *)peer_data->peer;
+ WSLPeer *peer = static_cast<WSLPeer *>(peer_data->peer);
if (peer->parse_message(arg) != OK) {
return;
}
if (peer_data->is_server) {
- WSLServer *helper = (WSLServer *)peer_data->obj;
+ WSLServer *helper = static_cast<WSLServer *>(peer_data->obj);
helper->_on_peer_packet(peer_data->id);
} else {
- WSLClient *helper = (WSLClient *)peer_data->obj;
+ WSLClient *helper = static_cast<WSLClient *>(peer_data->obj);
helper->_on_peer_packet();
}
}
@@ -184,10 +184,10 @@ Error WSLPeer::parse_message(const wslay_event_on_msg_recv_arg *arg) {
}
if (!wslay_event_get_close_sent(_data->ctx)) {
if (_data->is_server) {
- WSLServer *helper = (WSLServer *)_data->obj;
+ WSLServer *helper = static_cast<WSLServer *>(_data->obj);
helper->_on_close_request(_data->id, close_code, close_reason);
} else {
- WSLClient *helper = (WSLClient *)_data->obj;
+ WSLClient *helper = static_cast<WSLClient *>(_data->obj);
helper->_on_close_request(close_code, close_reason);
}
}
diff --git a/modules/websocket/wsl_peer.h b/modules/websocket/wsl_peer.h
index 555559c6e1..abeecdd537 100644
--- a/modules/websocket/wsl_peer.h
+++ b/modules/websocket/wsl_peer.h
@@ -85,22 +85,22 @@ public:
String close_reason;
void poll(); // Used by client and server.
- virtual int get_available_packet_count() const;
- virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size);
- virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size);
- virtual int get_max_packet_size() const { return _packet_buffer.size(); };
- virtual int get_current_outbound_buffered_amount() const;
+ 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 int get_max_packet_size() const override { return _packet_buffer.size(); };
+ virtual int get_current_outbound_buffered_amount() const override;
virtual void close_now();
- virtual void close(int p_code = 1000, String p_reason = "");
- virtual bool is_connected_to_host() const;
- virtual IPAddress get_connected_host() const;
- virtual uint16_t get_connected_port() const;
-
- virtual WriteMode get_write_mode() const;
- virtual void set_write_mode(WriteMode p_mode);
- virtual bool was_string_packet() const;
- virtual void set_no_delay(bool p_enabled);
+ virtual void close(int p_code = 1000, String p_reason = "") override;
+ virtual bool is_connected_to_host() const override;
+ virtual IPAddress get_connected_host() const override;
+ virtual uint16_t get_connected_port() const override;
+
+ virtual WriteMode get_write_mode() const override;
+ virtual void set_write_mode(WriteMode p_mode) override;
+ virtual bool was_string_packet() const override;
+ virtual void set_no_delay(bool p_enabled) override;
void make_context(PeerData *p_data, unsigned int p_in_buf_size, unsigned int p_in_pkt_size, unsigned int p_out_buf_size, unsigned int p_out_pkt_size);
Error parse_message(const wslay_event_on_msg_recv_arg *arg);
diff --git a/modules/websocket/wsl_server.cpp b/modules/websocket/wsl_server.cpp
index eadd7ef7ac..517b9643f8 100644
--- a/modules/websocket/wsl_server.cpp
+++ b/modules/websocket/wsl_server.cpp
@@ -46,7 +46,7 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols, St
ERR_FAIL_COND_V_MSG(req[0] != "GET" || req[2] != "HTTP/1.1", false, "Invalid method or HTTP version.");
r_resource_name = req[1];
- Map<String, String> headers;
+ HashMap<String, String> headers;
for (int i = 1; i < len; i++) {
Vector<String> header = psa[i].split(":", false, 1);
ERR_FAIL_COND_V_MSG(header.size() != 2, false, "Invalid header -> " + psa[i]);
@@ -96,7 +96,7 @@ bool WSLServer::PendingPeer::_parse_request(const Vector<String> p_protocols, St
return true;
}
-Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name) {
+Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name, const Vector<String> &p_extra_headers) {
if (OS::get_singleton()->get_ticks_msec() - time > p_timeout) {
print_verbose(vformat("WebSocket handshake timed out after %.3f seconds.", p_timeout * 0.001));
return ERR_TIMEOUT;
@@ -141,6 +141,9 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uin
if (!protocol.is_empty()) {
s += "Sec-WebSocket-Protocol: " + protocol + "\r\n";
}
+ for (int i = 0; i < p_extra_headers.size(); i++) {
+ s += p_extra_headers[i] + "\r\n";
+ }
s += "\r\n";
response = s.utf8();
has_request = true;
@@ -167,6 +170,10 @@ Error WSLServer::PendingPeer::do_handshake(const Vector<String> p_protocols, uin
return OK;
}
+void WSLServer::set_extra_headers(const Vector<String> &p_headers) {
+ _extra_headers = p_headers;
+}
+
Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp_api) {
ERR_FAIL_COND_V(is_listening(), ERR_ALREADY_IN_USE);
@@ -183,7 +190,7 @@ Error WSLServer::listen(int p_port, const Vector<String> p_protocols, bool gd_mp
void WSLServer::poll() {
List<int> remove_ids;
for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr();
+ Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr()));
peer->poll();
if (!peer->is_connected_to_host()) {
_on_disconnect(E.key, peer->close_code != -1);
@@ -199,7 +206,7 @@ void WSLServer::poll() {
for (const Ref<PendingPeer> &E : _pending) {
String resource_name;
Ref<PendingPeer> ppeer = E;
- Error err = ppeer->do_handshake(_protocols, handshake_timeout, resource_name);
+ Error err = ppeer->do_handshake(_protocols, handshake_timeout, resource_name, _extra_headers);
if (err == ERR_BUSY) {
continue;
} else if (err != OK) {
@@ -266,7 +273,7 @@ int WSLServer::get_max_packet_size() const {
void WSLServer::stop() {
_server->stop();
for (const KeyValue<int, Ref<WebSocketPeer>> &E : _peer_map) {
- Ref<WSLPeer> peer = (WSLPeer *)E.value.ptr();
+ Ref<WSLPeer> peer = const_cast<WSLPeer *>(static_cast<const WSLPeer *>(E.value.ptr()));
peer->close_now();
}
_pending.clear();
diff --git a/modules/websocket/wsl_server.h b/modules/websocket/wsl_server.h
index 221cae4793..a920e9c665 100644
--- a/modules/websocket/wsl_server.h
+++ b/modules/websocket/wsl_server.h
@@ -62,7 +62,7 @@ private:
CharString response;
int response_sent = 0;
- Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name);
+ Error do_handshake(const Vector<String> p_protocols, uint64_t p_timeout, String &r_resource_name, const Vector<String> &p_extra_headers);
};
int _in_buf_size = DEF_BUF_SHIFT;
@@ -73,19 +73,21 @@ private:
List<Ref<PendingPeer>> _pending;
Ref<TCPServer> _server;
Vector<String> _protocols;
+ Vector<String> _extra_headers;
public:
- Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets);
- Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false);
- void stop();
- bool is_listening() const;
- int get_max_packet_size() const;
- bool has_peer(int p_id) const;
- Ref<WebSocketPeer> get_peer(int p_id) const;
- IPAddress get_peer_address(int p_peer_id) const;
- int get_peer_port(int p_peer_id) const;
- void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "");
- virtual void poll();
+ Error set_buffers(int p_in_buffer, int p_in_packets, int p_out_buffer, int p_out_packets) override;
+ void set_extra_headers(const Vector<String> &p_headers) override;
+ Error listen(int p_port, const Vector<String> p_protocols = Vector<String>(), bool gd_mp_api = false) override;
+ void stop() override;
+ bool is_listening() const override;
+ int get_max_packet_size() const override;
+ bool has_peer(int p_id) const override;
+ Ref<WebSocketPeer> get_peer(int p_id) const override;
+ IPAddress get_peer_address(int p_peer_id) const override;
+ int get_peer_port(int p_peer_id) const override;
+ void disconnect_peer(int p_peer_id, int p_code = 1000, String p_reason = "") override;
+ virtual void poll() override;
WSLServer();
~WSLServer();
diff --git a/modules/webxr/register_types.cpp b/modules/webxr/register_types.cpp
index a15dc93248..cd403a4996 100644
--- a/modules/webxr/register_types.cpp
+++ b/modules/webxr/register_types.cpp
@@ -37,7 +37,11 @@
Ref<WebXRInterfaceJS> webxr;
#endif
-void register_webxr_types() {
+void initialize_webxr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
GDREGISTER_ABSTRACT_CLASS(WebXRInterface);
#ifdef JAVASCRIPT_ENABLED
@@ -46,7 +50,11 @@ void register_webxr_types() {
#endif
}
-void unregister_webxr_types() {
+void uninitialize_webxr_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
#ifdef JAVASCRIPT_ENABLED
if (webxr.is_valid()) {
// uninitialise our interface if it is initialised
diff --git a/modules/webxr/register_types.h b/modules/webxr/register_types.h
index 5dda728099..2ea9bc1169 100644
--- a/modules/webxr/register_types.h
+++ b/modules/webxr/register_types.h
@@ -31,7 +31,9 @@
#ifndef WEBXR_REGISTER_TYPES_H
#define WEBXR_REGISTER_TYPES_H
-void register_webxr_types();
-void unregister_webxr_types();
+#include "modules/register_module_types.h"
+
+void initialize_webxr_module(ModuleInitializationLevel p_level);
+void uninitialize_webxr_module(ModuleInitializationLevel p_level);
#endif // WEBXR_REGISTER_TYPES_H
diff --git a/modules/webxr/webxr_interface_js.cpp b/modules/webxr/webxr_interface_js.cpp
index 06b0e31801..74e744402b 100644
--- a/modules/webxr/webxr_interface_js.cpp
+++ b/modules/webxr/webxr_interface_js.cpp
@@ -59,7 +59,7 @@ void _emwebxr_on_session_started(char *p_reference_space_type) {
ERR_FAIL_COND(interface.is_null());
String reference_space_type = String(p_reference_space_type);
- ((WebXRInterfaceJS *)interface.ptr())->_set_reference_space_type(reference_space_type);
+ static_cast<WebXRInterfaceJS *>(interface.ptr())->_set_reference_space_type(reference_space_type);
interface->emit_signal(SNAME("session_started"));
}
@@ -94,7 +94,7 @@ void _emwebxr_on_controller_changed() {
Ref<XRInterface> interface = xr_server->find_interface("WebXR");
ERR_FAIL_COND(interface.is_null());
- ((WebXRInterfaceJS *)interface.ptr())->_on_controller_changed();
+ static_cast<WebXRInterfaceJS *>(interface.ptr())->_on_controller_changed();
}
extern "C" EMSCRIPTEN_KEEPALIVE void _emwebxr_on_input_event(char *p_signal_name, int p_input_source) {
@@ -291,15 +291,15 @@ void WebXRInterfaceJS::uninitialize() {
Transform3D WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
Transform3D transform;
- transform.basis.elements[0].x = p_js_matrix[0];
- transform.basis.elements[1].x = p_js_matrix[1];
- transform.basis.elements[2].x = p_js_matrix[2];
- transform.basis.elements[0].y = p_js_matrix[4];
- transform.basis.elements[1].y = p_js_matrix[5];
- transform.basis.elements[2].y = p_js_matrix[6];
- transform.basis.elements[0].z = p_js_matrix[8];
- transform.basis.elements[1].z = p_js_matrix[9];
- transform.basis.elements[2].z = p_js_matrix[10];
+ transform.basis.rows[0].x = p_js_matrix[0];
+ transform.basis.rows[1].x = p_js_matrix[1];
+ transform.basis.rows[2].x = p_js_matrix[2];
+ transform.basis.rows[0].y = p_js_matrix[4];
+ transform.basis.rows[1].y = p_js_matrix[5];
+ transform.basis.rows[2].y = p_js_matrix[6];
+ transform.basis.rows[0].z = p_js_matrix[8];
+ transform.basis.rows[1].z = p_js_matrix[9];
+ transform.basis.rows[2].z = p_js_matrix[10];
transform.origin.x = p_js_matrix[12];
transform.origin.y = p_js_matrix[13];
transform.origin.z = p_js_matrix[14];
diff --git a/modules/xatlas_unwrap/register_types.cpp b/modules/xatlas_unwrap/register_types.cpp
index 139df9c735..e9985984a6 100644
--- a/modules/xatlas_unwrap/register_types.cpp
+++ b/modules/xatlas_unwrap/register_types.cpp
@@ -222,9 +222,16 @@ bool xatlas_mesh_lightmap_unwrap_callback(float p_texel_size, const float *p_ver
return true;
}
-void register_xatlas_unwrap_types() {
+void initialize_xatlas_unwrap_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+
array_mesh_lightmap_unwrap_callback = xatlas_mesh_lightmap_unwrap_callback;
}
-void unregister_xatlas_unwrap_types() {
+void uninitialize_xatlas_unwrap_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
}
diff --git a/modules/xatlas_unwrap/register_types.h b/modules/xatlas_unwrap/register_types.h
index 63a985f8c5..f82b5912f4 100644
--- a/modules/xatlas_unwrap/register_types.h
+++ b/modules/xatlas_unwrap/register_types.h
@@ -31,7 +31,9 @@
#ifndef XATLAS_UNWRAP_REGISTER_TYPES_H
#define XATLAS_UNWRAP_REGISTER_TYPES_H
-void register_xatlas_unwrap_types();
-void unregister_xatlas_unwrap_types();
+#include "modules/register_module_types.h"
+
+void initialize_xatlas_unwrap_module(ModuleInitializationLevel p_level);
+void uninitialize_xatlas_unwrap_module(ModuleInitializationLevel p_level);
#endif // XATLAS_UNWRAP_REGISTER_TYPES_H